1*9ef1f84bSDavid du Colombier /*
2*9ef1f84bSDavid du Colombier * IP packet filter
3*9ef1f84bSDavid du Colombier */
4*9ef1f84bSDavid du Colombier #include "u.h"
5*9ef1f84bSDavid du Colombier #include "../port/lib.h"
6*9ef1f84bSDavid du Colombier #include "mem.h"
7*9ef1f84bSDavid du Colombier #include "dat.h"
8*9ef1f84bSDavid du Colombier #include "fns.h"
9*9ef1f84bSDavid du Colombier #include "../port/error.h"
10*9ef1f84bSDavid du Colombier
11*9ef1f84bSDavid du Colombier #include "ip.h"
12*9ef1f84bSDavid du Colombier #include "ipv6.h"
13*9ef1f84bSDavid du Colombier
14*9ef1f84bSDavid du Colombier typedef struct Ipmuxrock Ipmuxrock;
15*9ef1f84bSDavid du Colombier typedef struct Ipmux Ipmux;
16*9ef1f84bSDavid du Colombier
17*9ef1f84bSDavid du Colombier typedef struct Myip4hdr Myip4hdr;
18*9ef1f84bSDavid du Colombier struct Myip4hdr
19*9ef1f84bSDavid du Colombier {
20*9ef1f84bSDavid du Colombier uchar vihl; /* Version and header length */
21*9ef1f84bSDavid du Colombier uchar tos; /* Type of service */
22*9ef1f84bSDavid du Colombier uchar length[2]; /* packet length */
23*9ef1f84bSDavid du Colombier uchar id[2]; /* ip->identification */
24*9ef1f84bSDavid du Colombier uchar frag[2]; /* Fragment information */
25*9ef1f84bSDavid du Colombier uchar ttl; /* Time to live */
26*9ef1f84bSDavid du Colombier uchar proto; /* Protocol */
27*9ef1f84bSDavid du Colombier uchar cksum[2]; /* Header checksum */
28*9ef1f84bSDavid du Colombier uchar src[4]; /* IP source */
29*9ef1f84bSDavid du Colombier uchar dst[4]; /* IP destination */
30*9ef1f84bSDavid du Colombier
31*9ef1f84bSDavid du Colombier uchar data[1]; /* start of data */
32*9ef1f84bSDavid du Colombier };
33*9ef1f84bSDavid du Colombier Myip4hdr *ipoff = 0;
34*9ef1f84bSDavid du Colombier
35*9ef1f84bSDavid du Colombier enum
36*9ef1f84bSDavid du Colombier {
37*9ef1f84bSDavid du Colombier Tproto,
38*9ef1f84bSDavid du Colombier Tdata,
39*9ef1f84bSDavid du Colombier Tiph,
40*9ef1f84bSDavid du Colombier Tdst,
41*9ef1f84bSDavid du Colombier Tsrc,
42*9ef1f84bSDavid du Colombier Tifc,
43*9ef1f84bSDavid du Colombier
44*9ef1f84bSDavid du Colombier Cother = 0,
45*9ef1f84bSDavid du Colombier Cbyte, /* single byte */
46*9ef1f84bSDavid du Colombier Cmbyte, /* single byte with mask */
47*9ef1f84bSDavid du Colombier Cshort, /* single short */
48*9ef1f84bSDavid du Colombier Cmshort, /* single short with mask */
49*9ef1f84bSDavid du Colombier Clong, /* single long */
50*9ef1f84bSDavid du Colombier Cmlong, /* single long with mask */
51*9ef1f84bSDavid du Colombier Cifc,
52*9ef1f84bSDavid du Colombier Cmifc,
53*9ef1f84bSDavid du Colombier };
54*9ef1f84bSDavid du Colombier
55*9ef1f84bSDavid du Colombier char *ftname[] =
56*9ef1f84bSDavid du Colombier {
57*9ef1f84bSDavid du Colombier [Tproto] "proto",
58*9ef1f84bSDavid du Colombier [Tdata] "data",
59*9ef1f84bSDavid du Colombier [Tiph] "iph",
60*9ef1f84bSDavid du Colombier [Tdst] "dst",
61*9ef1f84bSDavid du Colombier [Tsrc] "src",
62*9ef1f84bSDavid du Colombier [Tifc] "ifc",
63*9ef1f84bSDavid du Colombier };
64*9ef1f84bSDavid du Colombier
65*9ef1f84bSDavid du Colombier /*
66*9ef1f84bSDavid du Colombier * a node in the decision tree
67*9ef1f84bSDavid du Colombier */
68*9ef1f84bSDavid du Colombier struct Ipmux
69*9ef1f84bSDavid du Colombier {
70*9ef1f84bSDavid du Colombier Ipmux *yes;
71*9ef1f84bSDavid du Colombier Ipmux *no;
72*9ef1f84bSDavid du Colombier uchar type; /* type of field(Txxxx) */
73*9ef1f84bSDavid du Colombier uchar ctype; /* tupe of comparison(Cxxxx) */
74*9ef1f84bSDavid du Colombier uchar len; /* length in bytes of item to compare */
75*9ef1f84bSDavid du Colombier uchar n; /* number of items val points to */
76*9ef1f84bSDavid du Colombier short off; /* offset of comparison */
77*9ef1f84bSDavid du Colombier short eoff; /* end offset of comparison */
78*9ef1f84bSDavid du Colombier uchar skiphdr; /* should offset start after ipheader */
79*9ef1f84bSDavid du Colombier uchar *val;
80*9ef1f84bSDavid du Colombier uchar *mask;
81*9ef1f84bSDavid du Colombier uchar *e; /* val+n*len*/
82*9ef1f84bSDavid du Colombier
83*9ef1f84bSDavid du Colombier int ref; /* so we can garbage collect */
84*9ef1f84bSDavid du Colombier Conv *conv;
85*9ef1f84bSDavid du Colombier };
86*9ef1f84bSDavid du Colombier
87*9ef1f84bSDavid du Colombier /*
88*9ef1f84bSDavid du Colombier * someplace to hold per conversation data
89*9ef1f84bSDavid du Colombier */
90*9ef1f84bSDavid du Colombier struct Ipmuxrock
91*9ef1f84bSDavid du Colombier {
92*9ef1f84bSDavid du Colombier Ipmux *chain;
93*9ef1f84bSDavid du Colombier };
94*9ef1f84bSDavid du Colombier
95*9ef1f84bSDavid du Colombier static int ipmuxsprint(Ipmux*, int, char*, int);
96*9ef1f84bSDavid du Colombier static void ipmuxkick(void *x);
97*9ef1f84bSDavid du Colombier
98*9ef1f84bSDavid du Colombier static char*
skipwhite(char * p)99*9ef1f84bSDavid du Colombier skipwhite(char *p)
100*9ef1f84bSDavid du Colombier {
101*9ef1f84bSDavid du Colombier while(*p == ' ' || *p == '\t')
102*9ef1f84bSDavid du Colombier p++;
103*9ef1f84bSDavid du Colombier return p;
104*9ef1f84bSDavid du Colombier }
105*9ef1f84bSDavid du Colombier
106*9ef1f84bSDavid du Colombier static char*
follows(char * p,char c)107*9ef1f84bSDavid du Colombier follows(char *p, char c)
108*9ef1f84bSDavid du Colombier {
109*9ef1f84bSDavid du Colombier char *f;
110*9ef1f84bSDavid du Colombier
111*9ef1f84bSDavid du Colombier f = strchr(p, c);
112*9ef1f84bSDavid du Colombier if(f == nil)
113*9ef1f84bSDavid du Colombier return nil;
114*9ef1f84bSDavid du Colombier *f++ = 0;
115*9ef1f84bSDavid du Colombier f = skipwhite(f);
116*9ef1f84bSDavid du Colombier if(*f == 0)
117*9ef1f84bSDavid du Colombier return nil;
118*9ef1f84bSDavid du Colombier return f;
119*9ef1f84bSDavid du Colombier }
120*9ef1f84bSDavid du Colombier
121*9ef1f84bSDavid du Colombier static Ipmux*
parseop(char ** pp)122*9ef1f84bSDavid du Colombier parseop(char **pp)
123*9ef1f84bSDavid du Colombier {
124*9ef1f84bSDavid du Colombier char *p = *pp;
125*9ef1f84bSDavid du Colombier int type, off, end, len;
126*9ef1f84bSDavid du Colombier Ipmux *f;
127*9ef1f84bSDavid du Colombier
128*9ef1f84bSDavid du Colombier p = skipwhite(p);
129*9ef1f84bSDavid du Colombier if(strncmp(p, "dst", 3) == 0){
130*9ef1f84bSDavid du Colombier type = Tdst;
131*9ef1f84bSDavid du Colombier off = (uintptr)(ipoff->dst);
132*9ef1f84bSDavid du Colombier len = IPv4addrlen;
133*9ef1f84bSDavid du Colombier p += 3;
134*9ef1f84bSDavid du Colombier }
135*9ef1f84bSDavid du Colombier else if(strncmp(p, "src", 3) == 0){
136*9ef1f84bSDavid du Colombier type = Tsrc;
137*9ef1f84bSDavid du Colombier off = (uintptr)(ipoff->src);
138*9ef1f84bSDavid du Colombier len = IPv4addrlen;
139*9ef1f84bSDavid du Colombier p += 3;
140*9ef1f84bSDavid du Colombier }
141*9ef1f84bSDavid du Colombier else if(strncmp(p, "ifc", 3) == 0){
142*9ef1f84bSDavid du Colombier type = Tifc;
143*9ef1f84bSDavid du Colombier off = -IPv4addrlen;
144*9ef1f84bSDavid du Colombier len = IPv4addrlen;
145*9ef1f84bSDavid du Colombier p += 3;
146*9ef1f84bSDavid du Colombier }
147*9ef1f84bSDavid du Colombier else if(strncmp(p, "proto", 5) == 0){
148*9ef1f84bSDavid du Colombier type = Tproto;
149*9ef1f84bSDavid du Colombier off = (uintptr)&(ipoff->proto);
150*9ef1f84bSDavid du Colombier len = 1;
151*9ef1f84bSDavid du Colombier p += 5;
152*9ef1f84bSDavid du Colombier }
153*9ef1f84bSDavid du Colombier else if(strncmp(p, "data", 4) == 0 || strncmp(p, "iph", 3) == 0){
154*9ef1f84bSDavid du Colombier if(strncmp(p, "data", 4) == 0) {
155*9ef1f84bSDavid du Colombier type = Tdata;
156*9ef1f84bSDavid du Colombier p += 4;
157*9ef1f84bSDavid du Colombier }
158*9ef1f84bSDavid du Colombier else {
159*9ef1f84bSDavid du Colombier type = Tiph;
160*9ef1f84bSDavid du Colombier p += 3;
161*9ef1f84bSDavid du Colombier }
162*9ef1f84bSDavid du Colombier p = skipwhite(p);
163*9ef1f84bSDavid du Colombier if(*p != '[')
164*9ef1f84bSDavid du Colombier return nil;
165*9ef1f84bSDavid du Colombier p++;
166*9ef1f84bSDavid du Colombier off = strtoul(p, &p, 0);
167*9ef1f84bSDavid du Colombier if(off < 0 || off > (64-IP4HDR))
168*9ef1f84bSDavid du Colombier return nil;
169*9ef1f84bSDavid du Colombier p = skipwhite(p);
170*9ef1f84bSDavid du Colombier if(*p != ':')
171*9ef1f84bSDavid du Colombier end = off;
172*9ef1f84bSDavid du Colombier else {
173*9ef1f84bSDavid du Colombier p++;
174*9ef1f84bSDavid du Colombier p = skipwhite(p);
175*9ef1f84bSDavid du Colombier end = strtoul(p, &p, 0);
176*9ef1f84bSDavid du Colombier if(end < off)
177*9ef1f84bSDavid du Colombier return nil;
178*9ef1f84bSDavid du Colombier p = skipwhite(p);
179*9ef1f84bSDavid du Colombier }
180*9ef1f84bSDavid du Colombier if(*p != ']')
181*9ef1f84bSDavid du Colombier return nil;
182*9ef1f84bSDavid du Colombier p++;
183*9ef1f84bSDavid du Colombier len = end - off + 1;
184*9ef1f84bSDavid du Colombier }
185*9ef1f84bSDavid du Colombier else
186*9ef1f84bSDavid du Colombier return nil;
187*9ef1f84bSDavid du Colombier
188*9ef1f84bSDavid du Colombier f = smalloc(sizeof(*f));
189*9ef1f84bSDavid du Colombier f->type = type;
190*9ef1f84bSDavid du Colombier f->len = len;
191*9ef1f84bSDavid du Colombier f->off = off;
192*9ef1f84bSDavid du Colombier f->val = nil;
193*9ef1f84bSDavid du Colombier f->mask = nil;
194*9ef1f84bSDavid du Colombier f->n = 1;
195*9ef1f84bSDavid du Colombier f->ref = 1;
196*9ef1f84bSDavid du Colombier if(type == Tdata)
197*9ef1f84bSDavid du Colombier f->skiphdr = 1;
198*9ef1f84bSDavid du Colombier else
199*9ef1f84bSDavid du Colombier f->skiphdr = 0;
200*9ef1f84bSDavid du Colombier
201*9ef1f84bSDavid du Colombier return f;
202*9ef1f84bSDavid du Colombier }
203*9ef1f84bSDavid du Colombier
204*9ef1f84bSDavid du Colombier static int
htoi(char x)205*9ef1f84bSDavid du Colombier htoi(char x)
206*9ef1f84bSDavid du Colombier {
207*9ef1f84bSDavid du Colombier if(x >= '0' && x <= '9')
208*9ef1f84bSDavid du Colombier x -= '0';
209*9ef1f84bSDavid du Colombier else if(x >= 'a' && x <= 'f')
210*9ef1f84bSDavid du Colombier x -= 'a' - 10;
211*9ef1f84bSDavid du Colombier else if(x >= 'A' && x <= 'F')
212*9ef1f84bSDavid du Colombier x -= 'A' - 10;
213*9ef1f84bSDavid du Colombier else
214*9ef1f84bSDavid du Colombier x = 0;
215*9ef1f84bSDavid du Colombier return x;
216*9ef1f84bSDavid du Colombier }
217*9ef1f84bSDavid du Colombier
218*9ef1f84bSDavid du Colombier static int
hextoi(char * p)219*9ef1f84bSDavid du Colombier hextoi(char *p)
220*9ef1f84bSDavid du Colombier {
221*9ef1f84bSDavid du Colombier return (htoi(p[0])<<4) | htoi(p[1]);
222*9ef1f84bSDavid du Colombier }
223*9ef1f84bSDavid du Colombier
224*9ef1f84bSDavid du Colombier static void
parseval(uchar * v,char * p,int len)225*9ef1f84bSDavid du Colombier parseval(uchar *v, char *p, int len)
226*9ef1f84bSDavid du Colombier {
227*9ef1f84bSDavid du Colombier while(*p && len-- > 0){
228*9ef1f84bSDavid du Colombier *v++ = hextoi(p);
229*9ef1f84bSDavid du Colombier p += 2;
230*9ef1f84bSDavid du Colombier }
231*9ef1f84bSDavid du Colombier }
232*9ef1f84bSDavid du Colombier
233*9ef1f84bSDavid du Colombier static Ipmux*
parsemux(char * p)234*9ef1f84bSDavid du Colombier parsemux(char *p)
235*9ef1f84bSDavid du Colombier {
236*9ef1f84bSDavid du Colombier int n, nomask;
237*9ef1f84bSDavid du Colombier Ipmux *f;
238*9ef1f84bSDavid du Colombier char *val;
239*9ef1f84bSDavid du Colombier char *mask;
240*9ef1f84bSDavid du Colombier char *vals[20];
241*9ef1f84bSDavid du Colombier uchar *v;
242*9ef1f84bSDavid du Colombier
243*9ef1f84bSDavid du Colombier /* parse operand */
244*9ef1f84bSDavid du Colombier f = parseop(&p);
245*9ef1f84bSDavid du Colombier if(f == nil)
246*9ef1f84bSDavid du Colombier return nil;
247*9ef1f84bSDavid du Colombier
248*9ef1f84bSDavid du Colombier /* find value */
249*9ef1f84bSDavid du Colombier val = follows(p, '=');
250*9ef1f84bSDavid du Colombier if(val == nil)
251*9ef1f84bSDavid du Colombier goto parseerror;
252*9ef1f84bSDavid du Colombier
253*9ef1f84bSDavid du Colombier /* parse mask */
254*9ef1f84bSDavid du Colombier mask = follows(p, '&');
255*9ef1f84bSDavid du Colombier if(mask != nil){
256*9ef1f84bSDavid du Colombier switch(f->type){
257*9ef1f84bSDavid du Colombier case Tsrc:
258*9ef1f84bSDavid du Colombier case Tdst:
259*9ef1f84bSDavid du Colombier case Tifc:
260*9ef1f84bSDavid du Colombier f->mask = smalloc(f->len);
261*9ef1f84bSDavid du Colombier v4parseip(f->mask, mask);
262*9ef1f84bSDavid du Colombier break;
263*9ef1f84bSDavid du Colombier case Tdata:
264*9ef1f84bSDavid du Colombier case Tiph:
265*9ef1f84bSDavid du Colombier f->mask = smalloc(f->len);
266*9ef1f84bSDavid du Colombier parseval(f->mask, mask, f->len);
267*9ef1f84bSDavid du Colombier break;
268*9ef1f84bSDavid du Colombier default:
269*9ef1f84bSDavid du Colombier goto parseerror;
270*9ef1f84bSDavid du Colombier }
271*9ef1f84bSDavid du Colombier nomask = 0;
272*9ef1f84bSDavid du Colombier } else {
273*9ef1f84bSDavid du Colombier nomask = 1;
274*9ef1f84bSDavid du Colombier f->mask = smalloc(f->len);
275*9ef1f84bSDavid du Colombier memset(f->mask, 0xff, f->len);
276*9ef1f84bSDavid du Colombier }
277*9ef1f84bSDavid du Colombier
278*9ef1f84bSDavid du Colombier /* parse vals */
279*9ef1f84bSDavid du Colombier f->n = getfields(val, vals, sizeof(vals)/sizeof(char*), 1, "|");
280*9ef1f84bSDavid du Colombier if(f->n == 0)
281*9ef1f84bSDavid du Colombier goto parseerror;
282*9ef1f84bSDavid du Colombier f->val = smalloc(f->n*f->len);
283*9ef1f84bSDavid du Colombier v = f->val;
284*9ef1f84bSDavid du Colombier for(n = 0; n < f->n; n++){
285*9ef1f84bSDavid du Colombier switch(f->type){
286*9ef1f84bSDavid du Colombier case Tsrc:
287*9ef1f84bSDavid du Colombier case Tdst:
288*9ef1f84bSDavid du Colombier case Tifc:
289*9ef1f84bSDavid du Colombier v4parseip(v, vals[n]);
290*9ef1f84bSDavid du Colombier break;
291*9ef1f84bSDavid du Colombier case Tproto:
292*9ef1f84bSDavid du Colombier case Tdata:
293*9ef1f84bSDavid du Colombier case Tiph:
294*9ef1f84bSDavid du Colombier parseval(v, vals[n], f->len);
295*9ef1f84bSDavid du Colombier break;
296*9ef1f84bSDavid du Colombier }
297*9ef1f84bSDavid du Colombier v += f->len;
298*9ef1f84bSDavid du Colombier }
299*9ef1f84bSDavid du Colombier
300*9ef1f84bSDavid du Colombier f->eoff = f->off + f->len;
301*9ef1f84bSDavid du Colombier f->e = f->val + f->n*f->len;
302*9ef1f84bSDavid du Colombier f->ctype = Cother;
303*9ef1f84bSDavid du Colombier if(f->n == 1){
304*9ef1f84bSDavid du Colombier switch(f->len){
305*9ef1f84bSDavid du Colombier case 1:
306*9ef1f84bSDavid du Colombier f->ctype = nomask ? Cbyte : Cmbyte;
307*9ef1f84bSDavid du Colombier break;
308*9ef1f84bSDavid du Colombier case 2:
309*9ef1f84bSDavid du Colombier f->ctype = nomask ? Cshort : Cmshort;
310*9ef1f84bSDavid du Colombier break;
311*9ef1f84bSDavid du Colombier case 4:
312*9ef1f84bSDavid du Colombier if(f->type == Tifc)
313*9ef1f84bSDavid du Colombier f->ctype = nomask ? Cifc : Cmifc;
314*9ef1f84bSDavid du Colombier else
315*9ef1f84bSDavid du Colombier f->ctype = nomask ? Clong : Cmlong;
316*9ef1f84bSDavid du Colombier break;
317*9ef1f84bSDavid du Colombier }
318*9ef1f84bSDavid du Colombier }
319*9ef1f84bSDavid du Colombier return f;
320*9ef1f84bSDavid du Colombier
321*9ef1f84bSDavid du Colombier parseerror:
322*9ef1f84bSDavid du Colombier if(f->mask)
323*9ef1f84bSDavid du Colombier free(f->mask);
324*9ef1f84bSDavid du Colombier if(f->val)
325*9ef1f84bSDavid du Colombier free(f->val);
326*9ef1f84bSDavid du Colombier free(f);
327*9ef1f84bSDavid du Colombier return nil;
328*9ef1f84bSDavid du Colombier }
329*9ef1f84bSDavid du Colombier
330*9ef1f84bSDavid du Colombier /*
331*9ef1f84bSDavid du Colombier * Compare relative ordering of two ipmuxs. This doesn't compare the
332*9ef1f84bSDavid du Colombier * values, just the fields being looked at.
333*9ef1f84bSDavid du Colombier *
334*9ef1f84bSDavid du Colombier * returns: <0 if a is a more specific match
335*9ef1f84bSDavid du Colombier * 0 if a and b are matching on the same fields
336*9ef1f84bSDavid du Colombier * >0 if b is a more specific match
337*9ef1f84bSDavid du Colombier */
338*9ef1f84bSDavid du Colombier static int
ipmuxcmp(Ipmux * a,Ipmux * b)339*9ef1f84bSDavid du Colombier ipmuxcmp(Ipmux *a, Ipmux *b)
340*9ef1f84bSDavid du Colombier {
341*9ef1f84bSDavid du Colombier int n;
342*9ef1f84bSDavid du Colombier
343*9ef1f84bSDavid du Colombier /* compare types, lesser ones are more important */
344*9ef1f84bSDavid du Colombier n = a->type - b->type;
345*9ef1f84bSDavid du Colombier if(n != 0)
346*9ef1f84bSDavid du Colombier return n;
347*9ef1f84bSDavid du Colombier
348*9ef1f84bSDavid du Colombier /* compare offsets, call earlier ones more specific */
349*9ef1f84bSDavid du Colombier n = (a->off+((int)a->skiphdr)*(uintptr)ipoff->data) -
350*9ef1f84bSDavid du Colombier (b->off+((int)b->skiphdr)*(uintptr)ipoff->data);
351*9ef1f84bSDavid du Colombier if(n != 0)
352*9ef1f84bSDavid du Colombier return n;
353*9ef1f84bSDavid du Colombier
354*9ef1f84bSDavid du Colombier /* compare match lengths, longer ones are more specific */
355*9ef1f84bSDavid du Colombier n = b->len - a->len;
356*9ef1f84bSDavid du Colombier if(n != 0)
357*9ef1f84bSDavid du Colombier return n;
358*9ef1f84bSDavid du Colombier
359*9ef1f84bSDavid du Colombier /*
360*9ef1f84bSDavid du Colombier * if we get here we have two entries matching
361*9ef1f84bSDavid du Colombier * the same bytes of the record. Now check
362*9ef1f84bSDavid du Colombier * the mask for equality. Longer masks are
363*9ef1f84bSDavid du Colombier * more specific.
364*9ef1f84bSDavid du Colombier */
365*9ef1f84bSDavid du Colombier if(a->mask != nil && b->mask == nil)
366*9ef1f84bSDavid du Colombier return -1;
367*9ef1f84bSDavid du Colombier if(a->mask == nil && b->mask != nil)
368*9ef1f84bSDavid du Colombier return 1;
369*9ef1f84bSDavid du Colombier if(a->mask != nil && b->mask != nil){
370*9ef1f84bSDavid du Colombier n = memcmp(b->mask, a->mask, a->len);
371*9ef1f84bSDavid du Colombier if(n != 0)
372*9ef1f84bSDavid du Colombier return n;
373*9ef1f84bSDavid du Colombier }
374*9ef1f84bSDavid du Colombier return 0;
375*9ef1f84bSDavid du Colombier }
376*9ef1f84bSDavid du Colombier
377*9ef1f84bSDavid du Colombier /*
378*9ef1f84bSDavid du Colombier * Compare the values of two ipmuxs. We're assuming that ipmuxcmp
379*9ef1f84bSDavid du Colombier * returned 0 comparing them.
380*9ef1f84bSDavid du Colombier */
381*9ef1f84bSDavid du Colombier static int
ipmuxvalcmp(Ipmux * a,Ipmux * b)382*9ef1f84bSDavid du Colombier ipmuxvalcmp(Ipmux *a, Ipmux *b)
383*9ef1f84bSDavid du Colombier {
384*9ef1f84bSDavid du Colombier int n;
385*9ef1f84bSDavid du Colombier
386*9ef1f84bSDavid du Colombier n = b->len*b->n - a->len*a->n;
387*9ef1f84bSDavid du Colombier if(n != 0)
388*9ef1f84bSDavid du Colombier return n;
389*9ef1f84bSDavid du Colombier return memcmp(a->val, b->val, a->len*a->n);
390*9ef1f84bSDavid du Colombier }
391*9ef1f84bSDavid du Colombier
392*9ef1f84bSDavid du Colombier /*
393*9ef1f84bSDavid du Colombier * add onto an existing ipmux chain in the canonical comparison
394*9ef1f84bSDavid du Colombier * order
395*9ef1f84bSDavid du Colombier */
396*9ef1f84bSDavid du Colombier static void
ipmuxchain(Ipmux ** l,Ipmux * f)397*9ef1f84bSDavid du Colombier ipmuxchain(Ipmux **l, Ipmux *f)
398*9ef1f84bSDavid du Colombier {
399*9ef1f84bSDavid du Colombier for(; *l; l = &(*l)->yes)
400*9ef1f84bSDavid du Colombier if(ipmuxcmp(f, *l) < 0)
401*9ef1f84bSDavid du Colombier break;
402*9ef1f84bSDavid du Colombier f->yes = *l;
403*9ef1f84bSDavid du Colombier *l = f;
404*9ef1f84bSDavid du Colombier }
405*9ef1f84bSDavid du Colombier
406*9ef1f84bSDavid du Colombier /*
407*9ef1f84bSDavid du Colombier * copy a tree
408*9ef1f84bSDavid du Colombier */
409*9ef1f84bSDavid du Colombier static Ipmux*
ipmuxcopy(Ipmux * f)410*9ef1f84bSDavid du Colombier ipmuxcopy(Ipmux *f)
411*9ef1f84bSDavid du Colombier {
412*9ef1f84bSDavid du Colombier Ipmux *nf;
413*9ef1f84bSDavid du Colombier
414*9ef1f84bSDavid du Colombier if(f == nil)
415*9ef1f84bSDavid du Colombier return nil;
416*9ef1f84bSDavid du Colombier nf = smalloc(sizeof *nf);
417*9ef1f84bSDavid du Colombier *nf = *f;
418*9ef1f84bSDavid du Colombier nf->no = ipmuxcopy(f->no);
419*9ef1f84bSDavid du Colombier nf->yes = ipmuxcopy(f->yes);
420*9ef1f84bSDavid du Colombier nf->val = smalloc(f->n*f->len);
421*9ef1f84bSDavid du Colombier nf->e = nf->val + f->len*f->n;
422*9ef1f84bSDavid du Colombier memmove(nf->val, f->val, f->n*f->len);
423*9ef1f84bSDavid du Colombier return nf;
424*9ef1f84bSDavid du Colombier }
425*9ef1f84bSDavid du Colombier
426*9ef1f84bSDavid du Colombier static void
ipmuxfree(Ipmux * f)427*9ef1f84bSDavid du Colombier ipmuxfree(Ipmux *f)
428*9ef1f84bSDavid du Colombier {
429*9ef1f84bSDavid du Colombier if(f->val != nil)
430*9ef1f84bSDavid du Colombier free(f->val);
431*9ef1f84bSDavid du Colombier free(f);
432*9ef1f84bSDavid du Colombier }
433*9ef1f84bSDavid du Colombier
434*9ef1f84bSDavid du Colombier static void
ipmuxtreefree(Ipmux * f)435*9ef1f84bSDavid du Colombier ipmuxtreefree(Ipmux *f)
436*9ef1f84bSDavid du Colombier {
437*9ef1f84bSDavid du Colombier if(f == nil)
438*9ef1f84bSDavid du Colombier return;
439*9ef1f84bSDavid du Colombier if(f->no != nil)
440*9ef1f84bSDavid du Colombier ipmuxfree(f->no);
441*9ef1f84bSDavid du Colombier if(f->yes != nil)
442*9ef1f84bSDavid du Colombier ipmuxfree(f->yes);
443*9ef1f84bSDavid du Colombier ipmuxfree(f);
444*9ef1f84bSDavid du Colombier }
445*9ef1f84bSDavid du Colombier
446*9ef1f84bSDavid du Colombier /*
447*9ef1f84bSDavid du Colombier * merge two trees
448*9ef1f84bSDavid du Colombier */
449*9ef1f84bSDavid du Colombier static Ipmux*
ipmuxmerge(Ipmux * a,Ipmux * b)450*9ef1f84bSDavid du Colombier ipmuxmerge(Ipmux *a, Ipmux *b)
451*9ef1f84bSDavid du Colombier {
452*9ef1f84bSDavid du Colombier int n;
453*9ef1f84bSDavid du Colombier Ipmux *f;
454*9ef1f84bSDavid du Colombier
455*9ef1f84bSDavid du Colombier if(a == nil)
456*9ef1f84bSDavid du Colombier return b;
457*9ef1f84bSDavid du Colombier if(b == nil)
458*9ef1f84bSDavid du Colombier return a;
459*9ef1f84bSDavid du Colombier n = ipmuxcmp(a, b);
460*9ef1f84bSDavid du Colombier if(n < 0){
461*9ef1f84bSDavid du Colombier f = ipmuxcopy(b);
462*9ef1f84bSDavid du Colombier a->yes = ipmuxmerge(a->yes, b);
463*9ef1f84bSDavid du Colombier a->no = ipmuxmerge(a->no, f);
464*9ef1f84bSDavid du Colombier return a;
465*9ef1f84bSDavid du Colombier }
466*9ef1f84bSDavid du Colombier if(n > 0){
467*9ef1f84bSDavid du Colombier f = ipmuxcopy(a);
468*9ef1f84bSDavid du Colombier b->yes = ipmuxmerge(b->yes, a);
469*9ef1f84bSDavid du Colombier b->no = ipmuxmerge(b->no, f);
470*9ef1f84bSDavid du Colombier return b;
471*9ef1f84bSDavid du Colombier }
472*9ef1f84bSDavid du Colombier if(ipmuxvalcmp(a, b) == 0){
473*9ef1f84bSDavid du Colombier a->yes = ipmuxmerge(a->yes, b->yes);
474*9ef1f84bSDavid du Colombier a->no = ipmuxmerge(a->no, b->no);
475*9ef1f84bSDavid du Colombier a->ref++;
476*9ef1f84bSDavid du Colombier ipmuxfree(b);
477*9ef1f84bSDavid du Colombier return a;
478*9ef1f84bSDavid du Colombier }
479*9ef1f84bSDavid du Colombier a->no = ipmuxmerge(a->no, b);
480*9ef1f84bSDavid du Colombier return a;
481*9ef1f84bSDavid du Colombier }
482*9ef1f84bSDavid du Colombier
483*9ef1f84bSDavid du Colombier /*
484*9ef1f84bSDavid du Colombier * remove a chain from a demux tree. This is like merging accept that
485*9ef1f84bSDavid du Colombier * we remove instead of insert.
486*9ef1f84bSDavid du Colombier */
487*9ef1f84bSDavid du Colombier static int
ipmuxremove(Ipmux ** l,Ipmux * f)488*9ef1f84bSDavid du Colombier ipmuxremove(Ipmux **l, Ipmux *f)
489*9ef1f84bSDavid du Colombier {
490*9ef1f84bSDavid du Colombier int n, rv;
491*9ef1f84bSDavid du Colombier Ipmux *ft;
492*9ef1f84bSDavid du Colombier
493*9ef1f84bSDavid du Colombier if(f == nil)
494*9ef1f84bSDavid du Colombier return 0; /* we've removed it all */
495*9ef1f84bSDavid du Colombier if(*l == nil)
496*9ef1f84bSDavid du Colombier return -1;
497*9ef1f84bSDavid du Colombier
498*9ef1f84bSDavid du Colombier ft = *l;
499*9ef1f84bSDavid du Colombier n = ipmuxcmp(ft, f);
500*9ef1f84bSDavid du Colombier if(n < 0){
501*9ef1f84bSDavid du Colombier /* *l is maching an earlier field, descend both paths */
502*9ef1f84bSDavid du Colombier rv = ipmuxremove(&ft->yes, f);
503*9ef1f84bSDavid du Colombier rv += ipmuxremove(&ft->no, f);
504*9ef1f84bSDavid du Colombier return rv;
505*9ef1f84bSDavid du Colombier }
506*9ef1f84bSDavid du Colombier if(n > 0){
507*9ef1f84bSDavid du Colombier /* f represents an earlier field than *l, this should be impossible */
508*9ef1f84bSDavid du Colombier return -1;
509*9ef1f84bSDavid du Colombier }
510*9ef1f84bSDavid du Colombier
511*9ef1f84bSDavid du Colombier /* if we get here f and *l are comparing the same fields */
512*9ef1f84bSDavid du Colombier if(ipmuxvalcmp(ft, f) != 0){
513*9ef1f84bSDavid du Colombier /* different values mean mutually exclusive */
514*9ef1f84bSDavid du Colombier return ipmuxremove(&ft->no, f);
515*9ef1f84bSDavid du Colombier }
516*9ef1f84bSDavid du Colombier
517*9ef1f84bSDavid du Colombier /* we found a match */
518*9ef1f84bSDavid du Colombier if(--(ft->ref) == 0){
519*9ef1f84bSDavid du Colombier /*
520*9ef1f84bSDavid du Colombier * a dead node implies the whole yes side is also dead.
521*9ef1f84bSDavid du Colombier * since our chain is constrained to be on that side,
522*9ef1f84bSDavid du Colombier * we're done.
523*9ef1f84bSDavid du Colombier */
524*9ef1f84bSDavid du Colombier ipmuxtreefree(ft->yes);
525*9ef1f84bSDavid du Colombier *l = ft->no;
526*9ef1f84bSDavid du Colombier ipmuxfree(ft);
527*9ef1f84bSDavid du Colombier return 0;
528*9ef1f84bSDavid du Colombier }
529*9ef1f84bSDavid du Colombier
530*9ef1f84bSDavid du Colombier /*
531*9ef1f84bSDavid du Colombier * free the rest of the chain. it is constrained to match the
532*9ef1f84bSDavid du Colombier * yes side.
533*9ef1f84bSDavid du Colombier */
534*9ef1f84bSDavid du Colombier return ipmuxremove(&ft->yes, f->yes);
535*9ef1f84bSDavid du Colombier }
536*9ef1f84bSDavid du Colombier
537*9ef1f84bSDavid du Colombier /*
538*9ef1f84bSDavid du Colombier * connection request is a semi separated list of filters
539*9ef1f84bSDavid du Colombier * e.g. proto=17;data[0:4]=11aa22bb;ifc=135.104.9.2&255.255.255.0
540*9ef1f84bSDavid du Colombier *
541*9ef1f84bSDavid du Colombier * there's no protection against overlapping specs.
542*9ef1f84bSDavid du Colombier */
543*9ef1f84bSDavid du Colombier static char*
ipmuxconnect(Conv * c,char ** argv,int argc)544*9ef1f84bSDavid du Colombier ipmuxconnect(Conv *c, char **argv, int argc)
545*9ef1f84bSDavid du Colombier {
546*9ef1f84bSDavid du Colombier int i, n;
547*9ef1f84bSDavid du Colombier char *field[10];
548*9ef1f84bSDavid du Colombier Ipmux *mux, *chain;
549*9ef1f84bSDavid du Colombier Ipmuxrock *r;
550*9ef1f84bSDavid du Colombier Fs *f;
551*9ef1f84bSDavid du Colombier
552*9ef1f84bSDavid du Colombier f = c->p->f;
553*9ef1f84bSDavid du Colombier
554*9ef1f84bSDavid du Colombier if(argc != 2)
555*9ef1f84bSDavid du Colombier return Ebadarg;
556*9ef1f84bSDavid du Colombier
557*9ef1f84bSDavid du Colombier n = getfields(argv[1], field, nelem(field), 1, ";");
558*9ef1f84bSDavid du Colombier if(n <= 0)
559*9ef1f84bSDavid du Colombier return Ebadarg;
560*9ef1f84bSDavid du Colombier
561*9ef1f84bSDavid du Colombier chain = nil;
562*9ef1f84bSDavid du Colombier mux = nil;
563*9ef1f84bSDavid du Colombier for(i = 0; i < n; i++){
564*9ef1f84bSDavid du Colombier mux = parsemux(field[i]);
565*9ef1f84bSDavid du Colombier if(mux == nil){
566*9ef1f84bSDavid du Colombier ipmuxtreefree(chain);
567*9ef1f84bSDavid du Colombier return Ebadarg;
568*9ef1f84bSDavid du Colombier }
569*9ef1f84bSDavid du Colombier ipmuxchain(&chain, mux);
570*9ef1f84bSDavid du Colombier }
571*9ef1f84bSDavid du Colombier if(chain == nil)
572*9ef1f84bSDavid du Colombier return Ebadarg;
573*9ef1f84bSDavid du Colombier mux->conv = c;
574*9ef1f84bSDavid du Colombier
575*9ef1f84bSDavid du Colombier /* save a copy of the chain so we can later remove it */
576*9ef1f84bSDavid du Colombier mux = ipmuxcopy(chain);
577*9ef1f84bSDavid du Colombier r = (Ipmuxrock*)(c->ptcl);
578*9ef1f84bSDavid du Colombier r->chain = chain;
579*9ef1f84bSDavid du Colombier
580*9ef1f84bSDavid du Colombier /* add the chain to the protocol demultiplexor tree */
581*9ef1f84bSDavid du Colombier wlock(f);
582*9ef1f84bSDavid du Colombier f->ipmux->priv = ipmuxmerge(f->ipmux->priv, mux);
583*9ef1f84bSDavid du Colombier wunlock(f);
584*9ef1f84bSDavid du Colombier
585*9ef1f84bSDavid du Colombier Fsconnected(c, nil);
586*9ef1f84bSDavid du Colombier return nil;
587*9ef1f84bSDavid du Colombier }
588*9ef1f84bSDavid du Colombier
589*9ef1f84bSDavid du Colombier static int
ipmuxstate(Conv * c,char * state,int n)590*9ef1f84bSDavid du Colombier ipmuxstate(Conv *c, char *state, int n)
591*9ef1f84bSDavid du Colombier {
592*9ef1f84bSDavid du Colombier Ipmuxrock *r;
593*9ef1f84bSDavid du Colombier
594*9ef1f84bSDavid du Colombier r = (Ipmuxrock*)(c->ptcl);
595*9ef1f84bSDavid du Colombier return ipmuxsprint(r->chain, 0, state, n);
596*9ef1f84bSDavid du Colombier }
597*9ef1f84bSDavid du Colombier
598*9ef1f84bSDavid du Colombier static void
ipmuxcreate(Conv * c)599*9ef1f84bSDavid du Colombier ipmuxcreate(Conv *c)
600*9ef1f84bSDavid du Colombier {
601*9ef1f84bSDavid du Colombier Ipmuxrock *r;
602*9ef1f84bSDavid du Colombier
603*9ef1f84bSDavid du Colombier c->rq = qopen(64*1024, Qmsg, 0, c);
604*9ef1f84bSDavid du Colombier c->wq = qopen(64*1024, Qkick, ipmuxkick, c);
605*9ef1f84bSDavid du Colombier r = (Ipmuxrock*)(c->ptcl);
606*9ef1f84bSDavid du Colombier r->chain = nil;
607*9ef1f84bSDavid du Colombier }
608*9ef1f84bSDavid du Colombier
609*9ef1f84bSDavid du Colombier static char*
ipmuxannounce(Conv *,char **,int)610*9ef1f84bSDavid du Colombier ipmuxannounce(Conv*, char**, int)
611*9ef1f84bSDavid du Colombier {
612*9ef1f84bSDavid du Colombier return "ipmux does not support announce";
613*9ef1f84bSDavid du Colombier }
614*9ef1f84bSDavid du Colombier
615*9ef1f84bSDavid du Colombier static void
ipmuxclose(Conv * c)616*9ef1f84bSDavid du Colombier ipmuxclose(Conv *c)
617*9ef1f84bSDavid du Colombier {
618*9ef1f84bSDavid du Colombier Ipmuxrock *r;
619*9ef1f84bSDavid du Colombier Fs *f = c->p->f;
620*9ef1f84bSDavid du Colombier
621*9ef1f84bSDavid du Colombier r = (Ipmuxrock*)(c->ptcl);
622*9ef1f84bSDavid du Colombier
623*9ef1f84bSDavid du Colombier qclose(c->rq);
624*9ef1f84bSDavid du Colombier qclose(c->wq);
625*9ef1f84bSDavid du Colombier qclose(c->eq);
626*9ef1f84bSDavid du Colombier ipmove(c->laddr, IPnoaddr);
627*9ef1f84bSDavid du Colombier ipmove(c->raddr, IPnoaddr);
628*9ef1f84bSDavid du Colombier c->lport = 0;
629*9ef1f84bSDavid du Colombier c->rport = 0;
630*9ef1f84bSDavid du Colombier
631*9ef1f84bSDavid du Colombier wlock(f);
632*9ef1f84bSDavid du Colombier ipmuxremove(&(c->p->priv), r->chain);
633*9ef1f84bSDavid du Colombier wunlock(f);
634*9ef1f84bSDavid du Colombier ipmuxtreefree(r->chain);
635*9ef1f84bSDavid du Colombier r->chain = nil;
636*9ef1f84bSDavid du Colombier }
637*9ef1f84bSDavid du Colombier
638*9ef1f84bSDavid du Colombier /*
639*9ef1f84bSDavid du Colombier * takes a fully formed ip packet and just passes it down
640*9ef1f84bSDavid du Colombier * the stack
641*9ef1f84bSDavid du Colombier */
642*9ef1f84bSDavid du Colombier static void
ipmuxkick(void * x)643*9ef1f84bSDavid du Colombier ipmuxkick(void *x)
644*9ef1f84bSDavid du Colombier {
645*9ef1f84bSDavid du Colombier Conv *c = x;
646*9ef1f84bSDavid du Colombier Block *bp;
647*9ef1f84bSDavid du Colombier
648*9ef1f84bSDavid du Colombier bp = qget(c->wq);
649*9ef1f84bSDavid du Colombier if(bp != nil) {
650*9ef1f84bSDavid du Colombier Myip4hdr *ih4 = (Myip4hdr*)(bp->rp);
651*9ef1f84bSDavid du Colombier
652*9ef1f84bSDavid du Colombier if((ih4->vihl & 0xF0) != IP_VER6)
653*9ef1f84bSDavid du Colombier ipoput4(c->p->f, bp, 0, ih4->ttl, ih4->tos, nil);
654*9ef1f84bSDavid du Colombier else
655*9ef1f84bSDavid du Colombier ipoput6(c->p->f, bp, 0, ((Ip6hdr*)ih4)->ttl, 0, nil);
656*9ef1f84bSDavid du Colombier }
657*9ef1f84bSDavid du Colombier }
658*9ef1f84bSDavid du Colombier
659*9ef1f84bSDavid du Colombier static void
ipmuxiput(Proto * p,Ipifc * ifc,Block * bp)660*9ef1f84bSDavid du Colombier ipmuxiput(Proto *p, Ipifc *ifc, Block *bp)
661*9ef1f84bSDavid du Colombier {
662*9ef1f84bSDavid du Colombier int len, hl;
663*9ef1f84bSDavid du Colombier Fs *f = p->f;
664*9ef1f84bSDavid du Colombier uchar *m, *h, *v, *e, *ve, *hp;
665*9ef1f84bSDavid du Colombier Conv *c;
666*9ef1f84bSDavid du Colombier Ipmux *mux;
667*9ef1f84bSDavid du Colombier Myip4hdr *ip;
668*9ef1f84bSDavid du Colombier Ip6hdr *ip6;
669*9ef1f84bSDavid du Colombier
670*9ef1f84bSDavid du Colombier ip = (Myip4hdr*)bp->rp;
671*9ef1f84bSDavid du Colombier hl = (ip->vihl&0x0F)<<2;
672*9ef1f84bSDavid du Colombier
673*9ef1f84bSDavid du Colombier if(p->priv == nil)
674*9ef1f84bSDavid du Colombier goto nomatch;
675*9ef1f84bSDavid du Colombier
676*9ef1f84bSDavid du Colombier h = bp->rp;
677*9ef1f84bSDavid du Colombier len = BLEN(bp);
678*9ef1f84bSDavid du Colombier
679*9ef1f84bSDavid du Colombier /* run the v4 filter */
680*9ef1f84bSDavid du Colombier rlock(f);
681*9ef1f84bSDavid du Colombier c = nil;
682*9ef1f84bSDavid du Colombier mux = f->ipmux->priv;
683*9ef1f84bSDavid du Colombier while(mux != nil){
684*9ef1f84bSDavid du Colombier if(mux->eoff > len){
685*9ef1f84bSDavid du Colombier mux = mux->no;
686*9ef1f84bSDavid du Colombier continue;
687*9ef1f84bSDavid du Colombier }
688*9ef1f84bSDavid du Colombier hp = h + mux->off + ((int)mux->skiphdr)*hl;
689*9ef1f84bSDavid du Colombier switch(mux->ctype){
690*9ef1f84bSDavid du Colombier case Cbyte:
691*9ef1f84bSDavid du Colombier if(*mux->val == *hp)
692*9ef1f84bSDavid du Colombier goto yes;
693*9ef1f84bSDavid du Colombier break;
694*9ef1f84bSDavid du Colombier case Cmbyte:
695*9ef1f84bSDavid du Colombier if((*hp & *mux->mask) == *mux->val)
696*9ef1f84bSDavid du Colombier goto yes;
697*9ef1f84bSDavid du Colombier break;
698*9ef1f84bSDavid du Colombier case Cshort:
699*9ef1f84bSDavid du Colombier if(*((ushort*)mux->val) == *(ushort*)hp)
700*9ef1f84bSDavid du Colombier goto yes;
701*9ef1f84bSDavid du Colombier break;
702*9ef1f84bSDavid du Colombier case Cmshort:
703*9ef1f84bSDavid du Colombier if((*(ushort*)hp & (*((ushort*)mux->mask))) == *((ushort*)mux->val))
704*9ef1f84bSDavid du Colombier goto yes;
705*9ef1f84bSDavid du Colombier break;
706*9ef1f84bSDavid du Colombier case Clong:
707*9ef1f84bSDavid du Colombier if(*((ulong*)mux->val) == *(ulong*)hp)
708*9ef1f84bSDavid du Colombier goto yes;
709*9ef1f84bSDavid du Colombier break;
710*9ef1f84bSDavid du Colombier case Cmlong:
711*9ef1f84bSDavid du Colombier if((*(ulong*)hp & (*((ulong*)mux->mask))) == *((ulong*)mux->val))
712*9ef1f84bSDavid du Colombier goto yes;
713*9ef1f84bSDavid du Colombier break;
714*9ef1f84bSDavid du Colombier case Cifc:
715*9ef1f84bSDavid du Colombier if(*((ulong*)mux->val) == *(ulong*)(ifc->lifc->local + IPv4off))
716*9ef1f84bSDavid du Colombier goto yes;
717*9ef1f84bSDavid du Colombier break;
718*9ef1f84bSDavid du Colombier case Cmifc:
719*9ef1f84bSDavid du Colombier if((*(ulong*)(ifc->lifc->local + IPv4off) & (*((ulong*)mux->mask))) == *((ulong*)mux->val))
720*9ef1f84bSDavid du Colombier goto yes;
721*9ef1f84bSDavid du Colombier break;
722*9ef1f84bSDavid du Colombier default:
723*9ef1f84bSDavid du Colombier v = mux->val;
724*9ef1f84bSDavid du Colombier for(e = mux->e; v < e; v = ve){
725*9ef1f84bSDavid du Colombier m = mux->mask;
726*9ef1f84bSDavid du Colombier hp = h + mux->off;
727*9ef1f84bSDavid du Colombier for(ve = v + mux->len; v < ve; v++){
728*9ef1f84bSDavid du Colombier if((*hp++ & *m++) != *v)
729*9ef1f84bSDavid du Colombier break;
730*9ef1f84bSDavid du Colombier }
731*9ef1f84bSDavid du Colombier if(v == ve)
732*9ef1f84bSDavid du Colombier goto yes;
733*9ef1f84bSDavid du Colombier }
734*9ef1f84bSDavid du Colombier }
735*9ef1f84bSDavid du Colombier mux = mux->no;
736*9ef1f84bSDavid du Colombier continue;
737*9ef1f84bSDavid du Colombier yes:
738*9ef1f84bSDavid du Colombier if(mux->conv != nil)
739*9ef1f84bSDavid du Colombier c = mux->conv;
740*9ef1f84bSDavid du Colombier mux = mux->yes;
741*9ef1f84bSDavid du Colombier }
742*9ef1f84bSDavid du Colombier runlock(f);
743*9ef1f84bSDavid du Colombier
744*9ef1f84bSDavid du Colombier if(c != nil){
745*9ef1f84bSDavid du Colombier /* tack on interface address */
746*9ef1f84bSDavid du Colombier bp = padblock(bp, IPaddrlen);
747*9ef1f84bSDavid du Colombier ipmove(bp->rp, ifc->lifc->local);
748*9ef1f84bSDavid du Colombier bp = concatblock(bp);
749*9ef1f84bSDavid du Colombier if(bp != nil)
750*9ef1f84bSDavid du Colombier if(qpass(c->rq, bp) < 0)
751*9ef1f84bSDavid du Colombier print("Q");
752*9ef1f84bSDavid du Colombier return;
753*9ef1f84bSDavid du Colombier }
754*9ef1f84bSDavid du Colombier
755*9ef1f84bSDavid du Colombier nomatch:
756*9ef1f84bSDavid du Colombier /* doesn't match any filter, hand it to the specific protocol handler */
757*9ef1f84bSDavid du Colombier ip = (Myip4hdr*)bp->rp;
758*9ef1f84bSDavid du Colombier if((ip->vihl & 0xF0) == IP_VER4) {
759*9ef1f84bSDavid du Colombier p = f->t2p[ip->proto];
760*9ef1f84bSDavid du Colombier } else {
761*9ef1f84bSDavid du Colombier ip6 = (Ip6hdr*)bp->rp;
762*9ef1f84bSDavid du Colombier p = f->t2p[ip6->proto];
763*9ef1f84bSDavid du Colombier }
764*9ef1f84bSDavid du Colombier if(p && p->rcv)
765*9ef1f84bSDavid du Colombier (*p->rcv)(p, ifc, bp);
766*9ef1f84bSDavid du Colombier else
767*9ef1f84bSDavid du Colombier freeblist(bp);
768*9ef1f84bSDavid du Colombier return;
769*9ef1f84bSDavid du Colombier }
770*9ef1f84bSDavid du Colombier
771*9ef1f84bSDavid du Colombier static int
ipmuxsprint(Ipmux * mux,int level,char * buf,int len)772*9ef1f84bSDavid du Colombier ipmuxsprint(Ipmux *mux, int level, char *buf, int len)
773*9ef1f84bSDavid du Colombier {
774*9ef1f84bSDavid du Colombier int i, j, n;
775*9ef1f84bSDavid du Colombier uchar *v;
776*9ef1f84bSDavid du Colombier
777*9ef1f84bSDavid du Colombier n = 0;
778*9ef1f84bSDavid du Colombier for(i = 0; i < level; i++)
779*9ef1f84bSDavid du Colombier n += snprint(buf+n, len-n, " ");
780*9ef1f84bSDavid du Colombier if(mux == nil){
781*9ef1f84bSDavid du Colombier n += snprint(buf+n, len-n, "\n");
782*9ef1f84bSDavid du Colombier return n;
783*9ef1f84bSDavid du Colombier }
784*9ef1f84bSDavid du Colombier n += snprint(buf+n, len-n, "h[%lld:%lld]&",
785*9ef1f84bSDavid du Colombier mux->off+((int)mux->skiphdr)*((uintptr)ipoff->data),
786*9ef1f84bSDavid du Colombier mux->off+(((int)mux->skiphdr)*((uintptr)ipoff->data))+mux->len-1);
787*9ef1f84bSDavid du Colombier for(i = 0; i < mux->len; i++)
788*9ef1f84bSDavid du Colombier n += snprint(buf+n, len - n, "%2.2ux", mux->mask[i]);
789*9ef1f84bSDavid du Colombier n += snprint(buf+n, len-n, "=");
790*9ef1f84bSDavid du Colombier v = mux->val;
791*9ef1f84bSDavid du Colombier for(j = 0; j < mux->n; j++){
792*9ef1f84bSDavid du Colombier for(i = 0; i < mux->len; i++)
793*9ef1f84bSDavid du Colombier n += snprint(buf+n, len - n, "%2.2ux", *v++);
794*9ef1f84bSDavid du Colombier n += snprint(buf+n, len-n, "|");
795*9ef1f84bSDavid du Colombier }
796*9ef1f84bSDavid du Colombier n += snprint(buf+n, len-n, "\n");
797*9ef1f84bSDavid du Colombier level++;
798*9ef1f84bSDavid du Colombier n += ipmuxsprint(mux->no, level, buf+n, len-n);
799*9ef1f84bSDavid du Colombier n += ipmuxsprint(mux->yes, level, buf+n, len-n);
800*9ef1f84bSDavid du Colombier return n;
801*9ef1f84bSDavid du Colombier }
802*9ef1f84bSDavid du Colombier
803*9ef1f84bSDavid du Colombier static int
ipmuxstats(Proto * p,char * buf,int len)804*9ef1f84bSDavid du Colombier ipmuxstats(Proto *p, char *buf, int len)
805*9ef1f84bSDavid du Colombier {
806*9ef1f84bSDavid du Colombier int n;
807*9ef1f84bSDavid du Colombier Fs *f = p->f;
808*9ef1f84bSDavid du Colombier
809*9ef1f84bSDavid du Colombier rlock(f);
810*9ef1f84bSDavid du Colombier n = ipmuxsprint(p->priv, 0, buf, len);
811*9ef1f84bSDavid du Colombier runlock(f);
812*9ef1f84bSDavid du Colombier
813*9ef1f84bSDavid du Colombier return n;
814*9ef1f84bSDavid du Colombier }
815*9ef1f84bSDavid du Colombier
816*9ef1f84bSDavid du Colombier void
ipmuxinit(Fs * f)817*9ef1f84bSDavid du Colombier ipmuxinit(Fs *f)
818*9ef1f84bSDavid du Colombier {
819*9ef1f84bSDavid du Colombier Proto *ipmux;
820*9ef1f84bSDavid du Colombier
821*9ef1f84bSDavid du Colombier ipmux = smalloc(sizeof(Proto));
822*9ef1f84bSDavid du Colombier ipmux->priv = nil;
823*9ef1f84bSDavid du Colombier ipmux->name = "ipmux";
824*9ef1f84bSDavid du Colombier ipmux->connect = ipmuxconnect;
825*9ef1f84bSDavid du Colombier ipmux->announce = ipmuxannounce;
826*9ef1f84bSDavid du Colombier ipmux->state = ipmuxstate;
827*9ef1f84bSDavid du Colombier ipmux->create = ipmuxcreate;
828*9ef1f84bSDavid du Colombier ipmux->close = ipmuxclose;
829*9ef1f84bSDavid du Colombier ipmux->rcv = ipmuxiput;
830*9ef1f84bSDavid du Colombier ipmux->ctl = nil;
831*9ef1f84bSDavid du Colombier ipmux->advise = nil;
832*9ef1f84bSDavid du Colombier ipmux->stats = ipmuxstats;
833*9ef1f84bSDavid du Colombier ipmux->ipproto = -1;
834*9ef1f84bSDavid du Colombier ipmux->nc = 64;
835*9ef1f84bSDavid du Colombier ipmux->ptclsize = sizeof(Ipmuxrock);
836*9ef1f84bSDavid du Colombier
837*9ef1f84bSDavid du Colombier f->ipmux = ipmux; /* hack for Fsrcvpcol */
838*9ef1f84bSDavid du Colombier
839*9ef1f84bSDavid du Colombier Fsproto(f, ipmux);
840*9ef1f84bSDavid du Colombier }
841