Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/ip/ipmux.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname ip/ipmux.c 1998/0324
## diff -e /dev/null /n/emeliedump/1998/0324/sys/src/brazil/ip/ipmux.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"

#include "ip.h"

#define DPRINT if(0)print

typedef struct Iphdr	Iphdr;

enum
{
	IPHDR		= 20,		/* sizeof(Iphdr) */
};

struct Iphdr
{
	uchar	vihl;		/* Version and header length */
	uchar	tos;		/* Type of service */
	uchar	length[2];	/* packet length */
	uchar	id[2];		/* ip->identification */
	uchar	frag[2];	/* Fragment information */
	uchar	ttl;		/* Time to live */
	uchar	proto;		/* Protocol */
	uchar	cksum[2];	/* Header checksum */
	uchar	src[4];		/* IP source */
	uchar	dst[4];		/* IP destination */
};

enum
{
	Tproto,
	Tdata,
	Tdst,
	Tsrc,
	Tifc,
};

char *ftname[] = 
{
[Tproto]	"proto",
[Tdata]		"data",
[Tdst]		"dst",
[Tsrc]		"src",
[Tifc]		"ifc",
};

typedef struct Ipmux Ipmux;

struct Ipmux
{
	Ipmux	*yes;
	Ipmux	*no;
	uchar	type;
	ushort	len;		/* length in bytes of item to compare */
	ushort	off;		/* offset of comparison */
	int	n;		/* number of items val points to */
	uchar	*val;
	uchar	*mask;

	int	ref;		/* so we can garbage collect */
};

static char*
skipwhite(char *p)
{
	while(*p == ' ' || *p == '\t')
		p++;
	return p;
}

static char*
follows(char *p, char c)
{
	char *f;

	f = strchr(p, c);
	if(f == nil)
		return nil;
	*f++ = 0;
	f = skipwhite(f);
	if(*f == 0)
		return nil;
	return f;
}

static Ipmux*
parseop(char **pp)
{
	char *p = *pp;
	int type, off, end, len;
	Ipmux *f;

	off = 0;
	p = skipwhite(p);
	if(strncmp(p, "dst", 3) == 0){
		type = Tdst;
		len = IPaddrlen;
		p += 3;
	}
	else if(strncmp(p, "src", 3) == 0){
		type = Tsrc;
		len = IPaddrlen;
		p += 3;
	}
	else if(strncmp(p, "ifc", 3) == 0){
		type = Tifc;
		len = IPaddrlen;
		p += 3;
	}
	else if(strncmp(p, "proto", 5) == 0){
		type = Tproto;
		len = 1;
		p += 5;
	}
	else if(strncmp(p, "data", 4) == 0){
		type = Tdata;
		p += 4;
		p = skipwhite(p);
		if(*p != '[')
			return nil;
		p++;
		off = strtoul(p, &p, 0);
		p = skipwhite(p);
		if(*p != ':')
			end = off;
		else {
			p++;
			p = skipwhite(p);
			end = strtoul(p, &p, 0);
			if(end < off)
				return nil;
			p = skipwhite(p);
		}
		if(*p != ']')
			return nil;
		len = end - off + 1;
		p++;
	}
	else 
		return nil;

	f = smalloc(sizeof(*f));
	f->type = type;
	f->len = len;
	f->off = off;
	f->val = nil;
	f->mask = nil;
	f->n = 1;
	f->ref = 1;

	return f;	
}

static int
htoi(char x)
{
	if(x >= '0' && x <= '9')
		x -= '0';
	else if(x >= 'a' && x <= 'f')
		x -= 'a' - 10;
	else if(x >= 'A' && x <= 'F')
		x -= 'A' - 10;
	else
		x = 0;
	return x;
}

static int
hextoi(char *p)
{
	return (htoi(p[0])<<4) | htoi(p[1]);
}

static void
parseval(uchar *v, char *p, int len)
{
	while(*p && len-- > 0){
		*v++ = hextoi(p);
		p += 2;
	}
}

static Ipmux*
parsedemux(char *p)
{
	int n;
	Ipmux *f;
	char *val;
	char *mask;
	char *vals[20];
	uchar *v;

	/* parse operand */
	f = parseop(&p);
	if(f == nil)
		return nil;

	/* find value */
	val = follows(p, '=');
	if(val == nil)
		goto parseerror;

	/* parse mask */
	mask = follows(p, '&');
	if(mask != nil){
		switch(f->type){
		case Tsrc:
		case Tdst:
		case Tifc:
			f->mask = smalloc(f->len);
			parseipmask(f->mask, mask);
			break;
		case Tdata:
			f->mask = smalloc(f->len);
			parseval(f->mask, mask, f->len);
			break;
		default:
			goto parseerror;
		}
	} else
		f->mask = nil;

	/* parse vals */
	f->n = tokenize(val, vals, sizeof(vals)/sizeof(char*));
	if(f->n == 0)
		goto parseerror;
	f->val = smalloc(f->n*f->len);
	v = f->val;
	for(n = 0; n < f->n; n++){
		switch(f->type){
		case Tsrc:
		case Tdst:
		case Tifc:
			parseip(v, vals[n]);
			break;
		case Tproto:
		case Tdata:
			parseval(v, vals[n], f->len);
			break;
		}
		v += f->len;
	}

	return f;

parseerror:
	if(f->mask)
		free(f->mask);
	if(f->val)
		free(f->val);
	free(f);
	return nil;
}

