xref: /plan9/sys/src/cmd/ip/snoopy/gre.c (revision 0b9a5132554aff81f12a30adb0ffd48684252652)
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