10774058cSDavid du Colombier /*
20774058cSDavid du Colombier * IP packet filter
30774058cSDavid du Colombier */
47dd7cddfSDavid du Colombier #include "u.h"
57dd7cddfSDavid du Colombier #include "../port/lib.h"
67dd7cddfSDavid du Colombier #include "mem.h"
77dd7cddfSDavid du Colombier #include "dat.h"
87dd7cddfSDavid du Colombier #include "fns.h"
97dd7cddfSDavid du Colombier #include "../port/error.h"
107dd7cddfSDavid du Colombier
117dd7cddfSDavid du Colombier #include "ip.h"
120774058cSDavid du Colombier #include "ipv6.h"
137dd7cddfSDavid du Colombier
147dd7cddfSDavid du Colombier typedef struct Ipmuxrock Ipmuxrock;
157dd7cddfSDavid du Colombier typedef struct Ipmux Ipmux;
167dd7cddfSDavid du Colombier
170774058cSDavid du Colombier typedef struct Myip4hdr Myip4hdr;
180774058cSDavid du Colombier struct Myip4hdr
197dd7cddfSDavid du Colombier {
207dd7cddfSDavid du Colombier uchar vihl; /* Version and header length */
217dd7cddfSDavid du Colombier uchar tos; /* Type of service */
227dd7cddfSDavid du Colombier uchar length[2]; /* packet length */
237dd7cddfSDavid du Colombier uchar id[2]; /* ip->identification */
247dd7cddfSDavid du Colombier uchar frag[2]; /* Fragment information */
257dd7cddfSDavid du Colombier uchar ttl; /* Time to live */
267dd7cddfSDavid du Colombier uchar proto; /* Protocol */
277dd7cddfSDavid du Colombier uchar cksum[2]; /* Header checksum */
287dd7cddfSDavid du Colombier uchar src[4]; /* IP source */
297dd7cddfSDavid du Colombier uchar dst[4]; /* IP destination */
300774058cSDavid du Colombier
317dd7cddfSDavid du Colombier uchar data[1]; /* start of data */
327dd7cddfSDavid du Colombier };
330774058cSDavid du Colombier Myip4hdr *ipoff = 0;
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier enum
367dd7cddfSDavid du Colombier {
377dd7cddfSDavid du Colombier Tproto,
387dd7cddfSDavid du Colombier Tdata,
393ff48bf5SDavid du Colombier Tiph,
407dd7cddfSDavid du Colombier Tdst,
417dd7cddfSDavid du Colombier Tsrc,
427dd7cddfSDavid du Colombier Tifc,
437dd7cddfSDavid du Colombier
447dd7cddfSDavid du Colombier Cother = 0,
457dd7cddfSDavid du Colombier Cbyte, /* single byte */
467dd7cddfSDavid du Colombier Cmbyte, /* single byte with mask */
477dd7cddfSDavid du Colombier Cshort, /* single short */
487dd7cddfSDavid du Colombier Cmshort, /* single short with mask */
497dd7cddfSDavid du Colombier Clong, /* single long */
507dd7cddfSDavid du Colombier Cmlong, /* single long with mask */
517dd7cddfSDavid du Colombier Cifc,
527dd7cddfSDavid du Colombier Cmifc,
537dd7cddfSDavid du Colombier };
547dd7cddfSDavid du Colombier
557dd7cddfSDavid du Colombier char *ftname[] =
567dd7cddfSDavid du Colombier {
577dd7cddfSDavid du Colombier [Tproto] "proto",
587dd7cddfSDavid du Colombier [Tdata] "data",
593ff48bf5SDavid du Colombier [Tiph] "iph",
607dd7cddfSDavid du Colombier [Tdst] "dst",
617dd7cddfSDavid du Colombier [Tsrc] "src",
627dd7cddfSDavid du Colombier [Tifc] "ifc",
637dd7cddfSDavid du Colombier };
647dd7cddfSDavid du Colombier
657dd7cddfSDavid du Colombier /*
667dd7cddfSDavid du Colombier * a node in the decision tree
677dd7cddfSDavid du Colombier */
687dd7cddfSDavid du Colombier struct Ipmux
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier Ipmux *yes;
717dd7cddfSDavid du Colombier Ipmux *no;
727dd7cddfSDavid du Colombier uchar type; /* type of field(Txxxx) */
737dd7cddfSDavid du Colombier uchar ctype; /* tupe of comparison(Cxxxx) */
747dd7cddfSDavid du Colombier uchar len; /* length in bytes of item to compare */
757dd7cddfSDavid du Colombier uchar n; /* number of items val points to */
767dd7cddfSDavid du Colombier short off; /* offset of comparison */
777dd7cddfSDavid du Colombier short eoff; /* end offset of comparison */
783ff48bf5SDavid du Colombier uchar skiphdr; /* should offset start after ipheader */
797dd7cddfSDavid du Colombier uchar *val;
807dd7cddfSDavid du Colombier uchar *mask;
817dd7cddfSDavid du Colombier uchar *e; /* val+n*len*/
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier int ref; /* so we can garbage collect */
847dd7cddfSDavid du Colombier Conv *conv;
857dd7cddfSDavid du Colombier };
867dd7cddfSDavid du Colombier
877dd7cddfSDavid du Colombier /*
887dd7cddfSDavid du Colombier * someplace to hold per conversation data
897dd7cddfSDavid du Colombier */
907dd7cddfSDavid du Colombier struct Ipmuxrock
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier Ipmux *chain;
937dd7cddfSDavid du Colombier };
947dd7cddfSDavid du Colombier
957dd7cddfSDavid du Colombier static int ipmuxsprint(Ipmux*, int, char*, int);
963ff48bf5SDavid du Colombier static void ipmuxkick(void *x);
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier static char*
skipwhite(char * p)997dd7cddfSDavid du Colombier skipwhite(char *p)
1007dd7cddfSDavid du Colombier {
1017dd7cddfSDavid du Colombier while(*p == ' ' || *p == '\t')
1027dd7cddfSDavid du Colombier p++;
1037dd7cddfSDavid du Colombier return p;
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier static char*
follows(char * p,char c)1077dd7cddfSDavid du Colombier follows(char *p, char c)
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier char *f;
1107dd7cddfSDavid du Colombier
1117dd7cddfSDavid du Colombier f = strchr(p, c);
1127dd7cddfSDavid du Colombier if(f == nil)
1137dd7cddfSDavid du Colombier return nil;
1147dd7cddfSDavid du Colombier *f++ = 0;
1157dd7cddfSDavid du Colombier f = skipwhite(f);
1167dd7cddfSDavid du Colombier if(*f == 0)
1177dd7cddfSDavid du Colombier return nil;
1187dd7cddfSDavid du Colombier return f;
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier
1217dd7cddfSDavid du Colombier static Ipmux*
parseop(char ** pp)1227dd7cddfSDavid du Colombier parseop(char **pp)
1237dd7cddfSDavid du Colombier {
1247dd7cddfSDavid du Colombier char *p = *pp;
1257dd7cddfSDavid du Colombier int type, off, end, len;
1267dd7cddfSDavid du Colombier Ipmux *f;
1277dd7cddfSDavid du Colombier
1287dd7cddfSDavid du Colombier p = skipwhite(p);
1297dd7cddfSDavid du Colombier if(strncmp(p, "dst", 3) == 0){
1307dd7cddfSDavid du Colombier type = Tdst;
1317dd7cddfSDavid du Colombier off = (ulong)(ipoff->dst);
1327dd7cddfSDavid du Colombier len = IPv4addrlen;
1337dd7cddfSDavid du Colombier p += 3;
1347dd7cddfSDavid du Colombier }
1357dd7cddfSDavid du Colombier else if(strncmp(p, "src", 3) == 0){
1367dd7cddfSDavid du Colombier type = Tsrc;
1377dd7cddfSDavid du Colombier off = (ulong)(ipoff->src);
1387dd7cddfSDavid du Colombier len = IPv4addrlen;
1397dd7cddfSDavid du Colombier p += 3;
1407dd7cddfSDavid du Colombier }
1417dd7cddfSDavid du Colombier else if(strncmp(p, "ifc", 3) == 0){
1427dd7cddfSDavid du Colombier type = Tifc;
1437dd7cddfSDavid du Colombier off = -IPv4addrlen;
1447dd7cddfSDavid du Colombier len = IPv4addrlen;
1457dd7cddfSDavid du Colombier p += 3;
1467dd7cddfSDavid du Colombier }
1477dd7cddfSDavid du Colombier else if(strncmp(p, "proto", 5) == 0){
1487dd7cddfSDavid du Colombier type = Tproto;
1497dd7cddfSDavid du Colombier off = (ulong)&(ipoff->proto);
1507dd7cddfSDavid du Colombier len = 1;
1517dd7cddfSDavid du Colombier p += 5;
1527dd7cddfSDavid du Colombier }
1533ff48bf5SDavid du Colombier else if(strncmp(p, "data", 4) == 0 || strncmp(p, "iph", 3) == 0){
1543ff48bf5SDavid du Colombier if(strncmp(p, "data", 4) == 0) {
1557dd7cddfSDavid du Colombier type = Tdata;
1567dd7cddfSDavid du Colombier p += 4;
1573ff48bf5SDavid du Colombier }
1583ff48bf5SDavid du Colombier else {
1593ff48bf5SDavid du Colombier type = Tiph;
1603ff48bf5SDavid du Colombier p += 3;
1613ff48bf5SDavid du Colombier }
1627dd7cddfSDavid du Colombier p = skipwhite(p);
1637dd7cddfSDavid du Colombier if(*p != '[')
1647dd7cddfSDavid du Colombier return nil;
1657dd7cddfSDavid du Colombier p++;
1667dd7cddfSDavid du Colombier off = strtoul(p, &p, 0);
1670774058cSDavid du Colombier if(off < 0 || off > (64-IP4HDR))
1687dd7cddfSDavid du Colombier return nil;
1697dd7cddfSDavid du Colombier p = skipwhite(p);
1707dd7cddfSDavid du Colombier if(*p != ':')
1717dd7cddfSDavid du Colombier end = off;
1727dd7cddfSDavid du Colombier else {
1737dd7cddfSDavid du Colombier p++;
1747dd7cddfSDavid du Colombier p = skipwhite(p);
1757dd7cddfSDavid du Colombier end = strtoul(p, &p, 0);
1767dd7cddfSDavid du Colombier if(end < off)
1777dd7cddfSDavid du Colombier return nil;
1787dd7cddfSDavid du Colombier p = skipwhite(p);
1797dd7cddfSDavid du Colombier }
1807dd7cddfSDavid du Colombier if(*p != ']')
1817dd7cddfSDavid du Colombier return nil;
1827dd7cddfSDavid du Colombier p++;
1837dd7cddfSDavid du Colombier len = end - off + 1;
1847dd7cddfSDavid du Colombier }
1857dd7cddfSDavid du Colombier else
1867dd7cddfSDavid du Colombier return nil;
1877dd7cddfSDavid du Colombier
1887dd7cddfSDavid du Colombier f = smalloc(sizeof(*f));
1897dd7cddfSDavid du Colombier f->type = type;
1907dd7cddfSDavid du Colombier f->len = len;
1917dd7cddfSDavid du Colombier f->off = off;
1927dd7cddfSDavid du Colombier f->val = nil;
1937dd7cddfSDavid du Colombier f->mask = nil;
1947dd7cddfSDavid du Colombier f->n = 1;
1957dd7cddfSDavid du Colombier f->ref = 1;
1963ff48bf5SDavid du Colombier if(type == Tdata)
1973ff48bf5SDavid du Colombier f->skiphdr = 1;
1983ff48bf5SDavid du Colombier else
1993ff48bf5SDavid du Colombier f->skiphdr = 0;
2007dd7cddfSDavid du Colombier
2017dd7cddfSDavid du Colombier return f;
2027dd7cddfSDavid du Colombier }
2037dd7cddfSDavid du Colombier
2047dd7cddfSDavid du Colombier static int
htoi(char x)2057dd7cddfSDavid du Colombier htoi(char x)
2067dd7cddfSDavid du Colombier {
2077dd7cddfSDavid du Colombier if(x >= '0' && x <= '9')
2087dd7cddfSDavid du Colombier x -= '0';
2097dd7cddfSDavid du Colombier else if(x >= 'a' && x <= 'f')
2107dd7cddfSDavid du Colombier x -= 'a' - 10;
2117dd7cddfSDavid du Colombier else if(x >= 'A' && x <= 'F')
2127dd7cddfSDavid du Colombier x -= 'A' - 10;
2137dd7cddfSDavid du Colombier else
2147dd7cddfSDavid du Colombier x = 0;
2157dd7cddfSDavid du Colombier return x;
2167dd7cddfSDavid du Colombier }
2177dd7cddfSDavid du Colombier
2187dd7cddfSDavid du Colombier static int
hextoi(char * p)2197dd7cddfSDavid du Colombier hextoi(char *p)
2207dd7cddfSDavid du Colombier {
2217dd7cddfSDavid du Colombier return (htoi(p[0])<<4) | htoi(p[1]);
2227dd7cddfSDavid du Colombier }
2237dd7cddfSDavid du Colombier
2247dd7cddfSDavid du Colombier static void
parseval(uchar * v,char * p,int len)2257dd7cddfSDavid du Colombier parseval(uchar *v, char *p, int len)
2267dd7cddfSDavid du Colombier {
2277dd7cddfSDavid du Colombier while(*p && len-- > 0){
2287dd7cddfSDavid du Colombier *v++ = hextoi(p);
2297dd7cddfSDavid du Colombier p += 2;
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier
2337dd7cddfSDavid du Colombier static Ipmux*
parsemux(char * p)2347dd7cddfSDavid du Colombier parsemux(char *p)
2357dd7cddfSDavid du Colombier {
2367dd7cddfSDavid du Colombier int n, nomask;
2377dd7cddfSDavid du Colombier Ipmux *f;
2387dd7cddfSDavid du Colombier char *val;
2397dd7cddfSDavid du Colombier char *mask;
2407dd7cddfSDavid du Colombier char *vals[20];
2417dd7cddfSDavid du Colombier uchar *v;
2427dd7cddfSDavid du Colombier
2437dd7cddfSDavid du Colombier /* parse operand */
2447dd7cddfSDavid du Colombier f = parseop(&p);
2457dd7cddfSDavid du Colombier if(f == nil)
2467dd7cddfSDavid du Colombier return nil;
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier /* find value */
2497dd7cddfSDavid du Colombier val = follows(p, '=');
2507dd7cddfSDavid du Colombier if(val == nil)
2517dd7cddfSDavid du Colombier goto parseerror;
2527dd7cddfSDavid du Colombier
2537dd7cddfSDavid du Colombier /* parse mask */
2547dd7cddfSDavid du Colombier mask = follows(p, '&');
2557dd7cddfSDavid du Colombier if(mask != nil){
2567dd7cddfSDavid du Colombier switch(f->type){
2577dd7cddfSDavid du Colombier case Tsrc:
2587dd7cddfSDavid du Colombier case Tdst:
2597dd7cddfSDavid du Colombier case Tifc:
2607dd7cddfSDavid du Colombier f->mask = smalloc(f->len);
2617dd7cddfSDavid du Colombier v4parseip(f->mask, mask);
2627dd7cddfSDavid du Colombier break;
2637dd7cddfSDavid du Colombier case Tdata:
2643ff48bf5SDavid du Colombier case Tiph:
2657dd7cddfSDavid du Colombier f->mask = smalloc(f->len);
2667dd7cddfSDavid du Colombier parseval(f->mask, mask, f->len);
2677dd7cddfSDavid du Colombier break;
2687dd7cddfSDavid du Colombier default:
2697dd7cddfSDavid du Colombier goto parseerror;
2707dd7cddfSDavid du Colombier }
2717dd7cddfSDavid du Colombier nomask = 0;
2727dd7cddfSDavid du Colombier } else {
2737dd7cddfSDavid du Colombier nomask = 1;
2747dd7cddfSDavid du Colombier f->mask = smalloc(f->len);
2757dd7cddfSDavid du Colombier memset(f->mask, 0xff, f->len);
2767dd7cddfSDavid du Colombier }
2777dd7cddfSDavid du Colombier
2787dd7cddfSDavid du Colombier /* parse vals */
2797dd7cddfSDavid du Colombier f->n = getfields(val, vals, sizeof(vals)/sizeof(char*), 1, "|");
2807dd7cddfSDavid du Colombier if(f->n == 0)
2817dd7cddfSDavid du Colombier goto parseerror;
2827dd7cddfSDavid du Colombier f->val = smalloc(f->n*f->len);
2837dd7cddfSDavid du Colombier v = f->val;
2847dd7cddfSDavid du Colombier for(n = 0; n < f->n; n++){
2857dd7cddfSDavid du Colombier switch(f->type){
2867dd7cddfSDavid du Colombier case Tsrc:
2877dd7cddfSDavid du Colombier case Tdst:
2887dd7cddfSDavid du Colombier case Tifc:
2897dd7cddfSDavid du Colombier v4parseip(v, vals[n]);
2907dd7cddfSDavid du Colombier break;
2917dd7cddfSDavid du Colombier case Tproto:
2927dd7cddfSDavid du Colombier case Tdata:
2933ff48bf5SDavid du Colombier case Tiph:
2947dd7cddfSDavid du Colombier parseval(v, vals[n], f->len);
2957dd7cddfSDavid du Colombier break;
2967dd7cddfSDavid du Colombier }
2977dd7cddfSDavid du Colombier v += f->len;
2987dd7cddfSDavid du Colombier }
2997dd7cddfSDavid du Colombier
3007dd7cddfSDavid du Colombier f->eoff = f->off + f->len;
3017dd7cddfSDavid du Colombier f->e = f->val + f->n*f->len;
3027dd7cddfSDavid du Colombier f->ctype = Cother;
3037dd7cddfSDavid du Colombier if(f->n == 1){
3047dd7cddfSDavid du Colombier switch(f->len){
3057dd7cddfSDavid du Colombier case 1:
3067dd7cddfSDavid du Colombier f->ctype = nomask ? Cbyte : Cmbyte;
3077dd7cddfSDavid du Colombier break;
3087dd7cddfSDavid du Colombier case 2:
3097dd7cddfSDavid du Colombier f->ctype = nomask ? Cshort : Cmshort;
3107dd7cddfSDavid du Colombier break;
3117dd7cddfSDavid du Colombier case 4:
3127dd7cddfSDavid du Colombier if(f->type == Tifc)
3137dd7cddfSDavid du Colombier f->ctype = nomask ? Cifc : Cmifc;
3147dd7cddfSDavid du Colombier else
3157dd7cddfSDavid du Colombier f->ctype = nomask ? Clong : Cmlong;
3167dd7cddfSDavid du Colombier break;
3177dd7cddfSDavid du Colombier }
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier return f;
3207dd7cddfSDavid du Colombier
3217dd7cddfSDavid du Colombier parseerror:
3227dd7cddfSDavid du Colombier if(f->mask)
3237dd7cddfSDavid du Colombier free(f->mask);
3247dd7cddfSDavid du Colombier if(f->val)
3257dd7cddfSDavid du Colombier free(f->val);
3267dd7cddfSDavid du Colombier free(f);
3277dd7cddfSDavid du Colombier return nil;
3287dd7cddfSDavid du Colombier }
3297dd7cddfSDavid du Colombier
3307dd7cddfSDavid du Colombier /*
3317dd7cddfSDavid du Colombier * Compare relative ordering of two ipmuxs. This doesn't compare the
3327dd7cddfSDavid du Colombier * values, just the fields being looked at.
3337dd7cddfSDavid du Colombier *
3347dd7cddfSDavid du Colombier * returns: <0 if a is a more specific match
3357dd7cddfSDavid du Colombier * 0 if a and b are matching on the same fields
3367dd7cddfSDavid du Colombier * >0 if b is a more specific match
3377dd7cddfSDavid du Colombier */
3387dd7cddfSDavid du Colombier static int
ipmuxcmp(Ipmux * a,Ipmux * b)3397dd7cddfSDavid du Colombier ipmuxcmp(Ipmux *a, Ipmux *b)
3407dd7cddfSDavid du Colombier {
3417dd7cddfSDavid du Colombier int n;
3427dd7cddfSDavid du Colombier
3437dd7cddfSDavid du Colombier /* compare types, lesser ones are more important */
3447dd7cddfSDavid du Colombier n = a->type - b->type;
3457dd7cddfSDavid du Colombier if(n != 0)
3467dd7cddfSDavid du Colombier return n;
3477dd7cddfSDavid du Colombier
3487dd7cddfSDavid du Colombier /* compare offsets, call earlier ones more specific */
3493ff48bf5SDavid du Colombier n = (a->off+((int)a->skiphdr)*(ulong)ipoff->data) -
3503ff48bf5SDavid du Colombier (b->off+((int)b->skiphdr)*(ulong)ipoff->data);
3517dd7cddfSDavid du Colombier if(n != 0)
3527dd7cddfSDavid du Colombier return n;
3537dd7cddfSDavid du Colombier
3547dd7cddfSDavid du Colombier /* compare match lengths, longer ones are more specific */
3557dd7cddfSDavid du Colombier n = b->len - a->len;
3567dd7cddfSDavid du Colombier if(n != 0)
3577dd7cddfSDavid du Colombier return n;
3587dd7cddfSDavid du Colombier
3597dd7cddfSDavid du Colombier /*
3607dd7cddfSDavid du Colombier * if we get here we have two entries matching
3617dd7cddfSDavid du Colombier * the same bytes of the record. Now check
3627dd7cddfSDavid du Colombier * the mask for equality. Longer masks are
3637dd7cddfSDavid du Colombier * more specific.
3647dd7cddfSDavid du Colombier */
3657dd7cddfSDavid du Colombier if(a->mask != nil && b->mask == nil)
3667dd7cddfSDavid du Colombier return -1;
3677dd7cddfSDavid du Colombier if(a->mask == nil && b->mask != nil)
3687dd7cddfSDavid du Colombier return 1;
3697dd7cddfSDavid du Colombier if(a->mask != nil && b->mask != nil){
3707dd7cddfSDavid du Colombier n = memcmp(b->mask, a->mask, a->len);
3717dd7cddfSDavid du Colombier if(n != 0)
3727dd7cddfSDavid du Colombier return n;
3737dd7cddfSDavid du Colombier }
3747dd7cddfSDavid du Colombier return 0;
3757dd7cddfSDavid du Colombier }
3767dd7cddfSDavid du Colombier
3777dd7cddfSDavid du Colombier /*
3787dd7cddfSDavid du Colombier * Compare the values of two ipmuxs. We're assuming that ipmuxcmp
3797dd7cddfSDavid du Colombier * returned 0 comparing them.
3807dd7cddfSDavid du Colombier */
3817dd7cddfSDavid du Colombier static int
ipmuxvalcmp(Ipmux * a,Ipmux * b)3827dd7cddfSDavid du Colombier ipmuxvalcmp(Ipmux *a, Ipmux *b)
3837dd7cddfSDavid du Colombier {
3847dd7cddfSDavid du Colombier int n;
3857dd7cddfSDavid du Colombier
3867dd7cddfSDavid du Colombier n = b->len*b->n - a->len*a->n;
3877dd7cddfSDavid du Colombier if(n != 0)
3887dd7cddfSDavid du Colombier return n;
3897dd7cddfSDavid du Colombier return memcmp(a->val, b->val, a->len*a->n);
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier
3927dd7cddfSDavid du Colombier /*
3937dd7cddfSDavid du Colombier * add onto an existing ipmux chain in the canonical comparison
3947dd7cddfSDavid du Colombier * order
3957dd7cddfSDavid du Colombier */
3967dd7cddfSDavid du Colombier static void
ipmuxchain(Ipmux ** l,Ipmux * f)3977dd7cddfSDavid du Colombier ipmuxchain(Ipmux **l, Ipmux *f)
3987dd7cddfSDavid du Colombier {
3997dd7cddfSDavid du Colombier for(; *l; l = &(*l)->yes)
4007dd7cddfSDavid du Colombier if(ipmuxcmp(f, *l) < 0)
4017dd7cddfSDavid du Colombier break;
4027dd7cddfSDavid du Colombier f->yes = *l;
4037dd7cddfSDavid du Colombier *l = f;
4047dd7cddfSDavid du Colombier }
4057dd7cddfSDavid du Colombier
4067dd7cddfSDavid du Colombier /*
4077dd7cddfSDavid du Colombier * copy a tree
4087dd7cddfSDavid du Colombier */
4097dd7cddfSDavid du Colombier static Ipmux*
ipmuxcopy(Ipmux * f)4107dd7cddfSDavid du Colombier ipmuxcopy(Ipmux *f)
4117dd7cddfSDavid du Colombier {
4127dd7cddfSDavid du Colombier Ipmux *nf;
4137dd7cddfSDavid du Colombier
4147dd7cddfSDavid du Colombier if(f == nil)
4157dd7cddfSDavid du Colombier return nil;
4167dd7cddfSDavid du Colombier nf = smalloc(sizeof *nf);
4177dd7cddfSDavid du Colombier *nf = *f;
4187dd7cddfSDavid du Colombier nf->no = ipmuxcopy(f->no);
4197dd7cddfSDavid du Colombier nf->yes = ipmuxcopy(f->yes);
4207dd7cddfSDavid du Colombier nf->val = smalloc(f->n*f->len);
4217dd7cddfSDavid du Colombier nf->e = nf->val + f->len*f->n;
4227dd7cddfSDavid du Colombier memmove(nf->val, f->val, f->n*f->len);
4237dd7cddfSDavid du Colombier return nf;
4247dd7cddfSDavid du Colombier }
4257dd7cddfSDavid du Colombier
4267dd7cddfSDavid du Colombier static void
ipmuxfree(Ipmux * f)4277dd7cddfSDavid du Colombier ipmuxfree(Ipmux *f)
4287dd7cddfSDavid du Colombier {
4297dd7cddfSDavid du Colombier if(f->val != nil)
4307dd7cddfSDavid du Colombier free(f->val);
4317dd7cddfSDavid du Colombier free(f);
4327dd7cddfSDavid du Colombier }
4337dd7cddfSDavid du Colombier
4347dd7cddfSDavid du Colombier static void
ipmuxtreefree(Ipmux * f)4357dd7cddfSDavid du Colombier ipmuxtreefree(Ipmux *f)
4367dd7cddfSDavid du Colombier {
4377dd7cddfSDavid du Colombier if(f == nil)
4387dd7cddfSDavid du Colombier return;
4397dd7cddfSDavid du Colombier if(f->no != nil)
4407dd7cddfSDavid du Colombier ipmuxfree(f->no);
4417dd7cddfSDavid du Colombier if(f->yes != nil)
4427dd7cddfSDavid du Colombier ipmuxfree(f->yes);
4437dd7cddfSDavid du Colombier ipmuxfree(f);
4447dd7cddfSDavid du Colombier }
4457dd7cddfSDavid du Colombier
4467dd7cddfSDavid du Colombier /*
4477dd7cddfSDavid du Colombier * merge two trees
4487dd7cddfSDavid du Colombier */
4497dd7cddfSDavid du Colombier static Ipmux*
ipmuxmerge(Ipmux * a,Ipmux * b)4507dd7cddfSDavid du Colombier ipmuxmerge(Ipmux *a, Ipmux *b)
4517dd7cddfSDavid du Colombier {
4527dd7cddfSDavid du Colombier int n;
4537dd7cddfSDavid du Colombier Ipmux *f;
4547dd7cddfSDavid du Colombier
4557dd7cddfSDavid du Colombier if(a == nil)
4567dd7cddfSDavid du Colombier return b;
4577dd7cddfSDavid du Colombier if(b == nil)
4587dd7cddfSDavid du Colombier return a;
4597dd7cddfSDavid du Colombier n = ipmuxcmp(a, b);
4607dd7cddfSDavid du Colombier if(n < 0){
4617dd7cddfSDavid du Colombier f = ipmuxcopy(b);
4627dd7cddfSDavid du Colombier a->yes = ipmuxmerge(a->yes, b);
4637dd7cddfSDavid du Colombier a->no = ipmuxmerge(a->no, f);
4647dd7cddfSDavid du Colombier return a;
4657dd7cddfSDavid du Colombier }
4667dd7cddfSDavid du Colombier if(n > 0){
4677dd7cddfSDavid du Colombier f = ipmuxcopy(a);
4687dd7cddfSDavid du Colombier b->yes = ipmuxmerge(b->yes, a);
4697dd7cddfSDavid du Colombier b->no = ipmuxmerge(b->no, f);
4707dd7cddfSDavid du Colombier return b;
4717dd7cddfSDavid du Colombier }
4727dd7cddfSDavid du Colombier if(ipmuxvalcmp(a, b) == 0){
4737dd7cddfSDavid du Colombier a->yes = ipmuxmerge(a->yes, b->yes);
4747dd7cddfSDavid du Colombier a->no = ipmuxmerge(a->no, b->no);
4757dd7cddfSDavid du Colombier a->ref++;
4767dd7cddfSDavid du Colombier ipmuxfree(b);
4777dd7cddfSDavid du Colombier return a;
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier a->no = ipmuxmerge(a->no, b);
4807dd7cddfSDavid du Colombier return a;
4817dd7cddfSDavid du Colombier }
4827dd7cddfSDavid du Colombier
4837dd7cddfSDavid du Colombier /*
4847dd7cddfSDavid du Colombier * remove a chain from a demux tree. This is like merging accept that
4857dd7cddfSDavid du Colombier * we remove instead of insert.
4867dd7cddfSDavid du Colombier */
4877dd7cddfSDavid du Colombier static int
ipmuxremove(Ipmux ** l,Ipmux * f)4887dd7cddfSDavid du Colombier ipmuxremove(Ipmux **l, Ipmux *f)
4897dd7cddfSDavid du Colombier {
4907dd7cddfSDavid du Colombier int n, rv;
4917dd7cddfSDavid du Colombier Ipmux *ft;
4927dd7cddfSDavid du Colombier
4937dd7cddfSDavid du Colombier if(f == nil)
4947dd7cddfSDavid du Colombier return 0; /* we've removed it all */
4957dd7cddfSDavid du Colombier if(*l == nil)
4967dd7cddfSDavid du Colombier return -1;
4977dd7cddfSDavid du Colombier
4987dd7cddfSDavid du Colombier ft = *l;
4997dd7cddfSDavid du Colombier n = ipmuxcmp(ft, f);
5007dd7cddfSDavid du Colombier if(n < 0){
5017dd7cddfSDavid du Colombier /* *l is maching an earlier field, descend both paths */
5027dd7cddfSDavid du Colombier rv = ipmuxremove(&ft->yes, f);
5037dd7cddfSDavid du Colombier rv += ipmuxremove(&ft->no, f);
5047dd7cddfSDavid du Colombier return rv;
5057dd7cddfSDavid du Colombier }
5067dd7cddfSDavid du Colombier if(n > 0){
5077dd7cddfSDavid du Colombier /* f represents an earlier field than *l, this should be impossible */
5087dd7cddfSDavid du Colombier return -1;
5097dd7cddfSDavid du Colombier }
5107dd7cddfSDavid du Colombier
5117dd7cddfSDavid du Colombier /* if we get here f and *l are comparing the same fields */
5127dd7cddfSDavid du Colombier if(ipmuxvalcmp(ft, f) != 0){
5137dd7cddfSDavid du Colombier /* different values mean mutually exclusive */
5147dd7cddfSDavid du Colombier return ipmuxremove(&ft->no, f);
5157dd7cddfSDavid du Colombier }
5167dd7cddfSDavid du Colombier
5177dd7cddfSDavid du Colombier /* we found a match */
5187dd7cddfSDavid du Colombier if(--(ft->ref) == 0){
5197dd7cddfSDavid du Colombier /*
5207dd7cddfSDavid du Colombier * a dead node implies the whole yes side is also dead.
5217dd7cddfSDavid du Colombier * since our chain is constrained to be on that side,
5227dd7cddfSDavid du Colombier * we're done.
5237dd7cddfSDavid du Colombier */
5247dd7cddfSDavid du Colombier ipmuxtreefree(ft->yes);
5257dd7cddfSDavid du Colombier *l = ft->no;
5267dd7cddfSDavid du Colombier ipmuxfree(ft);
5277dd7cddfSDavid du Colombier return 0;
5287dd7cddfSDavid du Colombier }
5297dd7cddfSDavid du Colombier
5307dd7cddfSDavid du Colombier /*
5317dd7cddfSDavid du Colombier * free the rest of the chain. it is constrained to match the
5327dd7cddfSDavid du Colombier * yes side.
5337dd7cddfSDavid du Colombier */
5347dd7cddfSDavid du Colombier return ipmuxremove(&ft->yes, f->yes);
5357dd7cddfSDavid du Colombier }
5367dd7cddfSDavid du Colombier
5377dd7cddfSDavid du Colombier /*
5387dd7cddfSDavid du Colombier * connection request is a semi separated list of filters
539d36a2583SDavid du Colombier * e.g. proto=17;data[0:4]=11aa22bb;ifc=135.104.9.2&255.255.255.0
5407dd7cddfSDavid du Colombier *
5417dd7cddfSDavid du Colombier * there's no protection against overlapping specs.
5427dd7cddfSDavid du Colombier */
5437dd7cddfSDavid du Colombier static char*
ipmuxconnect(Conv * c,char ** argv,int argc)5447dd7cddfSDavid du Colombier ipmuxconnect(Conv *c, char **argv, int argc)
5457dd7cddfSDavid du Colombier {
5467dd7cddfSDavid du Colombier int i, n;
5477dd7cddfSDavid du Colombier char *field[10];
5487dd7cddfSDavid du Colombier Ipmux *mux, *chain;
5497dd7cddfSDavid du Colombier Ipmuxrock *r;
5507dd7cddfSDavid du Colombier Fs *f;
5517dd7cddfSDavid du Colombier
5527dd7cddfSDavid du Colombier f = c->p->f;
5537dd7cddfSDavid du Colombier
5547dd7cddfSDavid du Colombier if(argc != 2)
5557dd7cddfSDavid du Colombier return Ebadarg;
5567dd7cddfSDavid du Colombier
5577dd7cddfSDavid du Colombier n = getfields(argv[1], field, nelem(field), 1, ";");
5587dd7cddfSDavid du Colombier if(n <= 0)
5597dd7cddfSDavid du Colombier return Ebadarg;
5607dd7cddfSDavid du Colombier
5617dd7cddfSDavid du Colombier chain = nil;
5627dd7cddfSDavid du Colombier mux = nil;
5637dd7cddfSDavid du Colombier for(i = 0; i < n; i++){
5647dd7cddfSDavid du Colombier mux = parsemux(field[i]);
5657dd7cddfSDavid du Colombier if(mux == nil){
5667dd7cddfSDavid du Colombier ipmuxtreefree(chain);
5677dd7cddfSDavid du Colombier return Ebadarg;
5687dd7cddfSDavid du Colombier }
5697dd7cddfSDavid du Colombier ipmuxchain(&chain, mux);
5707dd7cddfSDavid du Colombier }
5717dd7cddfSDavid du Colombier if(chain == nil)
5727dd7cddfSDavid du Colombier return Ebadarg;
5737dd7cddfSDavid du Colombier mux->conv = c;
5747dd7cddfSDavid du Colombier
5757dd7cddfSDavid du Colombier /* save a copy of the chain so we can later remove it */
5767dd7cddfSDavid du Colombier mux = ipmuxcopy(chain);
5777dd7cddfSDavid du Colombier r = (Ipmuxrock*)(c->ptcl);
5787dd7cddfSDavid du Colombier r->chain = chain;
5797dd7cddfSDavid du Colombier
5807dd7cddfSDavid du Colombier /* add the chain to the protocol demultiplexor tree */
5817dd7cddfSDavid du Colombier wlock(f);
5827dd7cddfSDavid du Colombier f->ipmux->priv = ipmuxmerge(f->ipmux->priv, mux);
5837dd7cddfSDavid du Colombier wunlock(f);
5847dd7cddfSDavid du Colombier
5857dd7cddfSDavid du Colombier Fsconnected(c, nil);
5867dd7cddfSDavid du Colombier return nil;
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier
5897dd7cddfSDavid du Colombier static int
ipmuxstate(Conv * c,char * state,int n)5907dd7cddfSDavid du Colombier ipmuxstate(Conv *c, char *state, int n)
5917dd7cddfSDavid du Colombier {
5927dd7cddfSDavid du Colombier Ipmuxrock *r;
5937dd7cddfSDavid du Colombier
5947dd7cddfSDavid du Colombier r = (Ipmuxrock*)(c->ptcl);
5957dd7cddfSDavid du Colombier return ipmuxsprint(r->chain, 0, state, n);
5967dd7cddfSDavid du Colombier }
5977dd7cddfSDavid du Colombier
5987dd7cddfSDavid du Colombier static void
ipmuxcreate(Conv * c)5997dd7cddfSDavid du Colombier ipmuxcreate(Conv *c)
6007dd7cddfSDavid du Colombier {
6017dd7cddfSDavid du Colombier Ipmuxrock *r;
6027dd7cddfSDavid du Colombier
6033ff48bf5SDavid du Colombier c->rq = qopen(64*1024, Qmsg, 0, c);
6043ff48bf5SDavid du Colombier c->wq = qopen(64*1024, Qkick, ipmuxkick, c);
6057dd7cddfSDavid du Colombier r = (Ipmuxrock*)(c->ptcl);
6067dd7cddfSDavid du Colombier r->chain = nil;
6077dd7cddfSDavid du Colombier }
6087dd7cddfSDavid du Colombier
6097dd7cddfSDavid du Colombier static char*
ipmuxannounce(Conv *,char **,int)6107dd7cddfSDavid du Colombier ipmuxannounce(Conv*, char**, int)
6117dd7cddfSDavid du Colombier {
6127dd7cddfSDavid du Colombier return "ipmux does not support announce";
6137dd7cddfSDavid du Colombier }
6147dd7cddfSDavid du Colombier
6157dd7cddfSDavid du Colombier static void
ipmuxclose(Conv * c)6167dd7cddfSDavid du Colombier ipmuxclose(Conv *c)
6177dd7cddfSDavid du Colombier {
6187dd7cddfSDavid du Colombier Ipmuxrock *r;
6197dd7cddfSDavid du Colombier Fs *f = c->p->f;
6207dd7cddfSDavid du Colombier
6217dd7cddfSDavid du Colombier r = (Ipmuxrock*)(c->ptcl);
6227dd7cddfSDavid du Colombier
6237dd7cddfSDavid du Colombier qclose(c->rq);
6247dd7cddfSDavid du Colombier qclose(c->wq);
6257dd7cddfSDavid du Colombier qclose(c->eq);
6267dd7cddfSDavid du Colombier ipmove(c->laddr, IPnoaddr);
6277dd7cddfSDavid du Colombier ipmove(c->raddr, IPnoaddr);
6287dd7cddfSDavid du Colombier c->lport = 0;
6297dd7cddfSDavid du Colombier c->rport = 0;
6307dd7cddfSDavid du Colombier
6317dd7cddfSDavid du Colombier wlock(f);
6327dd7cddfSDavid du Colombier ipmuxremove(&(c->p->priv), r->chain);
6337dd7cddfSDavid du Colombier wunlock(f);
6347dd7cddfSDavid du Colombier ipmuxtreefree(r->chain);
6357dd7cddfSDavid du Colombier r->chain = nil;
6367dd7cddfSDavid du Colombier }
6377dd7cddfSDavid du Colombier
6387dd7cddfSDavid du Colombier /*
6397dd7cddfSDavid du Colombier * takes a fully formed ip packet and just passes it down
6407dd7cddfSDavid du Colombier * the stack
6417dd7cddfSDavid du Colombier */
6427dd7cddfSDavid du Colombier static void
ipmuxkick(void * x)6433ff48bf5SDavid du Colombier ipmuxkick(void *x)
6447dd7cddfSDavid du Colombier {
6453ff48bf5SDavid du Colombier Conv *c = x;
6467dd7cddfSDavid du Colombier Block *bp;
6477dd7cddfSDavid du Colombier
6487dd7cddfSDavid du Colombier bp = qget(c->wq);
6490774058cSDavid du Colombier if(bp != nil) {
6500774058cSDavid du Colombier Myip4hdr *ih4 = (Myip4hdr*)(bp->rp);
6510774058cSDavid du Colombier
6520774058cSDavid du Colombier if((ih4->vihl & 0xF0) != IP_VER6)
653a6a9e072SDavid du Colombier ipoput4(c->p->f, bp, 0, ih4->ttl, ih4->tos, nil);
6540774058cSDavid du Colombier else
6550774058cSDavid du Colombier ipoput6(c->p->f, bp, 0, ((Ip6hdr*)ih4)->ttl, 0, nil);
6563ff48bf5SDavid du Colombier }
6577dd7cddfSDavid du Colombier }
6587dd7cddfSDavid du Colombier
6597dd7cddfSDavid du Colombier static void
ipmuxiput(Proto * p,Ipifc * ifc,Block * bp)6609a747e4fSDavid du Colombier ipmuxiput(Proto *p, Ipifc *ifc, Block *bp)
6617dd7cddfSDavid du Colombier {
6623ff48bf5SDavid du Colombier int len, hl;
6637dd7cddfSDavid du Colombier Fs *f = p->f;
6647dd7cddfSDavid du Colombier uchar *m, *h, *v, *e, *ve, *hp;
6657dd7cddfSDavid du Colombier Conv *c;
6667dd7cddfSDavid du Colombier Ipmux *mux;
6670774058cSDavid du Colombier Myip4hdr *ip;
6683ff48bf5SDavid du Colombier Ip6hdr *ip6;
6699a747e4fSDavid du Colombier
6700774058cSDavid du Colombier ip = (Myip4hdr*)bp->rp;
6713ff48bf5SDavid du Colombier hl = (ip->vihl&0x0F)<<2;
6727dd7cddfSDavid du Colombier
6737dd7cddfSDavid du Colombier if(p->priv == nil)
6747dd7cddfSDavid du Colombier goto nomatch;
6757dd7cddfSDavid du Colombier
6767dd7cddfSDavid du Colombier h = bp->rp;
6777dd7cddfSDavid du Colombier len = BLEN(bp);
6787dd7cddfSDavid du Colombier
6797dd7cddfSDavid du Colombier /* run the v4 filter */
6807dd7cddfSDavid du Colombier rlock(f);
6817dd7cddfSDavid du Colombier c = nil;
6827dd7cddfSDavid du Colombier mux = f->ipmux->priv;
6837dd7cddfSDavid du Colombier while(mux != nil){
6847dd7cddfSDavid du Colombier if(mux->eoff > len){
6857dd7cddfSDavid du Colombier mux = mux->no;
6867dd7cddfSDavid du Colombier continue;
6877dd7cddfSDavid du Colombier }
6883ff48bf5SDavid du Colombier hp = h + mux->off + ((int)mux->skiphdr)*hl;
6897dd7cddfSDavid du Colombier switch(mux->ctype){
6907dd7cddfSDavid du Colombier case Cbyte:
6917dd7cddfSDavid du Colombier if(*mux->val == *hp)
6927dd7cddfSDavid du Colombier goto yes;
6937dd7cddfSDavid du Colombier break;
6947dd7cddfSDavid du Colombier case Cmbyte:
6957dd7cddfSDavid du Colombier if((*hp & *mux->mask) == *mux->val)
6967dd7cddfSDavid du Colombier goto yes;
6977dd7cddfSDavid du Colombier break;
6987dd7cddfSDavid du Colombier case Cshort:
6997dd7cddfSDavid du Colombier if(*((ushort*)mux->val) == *(ushort*)hp)
7007dd7cddfSDavid du Colombier goto yes;
7017dd7cddfSDavid du Colombier break;
7027dd7cddfSDavid du Colombier case Cmshort:
7037dd7cddfSDavid du Colombier if((*(ushort*)hp & (*((ushort*)mux->mask))) == *((ushort*)mux->val))
7047dd7cddfSDavid du Colombier goto yes;
7057dd7cddfSDavid du Colombier break;
7067dd7cddfSDavid du Colombier case Clong:
7077dd7cddfSDavid du Colombier if(*((ulong*)mux->val) == *(ulong*)hp)
7087dd7cddfSDavid du Colombier goto yes;
7097dd7cddfSDavid du Colombier break;
7107dd7cddfSDavid du Colombier case Cmlong:
7117dd7cddfSDavid du Colombier if((*(ulong*)hp & (*((ulong*)mux->mask))) == *((ulong*)mux->val))
7127dd7cddfSDavid du Colombier goto yes;
7137dd7cddfSDavid du Colombier break;
7147dd7cddfSDavid du Colombier case Cifc:
7153ff48bf5SDavid du Colombier if(*((ulong*)mux->val) == *(ulong*)(ifc->lifc->local + IPv4off))
7167dd7cddfSDavid du Colombier goto yes;
7177dd7cddfSDavid du Colombier break;
7187dd7cddfSDavid du Colombier case Cmifc:
7193ff48bf5SDavid du Colombier if((*(ulong*)(ifc->lifc->local + IPv4off) & (*((ulong*)mux->mask))) == *((ulong*)mux->val))
7207dd7cddfSDavid du Colombier goto yes;
7217dd7cddfSDavid du Colombier break;
7227dd7cddfSDavid du Colombier default:
7237dd7cddfSDavid du Colombier v = mux->val;
7247dd7cddfSDavid du Colombier for(e = mux->e; v < e; v = ve){
7257dd7cddfSDavid du Colombier m = mux->mask;
7267dd7cddfSDavid du Colombier hp = h + mux->off;
7277dd7cddfSDavid du Colombier for(ve = v + mux->len; v < ve; v++){
7287dd7cddfSDavid du Colombier if((*hp++ & *m++) != *v)
7297dd7cddfSDavid du Colombier break;
7307dd7cddfSDavid du Colombier }
7317dd7cddfSDavid du Colombier if(v == ve)
7327dd7cddfSDavid du Colombier goto yes;
7337dd7cddfSDavid du Colombier }
7347dd7cddfSDavid du Colombier }
7357dd7cddfSDavid du Colombier mux = mux->no;
7367dd7cddfSDavid du Colombier continue;
7377dd7cddfSDavid du Colombier yes:
7387dd7cddfSDavid du Colombier if(mux->conv != nil)
7397dd7cddfSDavid du Colombier c = mux->conv;
7407dd7cddfSDavid du Colombier mux = mux->yes;
7417dd7cddfSDavid du Colombier }
7427dd7cddfSDavid du Colombier runlock(f);
7437dd7cddfSDavid du Colombier
7447dd7cddfSDavid du Colombier if(c != nil){
7457dd7cddfSDavid du Colombier /* tack on interface address */
7467dd7cddfSDavid du Colombier bp = padblock(bp, IPaddrlen);
7473ff48bf5SDavid du Colombier ipmove(bp->rp, ifc->lifc->local);
7487dd7cddfSDavid du Colombier bp = concatblock(bp);
7497dd7cddfSDavid du Colombier if(bp != nil)
7507dd7cddfSDavid du Colombier if(qpass(c->rq, bp) < 0)
751*6b7c5dceSDavid du Colombier print("ipmuxiput: qpass failed\n");
7527dd7cddfSDavid du Colombier return;
7537dd7cddfSDavid du Colombier }
7547dd7cddfSDavid du Colombier
7557dd7cddfSDavid du Colombier nomatch:
7567dd7cddfSDavid du Colombier /* doesn't match any filter, hand it to the specific protocol handler */
7570774058cSDavid du Colombier ip = (Myip4hdr*)bp->rp;
7580774058cSDavid du Colombier if((ip->vihl & 0xF0) == IP_VER4) {
7597dd7cddfSDavid du Colombier p = f->t2p[ip->proto];
7603ff48bf5SDavid du Colombier } else {
7613ff48bf5SDavid du Colombier ip6 = (Ip6hdr*)bp->rp;
7623ff48bf5SDavid du Colombier p = f->t2p[ip6->proto];
7633ff48bf5SDavid du Colombier }
7643ff48bf5SDavid du Colombier if(p && p->rcv)
7659a747e4fSDavid du Colombier (*p->rcv)(p, ifc, bp);
7667dd7cddfSDavid du Colombier else
7677dd7cddfSDavid du Colombier freeblist(bp);
7687dd7cddfSDavid du Colombier return;
7697dd7cddfSDavid du Colombier }
7707dd7cddfSDavid du Colombier
7717dd7cddfSDavid du Colombier static int
ipmuxsprint(Ipmux * mux,int level,char * buf,int len)7727dd7cddfSDavid du Colombier ipmuxsprint(Ipmux *mux, int level, char *buf, int len)
7737dd7cddfSDavid du Colombier {
7747dd7cddfSDavid du Colombier int i, j, n;
7757dd7cddfSDavid du Colombier uchar *v;
7767dd7cddfSDavid du Colombier
7777dd7cddfSDavid du Colombier n = 0;
7787dd7cddfSDavid du Colombier for(i = 0; i < level; i++)
7797dd7cddfSDavid du Colombier n += snprint(buf+n, len-n, " ");
7807dd7cddfSDavid du Colombier if(mux == nil){
7817dd7cddfSDavid du Colombier n += snprint(buf+n, len-n, "\n");
7827dd7cddfSDavid du Colombier return n;
7837dd7cddfSDavid du Colombier }
7843ff48bf5SDavid du Colombier n += snprint(buf+n, len-n, "h[%d:%d]&",
7853ff48bf5SDavid du Colombier mux->off+((int)mux->skiphdr)*((int)ipoff->data),
7863ff48bf5SDavid du Colombier mux->off+(((int)mux->skiphdr)*((int)ipoff->data))+mux->len-1);
7877dd7cddfSDavid du Colombier for(i = 0; i < mux->len; i++)
7887dd7cddfSDavid du Colombier n += snprint(buf+n, len - n, "%2.2ux", mux->mask[i]);
7897dd7cddfSDavid du Colombier n += snprint(buf+n, len-n, "=");
7907dd7cddfSDavid du Colombier v = mux->val;
7917dd7cddfSDavid du Colombier for(j = 0; j < mux->n; j++){
7927dd7cddfSDavid du Colombier for(i = 0; i < mux->len; i++)
7937dd7cddfSDavid du Colombier n += snprint(buf+n, len - n, "%2.2ux", *v++);
7947dd7cddfSDavid du Colombier n += snprint(buf+n, len-n, "|");
7957dd7cddfSDavid du Colombier }
7967dd7cddfSDavid du Colombier n += snprint(buf+n, len-n, "\n");
7977dd7cddfSDavid du Colombier level++;
7987dd7cddfSDavid du Colombier n += ipmuxsprint(mux->no, level, buf+n, len-n);
7997dd7cddfSDavid du Colombier n += ipmuxsprint(mux->yes, level, buf+n, len-n);
8007dd7cddfSDavid du Colombier return n;
8017dd7cddfSDavid du Colombier }
8027dd7cddfSDavid du Colombier
8037dd7cddfSDavid du Colombier static int
ipmuxstats(Proto * p,char * buf,int len)8047dd7cddfSDavid du Colombier ipmuxstats(Proto *p, char *buf, int len)
8057dd7cddfSDavid du Colombier {
8067dd7cddfSDavid du Colombier int n;
8077dd7cddfSDavid du Colombier Fs *f = p->f;
8087dd7cddfSDavid du Colombier
8097dd7cddfSDavid du Colombier rlock(f);
8107dd7cddfSDavid du Colombier n = ipmuxsprint(p->priv, 0, buf, len);
8117dd7cddfSDavid du Colombier runlock(f);
8127dd7cddfSDavid du Colombier
8137dd7cddfSDavid du Colombier return n;
8147dd7cddfSDavid du Colombier }
8157dd7cddfSDavid du Colombier
8167dd7cddfSDavid du Colombier void
ipmuxinit(Fs * f)8177dd7cddfSDavid du Colombier ipmuxinit(Fs *f)
8187dd7cddfSDavid du Colombier {
8197dd7cddfSDavid du Colombier Proto *ipmux;
8207dd7cddfSDavid du Colombier
8217dd7cddfSDavid du Colombier ipmux = smalloc(sizeof(Proto));
8227dd7cddfSDavid du Colombier ipmux->priv = nil;
8237dd7cddfSDavid du Colombier ipmux->name = "ipmux";
8247dd7cddfSDavid du Colombier ipmux->connect = ipmuxconnect;
8257dd7cddfSDavid du Colombier ipmux->announce = ipmuxannounce;
8267dd7cddfSDavid du Colombier ipmux->state = ipmuxstate;
8277dd7cddfSDavid du Colombier ipmux->create = ipmuxcreate;
8287dd7cddfSDavid du Colombier ipmux->close = ipmuxclose;
8297dd7cddfSDavid du Colombier ipmux->rcv = ipmuxiput;
8307dd7cddfSDavid du Colombier ipmux->ctl = nil;
8317dd7cddfSDavid du Colombier ipmux->advise = nil;
8327dd7cddfSDavid du Colombier ipmux->stats = ipmuxstats;
8337dd7cddfSDavid du Colombier ipmux->ipproto = -1;
8347dd7cddfSDavid du Colombier ipmux->nc = 64;
8357dd7cddfSDavid du Colombier ipmux->ptclsize = sizeof(Ipmuxrock);
8367dd7cddfSDavid du Colombier
8377dd7cddfSDavid du Colombier f->ipmux = ipmux; /* hack for Fsrcvpcol */
8387dd7cddfSDavid du Colombier
8397dd7cddfSDavid du Colombier Fsproto(f, ipmux);
8407dd7cddfSDavid du Colombier }
841