/*
 *  Compare relative ordering of two ipmuxs.  This doesn't compare the
 *  values, just the fields being looked at.  
 *
 *  returns:	<0 if a is a more specific match
 *		 0 if a and b are matching on the same fields
 *		>0 if b is a more specific match
 */
static int
ipmuxcmp(Ipmux *a, Ipmux *b)
{
	int n;

	/* compare types, lesser ones are more important */
	n = a->type - b->type;
	if(n != 0)
		return n;

	/* compare offsets, call earlier ones more specific */
	n = a->off - b->off;
	if(n != 0)
		return n;

	/* compare match lengths, longer ones are more specific */
	n = b->len - a->len;
	if(n != 0)
		return n;

	/*
	 *  if we get here we have two entries matching
	 *  the same bytes of the record.  Now check
	 *  the mask for equality.  Longer masks are
	 *  more specific.
	 */
	if(a->mask != nil && b->mask == nil)
		return -1;
	if(a->mask == nil && b->mask != nil)
		return 1;
	if(a->mask != nil && b->mask != nil){
		n = memcmp(b->mask, a->mask, a->len);
		if(n != 0)
			return n;
	}
	return 0;
}

/*
 *  Compare the values of two ipmuxs.  We're assuming that ipmuxcmp
 *  returned 0 comparing them.
 */
static int
ipmuxvalcmp(Ipmux *a, Ipmux *b)
{
	int n;

	n = b->len*b->n - a->len*a->n;
	if(n != 0)
		return n;
	return memcmp(a->val, b->val, a->len*a->n);
} 

/*
 *  add onto an existing ipmux chain in the canonical comparison
 *  order
 */
static void
ipmuxchain(Ipmux **l, Ipmux *f)
{
	for(; *l; l = &(*l)->yes)
		if(ipmuxcmp(f, *l) < 0)
			break;
	f->yes = *l;
	*l = f;
}

/*
 *  copy a tree
 */
static Ipmux*
ipmuxcopy(Ipmux *f)
{
	Ipmux *nf;

	if(f == nil)
		return nil;
	nf = smalloc(sizeof *nf);
	*nf = *f;
	nf->no = ipmuxcopy(f->no);
	nf->yes = ipmuxcopy(f->yes);
	nf->val = smalloc(f->n*f->len);
	memmove(nf->val, f->val, f->n*f->len);
	return nf;
}

static void
ipmuxfree(Ipmux *f)
{
	if(f->val != nil)
		free(f->val);
	free(f);
}

static void
ipmuxtreefree(Ipmux *f)
{
	if(f->no != nil)
		ipmuxfree(f->no);
	if(f->yes != nil)
		ipmuxfree(f->yes);
	ipmuxfree(f);
}

/*
 *  merge two trees
 */
static Ipmux*
ipmuxmerge(Ipmux *a, Ipmux *b)
{
	int n;
	Ipmux *f;

	if(a == nil)
		return b;
	if(b == nil)
		return a;
	n = ipmuxcmp(a, b);
	if(n < 0){
		f = ipmuxcopy(b);
		a->yes = ipmuxmerge(a->yes, b);
		a->no = ipmuxmerge(a->no, f);
		return a;
	}
	if(n > 0){
		f = ipmuxcopy(a);
		b->yes = ipmuxmerge(b->yes, a);
		b->no = ipmuxmerge(b->no, f);
		return b;
	}
	if(ipmuxvalcmp(a, b) == 0){
		a->yes = ipmuxmerge(a->yes, b->yes);
		a->no = ipmuxmerge(a->no, b->no);
		a->ref++;
		ipmuxfree(b);
		return a;
	}
	a->no = ipmuxmerge(a->no, b);
	return a;
}

/*
 *  remove a chain from a demux tree.  This is like merging accept that
 *  we remove instead of insert.
 */
int
ipmuxremove(Ipmux **l, Ipmux *f)
{
	int n, rv;
	Ipmux *ft;

	if(f == nil)
		return 0;		/* we've removed it all */
	if(*l == nil)
		return -1;

	ft = *l;
	n = ipmuxcmp(ft, f);
	if(n < 0){
		/* *l is maching an earlier field, descend both paths */
		rv = ipmuxremove(&ft->yes, f);
		rv += ipmuxremove(&ft->no, f);
		return rv;
	}
	if(n > 0){
		/* f represents an earlier field than *l, this should be impossible */
		return -1;
	}

	/* if we get here f and *l are comparing the same fields */
	if(ipmuxvalcmp(ft, f) != 0){
		/* different values mean mutually exclusive */
		return ipmuxremove(&ft->no, f);
	}

	/* we found a match */
	if(--(ft->ref) == 0){
		/*
		 *  a dead node implies the whole yes side is also dead.
		 *  since our chain is constrained to be on that side,
		 *  we're done.
		 */
		ipmuxtreefree(ft->yes);
		*l = ft->no;
		ipmuxfree(ft);
		return 0;
	}

	/*
	 *  free the rest of the chain.  it is constrained to match the
	 *  yes side.
	 */
	return ipmuxremove(&ft->yes, f->yes);
}

