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