1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6
7 /*
8 GRE version 0 is specified in rfc1701.
9 GRE version 0 has been respecified in rfc2784 as a subset of rfc1701.
10 GRE version 1, as used by pptp, has been specified in rfc2637.
11 */
12
13
14 /* GRE flag bits */
15 enum {
16 GRE_chksum = (1<<15),
17 GRE_routing = (1<<14),
18 GRE_key = (1<<13),
19 GRE_seq = (1<<12),
20 GRE_srcrt = (1<<11),
21 GRE_recur = (7<<8),
22 GRE_ack = (1<<7),
23 GRE_version = 0x7,
24 };
25
26
27 typedef struct Hdr Hdr;
28 struct Hdr
29 {
30 ushort flags;
31 ushort proto;
32 uchar version;
33 ushort chksum;
34 ushort offset;
35 ulong key;
36 ulong seq;
37 ulong route;
38 ulong ack;
39 };
40
41 enum
42 {
43 Oproto,
44 };
45
46 static Field p_fields[] =
47 {
48 {"proto", Fnum, Oproto, "encapsulated protocol", } ,
49 {0}
50 };
51
52 static Mux p_mux[] =
53 {
54 {"pup", 0x0200, },
55 {"xns", 0x0600, },
56 {"ip", 0x0800, },
57 {"chaos", 0x0804, },
58 {"arp", 0x0806, },
59 {"frarp", 0x0808, },
60 {"vines", 0x0bad, },
61 {"vinesecho", 0x0bae, },
62 {"vinesloop", 0x0baf, },
63 {"ppp", 0x880b, },
64 {"llc", 0x007a, },
65 {"dot1q", 0x8100, },
66 {"eapol", 0x888e, },
67 {0},
68 };
69
70 int
parthdrlen(ushort flags)71 parthdrlen(ushort flags)
72 {
73 return 4 +
74 (flags&GRE_chksum || flags&GRE_routing) ? 4 : 0 +
75 flags&GRE_key ? 4 : 0 +
76 flags&GRE_seq ? 4 : 0 +
77 flags&GRE_ack ? 4 : 0;
78 }
79
80 int
parsehdr(Hdr * h,uchar * s,uchar * e)81 parsehdr(Hdr *h, uchar *s, uchar *e)
82 {
83 uchar *p;
84 uchar n;
85
86 if(e - s < 4)
87 return -1;
88
89 p = s;
90
91 h->flags = NetS(p);
92 p += 2;
93 h->proto = NetS(p);
94 p += 2;
95 h->version = h->flags&GRE_version;
96
97 if(parthdrlen(h->flags) > e - s)
98 return -1;
99
100 if(h->flags&(GRE_chksum|GRE_routing)){
101 h->chksum = NetS(p);
102 p += 2;
103 h->offset = NetS(p);
104 p += 2;
105 }
106 if(h->flags&GRE_key){
107 h->key = NetL(p);
108 p += 4;
109 }
110 if(h->flags&GRE_seq){
111 h->seq = NetL(p);
112 p += 4;
113 }
114 if(h->flags&GRE_ack){
115 h->ack = NetL(p);
116 p += 4;
117 }
118 if(h->flags&GRE_routing){
119 for(;;){
120 if(e - p < 4)
121 return -1;
122 if((n = p[3]) == 0)
123 break;
124 p += n;
125 }
126 }
127
128 return p - s;
129 }
130
131 static void
p_compile(Filter * f)132 p_compile(Filter *f)
133 {
134 Mux *m;
135
136 if(f->op == '='){
137 compile_cmp(gre.name, f, p_fields);
138 return;
139 }
140 for(m = p_mux; m->name != nil; m++)
141 if(strcmp(f->s, m->name) == 0){
142 f->pr = m->pr;
143 f->ulv = m->val;
144 f->subop = Oproto;
145 return;
146 }
147 sysfatal("unknown gre field or protocol: %s", f->s);
148 }
149
150 static int
p_filter(Filter * f,Msg * m)151 p_filter(Filter *f, Msg *m)
152 {
153 Hdr h;
154 int len;
155
156 len = parsehdr(&h, m->ps, m->pe);
157 if(len < 0)
158 return -1;
159 m->ps += len;
160
161 switch(f->subop){
162 case Oproto:
163 return h.proto == f->ulv;
164 }
165 return 0;
166 }
167
168 static int
p_seprint(Msg * m)169 p_seprint(Msg *m)
170 {
171 Hdr h;
172 int len;
173
174 len = parsehdr(&h, m->ps, m->pe);
175 if(len < 0)
176 return -1;
177 m->ps += len;
178
179 demux(p_mux, h.proto, h.proto, m, &dump);
180
181 m->p = seprint(m->p, m->e, "version=%d proto=%#ux flags=%#.4ux", h.version, h.proto, h.flags);
182 if(h.flags&GRE_chksum)
183 m->p = seprint(m->p, m->e, " checksum=%#.4ux", h.chksum);
184 if(h.flags&GRE_key)
185 m->p = seprint(m->p, m->e, " key=%#.8ulx", h.key);
186 if(h.flags&GRE_seq)
187 m->p = seprint(m->p, m->e, " seq=%#.8ulx", h.seq);
188 if(h.flags&GRE_ack)
189 m->p = seprint(m->p, m->e, " ack=%#.8ulx", h.ack);
190 if(h.flags&GRE_routing)
191 m->p = seprint(m->p, m->e, " offset=%#ux haverouting", h.offset);
192 if(h.version == 0)
193 m->p = seprint(m->p, m->e, " recursion=%ud", (h.flags&GRE_recur)>>8);
194
195 return 0;
196 }
197
198 Proto gre =
199 {
200 "gre",
201 p_compile,
202 p_filter,
203 p_seprint,
204 p_mux,
205 "%#.4ux",
206 p_fields,
207 defaultframer,
208 };
209