void
printtree(Biobuf *b, Ipmux *f, int level)
{
	int i, j;
	uchar *p;

	if(f == nil) {
		Bprint(b, "\n");
		return;
	}
	for(i = 0; i < level; i++)
		Bprint(b, " ");
	Bprint(b, "%s", ftname[f->type]);
	if(f->type == Tdata)
		Bprint(b, "[%d:%d]", f->off, f->off+f->len-1);
	if(f->mask){
		switch(f->type){
		case Tifc:
		case Tsrc:
		case Tdst:
			Bprint(b, " & %M", f->mask);
			break;
		case Tproto:
		case Tdata:
			Bprint(b, " & ");
			for(j = 0; j < f->len; j++)
				Bprint(b, "%2.2ux", f->mask[j]);
			break;
		}
	}
	p = f->val;
	Bprint(b, " =");
	for(i = 0; i < f->n; i++){
		switch(f->type){
		case Tifc:
		case Tsrc:
		case Tdst:
			Bprint(b, " %I", p);
			break;
		case Tproto:
		case Tdata:
			Bprint(b, " ");
			for(j = 0; j < f->len; j++)
				Bprint(b, "%2.2ux", p[j]);
			break;
		}
		p += f->len;
	}
	Bprint(b, "\n");
	printtree(b, f->yes, level+1);
	printtree(b, f->no, level+1);
}

void
main(void)
{
	Ipmux *f, *f1, *f2, *f1copy, *f2copy;
	Ipmux *root;
	Biobuf out;

	Binit(&out, 1, OWRITE);
	fmtinstall('I', eipconv);
	fmtinstall('M', eipconv);

	Bprint(&out, "demux 1:\n");
	f1 = parsedemux("data[0:3] = 12345678 23456789 3456789a");
	f = parsedemux("ifc = 135.104.9.2");
	ipmuxchain(&f1, f);
	f = parsedemux("src & 255.255.255.0 = 135.104.9.2");
	ipmuxchain(&f1, f);
	f = parsedemux("proto = 17");
	ipmuxchain(&f1, f);
	printtree(&out, f1, 0);

	f1copy = ipmuxcopy(f1);

	Bprint(&out, "demux 2:\n");
	f2 = parsedemux("data[0:3] = 12345678 23456789 3456789a");
	f = parsedemux("ifc = 135.104.9.1");
	ipmuxchain(&f2, f);
	f = parsedemux("src & 255.255.255.0 = 135.104.9.3");
	ipmuxchain(&f2, f);
	printtree(&out, f2, 0);

	f2copy = ipmuxcopy(f2);

	Bprint(&out, "merged demux:\n");
	root = ipmuxmerge(f1, f2);
	printtree(&out, root, 0);
	
	Bprint(&out, "demux 1 removed:\n");
	ipmuxremove(&root, f1copy);
	printtree(&out, root, 0);
	
	Bprint(&out, "demux 2 removed:\n");
	ipmuxremove(&root, f2copy);
	printtree(&out, root, 0);
}

enum
{
	Tproto,
	Tdata,
	Tdst,
	Tsrc,
	Tifc,
};

char *ftname[] = 
{
[Tdata]	"data",
[Tdst]	"dst",
[Tsrc]	"src",
[Tifc]	"ifc",
};

struct Ipmux
{
	Ipmux	*yes;
	Ipmux	*no;
	uchar	type;
	ushort	len;		/* length in bytes of item to compare */
	ushort	off;		/* offset of comparison */
	int	n;		/* number of items val points to */
	uchar	*val;
	uchar	*mask;

	Conv	*c;
	int	ref;		/* so we can garbage collect */
};

/*
 *  connection request is a semi separated list of filters
 *  e.g. proto=17;dat[0:4]=11aa22bb;ifc=135.104.9.2
 *
 *  there's no protection against overlapping specs.
 */
static char*
ipmuxconnect(Conv *c, char **argv, int argc)
{
	int n, proto;
	char *field[10];
	Ipmux *mux, *chain;
	Fs *f;

	f = c->p->f;

	if(argc != 2)
		return Ebadarg;

	n = parsefields(argv[1], field, nelem(field), ";");
	if(n <= 0)
		return Ebadarg;

	chain = nil; 
	for(i = 0; i < n; i++){
		mux = ipmuxparse(field[i]);
		if(mux == nil){
			ipmuxtreefree(chain);
			return Ebadarg;
		}
		ipmuxchain(&chain, mux);
	}

	/* optimize the protocol into an array lookup */
	if(chain->type != Tproto){
		ipmuxtreefree(chain);
		return "need proto rule";
	}
	mux = chain;
	proto = mux->val;
	chain = chain->yes;
	ipmuxfree(mux);

	/* save a copy of the chain so we can later remove it */
	mux->conv = c;
	mux = ipmuxcopy(chain);
	*(Ipmux***)(c->ptcl) = chain;

	/* add the chain to the protocol demultiplexor tree */
	qlock(p);
	f->t2m[proto] = ipmuxmerge(f->t2m[proto], mux);
	qunlock(p);

	Fsconnected(c, nil);
	return nil;
}

static int
ipmuxstate(Conv *c, char *state, int n)
{
	USED(c);
	return snprint(state, n, "%s", "Datagram");
}

static void
ipmuxcreate(Conv *c)
{
	c->rq = qopen(64*1024, 0, 0, c);
	c->wq = qopen(64*1024, 0, 0, 0);
	*(IPmux**)(c->ptcl) = nil;
}

static char*
ipmuxannounce(Conv*, char**, int)
{
	return "ipmux does not support announce";
}

static void
ipmuxclose(Conv *c)
{
	qclose(c->rq);
	qclose(c->wq);
	qclose(c->eq);
	ipmove(c->laddr, IPnoaddr);
	ipmove(c->raddr, IPnoaddr);
	c->lport = 0;
	c->rport = 0;

	unlock(c);
}

/*
 *  takes a fully formed ip packet and just passes it down
 *  the stack
 */
static void
ipmuxkick(Conv *c, int l)
{
}

static void
ipmuxiput(Proto *ipmux, uchar*, Block *bp)
{
}

int
ipmuxstats(Proto *ipmux, char *buf, int len)
{
	return 0;
}

void
ipmuxinit(Fs *fs)
{
	Proto *ipmux;

	ipmux = smalloc(sizeof(Proto));
	ipmux->priv = smalloc(sizeof(GREpriv));
	ipmux->name = "ipmux";
	ipmux->kick = ipmuxkick;
	ipmux->connect = ipmuxconnect;
	ipmux->announce = ipmuxannounce;
	ipmux->state = ipmuxstate;
	ipmux->create = ipmuxcreate;
	ipmux->close = ipmuxclose;
	ipmux->rcv = ipmuxiput;
	ipmux->ctl = nil;
	ipmux->advise = nil;
	ipmux->stats = ipmuxstats;
	ipmux->ipproto = -1;
	ipmux->nc = 64;
	ipmux->ptclsize = sizeof(Ipmux*);

	Fsproto(fs, ipmux);
}
.
## diffname ip/ipmux.c 1998/0325
## diff -e /n/emeliedump/1998/0324/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0325/sys/src/brazil/ip/ipmux.c
725c
	ipmux->ptclsize = sizeof(Ipmuxrock);
.
711c
	ipmux->priv = nil;
.
700c
ipmuxstats(Proto *p, char *buf, int len)
.
696a
	int len;
	Iphdr *ip;
	Fs *f = p->f;
	uchar *p;
	Conv *c;

	ip = bp->rptr;
	rlock(f);
	mux = f->t2m[ip->proto];
	if(mux == nil)
		goto out;

	/* run the v4 filter */
	len = BLEN(bp);
	if(len < 64 && bp->next){
		bp = concatblock(bp);
		len = BLEN(bp);
	}
	c = nil;
	while(mux != nil){
		while(mux){
			switch(mux->type){
			case Tia:
				p = ia;
				break;
			case Tsrc:
				p = ip->src;
				break;
			case Tdst:
				p = ip->dst;
				break;
			case Tdata:
				p = ip->data;
				if(mux->off+mux->len > len)
					goto no;
				break;
			}
		}
		if(mux->mask != nil){
		} else {
		}
no:
		mux = mux->no;
		continue;
	}
out:
	/* doesn't match any filter, hand it to the specific protocol handler */
	runlock(f);
	p = f->t2p[ip->proto];
	if(p)
		(*p->rcv)(p, ia, bp);
	else
		freeblist(bp);
	return;	
.
695c
ipmuxiput(Proto *p, uchar *ia, Block *bp)
.
681a
	wlock(f);
	ipmuxremove(&(f->t2m[r->proto]), r->chain);
	wunlock(f);
	ipmuxtreefree(f->chain);

.
673a
	Ipmuxrock *r;

	r = (Ipmuxrock*)(c->ptcl);
	r->chain = chain;
	r->proto = proto;

.
644c
	wunlock(f);
.
642c
	wlock(f);
.
639c
	r = (Ipmuxrock*)(c->ptcl);
	r->chain = chain;
	r->proto = proto;
.
604a
	Ipmuxrock *r;
.
462,592d
412c
static int
.
66a
/*
 *  someplace to hold per conversation data
 */
struct Ipmuxrock
{
	Ipmux	*chain;
	int	proto;
};

.
51,52c
/*
 *  a node in the decision tree
 */
.
30a
	uchar	data[1];	/* start of data */
.
12c
typedef struct Iphdr		Iphdr;
typedef struct Ipmuxrock	Ipmuxrock;
typedef struct Ipmux		Ipmux;
.
## diffname ip/ipmux.c 1998/0326
## diff -e /n/emeliedump/1998/0325/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0326/sys/src/brazil/ip/ipmux.c
631,634c
			
.
629a
			if(v == ve){
				if(mux->c != nil)
					c = mux->c;
				mux = mux->yes;
				if(
				
.
613,628c
		v = mux->val;
		for(e = v + mux->n*mux->len; v < e; v = ve){
			m = mux->mask;
			hp = h + mux->off;
			for(ve = v + mux->len; v < ve; v++){
				if((*hp++ & *m++) != *v++)
					break;
.
610a
	memmove(h, ia+IPv4off, ia);

	/* run the v4 filter */
.
605,609c
	/* make interface address part of packet */
	h = bp->rptr - IPHDR - IPv4addrlen;
	if(h < bp->base){
		bp = padblock(bp, IPHDR + IPv4addrlen);
		h = bp->rptr;
		bp->rptr += IPHDR + IPv4addrlen;
.
599d
596c
	uchar *m, *h, *v, *e, *ve, *hp;
.
594d
62c
	uchar	len;		/* length in bytes of item to compare */
.
## diffname ip/ipmux.c 1998/0327
## diff -e /n/emeliedump/1998/0326/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0327/sys/src/brazil/ip/ipmux.c
673c
	f->ipmux = ipmux;			/* hack for Fsrcvpcol */

	Fsproto(f, ipmux);
.
652c
ipmuxinit(Fs *f)
.
648c
	int n;
	Fs *f = p->f;

	rlock(f);
	n = ipmuxsprint(p->priv, 0, buf, len);
	runlock(f);

	return n;
.
645c
static int
ipmuxsprint(Ipmux *mux, int level, char *buf, int len)
{
	int i, j, n;

	n = 0;
	if(mux == nil)
		return n;
	for(i = 0; i < level; i++)
		n += snprint(buf+n, len-n, " ");
	n += snprint(buf+n, len-n, "h[%d:%d] & ", mux->off, mux->off+mux->len-1);
	for(i = 0; i < mux->len; i++)
		n += snprint(buf+n, len - n, "%2.2ux", mux->mask[i]);
	for(j = 0; j < mux->n; j++){
		for(i = 0; i < mux->len; i++)
			n += snprint(buf+n, len - n, "%2.2ux", mux->mask[i]);
		n += snprint(buf+n, len-n, "|");
	}
	level++;
	n += ipmuxsprint(mux->no, level, buf+n, len-n);
	n += ipmuxsprint(mux->yes, level, buf+n, len-n);
	return n;
}

static int
.
642c
	return;
.
636a

	if(c != nil){
		bp->rp -= IPHDR;
		if(bp->next){
			bp = concatblock(bp);
			if(bp == 0)
				panic("ilpullup");
		}
		qpass(c->rq, bp);
	}

nomatch:
	/* doesn't match any filter, hand it to the specific protocol handler */
	ip = (Iphdr*)bp->rp;
.
634,635d
630,632c
		if(v == e)
			mux = mux->no;
.
627,628c
				break;
			}
.
624,625c
				if(mux->conv != nil)
					c = mux->conv;
.
614a
		if(mux->len + mux->off > len){
			mux = mux->no;
			continue;
		}
.
613a
	mux = f->ipmux->priv;
.
612c
	/* run the v4 filter (needs optimizing) */
	rlock(f);
.
610c
	memmove(h, ia+IPv4off, IPv4addrlen);
	len = BLEN(bp);
.
607,608c
		h = bp->rp;
		bp->rp += IPHDR + IPv4addrlen;
.
604c
	h = bp->rp - IPHDR - IPv4addrlen;
.
598,601c
	if(p->priv == nil)
		goto nomatch;
.
596a
	Ipmux *mux;
	Iphdr *ip;
.
587a
	Block *bp;

	bp = qget(c->wq);
	if(bp == nil)
		return;
	ipoput(c->p->f, bp, 0, 0);
.
586c
ipmuxkick(Conv *c, int)
.
576c
	ipmuxtreefree(r->chain);
.
574c
	ipmuxremove(&(c->p->priv), r->chain);
.
562,563d
559a
	Fs *f = c->p->f;
.
547c
	r = (Ipmuxrock*)(c->ptcl);
	r->chain = nil;
.
544a
	Ipmuxrock *r;

.
528c
	f->ipmux->priv = ipmuxmerge(f->ipmux->priv, mux);
.
524d
520d
509,518d
507a
	if(chain == nil)
		return Ebadarg;
	mux->conv = c;
.
501c
		mux = parsemux(field[i]);
.
499c
	chain = nil;
	mux = nil;
.
484c
	int i, n;
.
376a
	if(f == nil)
		return;
.
241c
	f->n = parsefields(val, vals, sizeof(vals)/sizeof(char*), "|");
.
237,238c
	} else {
		f->mask = smalloc(f->len);
		memset(f->mask, 0xff, f->len);
	}
.
201c
parsemux(char *p)
.
154a
		len = end - off + 1;
		off += ((ulong)(ipoff->data)) - IPHDR;
.
153d
139a
		if(off < 0 || off > (64-IPHDR))
			return nil;
.
128a
		off = ((ulong)&(ipoff->proto)) - IPHDR;
.
124c
		off = -IPv4addrlen - IPHDR;
		len = IPv4addrlen;
.
119c
		off = ((ulong)(ipoff->src)) - IPHDR;
		len = IPv4addrlen;
.
114c
		off = ((ulong)(ipoff->dst)) - IPHDR;
		len = IPv4addrlen;
.
110d
77d
68a
	Conv	*conv;
.
34a
Iphdr *ipoff = 0;
.
## diffname ip/ipmux.c 1998/0328
## diff -e /n/emeliedump/1998/0327/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0328/sys/src/brazil/ip/ipmux.c
691a
	n += snprint(buf+n, len-n, "\n");
.
689c
			n += snprint(buf+n, len - n, "%2.2ux", *v++);
.
686a
	n += snprint(buf+n, len-n, "=");
	v = mux->val;
.
684c
	if(mux == nil){
		n += snprint(buf+n, len-n, "\n");
		return n;
	}
	n += snprint(buf+n, len-n, "h[%d:%d]&", mux->off, mux->off+mux->len-1);
.
680,681d
677a
	uchar *v;
.
660a
		return;
.
654d
648,649c
		mux = mux->no;
match:;
.
645c
				goto match;
.
638c
				if((*hp++ & *m++) != *v)
.
621c
	h = bp->rp;
	memmove(h-IPv4addrlen, ia+IPv4off, IPv4addrlen);
.
615,619c
	if(bp->rp - bp->base < IPv4addrlen){
		bp = padblock(bp, IPv4addrlen);
		bp->rp += IPv4addrlen;
.
581a
	r->chain = nil;
.
541,542c
	Ipmuxrock *r;
	
	r = (Ipmuxrock*)(c->ptcl);
	return ipmuxsprint(r->chain, 0, state, n);
.
260c
			v4parseip(v, vals[n]);
.
235c
			v4parseip(f->mask, mask);
.
161c
		off += (ulong)(ipoff->data);
.
132c
		off = (ulong)&(ipoff->proto);
.
126c
		off = -IPv4addrlen;
.
120c
		off = (ulong)(ipoff->src);
.
114c
		off = (ulong)(ipoff->dst);
.
80a
static int	ipmuxsprint(Ipmux*, int, char*, int);

.
64c
	short	off;		/* offset of comparison */
.
## diffname ip/ipmux.c 1998/0401
## diff -e /n/emeliedump/1998/0328/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0401/sys/src/brazil/ip/ipmux.c
653d
638c
		for(e = mux->e; v < e; v = ve){
.
631a
match:
.
372a
	nf->e = nf->val + f->n*f->len;
.
271a
	f->e = f->val + f->n*f->len;
.
67a
	uchar	*e;		/* val + n*len */
.
65d
63a
	uchar	n;		/* number of items val points to */
.
62c
	uchar	type;		/* type of field (Txxxx) */
.
## diffname ip/ipmux.c 1998/0402
## diff -e /n/emeliedump/1998/0401/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0402/sys/src/brazil/ip/ipmux.c
658,669d
656a
		continue;
yes:
		if(mux->conv != nil)
			c = mux->conv;
		mux = mux->yes;
.
649,654d
641,647c
		hp = h + mux->off;
		switch(mux->ctype){
		case Cbyte:
			if(*mux->val == *hp)
				goto yes;
			break;
		case Cmbyte:
			if((*mux->val & *mux->mask) == *hp)
				goto yes;
			break;
		case Cshort:
			if(*((ushort*)mux->val) == *(ushort*)hp)
				goto yes;
			break;
		case Cmshort:
			if((*((ushort*)mux->val) & (*((ushort*)mux->mask))) == *(ushort*)hp)
				goto yes;
			break;
		case Clong:
			if(*((ulong*)mux->val) == *(ulong*)hp)
				goto yes;
			break;
		case Cmlong:
			if((*((ulong*)mux->val) & (*((ulong*)mux->mask))) == *(ulong*)hp)
				goto yes;
			break;
		case Cifc:
			if(*((ulong*)mux->val) == *(ulong*)ia)
				goto yes;
			break;
		case Cmifc:
			if((*((ulong*)mux->val) & (*((ulong*)mux->mask))) == *(ulong*)ia)
				goto yes;
			break;
		default:
			v = mux->val;
			for(e = mux->e; v < e; v = ve){
				m = mux->mask;
				hp = h + mux->off;
				for(ve = v + mux->len; v < ve; v++){
					if((*hp++ & *m++) != *v)
						break;
				}
				if(v == ve)
					goto yes;
.
637c
		if(mux->eoff > len){
.
635d
631c
	/* run the v4 filter */
.
628d
622,626d
375c
	nf->e = nf->val + f->len*f->n;
.
273a
	f->ctype = Cother;
	if(f->n == 1){
		switch(f->len){
		case 1:
			f->ctype = nomask ? Cbyte : Cmbyte;
			break;
		case 2:
			f->ctype = nomask ? Cshort : Cmshort;
			break;
		case 4:
			if(f->type == Cifc)
				f->ctype = nomask ? Cifc : Cmifc;
			else
				f->ctype = nomask ? Clong : Cmlong;
			break;
		}
	}
.
272a
	f->eoff = f->off + f->len;
.
247a
		nomask = 1;
.
246a
		nomask = 0;
.
213c
	int n, nomask;
.
65a
	short	eoff;		/* end offset of comparison */
.
62a
	uchar	ctype;		/* tupe of comparison (Cxxxx) */
.
43a

	Cother = 0,
	Cbyte,		/* single byte */
	Cmbyte,		/* single byte with mask */
	Cshort,		/* single short */
	Cmshort,	/* single short with mask */
	Clong,		/* single long */
	Cmlong,		/* single long with mask */
	Cifc,
	Cmifc,
.
## diffname ip/ipmux.c 1998/0403
## diff -e /n/emeliedump/1998/0402/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0403/sys/src/brazil/ip/ipmux.c
719a
	if(c != nil){
		qpass(c->rq, bp);
		return;
	}
	runlock(f);
.
## diffname ip/ipmux.c 1998/0414
## diff -e /n/emeliedump/1998/0403/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0414/sys/src/brazil/ip/ipmux.c
724c

.
719a
	runlock(f);

.
638c

	ih = (Iphdr*)(bp->rp);

	ipoput(c->p->f, bp, 0, ih->ttl);
.
633a
	Iphdr *ih;
.
## diffname ip/ipmux.c 1998/0502
## diff -e /n/emeliedump/1998/0414/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0502/sys/src/brazil/ip/ipmux.c
525c
 *  e.g. proto=17;dat[0:4]=11aa22bb;ifc=135.104.9.2&255.255.255.0
.
## diffname ip/ipmux.c 1998/0507
## diff -e /n/emeliedump/1998/0502/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0507/sys/src/brazil/ip/ipmux.c
701c
			if((*(ulong*)(ia + IPv4off) & (*((ulong*)mux->mask))) == *((ulong*)mux->val))
.
697c
			if(*((ulong*)mux->val) == *(ulong*)(ia + IPv4off))
.
693c
			if((*(ulong*)hp & (*((ulong*)mux->mask))) == *((ulong*)mux->val))
.
685c
			if((*(ushort*)hp & (*((ushort*)mux->mask))) == *((ushort*)mux->val))
.
677c
			if((*hp & *mux->mask) == *mux->val)
.
299c
			if(f->type == Tifc)
.
## diffname ip/ipmux.c 1998/0602
## diff -e /n/emeliedump/1998/0507/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0602/sys/src/brazil/ip/ipmux.c
726a
		/* tack on interface address */
		bp = padblock(bp, IPaddrlen);
		ipmove(bp->rp, ia);
.
## diffname ip/ipmux.c 1998/0627
## diff -e /n/emeliedump/1998/0602/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0627/sys/src/brazil/ip/ipmux.c
730c
		bp = concatblock(bp);
		if(bp != nil)
			qpass(c->rq, bp);
.
## diffname ip/ipmux.c 1998/0630
## diff -e /n/emeliedump/1998/0627/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0630/sys/src/brazil/ip/ipmux.c
727,732c
		qpass(c->rq, bp);
.
## diffname ip/ipmux.c 1998/0701
## diff -e /n/emeliedump/1998/0630/sys/src/brazil/ip/ipmux.c /n/emeliedump/1998/0701/sys/src/brazil/ip/ipmux.c
727c
		/* tack on interface address */
		bp = padblock(bp, IPaddrlen);
		ipmove(bp->rp, ia);
		bp = concatblock(bp);
		if(bp != nil)
			if (qpass(c->rq, bp) < 0)
				print("Q");
.
## diffname ip/ipmux.c 1999/0302
## diff -e /n/emeliedump/1998/0701/sys/src/brazil/ip/ipmux.c /n/emeliedump/1999/0302/sys/src/brazil/ip/ipmux.c
623c
	qunlock(c);
.
## diffname ip/ipmux.c 1999/0817
## diff -e /n/emeliedump/1999/0302/sys/src/brazil/ip/ipmux.c /n/emeliedump/1999/0817/sys/src/brazil/ip/ipmux.c
642c
	ipoput(c->p->f, bp, 0, ih->ttl, ih->tos);
.
## diffname ip/ipmux.c 2000/0308
## diff -e /n/emeliedump/1999/0817/sys/src/brazil/ip/ipmux.c /n/emeliedump/2000/0308/sys/src/9/ip/ipmux.c
543c
	n = getfields(argv[1], field, nelem(field), 1, ";");
.
267c
	f->n = getfields(val, vals, sizeof(vals)/sizeof(char*), 1, "|");
.
## diffname ip/ipmux.c 2000/1220
## diff -e /n/emeliedump/2000/0308/sys/src/9/ip/ipmux.c /n/emeliedump/2000/1220/sys/src/9/ip/ipmux.c
622,623d
## diffname ip/ipmux.c 2001/0127
## diff -e /n/emeliedump/2000/1220/sys/src/9/ip/ipmux.c /n/emeliedump/2001/0127/sys/src/9/ip/ipmux.c
589c
	c->rq = qopen(64*1024, 1, 0, c);
.
## diffname ip/ipmux.c 2001/0306
## diff -e /n/emeliedump/2001/0127/sys/src/9/ip/ipmux.c /n/emeliedump/2001/0306/sys/src/9/ip/ipmux.c
629c
ipmuxkick(Conv *c)
.
## diffname ip/ipmux.c 2001/0623
## diff -e /n/emeliedump/2001/0306/sys/src/9/ip/ipmux.c /n/emeliedump/2001/0623/sys/src/9/ip/ipmux.c
740c
		(*p->rcv)(p, ifc, bp);
.
652a
	ia = ifc->lifc->local;

.
651a
	uchar *ia;
.
644c
ipmuxiput(Proto *p, Ipifc *ifc, Block *bp)
.
## diffname ip/ipmux.c 2002/0507
## diff -e /n/emeliedump/2001/0623/sys/src/9/ip/ipmux.c /n/emeliedump/2002/0507/sys/src/9/ip/ipmux.c
762c
	n += snprint(buf+n, len-n, "h[%d:%d]&", 
               mux->off+((int)mux->skiphdr)*((int)ipoff->data), 
               mux->off+(((int)mux->skiphdr)*((int)ipoff->data))+mux->len-1);
.
740,742c
	ip = (Ip4hdr*)bp->rp;
	if((ip->vihl&0xF0)==0x40) {
		p = f->t2p[ip->proto];
	} else {
		ip6 = (Ip6hdr*)bp->rp;
		p = f->t2p[ip6->proto];
	}
	if(p && p->rcv)
.
733c
			if(qpass(c->rq, bp) < 0)
.
730c
		ipmove(bp->rp, ifc->lifc->local);
.
702c
			if((*(ulong*)(ifc->lifc->local + IPv4off) & (*((ulong*)mux->mask))) == *((ulong*)mux->val))
.
698c
			if(*((ulong*)mux->val) == *(ulong*)(ifc->lifc->local + IPv4off))
.
671c
		hp = h + mux->off + ((int)mux->skiphdr)*hl;
.
654c
  ip = (Ip4hdr*)bp->rp;
  hl = (ip->vihl&0x0F)<<2;
.
651,652c
	Ip4hdr *ip;
	Ip6hdr *ip6;
.
646c
	int len, hl;
.
637,640c
	else {
		Ip4hdr *ih4 = (Ip4hdr*)(bp->rp);
		if((ih4->vihl)&0xF0 != 0x60)
			ipoput4(c->p->f, bp, 0, ih4->ttl, ih4->tos);
		else {
			ih6 = (struct Ip6hdr*)ih4;
			ipoput6(c->p->f, bp, 0, ih6->ttl, 0);
		}
	}
.
632c
	struct Ip6hdr *ih6;
.
336c
	n = (a->off+((int)a->skiphdr)*(ulong)ipoff->data) - 
      (b->off+((int)b->skiphdr)*(ulong)ipoff->data);
.
280a
    case Tiph:
.
252a
    case Tiph:
.
188a
  if(type == Tdata)
    f->skiphdr = 1;
  else
    f->skiphdr = 0;
.
178c
	else
.
176d
151,153c
	else if(strncmp(p, "data", 4) == 0 || strncmp(p, "iph", 3) == 0){
    if(strncmp(p, "data", 4) == 0) {
		  type = Tdata;
      p += 4;
    }
    else {
      type = Tiph;
	    p += 3;
    }
.
72,77c
	uchar	type;		 /* type of field (Txxxx) */
	uchar	ctype;   /* tupe of comparison (Cxxxx) */
	uchar	len;		 /* length in bytes of item to compare */
	uchar	n;		   /* number of items val points to */
	short	off;		 /* offset of comparison */
	short	eoff;		 /* end offset of comparison */
  uchar skiphdr; /* should offset start after ip header */
.
59a
[Tiph]	  "iph",
.
40a
  Tiph,
.
36a
struct Ip6hdr
{
  uchar vcf[4];  /* version, class label, and flow label */ 
  uchar ploadlen[2];  /* payload length */
  uchar proto; /* next header, i.e. proto */
  uchar ttl;   /* hop limit, i.e. ttl */
  uchar src[16]; /* IP source */
  uchar dst[16]; /* IP destination */
};


.
35c
Ip4hdr *ipoff = 0;
.
21c
struct Ip4hdr
.
18c
	IPHDR		= 20,		/* sizeof(Ip4hdr) */
.
12,14c
typedef struct Ipmuxrock  Ipmuxrock;
typedef struct Ipmux      Ipmux;
typedef struct Ip4hdr     Ip4hdr;
typedef struct Ip6hdr     Ip6hdr;
.
9d
## diffname ip/ipmux.c 2002/0711
## diff -e /n/emeliedump/2002/0507/sys/src/9/ip/ipmux.c /n/emeliedump/2002/0711/sys/src/9/ip/ipmux.c
615c
	c->rq = qopen(64*1024, Qmsg, 0, c);
.
## diffname ip/ipmux.c 2002/0712
## diff -e /n/emeliedump/2002/0711/sys/src/9/ip/ipmux.c /n/emeliedump/2002/0712/sys/src/9/ip/ipmux.c
839d
656a
	Conv *c = x;
.
655c
ipmuxkick(void *x)
.
616c
	c->wq = qopen(64*1024, Qkick, ipmuxkick, c);
.
108a
static void	ipmuxkick(void *x);
.
## diffname ip/ipmux.c 2002/1108
## diff -e /n/emeliedump/2002/0712/sys/src/9/ip/ipmux.c /n/emeliedump/2002/1108/sys/src/9/ip/ipmux.c
687,688c
	ip = (Ip4hdr*)bp->rp;
	hl = (ip->vihl&0x0F)<<2;
.
363c
		(b->off+((int)b->skiphdr)*(ulong)ipoff->data);
.
306c
		case Tiph:
.
277c
		case Tiph:
.
209,212c
	if(type == Tdata)
		f->skiphdr = 1;
	else
		f->skiphdr = 0;
.
167,174c
		if(strncmp(p, "data", 4) == 0) {
			type = Tdata;
			p += 4;
		}
		else {
			type = Tiph;
			p += 3;
		}
.
94c
	uchar	*e;		/* val+n*len*/
.
85,91c
	uchar	type;		/* type of field(Txxxx) */
	uchar	ctype;		/* tupe of comparison(Cxxxx) */
	uchar	len;		/* length in bytes of item to compare */
	uchar	n;		/* number of items val points to */
	short	off;		/* offset of comparison */
	short	eoff;		/* end offset of comparison */
	uchar	skiphdr;	/* should offset start after ipheader */
.
72c
[Tiph]	 	"iph",
.
52c
	Tiph,
.
39,44c
	uchar vcf[4];		/* version, class label, and flow label */ 
	uchar ploadlen[2];	/* payload length */
	uchar proto;		/* next header, i.e. proto */
	uchar ttl;		/* hop limit, i.e. ttl */
	uchar src[16];		/* IP source */
	uchar dst[16];		/* IP destination */
.
## diffname ip/ipmux.c 2003/0308
## diff -e /n/emeliedump/2002/1108/sys/src/9/ip/ipmux.c /n/emeliedump/2003/0308/sys/src/9/ip/ipmux.c
671c
			ipoput6(c->p->f, bp, 0, ih6->ttl, 0, nil);
.
668c
			ipoput4(c->p->f, bp, 0, ih4->ttl, ih4->tos, nil);
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].