~kris/9p

9hist

a1e5d4c3ad80b17f1989ec008b4eb25cb2e1315a — David du Colombier 28 years ago 83cbbe5
Plan 9 from Bell Labs 1998-03-13
M ip/arp.c => ip/arp.c +43 -36
@@ 27,30 27,38 @@ char *arpstate[] =
	"WAIT",
};

typedef struct Arpcache Arpcache;
struct Arpcache
/*
 *  one per Fs
 */
struct Arp
{
	QLock;
	Arpent*	hash[NHASH];
	Fs	*f;
	Arpent	*hash[NHASH];
	Arpent	cache[NCACHE];
};

Arpcache	arp;

char *Ebadarp = "bad arp";

#define haship(s) ((s)[IPaddrlen-1]%NHASH)

void
arpinit(Fs *f)
{
	f->arp = smalloc(sizeof(Arp));
	f->arp->f = f;
}

static Arpent*
newarp(uchar *ip, Medium *m)
newarp(Arp *arp, uchar *ip, Medium *m)
{
	uint t;
	Block *next, *xp;
	Arpent *a, *e, *f, **l;

	/* find oldest entry */
	e = &arp.cache[NCACHE];
	a = arp.cache;
	e = &arp->cache[NCACHE];
	a = arp->cache;
	t = a->used;
	for(f = a; f < e; f++){
		if(f->used < t){


@@ 69,7 77,7 @@ newarp(uchar *ip, Medium *m)
	}

	/* take out of current chain */
	l = &arp.hash[haship(a->ip)];
	l = &arp->hash[haship(a->ip)];
	for(f = *l; f; f = f->hash){
		if(f == a) {
			*l = a->hash;


@@ 79,7 87,7 @@ newarp(uchar *ip, Medium *m)
	}

	/* insert into new chain */
	l = &arp.hash[haship(ip)];
	l = &arp->hash[haship(ip)];
	a->hash = *l;
	*l = a;
	memmove(a->ip, ip, sizeof(a->ip));


@@ 91,7 99,7 @@ newarp(uchar *ip, Medium *m)
}

Arpent*
arpget(Block *bp, int version, Medium *type, uchar *ip, uchar *mac)
arpget(Arp *arp, Block *bp, int version, Medium *type, uchar *ip, uchar *mac)
{
	int hash;
	Arpent *a;


@@ 102,16 110,16 @@ arpget(Block *bp, int version, Medium *type, uchar *ip, uchar *mac)
		ip = v6ip;
	}

	qlock(&arp);
	qlock(arp);
	hash = haship(ip);
	for(a = arp.hash[hash]; a; a = a->hash) {
	for(a = arp->hash[hash]; a; a = a->hash) {
		if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
		if(type == a->type)
			break;
	}

	if(a == nil){
		a = newarp(ip, type);
		a = newarp(arp, ip, type);
		a->state = AWAIT;
	}
	a->used = msec;


@@ 126,7 134,7 @@ arpget(Block *bp, int version, Medium *type, uchar *ip, uchar *mac)
	}

	memmove(mac, a->mac, a->type->maclen);
	qunlock(&arp);
	qunlock(arp);
	return nil;
}



@@ 134,16 142,16 @@ arpget(Block *bp, int version, Medium *type, uchar *ip, uchar *mac)
 * called with arp locked
 */
void
arprelease(Arpent*)
arprelease(Arp *arp, Arpent*)
{
	qunlock(&arp);
	qunlock(arp);
}

/*
 * called with arp locked
 */
Block*
arpresolve(Arpent *a, Medium *type, uchar *mac)
arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
{
	Block *bp;



@@ 153,13 161,13 @@ arpresolve(Arpent *a, Medium *type, uchar *mac)
	a->used = msec;
	bp = a->hold;
	a->hold = nil;
	qunlock(&arp);
	qunlock(arp);

	return bp;
}

void
arpenter(Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int refresh)
arpenter(Arp *arp, Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int refresh)
{
	Arpent *a;
	Block *bp, *next;


@@ 170,8 178,8 @@ arpenter(Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int refre
		ip = v6ip;
	}

	qlock(&arp);
	for(a = arp.hash[haship(ip)]; a; a = a->hash) {
	qlock(arp);
	for(a = arp->hash[haship(ip)]; a; a = a->hash) {
		if(a->type != type || (a->state != AWAIT && a->state != AOK))
			continue;



@@ 182,7 190,7 @@ arpenter(Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int refre
			a->hold = nil;
			if(version == V4)
				ip += IPv4off;
			qunlock(&arp);
			qunlock(arp);
			while(bp) {
				next = bp->list;
				if(ifc != nil){


@@ 206,19 214,18 @@ arpenter(Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int refre
		}
	}

	/* if nil, we're adding a new entry */
	if(refresh == 0){
		a = newarp(ip, type);
		a = newarp(arp, ip, type);
		a->state = AOK;
		a->type = type;
		memmove(a->mac, mac, type->maclen);
	}

	qunlock(&arp);
	qunlock(arp);
}

int
arpwrite(char *s, int len)
arpwrite(Arp *arp, char *s, int len)
{
	int n;
	Block *bp;


@@ 238,8 245,8 @@ arpwrite(char *s, int len)

	n = parsefields(buf, f, 4, " ");
	if(strcmp(f[0], "flush") == 0){
		qlock(&arp);
		for(a = arp.cache; a < &arp.cache[NCACHE]; a++){
		qlock(arp);
		for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
			memset(a->ip, 0, sizeof(a->ip));
			memset(a->mac, 0, sizeof(a->mac));
			a->hash = nil;


@@ 251,8 258,8 @@ arpwrite(char *s, int len)
				a->hold = bp;
			}
		}
		memset(arp.hash, 0, sizeof(arp.hash));
		qunlock(&arp);
		memset(arp->hash, 0, sizeof(arp->hash));
		qunlock(arp);
	} else if(strcmp(f[0], "add") == 0){
		if(n != 4)
			error(Ebadarp);


@@ 261,7 268,7 @@ arpwrite(char *s, int len)
			error(Ebadarp);
		parseip(ip, f[2]);
		parsemac(mac, f[3], m->maclen);
		arpenter(nil, V6, ip, mac, m, 0);
		arpenter(arp, nil, V6, ip, mac, m, 0);
	} else
		error(Ebadarp);



@@ 283,7 290,7 @@ convmac(char *p, uchar *mac, int n)
}

int
arpread(char *p, ulong offset, int len)
arpread(Arp *arp, char *p, ulong offset, int len)
{
	Arpent *a;
	int n;


@@ 296,7 303,7 @@ arpread(char *p, ulong offset, int len)
	len = len/Alinelen;

	n = 0;
	for(a = arp.cache; len > 0 && a < &arp.cache[NCACHE]; a++){
	for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
		if(a->state == 0)
			continue;
		if(offset > 0){


@@ 304,10 311,10 @@ arpread(char *p, ulong offset, int len)
			continue;
		}
		len--;
		qlock(&arp);
		qlock(arp);
		convmac(mac, a->mac, a->type->maclen);
		n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac);
		qunlock(&arp);
		qunlock(arp);
	}

	return n;

M ip/devip.c => ip/devip.c +128 -63
@@ 6,14 6,12 @@
#include	"../port/error.h"
#include	"../ip/ip.h"

Fs fs;
Queue* qlog;

enum
{
	Qtopdir=	1,		/* top level directory */
	Qtopbase,
	Qarp=		Qtopbase,
	Qbootp,
	Qiproute,
	Qiprouter,
	Qipselftab,


@@ 33,14 31,29 @@ enum
	Qlocal,
	Qremote,
	Qstatus,

	Logtype=	5,
	Masktype=	(1<<Logtype)-1,
	Logconv=	12,
	Maskconv=	(1<<Logconv)-1,
	Shiftconv=	Logtype,
	Logproto=	8,
	Maskproto=	(1<<Logproto)-1,
	Shiftproto=	Logtype + Logconv,

	Nfs=		16,
};
#define TYPE(x) 	((x).path & 0x1f)
#define CONV(x) 	(((x).path >> 5)&0xfff)
#define PROTO(x) 	(((x).path >> 17)&0xff)
#define QID(p, c, y) 	(((p)<<17) | ((c)<<5) | (y))
#define TYPE(x) 	( (x).path & Masktype )
#define CONV(x) 	( ((x).path >> Shiftconv) & Maskconv )
#define PROTO(x) 	( ((x).path >> Shiftproto) & Maskproto )
#define QID(p, c, y) 	( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) )

static char network[] = "network";

QLock	fslock;
Fs	*ipfs[Nfs];	/* attached fs's */
Queue	*qlog;

static int
ip3gen(Chan *c, int i, Dir *dp)
{


@@ 48,7 61,7 @@ ip3gen(Chan *c, int i, Dir *dp)
	Conv *cv;
	char *p;

	cv = fs.p[PROTO(c->qid)]->conv[CONV(c->qid)];
	cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
	switch(i) {
	default:
		return -1;


@@ 118,6 131,10 @@ ip1gen(Chan *c, int i, Dir *dp)
		p = "arp";
		q = (Qid){QID(0, 0, Qarp), 0};
		break;
	case Qbootp:
		p = "bootp";
		q = (Qid){QID(0, 0, Qbootp), 0};
		break;
	case Qiproute:
		p = "iproute";
		q = (Qid){QID(0, 0, Qiproute), 0};


@@ 146,33 163,37 @@ ipgen(Chan *c, Dirtab*, int, int s, Dir *dp)
	Qid q;
	Conv *cv;
	char name[16];
	Fs *f;

	f = ipfs[c->dev];

	switch(TYPE(c->qid)) {
	case Qtopdir:
		if(s < fs.np) {
			if(fs.p[s]->connect == nil)
		if(s < f->np) {
			if(f->p[s]->connect == nil)
				return 0;	/* protocol with no user interface */
			q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0};
			devdir(c, q, fs.p[s]->name, 0, network, CHDIR|0555, dp);
			devdir(c, q, f->p[s]->name, 0, network, CHDIR|0555, dp);
			return 1;
		}
		s -= fs.np;
		s -= f->np;
		return ip1gen(c, s+Qtopbase, dp);
	case Qarp:
	case Qbootp:
	case Qlog:
	case Qiproute:
	case Qiprouter:
	case Qipselftab:
		return ip1gen(c, TYPE(c->qid), dp);
	case Qprotodir:
		if(s < fs.p[PROTO(c->qid)]->ac) {
			cv = fs.p[PROTO(c->qid)]->conv[s];
		if(s < f->p[PROTO(c->qid)]->ac) {
			cv = f->p[PROTO(c->qid)]->conv[s];
			sprint(name, "%d", s);
			q = (Qid){QID(PROTO(c->qid), s, Qconvdir)|CHDIR, 0};
			devdir(c, q, name, 0, cv->owner, CHDIR|0555, dp);
			return 1;
		}
		s -= fs.p[PROTO(c->qid)]->ac;
		s -= f->p[PROTO(c->qid)]->ac;
		return ip2gen(c, s+Qprotobase, dp);
	case Qclone:
	case Qstats:


@@ 199,12 220,6 @@ ipreset(void)
static void
ipinit(void)
{
	int i;
	extern void (*ipprotoinit[])(Fs*);

	initfrag(100);
	for(i = 0; ipprotoinit[i]; i++)
		ipprotoinit[i](&fs);
	fmtinstall('i', eipconv);
	fmtinstall('I', eipconv);
	fmtinstall('E', eipconv);


@@ 212,13 227,45 @@ ipinit(void)
	fmtinstall('M', eipconv);
}

static Fs*
ipgetfs(int dev)
{
	extern void (*ipprotoinit[])(Fs*);
	Fs *f;
	int i;

	if(dev >= Nfs)
		return nil;

	qlock(&fslock);
	if(ipfs[dev] == nil){
		f = smalloc(sizeof(Fs));
		ip_init(f);
		arpinit(f);
		netloginit(f);
		for(i = 0; ipprotoinit[i]; i++)
			ipprotoinit[i](f);
		ipfs[dev] = f;
	}
	qunlock(&fslock);

	return ipfs[dev];
}

static Chan*
ipattach(char* spec)
{
	Chan *c;
	int dev;

	dev = atoi(spec);
	if(dev >= 16)
		error("bad specification");

	ipgetfs(dev);
	c = devattach('I', spec);
	c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
	c->dev = dev;

	return c;
}


@@ 281,18 328,21 @@ ipopen(Chan* c, int omode)
	Conv *cv, *nc;
	Proto *p;
	int perm;
	Fs *f;

	omode &= 3;
	perm = m2p[omode];

	f = ipfs[c->dev];

	switch(TYPE(c->qid)) {
	default:
		break;
	case Qlog:
		netlogopen();
		netlogopen(f);
		break;
	case Qiprouter:
		iprouteropen();
		iprouteropen(f);
		break;
	case Qiproute:
		memmove(c->tag, "none", sizeof(c->tag));


@@ 304,13 354,14 @@ ipopen(Chan* c, int omode)
	case Qremote:
	case Qlocal:
	case Qstats:
	case Qbootp:
	case Qipselftab:
		if(omode != OREAD)
			error(Eperm);
		break;
	case Qclone:
		p = fs.p[PROTO(c->qid)];
		cv = Fsprotoclone(p, up->user);
		p = f->p[PROTO(c->qid)];
		cv = Fsprotoclone(p, commonuser());
		if(cv == nil) {
			error(Enodev);
			break;


@@ 320,7 371,7 @@ ipopen(Chan* c, int omode)
	case Qdata:
	case Qctl:
	case Qerr:
		p = fs.p[PROTO(c->qid)];
		p = f->p[PROTO(c->qid)];
		qlock(p);
		cv = p->conv[CONV(c->qid)];
		lock(cv);


@@ 330,7 381,7 @@ ipopen(Chan* c, int omode)
			nexterror();
		}
		if((perm & (cv->perm>>6)) != perm) {
			if(strcmp(up->user, cv->owner) != 0)
			if(strcmp(commonuser(), cv->owner) != 0)
				error(Eperm);
		 	if((perm & cv->perm) != perm)
				error(Eperm); 


@@ 338,7 389,7 @@ ipopen(Chan* c, int omode)
		}
		cv->inuse++;
		if(cv->inuse == 1){
			memmove(cv->owner, up->user, NAMELEN);
			memmove(cv->owner, commonuser(), NAMELEN);
			cv->perm = 0660;
		}
		unlock(cv);


@@ 346,7 397,7 @@ ipopen(Chan* c, int omode)
		poperror();
		break;
	case Qlisten:
		cv = fs.p[PROTO(c->qid)]->conv[CONV(c->qid)];
		cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
		if(cv->state != Announced)
			error("not announced");



@@ 365,7 416,7 @@ ipopen(Chan* c, int omode)
			if(nc != nil){
				cv->incall = nc->next;
				c->qid = (Qid){QID(PROTO(c->qid), nc->x, Qctl), 0};
				memmove(cv->owner, up->user, NAMELEN);
				memmove(cv->owner, commonuser(), NAMELEN);
			}
			unlock(cv);



@@ 430,22 481,25 @@ closeconv(Conv *cv)
static void
ipclose(Chan* c)
{
	Fs *f;

	f = ipfs[c->dev];
	switch(TYPE(c->qid)) {
	default:
		break;
	case Qlog:
		if(c->flag & COPEN)
			netlogclose();
			netlogclose(f);
		break;
	case Qiprouter:
		if(c->flag & COPEN)
			iprouterclose();
			iprouterclose(f);
		break;
	case Qdata:
	case Qctl:
	case Qerr:
		if(c->flag & COPEN)
			closeconv(fs.p[PROTO(c->qid)]->conv[CONV(c->qid)]);
			closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);
	}
}



@@ 461,6 515,9 @@ ipread(Chan *ch, void *a, long n, ulong offset)
	Proto *x;
	char *buf, *p;
	long m, rv;
	Fs *f;

	f = ipfs[ch->dev];

	p = a;
	switch(TYPE(ch->qid)) {


@@ 471,13 528,15 @@ ipread(Chan *ch, void *a, long n, ulong offset)
	case Qconvdir:
		return devdirread(ch, a, n, 0, 0, ipgen);
	case Qarp:
		return arpread(a, offset, n);
		return arpread(f->arp, a, offset, n);
 	case Qbootp:
 		return bootpread(a, offset, n);
	case Qiproute:
		return routeread(a, offset, n);
		return routeread(f, a, offset, n);
	case Qipselftab:
		return ipselftabread(a, offset, n);
		return ipselftabread(f, a, offset, n);
	case Qlog:
		return netlogread(a, offset, n);
		return netlogread(f, a, offset, n);
	case Qctl:
		buf = smalloc(16);
		sprint(buf, "%d", CONV(ch->qid));


@@ 486,14 545,14 @@ ipread(Chan *ch, void *a, long n, ulong offset)
		return rv;
	case Qremote:
		buf = smalloc(Statelen);
		c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
		sprint(buf, "%I!%d\n", c->raddr, c->rport);
		rv = readstr(offset, p, n, buf);
		free(buf);
		return rv;
	case Qlocal:
		buf = smalloc(Statelen);
		x = fs.p[PROTO(ch->qid)];
		x = f->p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];
		if(x->local == nil) {
			sprint(buf, "%I!%d\n", c->laddr, c->lport);


@@ 505,7 564,7 @@ ipread(Chan *ch, void *a, long n, ulong offset)
		return rv;
	case Qstatus:
		buf = smalloc(Statelen);
		x = fs.p[PROTO(ch->qid)];
		x = f->p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];
		m = sprint(buf, "%s/%d %d ", c->p->name, c->x, c->inuse);
		(*x->state)(c, buf, Statelen-m-2);


@@ 513,17 572,17 @@ ipread(Chan *ch, void *a, long n, ulong offset)
		free(buf);
		return rv;
	case Qdata:
		c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
		return qread(c->rq, a, n);
	case Qerr:
		c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
		return qread(c->eq, a, n);
	case Qstats:
		x = fs.p[PROTO(ch->qid)];
		x = f->p[PROTO(ch->qid)];
		if(x->stats == nil)
			error("stats not implemented");
		buf = smalloc(Statelen);
		(*x->stats)(buf, Statelen);
		(*x->stats)(x, buf, Statelen);
		rv = readstr(offset, p, n, buf);
		free(buf);
		return rv;


@@ 542,7 601,7 @@ ipbread(Chan* c, long n, ulong offset)
static void
setladdr(Conv* c)
{
	findlocalip(c->laddr, c->raddr);
	findlocalip(c->p->f, c->laddr, c->raddr);
}

/*


@@ 787,12 846,15 @@ ipwrite(Chan* ch, char* a, long n, ulong)
	char *p;
	Cmdbuf *cb;
	uchar ia[IPaddrlen];
	Fs *f;

	f = ipfs[ch->dev];

	switch(TYPE(ch->qid)){
	default:
		error(Eperm);
	case Qdata:
		x = fs.p[PROTO(ch->qid)];
		x = f->p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];

		if(c->wq == nil)


@@ 802,16 864,16 @@ ipwrite(Chan* ch, char* a, long n, ulong)
		x->kick(c, n);
		break;
	case Qarp:
		return arpwrite(a, n);
		return arpwrite(f->arp, a, n);
	case Qiproute:
		return routewrite(ch, a, n);
		return routewrite(f, ch, a, n);
	case Qlog:
		p = netlogctl(a, n);
		p = netlogctl(f, a, n);
		if(p != nil)
			error(p);
		return n;
	case Qctl:
		x = fs.p[PROTO(ch->qid)];
		x = f->p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];
		cb = parsecmd(a, n);



@@ 887,26 949,29 @@ Dev ipdevtab = {
};

int
Fsproto(Fs *fs, Proto *p)
Fsproto(Fs *f, Proto *p)
{
	if(fs->np >= Maxproto)
	if(f->np >= Maxproto)
		return -1;

	p->f = f;

	if(p->ipproto > 0){
		if(fs->t2p[p->ipproto] != nil)
		if(f->t2p[p->ipproto] != nil)
			return -1;
		fs->t2p[p->ipproto] = p;
		f->t2p[p->ipproto] = p;
	}

	p->qid.path = CHDIR|QID(fs->np, 0, Qprotodir);
	p->qid.path = CHDIR|QID(f->np, 0, Qprotodir);
	p->conv = malloc(sizeof(Conv*)*(p->nc+1));
	if(p->conv == nil)
		panic("Fsproto");

	p->x = fs->np;
	p->x = f->np;
	p->nextport = 0;
	p->nextrport = 600;
	fs->p[fs->np++] = p;
	f->p[f->np++] = p;

	return 0;
}



@@ 915,9 980,9 @@ Fsproto(Fs *fs, Proto *p)
 *  built in
 */
int
Fsbuiltinproto(Fs* fs, uchar proto)
Fsbuiltinproto(Fs* f, uchar proto)
{
	return fs->t2p[proto] != nil;
	return f->t2p[proto] != nil;
}

Conv*


@@ 990,7 1055,7 @@ Fsprotoclone(Proto *p, char *user)
}

int
Fsconnected(Fs*, Conv* c, char* msg)
Fsconnected(Conv* c, char* msg)
{
	if(msg != nil && *msg != '\0')
		strncpy(c->cerr, msg, ERRLEN-1);


@@ 1011,13 1076,13 @@ Fsconnected(Fs*, Conv* c, char* msg)
}

Proto*
Fsrcvpcol(Fs* fs, uchar proto)
Fsrcvpcol(Fs* f, uchar proto)
{
	return fs->t2p[proto];
	return f->t2p[proto];
}

Conv*
Fsnewcall(Fs*, Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport)
Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport)
{
	Conv *nc;
	Conv **l;

M ip/ethermedium.c => ip/ethermedium.c +18 -16
@@ 22,7 22,7 @@ static void	etherunbind(Ipifc *ifc);
static void	etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
static void	etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
static void	etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
static Block*	multicastarp(Arpent *a, uchar *mac);
static Block*	multicastarp(Fs *f, Arpent *a, uchar *mac);
static void	sendarp(Ipifc *ifc, Arpent *a);
static int	multicastea(uchar *ea, uchar *ip);
static void	recvarpproc(Ipifc *ifc);


@@ 51,6 51,7 @@ Medium ethermedium =
typedef struct	Etherrock Etherrock;
struct Etherrock
{
	Fs	*f;		/* file system we belong to */
	Proc	*arpp;		/* arp process */
	Proc	*readp;		/* reading process */
	Chan	*mchan;		/* Data channel */


@@ 128,8 129,8 @@ etherbind(Ipifc *ifc, int argc, char **argv)
	fd = kdial(addr, nil, dir, &cfd);
	if(fd < 0)
		error("dial 0x800 failed");
	mchan = fdtochan(fd, ORDWR, 0, 1);
	cchan = fdtochan(cfd, ORDWR, 0, 1);
	mchan = commonfdtochan(fd, ORDWR, 0, 1);
	cchan = commonfdtochan(cfd, ORDWR, 0, 1);
	kclose(fd);
	kclose(cfd);



@@ 162,13 163,14 @@ etherbind(Ipifc *ifc, int argc, char **argv)
	fd = kdial(addr, nil, nil, nil);
	if(fd < 0)
		error("dial 0x806 failed");
	achan = fdtochan(fd, ORDWR, 0, 1);
	achan = commonfdtochan(fd, ORDWR, 0, 1);
	kclose(fd);

	er = smalloc(sizeof(*er));
	er->mchan = mchan;
	er->cchan = cchan;
	er->achan = achan;
	er->f = ifc->conv->p->f;
	ifc->arg = er;

	free(buf);


@@ 217,10 219,10 @@ etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
	Etherrock *er = ifc->arg;

	/* get mac address of destination */
	a = arpget(bp, version, &ethermedium, ip, mac);
	a = arpget(er->f->arp, bp, version, &ethermedium, ip, mac);
	if(a){
		/* check for broadcast or multicast */
		bp = multicastarp(a, mac);
		bp = multicastarp(er->f, a, mac);
		if(bp == nil){
			sendarp(ifc, a);
			return;


@@ 281,7 283,7 @@ etherread(void *a)
		if(ifc->lifc == nil)
			freeb(bp);
		else
			ipiput(ifc->lifc->local, bp);
			ipiput(er->f, ifc->lifc->local, bp);
		runlock(ifc);	locked = 0;	USED(locked);

	}


@@ 325,7 327,7 @@ sendarp(Ipifc *ifc, Arpent *a)

	/* don't do anything if it's been less than a second since the last */
	if(msec - a->time < 1000){
		arprelease(a);
		arprelease(er->f->arp, a);
		return;
	}



@@ 339,7 341,7 @@ sendarp(Ipifc *ifc, Arpent *a)

	/* try to keep it around for a second more */
	a->time = msec;
	arprelease(a);
	arprelease(er->f->arp, a);

	n = sizeof(Etherarp);
	if(n < a->type->minmtu)


@@ 387,7 389,7 @@ recvarp(Ipifc *ifc)
		break;

	case ARPREPLY:
		arpenter(ifc, V4, e->spa, e->sha, &ethermedium, 0);
		arpenter(er->f->arp, ifc, V4, e->spa, e->sha, &ethermedium, 0);
		break;

	case ARPREQUEST:


@@ 408,12 410,12 @@ recvarp(Ipifc *ifc)
		}

		/* refresh what we know about sender */
		arpenter(ifc, V4, e->spa, e->sha, &ethermedium, 1);
		arpenter(er->f->arp, ifc, V4, e->spa, e->sha, &ethermedium, 1);

		/* answer only requests for our address or systems we're proxying for */
		v4tov6(ip, e->tpa);
		if(!iplocalonifc(ifc, ip))
		if(ipproxyifc(ifc, ip) == 0)
		if(ipproxyifc(er->f, ifc, ip) == 0)
			break;

/* print("arp: rem %I %E (for %I)\n", e->spa, e->sha, e->tpa); /**/


@@ 490,15 492,15 @@ multicastea(uchar *ea, uchar *ip)
 *  addresses
 */
static Block*
multicastarp(Arpent *a, uchar *mac)
multicastarp(Fs *f, Arpent *a, uchar *mac)
{
	/* is it broadcast? */
	switch(ipforme(a->ip)){
	switch(ipforme(f, a->ip)){
	case Runi:
		return nil;
	case Rbcast:
		memset(mac, 0xff, 6);
		return arpresolve(a, &ethermedium, mac);
		return arpresolve(f->arp, a, &ethermedium, mac);
	default:
		break;
	}


@@ 507,7 509,7 @@ multicastarp(Arpent *a, uchar *mac)
	switch(multicastea(mac, a->ip)){
	case V4:
	case V6:
		return arpresolve(a, &ethermedium, mac);
		return arpresolve(f->arp, a, &ethermedium, mac);
	}

	/* let arp take care of it */

M ip/gre.c => ip/gre.c +41 -29
@@ 39,9 39,13 @@ typedef struct GREhdr
	uchar	eproto[2];	/* encapsulation protocol */
} GREhdr;

	Proto	gre;
extern	Fs	fs;
	int	gredebug;
typedef struct GREpriv GREpriv;
struct GREpriv
{
	/* non-MIB stats */
	ulong		csumerr;		/* checksum errors */
	ulong		lenerr;			/* short packet */
};

static char*
greconnect(Conv *c, char **argv, int argc)


@@ 75,7 79,7 @@ greconnect(Conv *c, char **argv, int argc)

	if(err != nil)
		return err;
	Fsconnected(&fs, c, nil);
	Fsconnected(c, nil);

	return nil;
}


@@ 147,7 151,7 @@ grekick(Conv *c, int l)
	v4tov6(laddr, ghp->src);
	if(ipcmp(laddr, v4prefix) == 0){
		if(ipcmp(c->laddr, IPnoaddr) == 0)
			findlocalip(c->laddr, raddr); /* pick interface closest to dest */
			findlocalip(c->p->f, c->laddr, raddr); /* pick interface closest to dest */
		memmove(ghp->src, c->laddr + IPv4off, IPv4addrlen);
	}



@@ 156,18 160,20 @@ grekick(Conv *c, int l)
	ghp->frag[0] = 0;
	ghp->frag[1] = 0;

	ipoput(bp, 0, c->ttl);
	ipoput(c->p->f, bp, 0, c->ttl);
}

static void
greiput(uchar*, Block *bp)
greiput(Proto *gre, uchar*, Block *bp)
{
	int len;
	GREhdr *ghp;
	Conv *c, **p;
	ushort eproto;
	uchar raddr[IPaddrlen];
	GREpriv *gpriv;

	gpriv = gre->priv;
	ghp = (GREhdr*)(bp->rp);

	v4tov6(raddr, ghp->src);


@@ 175,7 181,7 @@ greiput(uchar*, Block *bp)

	/* Look for a conversation structure for this port and address */
	c = nil;
	for(p = gre.conv; *p; p++) {
	for(p = gre->conv; *p; p++) {
		c = *p;
		if(c->inuse == 0)
			continue;


@@ 198,7 204,7 @@ greiput(uchar*, Block *bp)
	}
	bp = trimblock(bp, GRE_IPONLY, len);
	if(bp == nil){
		gre.lenerr++;
		gpriv->lenerr++;
		return;
	}



@@ 216,30 222,36 @@ greiput(uchar*, Block *bp)
}

int
grestats(char *buf, int len)
grestats(Proto *gre, char *buf, int len)
{
	return snprint(buf, len,
		"gre: csum %d hlen %d len %d order %d rexmit %d\n",
		gre.csumerr, gre.hlenerr, gre.lenerr, gre.order, gre.rexmit);
	GREpriv *gpriv;

	gpriv = gre->priv;

	return snprint(buf, len, "gre: len %d\n", gpriv->lenerr);
}

void
greinit(Fs *fs)
{
	gre.name = "gre";
	gre.kick = grekick;
	gre.connect = greconnect;
	gre.announce = greannounce;
	gre.state = grestate;
	gre.create = grecreate;
	gre.close = greclose;
	gre.rcv = greiput;
	gre.ctl = nil;
	gre.advise = nil;
	gre.stats = grestats;
	gre.ipproto = IP_GREPROTO;
	gre.nc = 64;
	gre.ptclsize = 0;

	Fsproto(fs, &gre);
	Proto *gre;

	gre = smalloc(sizeof(Proto));
	gre->priv = smalloc(sizeof(GREpriv));
	gre->name = "gre";
	gre->kick = grekick;
	gre->connect = greconnect;
	gre->announce = greannounce;
	gre->state = grestate;
	gre->create = grecreate;
	gre->close = greclose;
	gre->rcv = greiput;
	gre->ctl = nil;
	gre->advise = nil;
	gre->stats = grestats;
	gre->ipproto = IP_GREPROTO;
	gre->nc = 64;
	gre->ptclsize = 0;

	Fsproto(fs, gre);
}

M ip/icmp.c => ip/icmp.c +73 -59
@@ 46,14 46,16 @@ enum {
	ICMP_HDRSIZE	= 8,
};

	Proto	icmp;
extern	Fs	fs;

static struct Icmpstats
typedef struct Icmppriv Icmppriv;
struct Icmppriv
{
	/* non-MIB stats */
	ulong	csumerr;		/* checksum errors */
	ulong	lenerr;			/* short packet */
	ulong	hlenerr;		/* short header */
	ulong	in[Maxtype+1];
	ulong	out[Maxtype+1];
} stats;
};

static char*
icmpconnect(Conv *c, char **argv, int argc)


@@ 61,7 63,7 @@ icmpconnect(Conv *c, char **argv, int argc)
	char *e;

	e = Fsstdconnect(c, argv, argc);
	Fsconnected(&fs, c, e);
	Fsconnected(c, e);

	return e;
}


@@ 88,7 90,7 @@ icmpannounce(Conv *c, char **argv, int argc)
	e = Fsstdannounce(c, argv, argc);
	if(e != nil);
		return e;
	Fsconnected(&fs, c, nil);
	Fsconnected(c, nil);

	return nil;
}


@@ 109,6 111,7 @@ icmpkick(Conv *c, int l)
{
	Icmp *p;
	Block *bp;
	Icmppriv *ipriv;

	USED(l);
	bp = qget(c->wq);


@@ 120,25 123,27 @@ icmpkick(Conv *c, int l)
		return;
	}
	p = (Icmp *)(bp->rp);
	if(p->type <= Maxtype)
		stats.out[p->type]++;
	if(p->type <= Maxtype){
		ipriv = c->p->priv;
		ipriv->out[p->type]++;
	}
	v6tov4(p->dst, c->raddr);
	v6tov4(p->src, c->laddr);
	p->proto = IP_ICMPPROTO;
	hnputs(p->icmpid, c->lport);
	memset(p->cksum, 0, sizeof(p->cksum));
	hnputs(p->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE));
	ipoput(bp, 0, c->ttl);
	ipoput(c->p->f, bp, 0, c->ttl);
}

extern void
icmpnoconv(Block *bp)
icmpnoconv(Fs *f, Block *bp)
{
	Block	*nbp;
	Icmp	*p, *np;

	p = (Icmp *)bp->rp;
	netlog(Logicmp, "sending icmpnoconv -> %V\n", p->src);
	netlog(f, Logicmp, "sending icmpnoconv -> %V\n", p->src);
	nbp = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8);
	nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8;
	np = (Icmp *)nbp->rp;


@@ 152,12 157,12 @@ icmpnoconv(Block *bp)
	hnputs(np->seq, 0);
	memset(np->cksum, 0, sizeof(np->cksum));
	hnputs(np->cksum, ptclcsum(nbp, ICMP_IPSIZE, blocklen(nbp) - ICMP_IPSIZE));
	stats.out[Unreachable]++;
	ipoput(nbp, 0, MAXTTL);
/*	stats.out[Unreachable]++; */
	ipoput(f, nbp, 0, MAXTTL);
}

static void
goticmpkt(Block *bp)
goticmpkt(Proto *icmp, Block *bp)
{
	Conv	**c, *s;
	Icmp	*p;


@@ 168,7 173,7 @@ goticmpkt(Block *bp)
	v4tov6(dst, p->src);
	recid = nhgets(p->icmpid);

	for(c = icmp.conv; *c; c++) {
	for(c = icmp->conv; *c; c++) {
		s = *c;
		if(s->lport == recid)
		if(ipcmp(s->raddr, dst) == 0){


@@ 207,7 212,7 @@ static char *unreachcode[] =
};

static void
icmpiput(uchar*, Block *bp)
icmpiput(Proto *icmp, uchar*, Block *bp)
{
	int	n, iplen;
	Icmp	*p;


@@ 215,33 220,36 @@ icmpiput(uchar*, Block *bp)
	Proto	*pr;
	char	*msg;
	char	m2[128];
	Icmppriv *ipriv;

	ipriv = icmp->priv;

	p = (Icmp *)bp->rp;
	netlog(Logicmp, "icmpiput %d %d\n", p->type, p->code);
	netlog(icmp->f, Logicmp, "icmpiput %d %d\n", p->type, p->code);
	n = blocklen(bp);
	if(n < ICMP_IPSIZE+ICMP_HDRSIZE){
		icmp.hlenerr++;
		netlog(Logicmp, "icmp hlen %d\n", n);
		ipriv->hlenerr++;
		netlog(icmp->f, Logicmp, "icmp hlen %d\n", n);
		goto raise;
	}
	iplen = nhgets(p->length);
	if(iplen > n || (iplen % 1)){
		icmp.lenerr++;
		netlog(Logicmp, "icmp length %d\n", iplen);
		ipriv->lenerr++;
		netlog(icmp->f, Logicmp, "icmp length %d\n", iplen);
		goto raise;
	}
	if(ptclcsum(bp, ICMP_IPSIZE, iplen - ICMP_IPSIZE)){
		icmp.csumerr++;
		netlog(Logicmp, "icmp checksum error\n");
		ipriv->csumerr++;
		netlog(icmp->f, Logicmp, "icmp checksum error\n");
		goto raise;
	}
	if(p->type <= Maxtype)
		stats.in[p->type]++;
		ipriv->in[p->type]++;
	switch(p->type) {
	case EchoRequest:
		r = mkechoreply(bp);
		stats.out[EchoReply]++;
		ipoput(r, 0, MAXTTL);
		ipriv->out[EchoReply]++;
		ipoput(icmp->f, r, 0, MAXTTL);
		break;
	case Unreachable:
		if(p->code > 5 || p->code < 0)


@@ 251,18 259,18 @@ icmpiput(uchar*, Block *bp)

		bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
		if(blocklen(bp) < 8){
			icmp.lenerr++;
			ipriv->lenerr++;
			goto raise;
		}
		p = (Icmp *)bp->rp;
		pr = Fsrcvpcol(&fs, p->proto);
		pr = Fsrcvpcol(icmp->f, p->proto);
		if(pr != nil && pr->advise != nil) {
			(*pr->advise)(bp, msg);
			(*pr->advise)(pr, bp, msg);
			return;
		}

		bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
		goticmpkt(bp);
		goticmpkt(icmp, bp);
		break;
	case TimeExceed:
		if(p->code == 0){


@@ 270,21 278,21 @@ icmpiput(uchar*, Block *bp)

			bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
			if(blocklen(bp) < 8){
				icmp.lenerr++;
				ipriv->lenerr++;
				goto raise;
			}
			p = (Icmp *)bp->rp;
			pr = Fsrcvpcol(&fs, p->proto);
			pr = Fsrcvpcol(icmp->f, p->proto);
			if(pr != nil && pr->advise != nil) {
				(*pr->advise)(bp, m2);
				(*pr->advise)(pr, bp, m2);
				return;
			}
		}

		goticmpkt(bp);
		goticmpkt(icmp, bp);
		break;
	default:
		goticmpkt(bp);
		goticmpkt(icmp, bp);
		break;
	}
	return;


@@ 294,7 302,7 @@ raise:
}

void
icmpadvise(Block *bp, char *msg)
icmpadvise(Proto *icmp, Block *bp, char *msg)
{
	Conv	**c, *s;
	Icmp	*p;


@@ 305,7 313,7 @@ icmpadvise(Block *bp, char *msg)
	v4tov6(dst, p->dst);
	recid = nhgets(p->icmpid);

	for(c = icmp.conv; *c; c++) {
	for(c = icmp->conv; *c; c++) {
		s = *c;
		if(s->lport == recid)
		if(ipcmp(s->raddr, dst) == 0){


@@ 318,20 326,22 @@ icmpadvise(Block *bp, char *msg)
}

int
icmpstats(char *buf, int len)
icmpstats(Proto *icmp, char *buf, int len)
{
	int i, n;
	Icmppriv *ipriv;

	ipriv = icmp->priv;

	n = snprint(buf, len,
		"icmp: csum %d hlen %d len %d order %d rexmit %d\n",
		icmp.csumerr, icmp.hlenerr, icmp.lenerr, icmp.order, icmp.rexmit);
		"icmp: csum %d hlen %d len %d\n",
		ipriv->csumerr, ipriv->hlenerr, ipriv->lenerr);
	n += snprint(buf+n, len-n, "\trcvd ");
	for(i = 0; i < Maxtype && len > n; i++)
		n += snprint(buf+n, len-n, " %d", stats.in[i]);	
		n += snprint(buf+n, len-n, " %d", ipriv->in[i]);	
	n += snprint(buf+n, len-n, "\n\tsent ");
	for(i = 0; i < Maxtype && len > n; i++)
		n += snprint(buf+n, len-n, " %d", stats.out[i]);
		n += snprint(buf+n, len-n, " %d", ipriv->out[i]);
	if(n < len)
		n += snprint(buf+n, len-n, "\n");
	return n;	


@@ 340,20 350,24 @@ icmpstats(char *buf, int len)
void
icmpinit(Fs *fs)
{
	icmp.name = "icmp";
	icmp.kick = icmpkick;
	icmp.connect = icmpconnect;
	icmp.announce = icmpannounce;
	icmp.state = icmpstate;
	icmp.create = icmpcreate;
	icmp.close = icmpclose;
	icmp.rcv = icmpiput;
	icmp.stats = icmpstats;
	icmp.ctl = nil;
	icmp.advise = icmpadvise;
	icmp.ipproto = IP_ICMPPROTO;
	icmp.nc = 16;
	icmp.ptclsize = 0;

	Fsproto(fs, &icmp);
	Proto *icmp;

	icmp = smalloc(sizeof(Proto));
	icmp->priv = smalloc(sizeof(Icmppriv));
	icmp->name = "icmp";
	icmp->kick = icmpkick;
	icmp->connect = icmpconnect;
	icmp->announce = icmpannounce;
	icmp->state = icmpstate;
	icmp->create = icmpcreate;
	icmp->close = icmpclose;
	icmp->rcv = icmpiput;
	icmp->stats = icmpstats;
	icmp->ctl = nil;
	icmp->advise = icmpadvise;
	icmp->ipproto = IP_ICMPPROTO;
	icmp->nc = 16;
	icmp->ptclsize = 0;

	Fsproto(fs, icmp);
}

M ip/il.c => ip/il.c +102 -75
@@ 121,11 121,22 @@ struct Ilhdr
	uchar	ilack[4];	/* Acked sequence */
};

static struct Ilstats

typedef struct Ilpriv Ilpriv;
struct Ilpriv
{
	ulong	dup;
	ulong	dupb;
} ilstats;

	/* non-MIB stats */
	ulong		csumerr;		/* checksum errors */
	ulong		hlenerr;		/* header length error */
	ulong		lenerr;			/* short packet */
	ulong		order;			/* out of order */
	ulong		rexmit;			/* retransmissions */
	ulong		dup;
	ulong		dupb;

	Rendez		ilr;
};

/* Always Acktime < Fasttime < Slowtime << Ackkeepalive */
enum


@@ 164,18 175,14 @@ void	ilrexmit(Ilcb*);
void	ilbackoff(Ilcb*);
void	iltimers(Ilcb*);
char*	ilstart(Conv*, int, int);
void	ilackproc();
void	ilackproc(void*);
void	iloutoforder(Conv*, Ilhdr*, Block*);
void	iliput(uchar*, Block*);
void	iladvise(Block*, char*);
void	iliput(Proto*, uchar*, Block*);
void	iladvise(Proto*, Block*, char*);
int	ilnextqt(Ilcb*);

#define DBG(x)	if((logmask & Logilmsg) && (iponly == 0 || x == iponly))netlog

	Proto	il;
	int 	ilcksum = 1;
static 	int 	initseq = 25001;
extern	Fs	fs;

static char*
ilconnect(Conv *c, char **argv, int argc)


@@ 222,7 229,7 @@ ilannounce(Conv *c, char **argv, int argc)
	e = ilstart(c, IL_LISTEN, 20);
	if(e != nil)
		return e;
	Fsconnected(&fs, c, nil);
	Fsconnected(c, nil);

	return nil;
}


@@ 266,9 273,11 @@ ilkick(Conv *c, int l)
	int dlen;
	ulong id;
	Block *bp;
	Fs *f;

	USED(l);

	f = c->p->f;
	ic = (Ilcb*)c->ptcl;

	bp = qget(c->wq);


@@ 327,7 336,7 @@ ilkick(Conv *c, int l)
	}
	ic->acktime = Ackkeepalive;

	ipoput(bp, 0, c->ttl);
	ipoput(f, bp, 0, c->ttl);
}

static void


@@ 338,40 347,46 @@ ilcreate(Conv *c)
}

int
ilxstats(char *buf, int len)
ilxstats(Proto *il, char *buf, int len)
{
	int n;
	Ilpriv *ipriv;

	ipriv = il->priv;

	n = snprint(buf, len,
		"il: csum %d hlen %d len %d order %d rexmit %d",
		il.csumerr, il.hlenerr, il.lenerr, il.order, il.rexmit);
		ipriv->csumerr, ipriv->hlenerr, ipriv->lenerr, ipriv->order, ipriv->rexmit);
	n += snprint(buf+n, len-n, " dupp %d dupb %d\n",
		ilstats.dup, ilstats.dupb);
		ipriv->dup, ipriv->dupb);
	return n;
}

void
ilinit(Fs *fs)
ilinit(Fs *f)
{
	il.name = "il";
	il.kick = ilkick;
	il.connect = ilconnect;
	il.announce = ilannounce;
	il.state = ilstate;
	il.create = ilcreate;
	il.close = ilclose;
	il.rcv = iliput;
	il.ctl = nil;
	il.advise = iladvise;
	il.stats = ilxstats;
	il.inuse = ilinuse;
	il.ipproto = IP_ILPROTO;
	il.nc = Nchans;
	il.ptclsize = sizeof(Ilcb);

	kproc("ilack", ilackproc, 0);

	Fsproto(fs, &il);
	Proto *il;

	il = smalloc(sizeof(Proto));
	il->priv = smalloc(sizeof(Ilpriv));
	il->name = "il";
	il->kick = ilkick;
	il->connect = ilconnect;
	il->announce = ilannounce;
	il->state = ilstate;
	il->create = ilcreate;
	il->close = ilclose;
	il->rcv = iliput;
	il->ctl = nil;
	il->advise = iladvise;
	il->stats = ilxstats;
	il->inuse = ilinuse;
	il->ipproto = IP_ILPROTO;
	il->nc = Nchans;
	il->ptclsize = sizeof(Ilcb);
	Fsproto(f, il);

	kproc("ilack", ilackproc, il);
}

void


@@ 467,7 482,7 @@ ilackto(Ilcb *ic, ulong ackto)
}

void
iliput(uchar*, Block *bp)
iliput(Proto *il, uchar*, Block *bp)
{
	char *st;
	Ilcb *ic;


@@ 477,19 492,22 @@ iliput(uchar*, Block *bp)
	ushort sp, dp, csum;
	int plen, illen;
	Conv *s, **p, *new, *spec, *gen;
	Ilpriv *ipriv;

	ipriv = il->priv;

	ih = (Ilhdr *)bp->rp;
	plen = blocklen(bp);
	if(plen < IL_IPSIZE+IL_HDRSIZE){
		netlog(Logil, "il: hlenerr\n");
		il.hlenerr++;
		netlog(il->f, Logil, "il: hlenerr\n");
		ipriv->hlenerr++;
		goto raise;
	}

	illen = nhgets(ih->illen);
	if(illen+IL_IPSIZE > plen){
		netlog(Logil, "il: lenerr\n");
		il.lenerr++;
		netlog(il->f, Logil, "il: lenerr\n");
		ipriv->lenerr++;
		goto raise;
	}



@@ 497,18 515,18 @@ iliput(uchar*, Block *bp)
	dp = nhgets(ih->ilsrc);
	v4tov6(raddr, ih->src);

	if(ilcksum && (csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) {
	if((csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) {
		if(ih->iltype < 0 || ih->iltype > Ilclose)
			st = "?";
		else
			st = iltype[ih->iltype];
		il.csumerr++;
		netlog(Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %I/%d->%d)\n",
		ipriv->csumerr++;
		netlog(il->f, Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %I/%d->%d)\n",
			csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp);
		goto raise;
	}

	for(p = il.conv; *p; p++) {
	for(p = il->conv; *p; p++) {
		s = *p;
		if(s->lport == sp)
		if(s->rport == dp)


@@ 523,14 541,14 @@ iliput(uchar*, Block *bp)
			st = "?";
		else
			st = iltype[ih->iltype];
		netlog(Logil, "il: no channel, pkt(%s id %lud ack %lud %I/%ud->%ud)\n",
		netlog(il->f, Logil, "il: no channel, pkt(%s id %lud ack %lud %I/%ud->%ud)\n",
			st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); 
		goto raise;
	}

	gen = nil;
	spec = nil;
	for(p = il.conv; *p; p++) {
	for(p = il->conv; *p; p++) {
		s = *p;
		ic = (Ilcb*)s->ptcl;
		if(ic->state != Illistening)


@@ 555,9 573,9 @@ iliput(uchar*, Block *bp)
		goto raise;

	v4tov6(laddr, ih->dst);
	new = Fsnewcall(&fs, s, raddr, dp, laddr, sp);
	new = Fsnewcall(s, raddr, dp, laddr, sp);
	if(new == nil){
		netlog(Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp);
		netlog(il->f, Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp);
		ilsendctl(nil, ih, Ilclose, 0, nhgetl(ih->ilid), 0);
		goto raise;
	}


@@ 602,7 620,7 @@ _ilprocess(Conv *s, Ilhdr *h, Block *bp)

	switch(ic->state) {
	default:
		netlog(Logil, "il: unknown state %d\n", ic->state);
		netlog(s->p->f, Logil, "il: unknown state %d\n", ic->state);
	case Ilclosed:
		freeblist(bp);
		break;


@@ 618,7 636,7 @@ _ilprocess(Conv *s, Ilhdr *h, Block *bp)
				ic->rstart = id;
				ilsendctl(s, nil, Ilack, ic->next, ic->recvd, 0);
				ic->state = Ilestablished;
				Fsconnected(&fs, s, nil);
				Fsconnected(s, nil);
				ilpullup(s);
				iltimers(ic);
			}


@@ 742,6 760,7 @@ ilrexmit(Ilcb *ic)
	Conv *c;
	ulong id;
	int x;
	Ilpriv *ipriv;

	nb = nil;
	qlock(&ic->ackq);


@@ 759,16 778,16 @@ ilrexmit(Ilcb *ic)
	h->ilspec = ilnextqt(ic);
	h->ilsum[0] = 0;
	h->ilsum[1] = 0;
	if(ilcksum)
		hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen)));
	hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen)));

	c = ic->conv;
	ipriv = c->p->priv;
	id = nhgetl(h->ilid);
	netlog(Logil, "il: rexmit %ud %ud: %d %d: %i %d/%d\n", id, ic->recvd,
	netlog(c->p->f, Logil, "il: rexmit %ud %ud: %d %d: %i %d/%d\n", id, ic->recvd,
		ic->fasttime, ic->timeout,
		c->raddr, c->lport, c->rport);

	il.rexmit++;
	ipriv->rexmit++;
	ic->rexmit++;

	/*


@@ 782,7 801,7 @@ ilrexmit(Ilcb *ic)
	if(x >= (1<<LogAGain))
		ic->rate = x;

	ipoput(nb, 0, ic->conv->ttl);
	ipoput(c->p->f, nb, 0, ic->conv->ttl);
}

/* DEBUG */


@@ 794,14 813,14 @@ ilprocess(Conv *s, Ilhdr *h, Block *bp)
	ic = (Ilcb*)s->ptcl;

	USED(ic);
	DBG(s->raddr)(Logilmsg, "%11s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ",
	netlog(s->p->f, Logilmsg, "%11s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ",
		ilstates[ic->state],  ic->rstart, ic->recvd, ic->start, 
		ic->next, iltype[h->iltype], nhgetl(h->ilid), 
		nhgetl(h->ilack), nhgets(h->ilsrc), nhgets(h->ildst));

	_ilprocess(s, h, bp);

	DBG(s->raddr)(Logilmsg, "%11s rcv %d snt %d\n", ilstates[ic->state], ic->recvd, ic->next);
	netlog(s->p->f, Logilmsg, "%11s rcv %d snt %d\n", ilstates[ic->state], ic->recvd, ic->next);
}

void


@@ 810,7 829,7 @@ ilhangup(Conv *s, char *msg)
	Ilcb *ic;
	int callout;

	netlog(Logil, "il: hangup! %I %d/%d: %s\n", s->raddr, s->lport, s->rport, msg?msg:"no reason");
	netlog(s->p->f, Logil, "il: hangup! %I %d/%d: %s\n", s->raddr, s->lport, s->rport, msg?msg:"no reason");

	ic = (Ilcb*)s->ptcl;
	callout = ic->state == Ilsyncer;


@@ 820,7 839,7 @@ ilhangup(Conv *s, char *msg)
	qhangup(s->wq, msg);

	if(callout)
		Fsconnected(&fs, s, msg);
		Fsconnected(s, msg);
}

void


@@ 830,6 849,7 @@ ilpullup(Conv *s)
	Ilhdr *oh;
	Block *bp;
	ulong oid, dlen;
	Ilpriv *ipriv;

	ic = (Ilcb*)s->ptcl;
	if(ic->state != Ilestablished)


@@ 846,7 866,8 @@ ilpullup(Conv *s)
			continue;
		}
		if(oid != ic->recvd+1){
			il.order++;
			ipriv = s->p->priv;
			ipriv->order++;
			break;
		}



@@ 875,14 896,16 @@ iloutoforder(Conv *s, Ilhdr *h, Block *bp)
	uchar *lid;
	Block *f, **l;
	ulong id, newid;
	Ilpriv *ipriv;

	ipriv = s->p->priv;
	ic = (Ilcb*)s->ptcl;
	bp->list = nil;

	id = nhgetl(h->ilid);
	/* Window checks */
	if(id <= ic->recvd || id > ic->recvd+ic->window) {
		netlog(Logil, "il: message outside window %ud <%ud-%ud>: %i %d/%d\n",
		netlog(s->p->f, Logil, "il: message outside window %ud <%ud-%ud>: %i %d/%d\n",
			id, ic->recvd, ic->recvd+ic->window, s->raddr, s->lport, s->rport);
		freeblist(bp);
		return;


@@ 899,8 922,8 @@ iloutoforder(Conv *s, Ilhdr *h, Block *bp)
			newid = nhgetl(lid);
			if(id <= newid) {
				if(id == newid) {
					ilstats.dup++;
					ilstats.dupb += blocklen(bp);
					ipriv->dup++;
					ipriv->dupb += blocklen(bp);
					qunlock(&ic->outo);
					freeblist(bp);
					return;


@@ 964,24 987,28 @@ ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec)
		hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE));

	if(ipc){
		DBG(ipc->raddr)(Logilmsg, "ctl(%s id %d ack %d %d->%d)\n",
		netlog(ipc->p->f, Logilmsg, "ctl(%s id %d ack %d %d->%d)\n",
		iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack), 
		nhgets(ih->ilsrc), nhgets(ih->ildst));
	}

	ipoput(bp, 0, ttl);
	ipoput(ipc->p->f, bp, 0, ttl);
}

void
ilackproc()
ilackproc(void *x)
{
	Ilcb *ic;
	Conv **s, *p;
	static Rendez ilr;
	Proto *il;
	Ilpriv *ipriv;

	il = x;
	ipriv = il->priv;

loop:
	tsleep(&ilr, return0, 0, Iltickms);
	for(s = il.conv; s && *s; s++) {
	tsleep(&ipriv->ilr, return0, 0, Iltickms);
	for(s = il->conv; s && *s; s++) {
		p = *s;
		ic = (Ilcb*)p->ptcl;



@@ 1016,7 1043,7 @@ loop:
			if(ic->querytime <= 0){
				ic->deathtime -= Querytime;
				if(ic->deathtime < 0){
					netlog(Logil, "il: hangup due to deathtime (%d) < 0 \n", ic->deathtime);
					netlog(il->f, Logil, "il: hangup due to deathtime (%d) < 0 \n", ic->deathtime);
					ilhangup(p, etime);
					break;
				}


@@ 1032,7 1059,7 @@ loop:
				ilbackoff(ic);
			}
			if(ic->timeout >= ic->slowtime) {
				netlog(Logil, "il: hangup due to timeout (%d) >= slowtime (%d)\n", ic->timeout, ic->slowtime);
				netlog(il->f, Logil, "il: hangup due to timeout (%d) >= slowtime (%d)\n", ic->timeout, ic->slowtime);
				ilhangup(p, etime);
				break;
			}


@@ 1080,7 1107,7 @@ ilstart(Conv *c, int type, int window)

	switch(type) {
	default:
		netlog(Logil, "il: start: type %d\n", type);
		netlog(c->p->f, Logil, "il: start: type %d\n", type);
		break;
	case IL_LISTEN:
		ic->state = Illistening;


@@ 1132,7 1159,7 @@ iltimers(Ilcb *ic)
}

void
iladvise(Block *bp, char *msg)
iladvise(Proto *il, Block *bp, char *msg)
{
	Ilhdr *h;
	Ilcb *ic;		


@@ 1148,7 1175,7 @@ iladvise(Block *bp, char *msg)


	/* Look for a connection, unfortunately the destination port is missing */
	for(p = il.conv; *p; p++) {
	for(p = il->conv; *p; p++) {
		s = *p;
		if(s->lport == psource)
		if(ipcmp(s->laddr, source) == 0)

A ip/inferno.c => ip/inferno.c +46 -0
@@ 0,0 1,46 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"
#include	"ip.h"

/*
 *  some hacks for commonality twixt inferno and plan9
 */

char*
commonuser(void)
{
	return up->user;
}

Chan*
commonfdtochan(int fd, int mode, int a, int b)
{
	return fdtochan(fd, mode, a, b);
}

char*
commonerror(void)
{
	return up->error;
}

char*
bootp(Ipifc*)
{
	return "unimplmented";
}

int
bootpread(char*, ulong, int)
{
	return	0;
}

Medium tripmedium =
{
	"trip",
};

M ip/ip.c => ip/ip.c +203 -118
@@ 26,13 26,13 @@ struct Iphdr
	uchar	vihl;		/* Version and header length */
	uchar	tos;		/* Type of service */
	uchar	length[2];	/* packet length */
	uchar	id[2];		/* Identification */
	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 */
	uchar	src[4];		/* IP source */
	uchar	dst[4];		/* IP destination */
};

struct Fragment


@@ 51,14 51,44 @@ struct Ipfrag
	ushort	flen;
};

QLock		fraglock;
Fragment*	flisthead;
Fragment*	fragfree;
ulong		Id;
int		iprouting;	/* true if we route like a gateway */
ulong		ipcsumerr;
ulong		ipin, ippin;		/* uchars, packets in */
ulong		ipout, ippout;		/* uchars, packets out */
/* MIB II counters */
typedef struct Ipstats Ipstats;
struct Ipstats
{
	ulong	ipForwarding;
	ulong	ipDefaultTTL;
	ulong	ipInReceives;
	ulong	ipInHdrErrors;
	ulong	ipInAddrErrors;
	ulong	ipForwDatagrams;
	ulong	ipInUnknownProtos;
	ulong	ipInDiscards;
	ulong	ipInDelivers;
	ulong	ipOutRequests;
	ulong	ipOutDiscards;
	ulong	ipOutNoRoutes;
	ulong	ipReasmTimeout;
	ulong	ipReasmReqds;
	ulong	ipReasmOKs;
	ulong	ipReasmFails;
	ulong	ipFragOKs;
	ulong	ipFragFails;
	ulong	ipFragCreates;
};

/* an instance of IP */
struct IP
{
	Ipstats		istats;

	QLock		fraglock;
	Fragment*	flisthead;
	Fragment*	fragfree;

	ulong		id;
	int		iprouting;			/* true if we route like a gateway */
	void 		(*ipextprotoiput)(Block*);
};

#define BLKIP(xp)	((Iphdr*)((xp)->rp))
/*


@@ 67,19 97,23 @@ ulong		ipout, ippout;		/* uchars, packets out */
 */
#define BKFG(xp)	((Ipfrag*)((xp)->base))

static struct Stats
ushort		ipcsum(uchar*);
Block*		ipreassemble(IP*, int, Block*, Iphdr*);
void		ipfragfree(IP*, Fragment*);
Fragment*	ipfragallo(IP*);

void
ip_init(Fs *f)
{
	ulong	noroute;
	ulong	droppedfrag;
} stats;
	IP *ip;

ushort		ipcsum(uchar*);
Block*		ipreassemble(int, Block*, Iphdr*);
void		ipfragfree(Fragment*);
Fragment*	ipfragallo(void);
	ip = smalloc(sizeof(IP));
	initfrag(ip, 100);
	f->ip = ip;
}

void
ipoput(Block *bp, int gating, int ttl)
ipoput(Fs *f, Block *bp, int gating, int ttl)
{
	Ipifc *ifc;
	uchar *gate;


@@ 87,45 121,60 @@ ipoput(Block *bp, int gating, int ttl)
	Block *xp, *nb;
	Iphdr *eh, *feh;
	int lid, len, seglen, chunk, dlen, blklen, offset, medialen;
	Route *r;
	Route *r, *sr;
	IP *ip;

	ip = f->ip;

	/* Fill out the ip header */
	eh = (Iphdr *)(bp->rp);

	ip->istats.ipOutRequests++;

	/* Number of uchars in data and ip header to write */
	len = blocklen(bp);
	ipout += len;
	ippout++;

	if(gating){
		chunk = nhgets(eh->length);
		if(chunk > len){
			netlog(Logip, "short gated packet\n");
			ip->istats.ipOutDiscards++;
			netlog(f, Logip, "short gated packet\n");
			goto free;
		}
		if(chunk < len)
			len = chunk;
	}
	if(len >= IP_MAX){
		netlog(Logip, "exceeded ip max size %V\n", eh->dst);
		ip->istats.ipOutDiscards++;
		netlog(f, Logip, "exceeded ip max size %V\n", eh->dst);
		goto free;
	}

	r = v4lookup(eh->dst);
	r = v4lookup(f, eh->dst);
	if(r == nil){
		stats.noroute++;
		netlog(Logip, "no interface %V\n", eh->dst);
		ip->istats.ipOutNoRoutes++;
		netlog(f, Logip, "no interface %V\n", eh->dst);
		goto free;
	}
	if(r->type & (Rifc|Runi|Rbcast|Rmulti))

	ifc = r->ifc;
	if(r->type & (Rifc|Runi))
		gate = eh->dst;
	else
	if(r->type & (Rbcast|Rmulti)) {
		gate = eh->dst;
		sr = v4lookup(f, eh->src);
		if(sr != nil && (sr->type & Runi))
			ifc = sr->ifc;
	}
	else
		gate = r->v4.gate;

	if(!gating){
		eh->vihl = IP_VER|IP_HLEN;
		eh->tos = 0;
		eh->ttl = ttl;
	}
	ifc = r->ifc;

	if(waserror()){
		runlock(ifc);


@@ 139,7 188,7 @@ ipoput(Block *bp, int gating, int ttl)
	medialen = ifc->m->maxmtu - ifc->m->hsize;
	if(len <= medialen) {
		if(!gating)
			hnputs(eh->id, Id++);
			hnputs(eh->id, ip->id++);
		hnputs(eh->length, len);
		eh->frag[0] = 0;
		eh->frag[1] = 0;


@@ 147,7 196,7 @@ ipoput(Block *bp, int gating, int ttl)
		eh->cksum[1] = 0;
		hnputs(eh->cksum, ipcsum(&eh->vihl));

/*print("ipoput %V->%V via %V\n", eh->src, eh->dst, gate);*/
/*		print("ipoput %V->%V via %V\n", eh->src, eh->dst, gate); /**/
		ifc->m->bwrite(ifc, bp, V4, gate);
		runlock(ifc);
		poperror();


@@ 155,13 204,15 @@ ipoput(Block *bp, int gating, int ttl)
	}

	if(eh->frag[0] & (IP_DF>>8)){
		netlog(Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
		ip->istats.ipOutDiscards++;
		netlog(f, Logip, "%V: eh->frag[0] & (IP_DF>>8)\n", eh->dst);
		goto raise;
	}

	seglen = (medialen - IPHDR) & ~7;
	if(seglen < 8){
		netlog(Logip, "%V seglen < 8\n", eh->dst);
		ip->istats.ipOutDiscards++;
		netlog(f, Logip, "%V seglen < 8\n", eh->dst);
		goto raise;
	}



@@ 170,7 221,7 @@ ipoput(Block *bp, int gating, int ttl)
	if(gating)
		lid = nhgets(eh->id);
	else
		lid = Id++;
		lid = ip->id++;

	offset = IPHDR;
	while(xp != nil && offset && offset >= BLEN(xp)) {


@@ 200,8 251,9 @@ ipoput(Block *bp, int gating, int ttl)
		chunk = seglen;
		while(chunk) {
			if(!xp) {
				ip->istats.ipOutDiscards++;
				freeblist(nb);
				netlog(Logip, "!xp: chunk %d\n", chunk);
				netlog(f, Logip, "!xp: chunk %d\n", chunk);
				goto raise;
			}
			blklen = chunk;


@@ 213,14 265,14 @@ ipoput(Block *bp, int gating, int ttl)
			chunk -= blklen;
			if(xp->rp == xp->wp)
				xp = xp->next;
		}
		} 

		feh->cksum[0] = 0;
		feh->cksum[1] = 0;
		hnputs(feh->cksum, ipcsum(&feh->vihl));
		ifc->m->bwrite(ifc, nb, V4, gate);
		ip->istats.ipFragCreates++;
	}

raise:
	runlock(ifc);
	poperror();


@@ 229,36 281,40 @@ free:
}

void
initfrag(int size)
initfrag(IP *ip, int size)
{
	Fragment *fq, *eq;

	fragfree = (Fragment*)malloc(sizeof(Fragment) * size);
	if(fragfree == nil)
	ip->fragfree = (Fragment*)malloc(sizeof(Fragment) * size);
	if(ip->fragfree == nil)
		panic("initfrag");

	eq = &fragfree[size];
	for(fq = fragfree; fq < eq; fq++)
	eq = &ip->fragfree[size];
	for(fq = ip->fragfree; fq < eq; fq++)
		fq->next = fq+1;

	fragfree[size-1].next = nil;
	ip->fragfree[size-1].next = nil;
}

void (*ipextprotoiput)(Block*);

//#define DBG(x)	if((logmask & Logipmsg) && (iponly == 0 || x == iponly))netlog
#define DBG(x)	if((logmask & Logipmsg) && (iponly == 0 || x == iponly))netlog

void
ipiput(uchar *ia, Block *bp)
ipiput(Fs *f, uchar *ia, Block *bp)
{
	int hl;
	Iphdr *h;
	Proto *p;
	ushort frag;
	int notforme;
	uchar v6dst[IPaddrlen];
	uchar *dp, v6dst[IPaddrlen];
	IP *ip;

	ip = f->ip;
	ip->istats.ipInReceives++;

//	h = (Iphdr *)(bp->rp);
//	DBG(nhgetl(h->src))(Logipmsg, "ipiput %I %I len %d proto %d\n", h->src, h->dst, BLEN(bp), h->proto);
//	DBG(nhgetl(h->src))(Logipmsg, "ipiput %V %V len %d proto %d\n",
//				h->src, h->dst, BLEN(bp), h->proto);

	/* Ensure we have enough data to process */
	if(BLEN(bp) < IPHDR) {


@@ 270,70 326,95 @@ ipiput(uchar *ia, Block *bp)

	/* dump anything that whose header doesn't checksum */
	if(ipcsum(&h->vihl)) {
		ipcsumerr++;
		netlog(Logip, "ip: checksum error %I\n", h->src);
		ip->istats.ipInHdrErrors++;
		netlog(f, Logip, "ip: checksum error %I\n", h->src);
		freeblist(bp);
		return;
	}

	/* route */
	v4tov6(v6dst, h->dst);
	notforme = ipforme(v6dst) == 0;
	notforme = ipforme(f, v6dst) == 0;

	/* Check header length and version */
	if(h->vihl != (IP_VER|IP_HLEN)) {
		hl = (h->vihl&0xF)<<2;
		if((h->vihl&0xF0) != IP_VER || hl < (IP_HLEN<<2)) {
			ip->istats.ipInHdrErrors++;
			netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl);
			freeblist(bp);
			return;
		}
		/* If this is not routed strip off the options */
		if(notforme == 0) {
			dp = bp->rp + (hl - (IP_HLEN<<2));
			memmove(dp, h, IP_HLEN<<2);
			bp->rp = dp;
			h = (Iphdr *)(bp->rp);
			h->vihl = (IP_VER|IP_HLEN);
		}
	}

	/* route */
	if(notforme) {
		if(iprouting) {
		if(ip->iprouting) {
			/* gate */
			if(h->ttl <= 1)
				freeblist(bp);
			else
				ipoput(bp, 1, h->ttl - 1);
			else {
				ip->istats.ipForwDatagrams++;
				ipoput(f, bp, 1, h->ttl - 1);
			}
		} else
			useriprouter(ia, bp);
			useriprouter(f, ia, bp);
		return;
	}

	/* Check header length and version */
	if(h->vihl != (IP_VER|IP_HLEN)) {
		netlog(Logip, "ip: %I bad hivl %ux\n", h->src, h->vihl);
		freeblist(bp);
		return;
	}


	frag = nhgets(h->frag);
	if(frag) {
		h->tos = 0;
		if(frag & IP_MF)
			h->tos = 1;
		bp = ipreassemble(frag, bp, h);
		bp = ipreassemble(ip, frag, bp, h);
		if(bp == nil)
			return;
		h = (Iphdr *)(bp->rp);
	}

	ipin += blocklen(bp);
	ippin++;

	p = Fsrcvpcol(&fs, h->proto);
	if(p != nil && p->rcv != nil)
		(*p->rcv)(ia, bp);
	else if(ipextprotoiput != nil)
		ipextprotoiput(bp);
	else
		freeblist(bp);
	p = Fsrcvpcol(f, h->proto);
	if(p != nil && p->rcv != nil) {
		ip->istats.ipInDelivers++;
		(*p->rcv)(p, ia, bp);
		return;
	}
	ip->istats.ipInDiscards++;
	ip->istats.ipInUnknownProtos++;
	freeblist(bp);
}

int
ipstats(char *buf, int len)
ipstats(Fs *f, char *buf, int len)
{
	int n;

	n = snprint(buf, len, "ip: csum %lud inb %lud outb %lud inp %lud outp %lud\n",
		ipcsumerr, ipin, ipout, ippin, ippout);
	n += snprint(buf+n, len - n, "\tnoroute %lud droppedfrag %lud\n",
		stats.noroute, stats.droppedfrag);
	return n;
	IP *ip;

	ip = f->ip;
	return snprint(buf, len, "%d %d %d %d %d %d %d %d %d %d "
				 "%d %d %d %d %d %d %d %d %d",
		ip->istats.ipForwarding, ip->istats.ipDefaultTTL,
		ip->istats.ipInReceives, ip->istats.ipInHdrErrors,
		ip->istats.ipInAddrErrors, ip->istats.ipForwDatagrams,
		ip->istats.ipInUnknownProtos, ip->istats.ipInDiscards,
		ip->istats.ipInDelivers, ip->istats.ipOutRequests,
		ip->istats.ipOutDiscards, ip->istats.ipOutNoRoutes,
		ip->istats.ipReasmTimeout, ip->istats.ipReasmReqds,
		ip->istats.ipReasmOKs, ip->istats.ipReasmFails,
		ip->istats.ipFragOKs, ip->istats.ipFragFails,
		ip->istats.ipFragCreates);
}

Block*
ipreassemble(int offset, Block *bp, Iphdr *ip)
ipreassemble(IP *ip, int offset, Block *bp, Iphdr *ih)
{
	int fend;
	ushort id;


@@ 342,30 423,30 @@ ipreassemble(int offset, Block *bp, Iphdr *ip)
	Block *bl, **l, *last, *prev;
	int ovlap, len, fragsize, pktposn;

	src = nhgetl(ip->src);
	dst = nhgetl(ip->dst);
	id = nhgets(ip->id);
	src = nhgetl(ih->src);
	dst = nhgetl(ih->dst);
	id = nhgets(ih->id);

	/*
	 *  block lists are too hard, pullupblock into a single block
	 */
	if(bp->next){
		bp = pullupblock(bp, blocklen(bp));
		ip = (Iphdr *)(bp->rp);
		ih = (Iphdr *)(bp->rp);
	}

	qlock(&fraglock);
	qlock(&ip->fraglock);

	/*
	 *  find a reassembly queue for this fragment
	 */
	for(f = flisthead; f; f = fnext){
	for(f = ip->flisthead; f; f = fnext){
		fnext = f->next;	/* because ipfragfree changes the list */
		if(f->src == src && f->dst == dst && f->id == id)
			break;
		if(f->age < msec){
			stats.droppedfrag++;
			ipfragfree(f);
			ip->istats.ipReasmTimeout++;
			ipfragfree(ip, f);
		}
	}



@@ 374,10 455,12 @@ ipreassemble(int offset, Block *bp, Iphdr *ip)
	 *  and get rid of any fragments that might go
	 *  with it.
	 */
	if(!ip->tos && (offset & ~(IP_MF|IP_DF)) == 0) {
		if(f != nil)
			ipfragfree(f);
		qunlock(&fraglock);
	if(!ih->tos && (offset & ~(IP_MF|IP_DF)) == 0) {
		if(f != nil) {
			ipfragfree(ip, f);
			ip->istats.ipReasmFails++;
		}
		qunlock(&ip->fraglock);
		return bp;
	}



@@ 387,18 470,19 @@ ipreassemble(int offset, Block *bp, Iphdr *ip)
	}

	BKFG(bp)->foff = offset<<3;
	BKFG(bp)->flen = nhgets(ip->length)-IPHDR;
	BKFG(bp)->flen = nhgets(ih->length)-IPHDR;

	/* First fragment allocates a reassembly queue */
	if(f == nil) {
		f = ipfragallo();
		f = ipfragallo(ip);
		f->id = id;
		f->src = src;
		f->dst = dst;

		f->blist = bp;

		qunlock(&fraglock);
		qunlock(&ip->fraglock);
		ip->istats.ipReasmReqds++;
		return nil;
	}



@@ 420,7 504,7 @@ ipreassemble(int offset, Block *bp, Iphdr *ip)
		if(ovlap > 0) {
			if(ovlap >= BKFG(bp)->flen) {
				freeblist(bp);
				qunlock(&fraglock);
				qunlock(&ip->fraglock);
				return nil;
			}
			BKFG(prev)->flen -= ovlap;


@@ 443,7 527,7 @@ ipreassemble(int offset, Block *bp, Iphdr *ip)
			if(ovlap < BKFG(*l)->flen) {
				BKFG(*l)->flen -= ovlap;
				BKFG(*l)->foff += ovlap;
				/* move up ip hdrs */
				/* move up ih hdrs */
				memmove((*l)->rp + ovlap, (*l)->rp, IPHDR);
				(*l)->rp += ovlap;
				break;


@@ 480,15 564,16 @@ ipreassemble(int offset, Block *bp, Iphdr *ip)

			bl = f->blist;
			f->blist = nil;
			ipfragfree(f);
			ip = BLKIP(bl);
			hnputs(ip->length, len);
			qunlock(&fraglock);
			ipfragfree(ip, f);
			ih = BLKIP(bl);
			hnputs(ih->length, len);
			qunlock(&ip->fraglock);
			ip->istats.ipReasmOKs++;
			return bl;		
		}
		pktposn += BKFG(bl)->flen;
	}
	qunlock(&fraglock);
	qunlock(&ip->fraglock);
	return nil;
}



@@ 496,7 581,7 @@ ipreassemble(int offset, Block *bp, Iphdr *ip)
 * ipfragfree - Free a list of fragments - assume hold fraglock
 */
void
ipfragfree(Fragment *frag)
ipfragfree(IP *ip, Fragment *frag)
{
	Fragment *fl, **l;



@@ 507,7 592,7 @@ ipfragfree(Fragment *frag)
	frag->id = 0;
	frag->blist = nil;

	l = &flisthead;
	l = &ip->flisthead;
	for(fl = *l; fl; fl = fl->next) {
		if(fl == frag) {
			*l = frag->next;


@@ 516,8 601,8 @@ ipfragfree(Fragment *frag)
		l = &fl->next;
	}

	frag->next = fragfree;
	fragfree = frag;
	frag->next = ip->fragfree;
	ip->fragfree = frag;

}



@@ 525,20 610,20 @@ ipfragfree(Fragment *frag)
 * ipfragallo - allocate a reassembly queue - assume hold fraglock
 */
Fragment *
ipfragallo(void)
ipfragallo(IP *ip)
{
	Fragment *f;

	while(fragfree == nil) {
	while(ip->fragfree == nil) {
		/* free last entry on fraglist */
		for(f = flisthead; f->next; f = f->next)
		for(f = ip->flisthead; f->next; f = f->next)
			;
		ipfragfree(f);
		ipfragfree(ip, f);
	}
	f = fragfree;
	fragfree = f->next;
	f->next = flisthead;
	flisthead = f;
	f = ip->fragfree;
	ip->fragfree = f->next;
	f->next = ip->flisthead;
	ip->flisthead = f;
	f->age = msec + 30000;

	return f;

M ip/ip.h => ip/ip.h +96 -53
@@ 2,17 2,22 @@ typedef struct	Conv	Conv;
typedef struct	Fs	Fs;
typedef union	Hwaddr	Hwaddr;
typedef struct	Ifcconv	Ifcconv;
typedef struct	IP	IP;
typedef struct	Ipself	Ipself;
typedef struct	Ipselftab	Ipselftab;
typedef struct	Iplink	Iplink;
typedef struct	Iplifc	Iplifc;
typedef struct	Ipmulti	Ipmulti;
typedef struct	Iproute	Iproute;
typedef struct	IProuter IProuter;
typedef struct	Ipifc	Ipifc;
typedef struct	Log	Log;
typedef struct	Medium	Medium;
typedef struct	Proto	Proto;
typedef struct	Pstate	Pstate;
typedef struct	Tcpc	Tcpc;
typedef struct	Arpent	Arpent;
typedef struct	Arp Arp;
typedef struct	Route	Route;

enum


@@ 34,6 39,9 @@ enum
	/* ip versions */
	V4=		4,
	V6=		6,

	/* 2^Lroot trees in the root table */
	Lroot	= 10,
};

enum


@@ 106,7 114,7 @@ struct Medium
	void	(*remmulti)(Ipifc *ifc, uchar *a, uchar *ia);

	/* process packets written to 'data' */
	void	(*pktin)(Ipifc *ifc, Block *bp);
	void	(*pktin)(Fs *f, Ipifc *ifc, Block *bp);

	/* routes for router boards */
	void	(*addroute)(Ipifc *ifc, int, uchar*, uchar*, uchar*, int);


@@ 114,7 122,7 @@ struct Medium
	void	(*flushroutes)(Ipifc *ifc);

	/* for routing multicast groups */
	void	(*joinmulti)(Ipifc *ifc, uchar *a, uchar *ia, uchar **iap);
	void	(*joinmulti)(Ipifc *ifc, uchar *a, uchar *ia);
	void	(*leavemulti)(Ipifc *ifc, uchar *a, uchar *ia);

	int	unbindonclose;	/* if non-zero, unbind on last close */


@@ 196,13 204,14 @@ struct Proto
	int		(*state)(Conv*, char*, int);
	void		(*create)(Conv*);
	void		(*close)(Conv*);
	void		(*rcv)(uchar*, Block*);
	void		(*rcv)(Proto*, uchar*, Block*);
	char*		(*ctl)(Conv*, char**, int);
	void		(*advise)(Block*, char*);
	int		(*stats)(char*, int);
	void		(*advise)(Proto*, Block*, char*);
	int		(*stats)(Proto*, char*, int);
	int		(*local)(Conv*, char*, int);
	int		(*inuse)(Conv*);

	Fs		*f;		/* file system this proto is part of */
	Conv		**conv;		/* array of conversations */
	int		ptclsize;	/* size of per protocol ctl block */
	int		nc;		/* number of conversations */


@@ 211,13 220,21 @@ struct Proto
	ushort		nextport;
	ushort		nextrport;

	ulong		csumerr;		/* checksum errors */
	ulong		hlenerr;		/* header length error */
	ulong		lenerr;			/* short packet */
	ulong		order;			/* out of order */
	ulong		rexmit;			/* retransmissions */
	void		*priv;
};

/*
 *  Stream for sending packets to user level
 */
struct IProuter {
	QLock;
	int	opens;
	Queue	*q;
};

/*
 *  one per IP protocol stack
 */
struct Fs
{
	Lock;


@@ 225,9 242,22 @@ struct Fs
	int	np;
	Proto*	p[Maxproto+1];		/* list of supported protocols */
	Proto*	t2p[256];		/* vector of all ip protocol handlers */
	Proto*	ipifc;			/* kludge for ipifcremroute & ipifcaddroute */

	IP	*ip;
	Ipselftab	*self;
	Arp	*arp;
	IProuter iprouter;

	Route	*v4root[1<<Lroot];	/* v4 routing forest */
	Route	*v6root[1<<Lroot];	/* v6 routing forest */
	Route	*queue;			/* used as temp when reinjecting routes */

	Log	*alog;
};
int	Fsconnected(Fs*, Conv*, char*);
Conv*	Fsnewcall(Fs*, Conv*, uchar*, ushort, uchar*, ushort);

int	Fsconnected(Conv*, char*);
Conv*	Fsnewcall(Conv*, uchar*, ushort, uchar*, ushort);
int	Fspcolstats(char*, int);
int	Fsproto(Fs*, Proto*);
int	Fsbuiltinproto(Fs*, uchar);


@@ 258,15 288,12 @@ enum
	Logipmsg=	1<<14,
};

extern int	logmask;	/* mask of things to debug */
extern uchar	iponly[IPaddrlen];		/* ip address to print debugging for */
extern int	iponlyset;

void netlogopen(void);
void netlogclose(void);
char* netlogctl(char*, int);
long netlogread(void*, ulong, long);
void netlog(int, char*, ...);
void	netloginit(Fs*);
void	netlogopen(Fs*);
void	netlogclose(Fs*);
char*	netlogctl(Fs*, char*, int);
long	netlogread(Fs*, void*, ulong, long);
void	netlog(Fs*, int, char*, ...);

/*
 *  iproute.c


@@ 332,15 359,17 @@ struct Route
		V4route v4;
	};
};
extern void	v4addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type);
extern void	v6addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type);
extern void	v4delroute(uchar *a, uchar *mask);
extern void	v6delroute(uchar *a, uchar *mask);
extern Route*	v4lookup(uchar *a);
extern Route*	v6lookup(uchar *a);
extern long	routeread(char*, ulong, int);
extern long	routewrite(Chan*, char*, int);
extern void	v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type);
extern void	v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type);
extern void	v4delroute(Fs *f, uchar *a, uchar *mask);
extern void	v6delroute(Fs *f, uchar *a, uchar *mask);
extern Route*	v4lookup(Fs *f, uchar *a);
extern Route*	v6lookup(Fs *f, uchar *a);
extern long	routeread(Fs *f, char*, ulong, int);
extern long	routewrite(Fs *f, Chan*, char*, int);
extern void	routetype(int, char*);
extern void	ipwalkroutes(Fs*, Routewalk*);
extern void	convroute(Route*, uchar*, uchar*, uchar*, char*, int*);

/*
 *  arp.c


@@ 358,12 387,13 @@ struct Arpent
	uchar	state;
};

extern int	arpread(char*, ulong, int);
extern int	arpwrite(char*, int);
extern Arpent*	arpget(Block *bp, int version, Medium *type, uchar *ip, uchar *h);
extern void	arprelease(Arpent *a);
extern Block*	arpresolve(Arpent *a, Medium *type, uchar *mac);
extern void	arpenter(Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int norefresh);
extern void	arpinit(Fs*);
extern int	arpread(Arp*, char*, ulong, int);
extern int	arpwrite(Arp*, char*, int);
extern Arpent*	arpget(Arp*, Block *bp, int version, Medium *type, uchar *ip, uchar *h);
extern void	arprelease(Arp*, Arpent *a);
extern Block*	arpresolve(Arp*, Arpent *a, Medium *type, uchar *mac);
extern void	arpenter(Arp*, Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int norefresh);

/*
 * ipaux.c


@@ 408,57 438,70 @@ extern uchar IPallbits[IPaddrlen];
extern Medium	ethermedium;
extern Medium	nullmedium;
extern Medium	pktmedium;
extern Medium	tripmedium;
extern Proto	ipifc;	

/*
 *  ipifc.c
 */
extern Medium*	ipfindmedium(char *name);
extern int	ipforme(uchar *addr);
extern int	ipforme(Fs*, uchar *addr);
extern int	ipismulticast(uchar *);
extern Ipifc*	findipifc(uchar *remote, int type);
extern void	findlocalip(uchar *local, uchar *remote);
extern Ipifc*	findipifc(Fs*, uchar *remote, int type);
extern void	findlocalip(Fs*, uchar *local, uchar *remote);
extern int	ipv4local(Ipifc *ifc, uchar *addr);
extern int	ipv6local(Ipifc *ifc, uchar *addr);
extern Iplifc*	iplocalonifc(Ipifc *ifc, uchar *ip);
extern int	ipproxyifc(Ipifc *ifc, uchar *ip);
extern int	ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip);
extern int	ipismulticast(uchar *ip);
extern int	ipisbooting(void);
extern int	ipifccheckin(Ipifc *ifc, Medium *med);
extern void	ipifccheckout(Ipifc *ifc);
extern int	ipifcgrab(Ipifc *ifc);
extern void	ipifcaddroute(int, uchar*, uchar*, uchar*, int);
extern void	ipifcremroute(int, uchar*, uchar*);
extern void	ipifcaddroute(Fs*, int, uchar*, uchar*, uchar*, int);
extern void	ipifcremroute(Fs*, int, uchar*, uchar*);
extern void	ipifcremmulti(Conv *c, uchar *ma, uchar *ia);
extern void	ipifcaddmulti(Conv *c, uchar *ma, uchar *ia);
extern char*	ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock);
extern char*	ipifcadd(Ipifc *ifc, char **argv, int argc);
extern long	ipselftabread(char *a, ulong offset, int n);
extern long	ipselftabread(Fs*, char *a, ulong offset, int n);

/*
 *  ip.c
 */
extern void	closeifcconv(Ifcconv*);
extern void	icmpnoconv(Block*);
extern void	initfrag(int);
extern void	icmpnoconv(Fs*, Block*);
extern void	initfrag(IP*, int);
extern ushort	ipcsum(uchar*);
extern void	(*ipextprotoiput)(Block*);
extern void	ipiput(uchar*, Block*);
extern void	ipoput(Block*, int, int);
extern int	ipstats(char*, int);
extern void	ipiput(Fs*, uchar*, Block*);
extern void	ipoput(Fs*, Block*, int, int);
extern int	ipstats(Fs*, char*, int);
extern uchar*	logctl(uchar*);
extern Ifcconv* newifcconv(void);
extern void	(*pktifcrcv)(Conv*, Block*);
extern ushort	ptclbsum(uchar*, int);
extern ushort	ptclcsum(Block*, int, int);
extern void	ip_init(Fs*);

/*
 * bootp.c
 */
extern char*	bootp(Ipifc*);
extern int	bootpread(char*, ulong, int);

/*
 *  iprouter.c
 */
void	useriprouter(uchar*, Block*);
void	iprouteropen(void);
void	iprouterclose(void);
long	iprouterread(void*, int);
void	useriprouter(Fs*, uchar*, Block*);
void	iprouteropen(Fs*);
void	iprouterclose(Fs*);
long	iprouterread(Fs*, void*, int);

/*
 *  resolving inferno/plan9 differences
 */
Chan*		commonfdtochan(int, int, int, int);
char*		commonuser(void);
char*		commonerror(void);

/*
 *  global to all of the stack

M ip/ipaux.c => ip/ipaux.c +2 -0
@@ 372,6 372,8 @@ parsecmd(char *p, int n)
	if(n > sizeof(cb->buf)-1)
		n = sizeof(cb->buf)-1;
	memmove(cb->buf, p, n);
	if(n > 0 && cb->buf[n-1] == '\n')
		n--;
	cb->buf[n] = '\0';
	cb->nf = parsefields(cb->buf, cb->f, nelem(cb->f), " ");
	return cb;

M ip/ipifc.c => ip/ipifc.c +110 -112
@@ 17,14 17,12 @@ enum {
	QMAX		= 64*1024-1,
};

	Proto	ipifc;
extern	Fs	fs;

Medium *media[] =
{
	&ethermedium,
	&pktmedium,
	&nullmedium,
	&tripmedium,
	0
};



@@ 43,7 41,6 @@ struct Ipself
	Ipself	*next;		/* free list */
};

typedef struct Ipselftab Ipselftab;
struct Ipselftab
{
	QLock;


@@ 51,7 48,6 @@ struct Ipselftab
	int	acceptall;	/* true if an interface has the null address */
	Ipself	*hash[NHASH];	/* hash chains */
};
Ipselftab	selftab;

/*
 *  Multicast addresses are chained onto a Chan so that


@@ 70,8 66,8 @@ struct Ipmcast

static char tifc[] = "ifc ";

static void	addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
static void	remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a);
static void	addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
static void	remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
static char*	ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
static char*	ipifcleavemulti(Ipifc *ifc, char **argv, int argc);



@@ 252,7 248,7 @@ ipifckick(Conv *c, int)
	if(ifc->m == nil || ifc->m->pktin == nil)
		freeb(bp);
	else
		(*ifc->m->pktin)(ifc, bp);
		(*ifc->m->pktin)(c->p->f, ifc, bp);
}

/*


@@ 299,6 295,9 @@ ipifcadd(Ipifc *ifc, char **argv, int argc)
	uchar bcast[IPaddrlen], net[IPaddrlen];
	Iplifc *lifc, **l;
	int i, type, mtu;
	Fs *f;

	f = ifc->conv->p->f;

	memset(ip, 0, IPaddrlen);
	memset(mask, 0, IPaddrlen);


@@ 359,24 358,24 @@ ipifcadd(Ipifc *ifc, char **argv, int argc)
	if(ipcmp(mask, IPallbits) == 0)
		type |= Rptpt;
	if(isv4(ip))
		v4addroute(tifc, rem+IPv4off, mask+IPv4off, ip+IPv4off, type);
		v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, ip+IPv4off, type);
	else
		v6addroute(tifc, ip, mask, rem, type);
		v6addroute(f, tifc, ip, mask, rem, type);

	addselfcache(ifc, lifc, ip, Runi);
	addselfcache(f, ifc, lifc, ip, Runi);

	/* add subnet directed broadcast addresses to the self cache */
	for(i = 0; i < IPaddrlen; i++)
		bcast[i] = (ip[i] & mask[i]) | ~mask[i];
	addselfcache(ifc, lifc, bcast, Rbcast);
	addselfcache(f, ifc, lifc, bcast, Rbcast);

	/* add network directed broadcast addresses to the self cache */
	memmove(mask, defmask(ip), IPaddrlen);
	for(i = 0; i < IPaddrlen; i++)
		bcast[i] = (ip[i] & mask[i]) | ~mask[i];
	addselfcache(ifc, lifc, bcast, Rbcast);
	addselfcache(f, ifc, lifc, bcast, Rbcast);

	addselfcache(ifc, lifc, IPv4bcast, Rbcast);
	addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);

out:
	wunlock(ifc);


@@ 394,10 393,13 @@ ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock)
	uchar ip[IPaddrlen];
	uchar mask[IPaddrlen];
	Iplifc *lifc, **l;
	Fs *f;

	if(argc < 3)
		return Ebadarg;

	f = ifc->conv->p->f;

	parseip(ip, argv[1]);
	parseipmask(mask, argv[2]);



@@ 424,13 426,13 @@ ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock)

	/* disassociate any addresses */
	while(lifc->link)
		remselfcache(ifc, lifc, lifc->link->self->a);
		remselfcache(f, ifc, lifc, lifc->link->self->a);

	/* remove the route for this logical interface */
	if(isv4(ip))
		v4delroute(lifc->remote+IPv4off, lifc->mask+IPv4off);
		v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off);
	else
		v6delroute(lifc->remote, lifc->mask);
		v6delroute(f, lifc->remote, lifc->mask);

	free(lifc);



@@ 447,13 449,14 @@ out:
 * TRIP linecards
 */
void
ipifcaddroute(int vers, uchar *addr, uchar *mask, uchar *gate, int type)
ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
{
	Medium *m;
	Conv **cp;
	Conv **cp, **e;
	Ipifc *ifc;

	for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
		if(*cp != nil) {
			ifc = (Ipifc*)(*cp)->ptcl;
			m = ifc->m;


@@ 466,13 469,14 @@ ipifcaddroute(int vers, uchar *addr, uchar *mask, uchar *gate, int type)
}

void
ipifcremroute(int vers, uchar *addr, uchar *mask)
ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
{
	Medium *m;
	Conv **cp;
	Conv **cp, **e;
	Ipifc *ifc;

	for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
		if(*cp != nil) {
			ifc = (Ipifc*)(*cp)->ptcl;
			m = ifc->m;


@@ 523,7 527,7 @@ ipifcconnect(Conv* c, char **argv, int argc)
	if(err)
		return err;

	Fsconnected(&fs, c, nil);
	Fsconnected(c, nil);

	return nil;
}


@@ 540,6 544,8 @@ ipifcctl(Conv* c, char**argv, int argc)
	ifc = (Ipifc*)c->ptcl;
	if(strcmp(argv[0], "add") == 0)
		return ipifcadd(ifc, argv, argc);
 	else if(strcmp(argv[0], "bootp") == 0)
		return bootp(ifc);
	else if(strcmp(argv[0], "remove") == 0)
		return ipifcrem(ifc, argv, argc, 1);
	else if(strcmp(argv[0], "unbind") == 0)


@@ 551,28 557,39 @@ ipifcctl(Conv* c, char**argv, int argc)
	return "unsupported ctl";
}

ipifcstats(Proto *ipifc, char *buf, int len)
{
	return ipstats(ipifc->f, buf, len);
}

void
ipifcinit(Fs *fs)
ipifcinit(Fs *f)
{
	ipifc.name = "ipifc";
	ipifc.kick = ipifckick;
	ipifc.connect = ipifcconnect;
	ipifc.announce = nil;
	ipifc.bind = ipifcbind;
	ipifc.state = ipifcstate;
	ipifc.create = ipifccreate;
	ipifc.close = ipifcclose;
	ipifc.rcv = nil;
	ipifc.ctl = ipifcctl;
	ipifc.advise = nil;
	ipifc.stats = ipstats;
	ipifc.inuse = ipifcinuse;
	ipifc.local = ipifclocal;
	ipifc.ipproto = -1;
	ipifc.nc = Maxmedia;
	ipifc.ptclsize = sizeof(Ipifc);

	Fsproto(fs, &ipifc);
	Proto *ipifc;

	ipifc = smalloc(sizeof(Ipifc));
	ipifc->name = "ipifc";
	ipifc->kick = ipifckick;
	ipifc->connect = ipifcconnect;
	ipifc->announce = nil;
	ipifc->bind = ipifcbind;
	ipifc->state = ipifcstate;
	ipifc->create = ipifccreate;
	ipifc->close = ipifcclose;
	ipifc->rcv = nil;
	ipifc->ctl = ipifcctl;
	ipifc->advise = nil;
	ipifc->stats = ipifcstats;
	ipifc->inuse = ipifcinuse;
	ipifc->local = ipifclocal;
	ipifc->ipproto = -1;
	ipifc->nc = Maxmedia;
	ipifc->ptclsize = sizeof(Ipifc);

	f->ipifc = ipifc;			/* hack for ipifcremroute, findipifc, ... */
	f->self = smalloc(sizeof(Ipselftab));	/* hack for ipforme */

	Fsproto(f, ipifc);
}

/*


@@ 580,17 597,17 @@ ipifcinit(Fs *fs)
 *	called with c->car locked
 */
static void
addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
{
	Ipself *p;
	Iplink *lp;
	int h;

	qlock(&selftab);
	qlock(f->self);

	/* see if the address already exists */
	h = hashipa(a);
	for(p = selftab.hash[h]; p; p = p->next)
	for(p = f->self->hash[h]; p; p = p->next)
		if(memcmp(a, p->a, IPaddrlen) == 0)
			break;



@@ 599,12 616,12 @@ addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
		p = smalloc(sizeof(*p));
		ipmove(p->a, a);
		p->type = type;
		p->next = selftab.hash[h];
		selftab.hash[h] = p;
		p->next = f->self->hash[h];
		f->self->hash[h] = p;

		/* if the null address, accept all packets */
		if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
			selftab.acceptall = 1;
			f->self->acceptall = 1;
	}

	/* look for a link for this lifc */


@@ 625,9 642,9 @@ addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type)

		/* add to routing table */
		if(isv4(a))
			v4addroute(tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type);
			v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type);
		else
			v6addroute(tifc, a, IPallbits, a, type);
			v6addroute(f, tifc, a, IPallbits, a, type);

		if((type & Rmulti) && ifc->m->addmulti != nil)
			(*ifc->m->addmulti)(ifc, a, lifc->local);


@@ 635,14 652,14 @@ addselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
		lp->ref++;
	}

	qunlock(&selftab);
	qunlock(f->self);
}

/*
 *  These structures are unlinked from their chains while
 *  other threads may be using them.  To avoid excessive locking,
 *  just put them aside for a while before freeing them.
 *	called with &selftab locked
 *	called with f->self locked
 */
static Iplink *freeiplink;
static Ipself *freeipself;


@@ 692,15 709,15 @@ ipselffree(Ipself *p)
 *	called with c->car locked
 */
static void
remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a)
remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
{
	Ipself *p, **l;
	Iplink *link, **l_self, **l_lifc;

	qlock(&selftab);
	qlock(f->self);

	/* find the unique selftab entry */
	l = &selftab.hash[hashipa(a)];
	l = &f->self->hash[hashipa(a)];
	for(p = *l; p; p = *l){
		if(ipcmp(p->a, a) == 0)
			break;


@@ 754,9 771,9 @@ remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a)

	/* remove from routing table */
	if(isv4(a))
		v4delroute(a+IPv4off, IPallbits+IPv4off);
		v4delroute(f, a+IPv4off, IPallbits+IPv4off);
	else
		v6delroute(a, IPallbits);
		v6delroute(f, a, IPallbits);
	
	/* no more links, remove from hash and free */
	*l = p->next;


@@ 764,29 781,10 @@ remselfcache(Ipifc *ifc, Iplifc *lifc, uchar *a)

	/* if IPnoaddr, forget */
	if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
		selftab.acceptall = 0;
		f->self->acceptall = 0;

out:
	qunlock(&selftab);
}

static void
dumpselftab(void)
{
	int i, count;
	Ipself *p;

	qlock(&selftab);
	for(i = 0; i < NHASH; i++){
		p = selftab.hash[i];
		if(p == nil)
			continue;
		count = 0;
		for(; p != nil && count++ < 6; p = p->next)
			print("(%I %d %lux)", p->a, p->type, p);
		print("\n");
	}
	qunlock(&selftab);
	qunlock(f->self);
}

static char *stformat = "%-32.32I %2.2d %4.4s\n";


@@ 796,7 794,7 @@ enum
};

long
ipselftabread(char *cp, ulong offset, int n)
ipselftabread(Fs *f, char *cp, ulong offset, int n)
{
	int i, m, nifc;
	Ipself *p;


@@ 804,9 802,9 @@ ipselftabread(char *cp, ulong offset, int n)
	char state[8];

	m = 0;
	qlock(&selftab);
	qlock(f->self);
	for(i = 0; i < NHASH && m < n; i++){
		for(p = selftab.hash[i]; p != nil && m < n; p = p->next){
		for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
			if(offset == 0){
				nifc = 0;
				for(link = p->link; link; link = link->selflink)


@@ 817,7 815,7 @@ ipselftabread(char *cp, ulong offset, int n)
			offset -= Nstformat;
		}
	}
	qunlock(&selftab);
	qunlock(f->self);
	return m;
}



@@ 830,24 828,18 @@ ipselftabread(char *cp, ulong offset, int n)
 *	Rmcast
 */
int
ipforme(uchar *addr)
ipforme(Fs *f, uchar *addr)
{
	Ipself *p;
	int count;

	p = selftab.hash[hashipa(addr)];
	count = 0;
	p = f->self->hash[hashipa(addr)];
	for(; p; p = p->next){
		if(count++ > 1000){	/* check for loops */
			dumpselftab();
			break;
		}
		if(ipcmp(addr, p->a) == 0)
			return p->type;
	}

	/* hack to say accept anything */
	if(selftab.acceptall)
	if(f->self->acceptall)
		return Runi;

	return 0;


@@ 858,29 850,28 @@ ipforme(uchar *addr)
 *  return nil.
 */
Ipifc*
findipifc(uchar *remote, int type)
findipifc(Fs *f, uchar *remote, int type)
{
	Ipifc *ifc;
	Iplifc *lifc;
	Conv **cp;
	Conv **cp, **e;
	uchar gnet[IPaddrlen];

	for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
		if(*cp == 0)
			continue;
		ifc = (Ipifc*)(*cp)->ptcl;
		for(lifc = ifc->lifc; lifc; lifc = lifc->next){
			maskip(remote, lifc->mask, gnet);
			if(ipcmp(gnet, lifc->net) == 0){
				qunlock(&ipifc);
			if(ipcmp(gnet, lifc->net) == 0)
				return ifc;
			}
		}
	}

	/* for now for broadcast and mutlicast, just use first interface */
	if(type & (Rbcast|Rmulti)){
		for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
		for(cp = f->ipifc->conv; cp < e; cp++){
			if(*cp == 0)
				continue;
			ifc = (Ipifc*)(*cp)->ptcl;


@@ 897,17 888,17 @@ findipifc(uchar *remote, int type)
 *  local and return the ifc for that address
 */
void
findlocalip(uchar *local, uchar *remote)
findlocalip(Fs *f, uchar *local, uchar *remote)
{
	Ipifc *ifc;
	Iplifc *lifc;
	Conv **cp;
	Conv **cp, **e;
	Route *r;
	uchar gate[IPaddrlen];
	uchar gnet[IPaddrlen];

	qlock(&ipifc);
	r = v6lookup(remote);
	qlock(f->ipifc);
	r = v6lookup(f, remote);
	
	if(r != nil){
		ifc = r->ifc;


@@ 932,7 923,8 @@ findlocalip(uchar *local, uchar *remote)
	}
		
	/* no match, choose first ifc local address */
	for(cp = ipifc.conv; cp < &ipifc.conv[ipifc.nc]; cp++){
	e = &f->ipifc->conv[f->ipifc->nc];
	for(cp = f->ipifc->conv; cp < e; cp++){
		if(*cp == 0)
			continue;
		ifc = (Ipifc*)(*cp)->ptcl;


@@ 943,7 935,7 @@ findlocalip(uchar *local, uchar *remote)
	}

out:
	qunlock(&ipifc);
	qunlock(f->ipifc);
}

/*


@@ 999,14 991,14 @@ iplocalonifc(Ipifc *ifc, uchar *ip)
 *  See if we're proxying for this address on this interface
 */
int
ipproxyifc(Ipifc *ifc, uchar *ip)
ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
{
	Route *r;
	uchar net[IPaddrlen];
	Iplifc *lifc;

	/* see if this is a direct connected pt to pt address */
	r = v6lookup(ip);
	r = v6lookup(f, ip);
	if(r == nil)
		return 0;
	if((r->type & Rifc) == 0)


@@ 1050,6 1042,9 @@ ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
	Iplifc *lifc;
	Conv **p;
	Ipmulti *multi, **l;
	Fs *f;

	f = c->p->f;
	
	for(l = &c->multi; *l; l = &(*l)->next)
		if(ipcmp(ma, (*l)->ma) == 0)


@@ 1061,7 1056,7 @@ ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
	ipmove(multi->ia, ia);
	multi->next = nil;

	for(p = ipifc.conv; *p; p++){
	for(p = f->ipifc->conv; *p; p++){
		if((*p)->inuse == 0)
			continue;
		ifc = (Ipifc*)(*p)->ptcl;


@@ 1072,7 1067,7 @@ ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
		wlock(ifc);
		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
			if(ipcmp(ia, lifc->local) == 0)
				addselfcache(ifc, lifc, ma, Rmulti);
				addselfcache(f, ifc, lifc, ma, Rmulti);
		wunlock(ifc);
		poperror();
	}


@@ 1089,6 1084,9 @@ ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
	Iplifc *lifc;
	Conv **p;
	Ipifc *ifc;
	Fs *f;

	f = c->p->f;
	
	for(l = &c->multi; *l; l = &(*l)->next)
		if(ipcmp(ma, (*l)->ma) == 0)


@@ 1101,7 1099,7 @@ ipifcremmulti(Conv *c, uchar *ma, uchar *ia)

	*l = multi->next;

	for(p = ipifc.conv; *p; p++){
	for(p = f->ipifc->conv; *p; p++){
		if((*p)->inuse == 0)
			continue;



@@ 1113,7 1111,7 @@ ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
		wlock(ifc);
		for(lifc = ifc->lifc; lifc; lifc = lifc->next)
			if(ipcmp(ia, lifc->local) == 0)
				remselfcache(ifc, lifc, ma);
				remselfcache(f, ifc, lifc, ma);
		wunlock(ifc);
		poperror();
	}

M ip/iproute.c => ip/iproute.c +73 -79
@@ 7,17 7,11 @@

#include	"ip.h"

enum
{
	Lroot	= 10,
};

Route *v4root[1<<Lroot], *v6root[1<<Lroot], *queue;

static void	walkadd(Route**, Route*);
static void	addnode(Route**, Route*);
static void	walkadd(Fs*, Route**, Route*);
static void	addnode(Fs*, Route**, Route*);
static void	calcd(Route*);

/* these are used for all instances of IP */
Route*	v4freelist;
Route*	v6freelist;
RWlock	routelock;


@@ 160,7 154,7 @@ copygate(Route *old, Route *new)
 *  walk down a tree adding nodes back in
 */
static void
walkadd(Route **root, Route *p)
walkadd(Fs *f, Route **root, Route *p)
{
	Route *l, *r;



@@ 168,11 162,11 @@ walkadd(Route **root, Route *p)
	r = p->right;
	p->left = 0;
	p->right = 0;
	addnode(root, p);
	addnode(f, root, p);
	if(l)
		walkadd(root, l);
		walkadd(f, root, l);
	if(r)
		walkadd(root, r);
		walkadd(f, root, r);
}

/*


@@ 238,7 232,7 @@ balancetree(Route **cur)
 *  add a new node to the tree
 */
static void
addnode(Route **cur, Route *new)
addnode(Fs *f, Route **cur, Route *new)
{
	Route *p;



@@ 251,10 245,10 @@ addnode(Route **cur, Route *new)

	switch(rangecompare(new, p)){
	case Rpreceeds:
		addnode(&p->left, new);
		addnode(f, &p->left, new);
		break;
	case Rfollows:
		addnode(&p->right, new);
		addnode(f, &p->right, new);
		break;
	case Rcontains:
		/*


@@ 266,14 260,14 @@ addnode(Route **cur, Route *new)
		 */
		*cur = new;
		new->depth = 1;
		addqueue(&queue, p);
		addqueue(&f->queue, p);
		break;
	case Requals:
		copygate(p, new);
		freeroute(new);
		break;
	case Rcontained:
		addnode(&p->mid, new);
		addnode(f, &p->mid, new);
		break;
	}
	


@@ 283,7 277,7 @@ addnode(Route **cur, Route *new)
#define	V4H(a)	((a&0x07ffffff)>>(32-Lroot-5))

void
v4addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type)
v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
{
	Route *p;
	ulong sa;


@@ 304,22 298,22 @@ v4addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type)
		memmove(p->tag, tag, sizeof(p->tag));

		wlock(&routelock);
		addnode(&v4root[h], p);
		while(p = queue) {
			queue = p->mid;
			walkadd(&v4root[h], p->left);
		addnode(f, &f->v4root[h], p);
		while(p = f->queue) {
			f->queue = p->mid;
			walkadd(f, &f->v4root[h], p->left);
			freeroute(p);
		}
		wunlock(&routelock);
	}

	ipifcaddroute(Rv4, a, mask, gate, type);
	ipifcaddroute(f, Rv4, a, mask, gate, type);
}

#define	V6H(a)	(((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))

void
v6addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type)
v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
{
	Route *p;
	ulong sa[IPllen], ea[IPllen];


@@ 342,16 336,16 @@ v6addroute(char *tag, uchar *a, uchar *mask, uchar *gate, int type)
		memmove(p->tag, tag, sizeof(p->tag));

		wlock(&routelock);
		addnode(&v6root[h], p);
		while(p = queue) {
			queue = p->mid;
			walkadd(&v6root[h], p->left);
		addnode(f, &f->v6root[h], p);
		while(p = f->queue) {
			f->queue = p->mid;
			walkadd(f, &f->v6root[h], p->left);
			freeroute(p);
		}
		wunlock(&routelock);
	}

	ipifcaddroute(0, a, mask, gate, type);
	ipifcaddroute(f, 0, a, mask, gate, type);
}

Route**


@@ 383,7 377,7 @@ looknode(Route **cur, Route *r)
}

void
v4delroute(uchar *a, uchar *mask)
v4delroute(Fs *f, uchar *a, uchar *mask)
{
	Route **r, *p;
	Route rt;


@@ 398,28 392,28 @@ v4delroute(uchar *a, uchar *mask)
	eh = V4H(rt.v4.endaddress);
	for(h=V4H(rt.v4.address); h<=eh; h++) {
		wlock(&routelock);
		r = looknode(&v4root[h], &rt);
		r = looknode(&f->v4root[h], &rt);
		if(r) {
			p = *r;
			*r = 0;
			addqueue(&queue, p->left);
			addqueue(&queue, p->mid);
			addqueue(&queue, p->right);
			addqueue(&f->queue, p->left);
			addqueue(&f->queue, p->mid);
			addqueue(&f->queue, p->right);
			freeroute(p);
			while(p = queue) {
				queue = p->mid;
				walkadd(&v4root[h], p->left);
			while(p = f->queue) {
				f->queue = p->mid;
				walkadd(f, &f->v4root[h], p->left);
				freeroute(p);
			}
		}
		wunlock(&routelock);
	}

	ipifcremroute(Rv4, a, mask);
	ipifcremroute(f, Rv4, a, mask);
}

void
v6delroute(uchar *a, uchar *mask)
v6delroute(Fs *f, uchar *a, uchar *mask)
{
	Route **r, *p;
	Route rt;


@@ 437,28 431,28 @@ v6delroute(uchar *a, uchar *mask)
	eh = V6H(rt.v6.endaddress);
	for(h=V6H(rt.v6.address); h<=eh; h++) {
		wlock(&routelock);
		r = looknode(&v6root[h], &rt);
		r = looknode(&f->v6root[h], &rt);
		if(r) {
			p = *r;
			*r = 0;
			addqueue(&queue, p->left);
			addqueue(&queue, p->mid);
			addqueue(&queue, p->right);
			addqueue(&f->queue, p->left);
			addqueue(&f->queue, p->mid);
			addqueue(&f->queue, p->right);
			freeroute(p);
			while(p = queue) {
				queue = p->mid;
				walkadd(&v6root[h], p->left);
			while(p = f->queue) {
				f->queue = p->mid;
				walkadd(f, &f->v6root[h], p->left);
				freeroute(p);
			}
		}
		wunlock(&routelock);
	}

	ipifcremroute(0, a, mask);
	ipifcremroute(f, 0, a, mask);
}

Route*
v4lookup(uchar *a)
v4lookup(Fs *f, uchar *a)
{
	Route *p, *q;
	ulong la;


@@ 466,7 460,7 @@ v4lookup(uchar *a)

	la = nhgetl(a);
	q = nil;
	for(p=v4root[V4H(la)]; p;)
	for(p=f->v4root[V4H(la)]; p;)
		if(la >= p->v4.address) {
			if(la <= p->v4.endaddress) {
				q = p;


@@ 478,7 472,7 @@ v4lookup(uchar *a)

	if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){
		v4tov6(gate, q->v4.gate);
		q->ifc = findipifc(gate, q->type);
		q->ifc = findipifc(f, gate, q->type);
		if(q->ifc == nil)
			return nil;
		q->ifcid = q->ifc->ifcid;


@@ 488,7 482,7 @@ v4lookup(uchar *a)
}

Route*
v6lookup(uchar *a)
v6lookup(Fs *f, uchar *a)
{
	Route *p, *q;
	ulong la[IPllen];


@@ 496,7 490,7 @@ v6lookup(uchar *a)
	ulong x, y;

	if(memcmp(a, v4prefix, 12) == 0){
		q = v4lookup(a+12);
		q = v4lookup(f, a+12);
		if(q != nil)
			return q;
	}


@@ 505,7 499,7 @@ v6lookup(uchar *a)
		la[h] = nhgetl(a+4*h);

	q = 0;
	for(p=v6root[V6H(la)]; p;){
	for(p=f->v6root[V6H(la)]; p;){
		for(h = 0; h < IPllen; h++){
			x = la[h];
			y = p->v6.address[h];


@@ 534,7 528,7 @@ next:		;
	}

	if(q && q->ifc == nil){
		q->ifc = findipifc(q->v6.gate, q->type);
		q->ifc = findipifc(f, q->v6.gate, q->type);
		if(q->ifc == nil)
			return nil;
		if(q->ifcid != q->ifc->ifcid)


@@ 654,24 648,24 @@ rr(Route *r, Routewalk *rw)
}

void
ipwalkroutes(Routewalk *rw)
ipwalkroutes(Fs *f, Routewalk *rw)
{
	rlock(&routelock);
	if(rw->n > rw->o) {
		for(rw->h = 0; rw->h < nelem(v4root); rw->h++)
			if(rr(v4root[rw->h], rw) == 0)
		for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++)
			if(rr(f->v4root[rw->h], rw) == 0)
				break;
	}
	if(rw->n > rw->o) {
		for(rw->h = 0; rw->h < nelem(v6root); rw->h++)
			if(rr(v6root[rw->h], rw) == 0)
		for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++)
			if(rr(f->v6root[rw->h], rw) == 0)
				break;
	}
	runlock(&routelock);
}

long
routeread(char *p, ulong offset, int n)
routeread(Fs *f, char *p, ulong offset, int n)
{
	Routewalk rw;



@@ 683,7 677,7 @@ routeread(char *p, ulong offset, int n)
	rw.o = -(offset/Rlinelen);
	rw.walk = sprintroute;

	ipwalkroutes(&rw);
	ipwalkroutes(f, &rw);

	if(rw.o < 0)
		rw.o = 0;


@@ 695,7 689,7 @@ routeread(char *p, ulong offset, int n)
 *  this code is not in routeflush to reduce stack size
 */
void
delroute(Route *r)
delroute(Fs *f, Route *r)
{
	uchar addr[IPaddrlen];
	uchar mask[IPaddrlen];


@@ 705,9 699,9 @@ delroute(Route *r)

	convroute(r, addr, mask, gate, t, &nifc);
	if(r->type & Rv4)
		v4delroute(addr+IPv4off, mask+IPv4off);
		v4delroute(f, addr+IPv4off, mask+IPv4off);
	else
		v6delroute(addr, mask);
		v6delroute(f, addr, mask);
}

/*


@@ 715,25 709,25 @@ delroute(Route *r)
 *    returns 0 if nothing is deleted, 1 otherwise
 */
int
routeflush(Route *r)
routeflush(Fs *f, Route *r)
{
	if(r == nil)
		return 0;
	if(routeflush(r->mid))
	if(routeflush(f, r->mid))
		return 1;
	if(routeflush(r->left))
	if(routeflush(f, r->left))
		return 1;
	if(routeflush(r->right))
	if(routeflush(f, r->right))
		return 1;
	if((r->type & Rifc) == 0){
		delroute(r);
		delroute(f, r);
		return 1;
	}
	return 0;
}

long
routewrite(Chan *c, char *p, int n)
routewrite(Fs *f, Chan *c, char *p, int n)
{
	int h;
	char *tag;


@@ 750,11 744,11 @@ routewrite(Chan *c, char *p, int n)

	if(strcmp(cb->f[0], "flush") == 0){
		wlock(&routelock);
		for(h = 0; h < nelem(v4root); h++)
			while(routeflush(v4root[h]) == 1)
		for(h = 0; h < nelem(f->v4root); h++)
			while(routeflush(f, f->v4root[h]) == 1)
				;
		for(h = 0; h < nelem(v6root); h++)
			while(routeflush(v6root[h]) == 1)
		for(h = 0; h < nelem(f->v6root); h++)
			while(routeflush(f, f->v6root[h]) == 1)
				;
		wunlock(&routelock);
	} else if(strcmp(cb->f[0], "remove") == 0){


@@ 763,9 757,9 @@ routewrite(Chan *c, char *p, int n)
		parseip(addr, cb->f[1]);
		parseipmask(mask, cb->f[2]);
		if(memcmp(addr, v4prefix, IPv4off) == 0)
			v4delroute(addr+IPv4off, mask+IPv4off);
			v4delroute(f, addr+IPv4off, mask+IPv4off);
		else
			v6delroute(addr, mask);
			v6delroute(f, addr, mask);
	} else if(strcmp(cb->f[0], "add") == 0){
		if(cb->nf < 4)
			error(Ebadarg);


@@ 776,9 770,9 @@ routewrite(Chan *c, char *p, int n)
		if(c != nil)
			tag = c->tag;
		if(memcmp(addr, v4prefix, IPv4off) == 0)
			v4addroute(tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
			v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0);
		else
			v6addroute(tag, addr, mask, gate, 0);
			v6addroute(f, tag, addr, mask, gate, 0);
	} else if(strcmp(cb->f[0], "tag") == 0) {
		if(cb->nf < 2)
			error(Ebadarg);

M ip/netlog.c => ip/netlog.c +82 -76
@@ 6,10 6,6 @@
#include	"../port/error.h"
#include	"../ip/ip.h"

int logmask;				/* mask of things to debug */
uchar iponly[IPaddrlen];		/* ip address to print debugging for */
int iponlyset;

enum {
	Nlog		= 4*1024,
};


@@ 17,7 13,7 @@ enum {
/*
 *  action log
 */
typedef struct Log {
struct Log {
	Lock;
	int	opens;
	char*	buf;


@@ 25,15 21,19 @@ typedef struct Log {
	char	*rptr;
	int	len;

	int	logmask;			/* mask of things to debug */
	uchar	iponly[IPaddrlen];		/* ip address to print debugging for */
	int	iponlyset;

	QLock;
	Rendez;
} Log;
static Log alog;
};

typedef struct Logflag {
	char*	name;
	int	mask;
} Logflag;

static Logflag flags[] =
{
	{ "ppp",	Logppp, },


@@ 55,73 55,81 @@ static Logflag flags[] =
static char Ebadnetctl[] = "unknown netlog ctl message";

void
netlogopen(void)
netloginit(Fs *f)
{
	f->alog = smalloc(sizeof(Log));
}

void
netlogopen(Fs *f)
{
	lock(&alog);
	lock(f->alog);
	if(waserror()){
		unlock(&alog);
		unlock(f->alog);
		nexterror();
	}
	if(alog.opens == 0){
		if(alog.buf == nil)
			alog.buf = malloc(Nlog);
		alog.rptr = alog.buf;
		alog.end = alog.buf + Nlog;
	if(f->alog->opens == 0){
		if(f->alog->buf == nil)
			f->alog->buf = malloc(Nlog);
		f->alog->rptr = f->alog->buf;
		f->alog->end = f->alog->buf + Nlog;
	}
	alog.opens++;
	unlock(&alog);
	f->alog->opens++;
	unlock(f->alog);
	poperror();
}

void
netlogclose(void)
netlogclose(Fs *f)
{
	lock(&alog);
	lock(f->alog);
	if(waserror()){
		unlock(&alog);
		unlock(f->alog);
		nexterror();
	}
	alog.opens--;
	if(alog.opens == 0){
		free(alog.buf);
		alog.buf = nil;
	f->alog->opens--;
	if(f->alog->opens == 0){
		free(f->alog->buf);
		f->alog->buf = nil;
	}
	unlock(&alog);
	unlock(f->alog);
	poperror();
}

static int
netlogready(void*)
netlogready(void *a)
{
	return alog.len;
	Fs *f = a;

	return f->alog->len;
}

long
netlogread(void* a, ulong, long n)
netlogread(Fs *f, void *a, ulong, long n)
{
	int i, d;
	char *p, *rptr;

	qlock(&alog);
	qlock(f->alog);
	if(waserror()){
		qunlock(&alog);
		qunlock(f->alog);
		nexterror();
	}

	for(;;){
		lock(&alog);
		if(alog.len){
			if(n > alog.len)
				n = alog.len;
		lock(f->alog);
		if(f->alog->len){
			if(n > f->alog->len)
				n = f->alog->len;
			d = 0;
			rptr = alog.rptr;
			alog.rptr += n;
			if(alog.rptr >= alog.end){
				d = alog.rptr - alog.end;
				alog.rptr = alog.buf + d;
			rptr = f->alog->rptr;
			f->alog->rptr += n;
			if(f->alog->rptr >= f->alog->end){
				d = f->alog->rptr - f->alog->end;
				f->alog->rptr = f->alog->buf + d;
			}
			alog.len -= n;
			unlock(&alog);
			f->alog->len -= n;
			unlock(f->alog);

			i = n;
			p = a;


@@ 129,28 137,28 @@ netlogread(void* a, ulong, long n)
				memmove(p, rptr, d);
				i -= d;
				p += d;
				rptr = alog.buf;
				rptr = f->alog->buf;
			}
			memmove(p, rptr, i);
			break;
		}
		else
			unlock(&alog);
			unlock(f->alog);

		sleep(&alog, netlogready, 0);
		sleep(f->alog, netlogready, 0);
	}

	qunlock(&alog);
	qunlock(f->alog);
	poperror();

	return n;
}

char*
netlogctl(char* s, int len)
netlogctl(Fs *f, char* s, int len)
{
	int i, n, set;
	Logflag *f;
	Logflag *fp;
	char *fields[10], *p, buf[256];

	if(len == 0)


@@ 172,11 180,11 @@ netlogctl(char* s, int len)
	else if(strcmp("clear", fields[0]) == 0)
		set = 0;
	else if(strcmp("only", fields[0]) == 0){
		parseip(iponly, fields[1]);
		if(ipcmp(iponly, IPnoaddr) == 0)
			iponlyset = 0;
		parseip(f->alog->iponly, fields[1]);
		if(ipcmp(f->alog->iponly, IPnoaddr) == 0)
			f->alog->iponlyset = 0;
		else
			iponlyset = 1;
			f->alog->iponlyset = 1;
		return nil;
	} else
		return Ebadnetctl;


@@ 186,56 194,54 @@ netlogctl(char* s, int len)
		*p = 0;

	for(i = 1; i < n; i++){
		for(f = flags; f->name; f++)
			if(strcmp(f->name, fields[i]) == 0)
		for(fp = flags; fp->name; fp++)
			if(strcmp(fp->name, fields[i]) == 0)
				break;
		if(f->name == nil)
		if(fp->name == nil)
			continue;
		if(set)
			logmask |= f->mask;
			f->alog->logmask |= fp->mask;
		else
			logmask &= ~f->mask;
			f->alog->logmask &= ~fp->mask;
	}

	return nil;
}

void
netlog(int mask, char *fmt, ...)
netlog(Fs *f, int mask, char *fmt, ...)
{
	char buf[128], *t, *f;
	char buf[128], *t, *fp;
	int i, n;
	va_list arg;

	if(!(logmask & mask))
	if(!(f->alog->logmask & mask))
		return;

	va_start(arg, fmt);
	n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf;
	va_end(arg);

print("%s", buf);

	if(alog.opens == 0)
	if(f->alog->opens == 0)
		return;

	lock(&alog);
	i = alog.len + n - Nlog;
	lock(f->alog);
	i = f->alog->len + n - Nlog;
	if(i > 0){
		alog.len -= i;
		alog.rptr += i;
		if(alog.rptr >= alog.end)
			alog.rptr = alog.buf + (alog.rptr - alog.end);
		f->alog->len -= i;
		f->alog->rptr += i;
		if(f->alog->rptr >= f->alog->end)
			f->alog->rptr = f->alog->buf + (f->alog->rptr - f->alog->end);
	}
	t = alog.rptr + alog.len;
	f = buf;
	alog.len += n;
	t = f->alog->rptr + f->alog->len;
	fp = buf;
	f->alog->len += n;
	while(n-- > 0){
		if(t >= alog.end)
			t = alog.buf + (t - alog.end);
		*t++ = *f++;
		if(t >= f->alog->end)
			t = f->alog->buf + (t - f->alog->end);
		*t++ = *fp++;
	}
	unlock(&alog);
	unlock(f->alog);

	wakeup(&alog);
	wakeup(f->alog);
}

M ip/pktmedium.c => ip/pktmedium.c +4 -4
@@ 12,7 12,7 @@
static void	pktbind(Ipifc *ifc, int argc, char **argv);
static void	pktunbind(Ipifc *ifc);
static void	pktbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
static void	pktin(Ipifc *ifc, Block *bp);
static void	pktin(Fs*, Ipifc *ifc, Block *bp);

Medium pktmedium =
{


@@ 64,13 64,13 @@ pktbwrite(Ipifc *ifc, Block *bp, int, uchar*)
}

/*
 *  called when someone write's to 'data' with ifc rlocked
 *  called with ifc rlocked when someone write's to 'data'
 */
static void
pktin(Ipifc *ifc, Block *bp)
pktin(Fs *f, Ipifc *ifc, Block *bp)
{
	if(ifc->lifc == nil)
		freeb(bp);
	else
		ipiput(ifc->lifc->local, bp);
		ipiput(f, ifc->lifc->local, bp);
}

M ip/tcp.c => ip/tcp.c +201 -119
@@ 180,25 180,52 @@ struct Tcpctl
	Tcphdr	protohdr;		/* prototype header */
};

#define DBG(x)	if((logmask & Logtcpmsg) && (iponlyset == 0 || memcmp(x, iponly+12, 4) == 0))netlog

Proto	tcp;
int	tcp_irtt = DEF_RTT;	/* Initial guess at round trip time */
ushort	tcp_mss  = DEF_MSS;	/* Maximum segment size to be sent */
Timer 	*timers;		/* List of active timers */
QLock 	tl;			/* Protect timer list */

static struct Tcpstats
/* MIB II counters */
typedef struct Tcpstats Tcpstats;
struct Tcpstats
{
	ulong	dup;		/* (partially) duplicated packets */
	ulong	dupb;		/* duplicated uchars */
} tstats;
	ulong	tcpRtoAlgorithm;
	ulong	tcpRtoMin;
	ulong	tcpRtoMax;
	ulong	tcpMaxConn;
	ulong	tcpActiveOpens;
	ulong	tcpPassiveOpens;
	ulong	tcpAttemptFails;
	ulong	tcpEstabResets;
	ulong	tcpCurrEstab;
	ulong	tcpInSegs;
	ulong	tcpOutSegs;
	ulong	tcpRetransSegs;
	ulong	InErrs;
	ulong	OutRsts;
};

typedef struct Tcppriv Tcppriv;
struct Tcppriv
{
	Timer 	*timers;		/* List of active timers */
	QLock 	tl;			/* Protect timer list */
	Rendez	tcpr;			/* used by tcpackproc */

	/* MIB stats */
	Tcpstats tstats;

	/* non-MIB stats */
	ulong		csumerr;		/* checksum errors */
	ulong		hlenerr;		/* header length error */
	ulong		lenerr;			/* short packet */
	ulong		order;			/* out of order */

};

void	addreseq(Tcpctl*, Tcp*, Block*, ushort);
void	getreseq(Tcpctl*, Tcp*, Block**, ushort*);
void	localclose(Conv*, char*);
void	procsyn(Conv*, Tcp*);
void	tcpiput(uchar*, Block*);
void	tcpiput(Proto*, uchar*, Block*);
void	tcpoutput(Conv*);
int	tcptrim(Tcpctl*, Tcp*, Block**, ushort*);
void	tcpstart(Conv*, int, ushort);


@@ 212,6 239,9 @@ tcpsetstate(Conv *s, uchar newstate)
{
	Tcpctl *tcb;
	uchar oldstate;
	Tcppriv *tpriv;

	tpriv = s->p->priv;

	tcb = (Tcpctl*)s->ptcl;



@@ 219,6 249,11 @@ tcpsetstate(Conv *s, uchar newstate)
	if(oldstate == newstate)
		return;

	if(oldstate == Established)
		tpriv->tstats.tcpCurrEstab--;
	if(newstate == Established)
		tpriv->tstats.tcpCurrEstab++;

	/*
	  print("%d/%d %s->%s\n", s->lport, s->rport,
			tcpstates[oldstate], tcpstates[newstate]);


@@ 241,7 276,7 @@ tcpsetstate(Conv *s, uchar newstate)
	}

	if(oldstate == Syn_sent && newstate != Closed)
		Fsconnected(&fs, s, nil);
		Fsconnected(s, nil);
}

static char*


@@ 288,7 323,7 @@ tcpannounce(Conv *c, char **argv, int argc)
	if(e != nil)
		return e;
	tcpstart(c, TCP_LISTEN, QMAX);
	Fsconnected(&fs, c, nil);
	Fsconnected(c, nil);

	return nil;
}


@@ 311,7 346,7 @@ tcpclose(Conv *c)
		/*
		 *  reset any incoming calls to this listener
		 */
		Fsconnected(&fs, c, "Hangup");
		Fsconnected(c, "Hangup");

		qlock(tcb);
		localclose(c, nil);


@@ 376,10 411,10 @@ tcpkick(Conv *s, int len)
 *  get remote sender going if it was flow controlled due to a closed window
 */
static void
deltimer(Timer *t)
deltimer(Tcppriv *tpriv, Timer *t)
{
	if(timers == t)
		timers = t->next;
	if(tpriv->timers == t)
		tpriv->timers = t->next;
	if(t->next)
		t->next->prev = t->prev;
	if(t->prev)


@@ 423,29 458,33 @@ tcpcreate(Conv *c)
}

void
tcpackproc(void*)
tcpackproc(void *a)
{
	Timer *t, *tp, *timeo;
	static Rendez tcpr;
	Proto *tcp;
	Tcppriv *tpriv;

	tcp = a;
	tpriv = tcp->priv;

	for(;;) {
		tsleep(&tcpr, return0, 0, MSPTICK);
		tsleep(&tpriv->tcpr, return0, 0, MSPTICK);

		qlock(&tl);
		qlock(&tpriv->tl);
		timeo = nil;
		for(t = timers; t != nil; t = tp) {
		for(t = tpriv->timers; t != nil; t = tp) {
			tp = t->next;
 			if(t->state == TimerON) {
				t->count--;
				if(t->count == 0) {
					deltimer(t);
					deltimer(tpriv, t);
					t->state = TimerDONE;
					t->next = timeo;
					timeo = t;
				}
			}
		}
		qunlock(&tl);
		qunlock(&tpriv->tl);

		for(;;) {
			t = timeo;


@@ 460,35 499,35 @@ tcpackproc(void*)
}

void
tcpgo(Timer *t)
tcpgo(Tcppriv *tpriv, Timer *t)
{
	if(t == nil || t->start == 0)
		return;

	qlock(&tl);
	qlock(&tpriv->tl);
	t->count = t->start;
	if(t->state != TimerON) {
		t->state = TimerON;
		t->prev = nil;
		t->next = timers;
		t->next = tpriv->timers;
		if(t->next)
			t->next->prev = t;
		timers = t;
		tpriv->timers = t;
	}
	qunlock(&tl);
	qunlock(&tpriv->tl);
}

void
tcphalt(Timer *t)
tcphalt(Tcppriv *tpriv, Timer *t)
{
	if(t == nil)
		return;

	qlock(&tl);
	qlock(&tpriv->tl);
	if(t->state == TimerON)
		deltimer(t);
		deltimer(tpriv, t);
	t->state = TimerOFF;
	qunlock(&tl);
	qunlock(&tpriv->tl);
}

int


@@ 505,11 544,13 @@ localclose(Conv *s, char *reason)	 /*  called with tcb locked */
{
	Tcpctl *tcb;
	Reseq *rp,*rp1;
	Tcppriv *tpriv;

	tpriv = s->p->priv;
	tcb = (Tcpctl*)s->ptcl;

	tcphalt(&tcb->timer);
	tcphalt(&tcb->rtt_timer);
	tcphalt(tpriv, &tcb->timer);
	tcphalt(tpriv, &tcb->rtt_timer);

	/* Flush reassembly queue; nothing more can arrive */
	for(rp = tcb->reseq; rp != nil; rp = rp1) {


@@ 519,7 560,7 @@ localclose(Conv *s, char *reason)	 /*  called with tcb locked */
	}

	if(tcb->state == Syn_sent)
		Fsconnected(&fs, s, reason);
		Fsconnected(s, reason);

	qhangup(s->rq, reason);
	qhangup(s->wq, reason);


@@ 553,7 594,7 @@ inittcpctl(Conv *s)

	/* create a prototype(pseudo) header */
	if(ipcmp(s->laddr, IPnoaddr) == 0)
		findlocalip(s->laddr, s->raddr);
		findlocalip(s->p->f, s->laddr, s->raddr);
	h = &tcb->protohdr;
	memset(h, 0, sizeof(*h));
	h->proto = IP_TCPPROTO;


@@ 571,7 612,7 @@ tcpmtu(Conv *s)
	int mtu;

	mtu = 0;
	ifc = findipifc(s->raddr, 0);
	ifc = findipifc(s->p->f, s->raddr, 0);
	if(ifc != nil)
		mtu = ifc->maxmtu - ifc->m->hsize - (TCP_PKT + TCP_HDRSIZE);
	if(mtu < 4)


@@ 583,6 624,9 @@ void
tcpstart(Conv *s, int mode, ushort window)
{
	Tcpctl *tcb;
	Tcppriv *tpriv;

	tpriv = s->p->priv;

	tcb = (Tcpctl*)s->ptcl;



@@ 592,11 636,13 @@ tcpstart(Conv *s, int mode, ushort window)

	switch(mode) {
	case TCP_LISTEN:
		tpriv->tstats.tcpPassiveOpens++;
		tcb->flags |= CLONE;
		tcpsetstate(s, Listen);
		break;

	case TCP_CONNECT:
		tpriv->tstats.tcpActiveOpens++;
		/* Send SYN, go into SYN_SENT state */
		qlock(tcb);
		tcb->flags |= ACTIVE;


@@ 676,10 722,10 @@ htontcp(Tcp *tcph, Block *data, Tcphdr *ph)
	csum = ptclcsum(data, TCP_IPLEN, hdrlen+dlen+TCP_PHDRSIZE);
	hnputs(h->tcpcksum, csum);

	DBG(h->tcpdst)(Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n",
/*	netlog(f, Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n",
		tcph->source, tcph->dest,
		tcph->seq, tcph->ack, tcpflag((hdrlen<<10)|tcph->flags),
		tcph->wnd, dlen);
		tcph->wnd, dlen); */

	return data;
}


@@ 717,10 763,10 @@ ntohtcp(Tcp *tcph, Block **bpp)
	if(*bpp == nil)
		return -1;

	DBG(h->tcpsrc)(Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n",
/*	netlog(Logtcpmsg, "%d > %d s %l8.8ux a %8.8lux %s w %.4ux l %d\n",
		tcph->source, tcph->dest,
		tcph->seq, tcph->ack, tcpflag((hdrlen<<10)|tcph->flags),
		tcph->wnd, nhgets(h->length)-hdrlen-TCP_PKT);
		tcph->wnd, nhgets(h->length)-hdrlen-TCP_PKT); */

	optr = h->tcpopt;
	for(i = TCP_HDRSIZE; i < hdrlen;) {


@@ 761,11 807,14 @@ tcpsndsyn(Tcpctl *tcb)
 *  called with v4 (4 byte) addresses
 */
void
sndrst(uchar *source, uchar *dest, ushort length, Tcp *seg)
sndrst(Proto *tcp, uchar *source, uchar *dest, ushort length, Tcp *seg)
{
	Tcphdr ph;
	Block *hbp;
	uchar rflags;
	Tcppriv *tpriv;

	tpriv = tcp->priv;

	if(seg->flags & RST)
		return;


@@ 779,6 828,7 @@ sndrst(uchar *source, uchar *dest, ushort length, Tcp *seg)
	hnputs(ph.tcpsport, seg->dest);
	hnputs(ph.tcpdport, seg->source);

	tpriv->tstats.OutRsts++;
	rflags = RST;

	/* convince the other end that this reset is in band */


@@ 804,7 854,7 @@ sndrst(uchar *source, uchar *dest, ushort length, Tcp *seg)
	if(hbp == nil)
		return;

	ipoput(hbp, 0, MAXTTL);
	ipoput(tcp->f, hbp, 0, MAXTTL);
}

/*


@@ 821,7 871,7 @@ tcphangup(Conv *s)
	tcb = (Tcpctl*)s->ptcl;
	if(waserror()){
		qunlock(tcb);
		return up->error;
		return commonerror();
	}
	qlock(tcb);
	if(s->raddr != 0) {


@@ 834,7 884,7 @@ tcphangup(Conv *s)
		tcb->last_ack = tcb->rcv.nxt;
		hnputs(ph.tcplen, TCP_HDRSIZE);
		hbp = htontcp(&seg, nil, &tcb->protohdr);
		ipoput(hbp, 0, s->ttl);
		ipoput(s->p->f, hbp, 0, s->ttl);
	}
	localclose(s, nil);
	poperror();


@@ 849,7 899,7 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst)
	Tcpctl *tcb;
	Tcphdr *h;

	new = Fsnewcall(&fs, s, src, segp->source, dst, segp->dest);
	new = Fsnewcall(s, src, segp->source, dst, segp->dest);
	if(new == nil)
		return nil;



@@ 919,15 969,17 @@ tcpsynackrtt(Conv *s)
{
	Tcpctl *tcb;
	int delta;
	Tcppriv *tpriv;

	tcb = (Tcpctl*)s->ptcl;
	tpriv = s->p->priv;

	delta = msec - tcb->sndsyntime;
	tcb->srtt = delta<<LOGAGAIN;
	tcb->mdev = delta<<LOGDGAIN;

	/* halt round trip timer */
	tcphalt(&tcb->rtt_timer);
	tcphalt(tpriv, &tcb->rtt_timer);
}

void


@@ 936,7 988,9 @@ update(Conv *s, Tcp *seg)
	int rtt, delta;
	Tcpctl *tcb;
	ushort acked, expand;
	Tcppriv *tpriv;

	tpriv = s->p->priv;
	tcb = (Tcpctl*)s->ptcl;

	tcb->kacounter = MAXBACKOFF;	/* keep alive count down */


@@ 983,7 1037,7 @@ update(Conv *s, Tcp *seg)

	/* Adjust the timers according to the round trip time */
	if(tcb->rtt_timer.state == TimerON && seq_ge(seg->ack, tcb->rttseq)) {
		tcphalt(&tcb->rtt_timer);
		tcphalt(tpriv, &tcb->rtt_timer);
		if((tcb->flags&RETRAN) == 0) {
			tcb->backoff = 0;
			rtt = tcb->rtt_timer.start - tcb->rtt_timer.count;


@@ 1020,9 1074,9 @@ update(Conv *s, Tcp *seg)
	if(seq_gt(seg->ack, tcb->snd.urg))
		tcb->snd.urg = seg->ack;

	tcphalt(&tcb->timer);
	tcphalt(tpriv, &tcb->timer);
	if(tcb->snd.una != tcb->snd.nxt)
		tcpgo(&tcb->timer);
		tcpgo(tpriv, &tcb->timer);

	if(seq_lt(tcb->snd.ptr, tcb->snd.una))
		tcb->snd.ptr = tcb->snd.una;


@@ 1032,7 1086,7 @@ update(Conv *s, Tcp *seg)
}

void
tcpiput(uchar*, Block *bp)
tcpiput(Proto *tcp, uchar*, Block *bp)
{
	Tcp seg;
	Tcphdr *h;


@@ 1041,6 1095,13 @@ tcpiput(uchar*, Block *bp)
	ushort length;
	uchar source[IPaddrlen], dest[IPaddrlen];
	Conv *spec, *gen, *s, **p;
	Fs *f;
	Tcppriv *tpriv;

	f = tcp->f;
	tpriv = tcp->priv;
	
	tpriv->tstats.tcpInSegs++;

	h = (Tcphdr*)(bp->rp);



@@ 1051,16 1112,16 @@ tcpiput(uchar*, Block *bp)
	h->Unused = 0;
	hnputs(h->tcplen, length-TCP_PKT);
	if(ptclcsum(bp, TCP_IPLEN, length-TCP_IPLEN)) {
		tcp.csumerr++;
		netlog(Logtcp, "bad tcp proto cksum\n");
		tpriv->csumerr++;
		netlog(f, Logtcp, "bad tcp proto cksum\n");
		freeblist(bp);
		return;
	}

	hdrlen = ntohtcp(&seg, &bp);
	if(hdrlen < 0){
		tcp.hlenerr++;
		netlog(Logtcp, "bad tcp hdr len\n");
		tpriv->hlenerr++;
		netlog(f, Logtcp, "bad tcp hdr len\n");
		return;
	}



@@ 1068,14 1129,14 @@ tcpiput(uchar*, Block *bp)
	length -= hdrlen+TCP_PKT;
	bp = trimblock(bp, hdrlen+TCP_PKT, length);
	if(bp == nil){
		tcp.lenerr++;
		netlog(Logtcp, "tcp len < 0 after trim\n");
		tpriv->lenerr++;
		netlog(f, Logtcp, "tcp len < 0 after trim\n");
		return;
	}


	/* Look for a connection. failing that look for a listener. */
	for(p = tcp.conv; *p; p++) {
	for(p = tcp->conv; *p; p++) {
		s = *p;
		if(s->rport == seg.source)
		if(s->lport == seg.dest)


@@ 1100,7 1161,7 @@ tcpiput(uchar*, Block *bp)
			return;
		}
		if(seg.flags & ACK) {
			sndrst(source, dest, length, &seg);
			sndrst(tcp, source, dest, length, &seg);
			freeblist(bp);
			return;
		}


@@ 1111,7 1172,7 @@ tcpiput(uchar*, Block *bp)
		 */
		gen = nil;
		spec = nil;
		for(p = tcp.conv; *p; p++) {
		for(p = tcp->conv; *p; p++) {
			s = *p;
			tcb = (Tcpctl*)s->ptcl;
			if((tcb->flags & CLONE) == 0)


@@ 1136,7 1197,7 @@ tcpiput(uchar*, Block *bp)
	}
	if(s == nil) {
		freeblist(bp);
		sndrst(source, dest, length, &seg);
		sndrst(tcp, source, dest, length, &seg);
		return;
	}



@@ 1149,7 1210,7 @@ tcpiput(uchar*, Block *bp)

	switch(tcb->state) {
	case Closed:
		sndrst(source, dest, length, &seg);
		sndrst(tcp, source, dest, length, &seg);
		goto raise;
	case Listen:
		if(seg.flags & SYN) {


@@ 1163,7 1224,7 @@ tcpiput(uchar*, Block *bp)
	case Syn_sent:
		if(seg.flags & ACK) {
			if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) {
				sndrst(source, dest, length, &seg);
				sndrst(tcp, source, dest, length, &seg);
				goto raise;
			}
		}


@@ 1203,12 1264,12 @@ tcpiput(uchar*, Block *bp)

	/* Cut the data to fit the receive window */
	if(tcptrim(tcb, &seg, &bp, &length) == -1) {
		netlog(Logtcp, "tcp len < 0, %lux\n", seg.seq);
		netlog(f, Logtcp, "tcp len < 0, %lux\n", seg.seq);
		update(s, &seg);
		if(tcb->sndcnt == 0 && tcb->state == Closing) {
			tcpsetstate(s, Time_wait);
			tcb->timer.start = MSL2*(1000 / MSPTICK);
			tcpgo(&tcb->timer);
			tcpgo(tpriv, &tcb->timer);
		}
		if(!(seg.flags & RST)) {
			tcb->flags |= FORCE;


@@ 1220,7 1281,7 @@ tcpiput(uchar*, Block *bp)

	/* Cannot accept so answer with a rst */
	if(length && tcb->state == Closed) {
		sndrst(source, dest, length, &seg);
		sndrst(tcp, source, dest, length, &seg);
		goto raise;
	}



@@ 1230,7 1291,7 @@ tcpiput(uchar*, Block *bp)
	if(seg.seq != tcb->rcv.nxt)
	if(length != 0 || (seg.flags & (SYN|FIN))) {
		update(s, &seg);
		tcp.order++;
		tpriv->order++;
		addreseq(tcb, &seg, bp, length);
		tcb->flags |= FORCE;
		goto output;


@@ 1242,6 1303,8 @@ tcpiput(uchar*, Block *bp)
	 */
	for(;;) {
		if(seg.flags & RST) {
			if(tcb->state == Established)
				tpriv->tstats.tcpEstabResets++;
			localclose(s, Econrefused);
			goto raise;
		}


@@ 1252,7 1315,7 @@ tcpiput(uchar*, Block *bp)
		switch(tcb->state) {
		case Syn_received:
			if(!seq_within(seg.ack, tcb->snd.una+1, tcb->snd.nxt)){
				sndrst(source, dest, length, &seg);
				sndrst(tcp, source, dest, length, &seg);
				goto raise;
			}
			update(s, &seg);


@@ 1267,7 1330,7 @@ tcpiput(uchar*, Block *bp)
				tcb->f2counter = MAXBACKOFF;
				tcpsetstate(s, Finwait2);
				tcb->timer.start = MSL2 * (1000 / MSPTICK);
				tcpgo(&tcb->timer);
				tcpgo(tpriv, &tcb->timer);
			}
			break;
		case Finwait2:


@@ 1278,7 1341,7 @@ tcpiput(uchar*, Block *bp)
			if(tcb->sndcnt == 0) {
				tcpsetstate(s, Time_wait);
				tcb->timer.start = MSL2*(1000 / MSPTICK);
				tcpgo(&tcb->timer);
				tcpgo(tpriv, &tcb->timer);
			}
			break;
		case Last_ack:


@@ 1290,7 1353,7 @@ tcpiput(uchar*, Block *bp)
		case Time_wait:
			tcb->flags |= FORCE;
			if(tcb->timer.state != TimerON)
				tcpgo(&tcb->timer);
				tcpgo(tpriv, &tcb->timer);
		}

		if((seg.flags&URG) && seg.urg) {


@@ 1328,7 1391,7 @@ tcpiput(uchar*, Block *bp)
				tcb->rcv.nxt += length;
				tcprcvwin(s);
				if(tcb->acktimer.state != TimerON)
					tcpgo(&tcb->acktimer);
					tcpgo(tpriv, &tcb->acktimer);

				/* force an ack if there's a lot of unacked data */
				if(tcb->rcv.nxt-tcb->last_ack > (QMAX>>4))


@@ 1339,7 1402,7 @@ tcpiput(uchar*, Block *bp)
				/* no process to read the data, send a reset */
				if(bp != nil)
					freeblist(bp);
				sndrst(source, dest, length, &seg);
				sndrst(tcp, source, dest, length, &seg);
				qunlock(tcb);
				return;
			}


@@ 1359,7 1422,7 @@ tcpiput(uchar*, Block *bp)
				if(tcb->sndcnt == 0) {
					tcpsetstate(s, Time_wait);
					tcb->timer.start = MSL2*(1000/MSPTICK);
					tcpgo(&tcb->timer);
					tcpgo(tpriv, &tcb->timer);
				}
				else
					tcpsetstate(s, Closing);


@@ 1368,14 1431,14 @@ tcpiput(uchar*, Block *bp)
				tcb->rcv.nxt++;
				tcpsetstate(s, Time_wait);
				tcb->timer.start = MSL2 * (1000/MSPTICK);
				tcpgo(&tcb->timer);
				tcpgo(tpriv, &tcb->timer);
				break;
			case Close_wait:
			case Closing:
			case Last_ack:
				break;
			case Time_wait:
				tcpgo(&tcb->timer);
				tcpgo(tpriv, &tcb->timer);
				break;
			}
		}


@@ 1420,6 1483,11 @@ tcpoutput(Conv *s)
	Block *hbp, *bp;
	int sndcnt, n, first;
	ulong ssize, dsize, usable, sent;
	Fs *f;
	Tcppriv *tpriv;

	f = s->p->f;
	tpriv = s->p->priv;

	tcb = (Tcpctl*)s->ptcl;



@@ 1489,7 1557,7 @@ tcpoutput(Conv *s)
		if((tcb->flags&FORCE) == 0)
			break;

		tcphalt(&tcb->acktimer);
		tcphalt(tpriv, &tcb->acktimer);

		tcb->flags &= ~FORCE;
		tcprcvwin(s);


@@ 1525,7 1593,7 @@ tcpoutput(Conv *s)
				seg.flags |= FIN;
				dsize--;
			}
			netlog(Logtcp, "qcopy: dlen %d blen %d sndcnt %d qlen %d sent %d rp[0] %d\n",
			netlog(f, Logtcp, "qcopy: dlen %d blen %d sndcnt %d qlen %d sent %d rp[0] %d\n",
				dsize, BLEN(bp), sndcnt, qlen(s->wq), sent, bp->rp[0]);
		}



@@ 1566,16 1634,17 @@ tcpoutput(Conv *s)
			tcb->timer.start = x;

			if(tcb->timer.state != TimerON)
				tcpgo(&tcb->timer);
				tcpgo(tpriv, &tcb->timer);

			/* If round trip timer isn't running, start it */
			if(tcb->rtt_timer.state != TimerON) {
				tcpgo(&tcb->rtt_timer);
				tcpgo(tpriv, &tcb->rtt_timer);
				tcb->rttseq = tcb->snd.ptr;
			}
		}

		ipoput(hbp, 0, s->ttl);
		tpriv->tstats.tcpOutSegs++;
		ipoput(f, hbp, 0, s->ttl);
	}
}



@@ 1616,17 1685,18 @@ tcpkeepalive(Conv *s)
		return;
	}

	ipoput(hbp, 0, s->ttl);
	ipoput(s->p->f, hbp, 0, s->ttl);
}

void
tcprxmit(Conv *s)
{
	Tcpctl *tcb;
	Tcppriv *tpriv;

	tpriv = s->p->priv;
	tcb = (Tcpctl*)s->ptcl;


	qlock(tcb);
	tcb->flags |= RETRAN|FORCE;
	tcb->snd.ptr = tcb->snd.una;


@@ 1642,8 1712,7 @@ tcprxmit(Conv *s)
	tcb->cwind = tcb->mss;
	tcpoutput(s);

	tcp.rexmit++;

	tpriv->tstats.tcpRetransSegs++;
	qunlock(tcb);
}



@@ 1678,7 1747,7 @@ tcptimeout(void *arg)
			qlock(tcb);
			tcpkeepalive(s);
			qunlock(tcb);
			tcpgo(&tcb->timer);
			tcpgo(s->p->priv, &tcb->timer);
		}
		break;
	case Time_wait:


@@ 1807,8 1876,6 @@ tcptrim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
	dupcnt = tcb->rcv.nxt - seg->seq;
	if(dupcnt > 0){
		tcb->rerecv += dupcnt;
		tstats.dup++;
		tstats.dupb += dupcnt;
		if(seg->flags & SYN){
			seg->flags &= ~SYN;
			seg->seq++;


@@ 1845,7 1912,7 @@ tcptrim(Tcpctl *tcb, Tcp *seg, Block **bp, ushort *length)
}

void
tcpadvise(Block *bp, char *msg)
tcpadvise(Proto *tcp, Block *bp, char *msg)
{
	Tcphdr *h;
	Tcpctl *tcb;


@@ 1862,7 1929,7 @@ tcpadvise(Block *bp, char *msg)
	pdest = nhgets(h->tcpdport);

	/* Look for a connection */
	for(p = tcp.conv; *p; p++) {
	for(p = tcp->conv; *p; p++) {
		s = *p;
		if(s->rport == pdest)
		if(s->lport == psource)


@@ 1892,39 1959,54 @@ tcpctl(Conv* c, char** f, int n)
}

int
tcpstats(char *buf, int len)
tcpstats(Proto *tcp, char *buf, int len)
{
	int n;

	n = snprint(buf, len,
		"tcp: csum %d hlen %d len %d order %d rexmit %d",
		tcp.csumerr, tcp.hlenerr, tcp.lenerr, tcp.order, tcp.rexmit);
	n += snprint(buf+n, len-n, " dupp %d dupb %d\n",
		tstats.dup, tstats.dupb);
	return n;
	Tcpstats *tstats;

	tstats = tcp->priv;
	return snprint(buf, len, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d",
		tstats->tcpRtoAlgorithm,
		tstats->tcpRtoMin,
		tstats->tcpRtoMax,
		tstats->tcpMaxConn,
		tstats->tcpActiveOpens,
		tstats->tcpPassiveOpens,
		tstats->tcpAttemptFails,
		tstats->tcpEstabResets,
		tstats->tcpCurrEstab,
		tstats->tcpInSegs,
		tstats->tcpOutSegs,
		tstats->tcpRetransSegs,
		tstats->InErrs,
		tstats->OutRsts);
}

void
tcpinit(Fs *fs)
{
	tcp.name = "tcp";
	tcp.kick = tcpkick;
	tcp.connect = tcpconnect;
	tcp.announce = tcpannounce;
	tcp.ctl = tcpctl;
	tcp.state = tcpstate;
	tcp.create = tcpcreate;
	tcp.close = tcpclose;
	tcp.rcv = tcpiput;
	tcp.advise = tcpadvise;
	tcp.stats = tcpstats;
	tcp.inuse = tcpinuse;
	tcp.ipproto = IP_TCPPROTO;
	tcp.nc = Nchans;
	tcp.ptclsize = sizeof(Tcpctl);

	kproc("tcpack", tcpackproc, 0);

	Fsproto(fs, &tcp);
	Proto *tcp;
	Tcppriv *tpriv;

	tcp = smalloc(sizeof(Proto));
	tpriv = tcp->priv = smalloc(sizeof(Tcppriv));
	tcp->name = "tcp";
	tcp->kick = tcpkick;
	tcp->connect = tcpconnect;
	tcp->announce = tcpannounce;
	tcp->ctl = tcpctl;
	tcp->state = tcpstate;
	tcp->create = tcpcreate;
	tcp->close = tcpclose;
	tcp->rcv = tcpiput;
	tcp->advise = tcpadvise;
	tcp->stats = tcpstats;
	tcp->inuse = tcpinuse;
	tcp->ipproto = IP_TCPPROTO;
	tcp->nc = Nchans;
	tcp->ptclsize = sizeof(Tcpctl);
	tpriv->tstats.tcpMaxConn = Nchans;

	Fsproto(fs, tcp);

	kproc("tcpack", tcpackproc, tcp);
}


M ip/udp.c => ip/udp.c +148 -66
@@ 15,7 15,8 @@ enum
	UDP_HDRSIZE	= 20,
	UDP_IPHDR	= 8,
	IP_UDPPROTO	= 17,
	UDP_USEAD	= 12,
	UDP_USEAD6	= 36,
	UDP_USEAD4	= 12,

	Udprxms		= 200,
	Udptickms	= 100,


@@ 44,6 45,27 @@ struct Udphdr
	uchar	udpcksum[2];	/* Checksum */
};

/* MIB II counters */
typedef struct Udpstats Udpstats;
struct Udpstats
{
	ulong	udpInDatagrams;
	ulong	udpNoPorts;
	ulong	udpInErrors;
	ulong	udpOutDatagrams;
};

typedef struct Udppriv Udppriv;
struct Udppriv
{
	/* MIB counters */
	Udpstats	ustats;

	/* non-MIB stats */
	ulong		csumerr;		/* checksum errors */
	ulong		lenerr;			/* short packet */
};

/*
 *  protocol specific part of Conv
 */


@@ 54,23 76,18 @@ struct Udpcb
	uchar	headers;
};

	Proto	udp;
	int	udpsum;
	uint	generation;
extern	Fs	fs;
	int	udpdebug;

static char*
udpconnect(Conv *c, char **argv, int argc)
{
	char *e;

	e = Fsstdconnect(c, argv, argc);
	Fsconnected(&fs, c, e);
	Fsconnected(c, e);

	return e;
}


static int
udpstate(Conv *c, char *state, int n)
{


@@ 86,7 103,7 @@ udpannounce(Conv *c, char** argv, int argc)
	e = Fsstdannounce(c, argv, argc);
	if(e != nil)
		return e;
	Fsconnected(&fs, c, nil);
	Fsconnected(c, nil);

	return nil;
}


@@ 126,30 143,54 @@ udpkick(Conv *c, int)
	Block *bp;
	Udpcb *ucb;
	int dlen, ptcllen;
	Udppriv *upriv;
	Fs *f;

	netlog(Logudp, "udp: kick\n");
	upriv = c->p->priv;
	f = c->p->f;

	netlog(c->p->f, Logudp, "udp: kick\n");
	bp = qget(c->wq);
	if(bp == nil)
		return;

	ucb = (Udpcb*)c->ptcl;
	if(ucb->headers) {
	switch(ucb->headers) {
	case 6:
		/* get user specified addresses */
		bp = pullupblock(bp, UDP_USEAD);
		bp = pullupblock(bp, UDP_USEAD6);
		if(bp == nil)
			return;
		ipmove(raddr, bp->rp);
		bp->rp += IPaddrlen;
		ipmove(laddr, bp->rp);
		bp->rp += IPaddrlen;
		if(ipforme(laddr) != Runi)
			findlocalip(laddr, raddr);	/* pick interface closest to dest */
		if(ipforme(f, laddr) != Runi)
			findlocalip(f, laddr, raddr);	/* pick interface closest to dest */
		rport = nhgets(bp->rp);
		bp->rp += 2;
		/* ignore local port number */
		bp->rp += 2;
		break;
	case 4:
		/* get user specified addresses */
		bp = pullupblock(bp, UDP_USEAD4);
		if(bp == nil)
			return;
		v4tov6(raddr, bp->rp);
		bp->rp += IPv4addrlen;
		v4tov6(laddr, bp->rp);
		bp->rp += IPv4addrlen;
		if(ipforme(f, laddr) != Runi)
			findlocalip(f, laddr, raddr);	/* pick interface closest to dest */
		rport = nhgets(bp->rp);
		bp->rp += 2;
		/* ignore local port number */
		bp->rp += 2;
	} else {
		break;
	default:
		rport = 0;
		break;
	}

	dlen = blocklen(bp);


@@ 167,16 208,24 @@ udpkick(Conv *c, int)
	uh->frag[0] = 0;
	uh->frag[1] = 0;
	hnputs(uh->udpplen, ptcllen);
	if(ucb->headers) {
	switch(ucb->headers){
	case 6:
		v6tov4(uh->udpdst, raddr);
		hnputs(uh->udpdport, rport);
		v6tov4(uh->udpsrc, laddr);
	} else {
		break;
	case 4:
		memmove(uh->udpdst, raddr, IPv4addrlen);
		hnputs(uh->udpdport, rport);
		memmove(uh->udpsrc, laddr, IPv4addrlen);
		break;
	default:
		v6tov4(uh->udpdst, c->raddr);
		hnputs(uh->udpdport, c->rport);
		if(ipcmp(c->laddr, IPnoaddr) == 0)
			findlocalip(c->laddr, c->raddr);	/* pick interface closest to dest */
			findlocalip(f, c->laddr, c->raddr);	/* pick interface closest to dest */
		v6tov4(uh->udpsrc, c->laddr);
		break;
	}
	hnputs(uh->udpsport, c->lport);
	hnputs(uh->udplen, ptcllen);


@@ 185,11 234,12 @@ udpkick(Conv *c, int)

	hnputs(uh->udpcksum, ptclcsum(bp, UDP_IPHDR, dlen+UDP_HDRSIZE));

	ipoput(bp, 0, c->ttl);
	upriv->ustats.udpOutDatagrams++;
	ipoput(f, bp, 0, c->ttl);
}

void
udpiput(uchar *ia, Block *bp)
udpiput(Proto *udp, uchar *ia, Block *bp)
{
	int len, olen, ottl;
	Udphdr *uh;


@@ 197,6 247,13 @@ udpiput(uchar *ia, Block *bp)
	Udpcb *ucb;
	uchar raddr[IPaddrlen], laddr[IPaddrlen];
	ushort rport, lport;
	Udppriv *upriv;
	Fs *f;

	upriv = udp->priv;
	f = udp->f;

	upriv->ustats.udpInDatagrams++;

	uh = (Udphdr*)(bp->rp);



@@ 212,10 269,10 @@ udpiput(uchar *ia, Block *bp)
	lport = nhgets(uh->udpdport);
	rport = nhgets(uh->udpsport);

	if(udpsum && nhgets(uh->udpcksum)) {
	if(nhgets(uh->udpcksum)) {
		if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) {
			udp.csumerr++;
			netlog(Logudp, "udp: checksum error %I\n", raddr);
			upriv->ustats.udpInErrors++;
			netlog(f, Logudp, "udp: checksum error %I\n", raddr);
			freeblist(bp);
			return;
		}


@@ 223,7 280,7 @@ udpiput(uchar *ia, Block *bp)

	/* Look for a conversation structure for this port */
	c = nil;
	for(p = udp.conv; *p; p++) {
	for(p = udp->conv; *p; p++) {
		c = *p;
		if(c->inuse == 0)
			continue;


@@ 232,13 289,14 @@ udpiput(uchar *ia, Block *bp)
	}

	if(*p == nil) {
		netlog(Logudp, "udp: no conv %I.%d -> %I.%d\n", raddr, rport,
		upriv->ustats.udpNoPorts++;
		netlog(f, Logudp, "udp: no conv %I.%d -> %I.%d\n", raddr, rport,
			laddr, lport);
		/* don't complain about broadcasts... */
		if(ipforme(raddr) == 0){
		if(ipforme(f, raddr) == 0){
			uh->Unused = ottl;
			hnputs(uh->udpplen, olen);
			icmpnoconv(bp);
			icmpnoconv(f, bp);
		}
		freeblist(bp);
		return;


@@ 250,28 308,41 @@ udpiput(uchar *ia, Block *bp)
	len -= (UDP_HDRSIZE-UDP_PHDRSIZE);
	bp = trimblock(bp, UDP_IPHDR+UDP_HDRSIZE, len);
	if(bp == nil){
		netlog(Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
		netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
			laddr, lport);
		udp.lenerr++;
		upriv->lenerr++;
		return;
	}

	netlog(Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
	netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
		laddr, lport, len);

	ucb = (Udpcb*)c->ptcl;

	if(ucb->headers) {
	switch(ucb->headers){
	case 6:
		/* pass the src address */
		bp = padblock(bp, UDP_USEAD);
		bp = padblock(bp, UDP_USEAD6);
		ipmove(bp->rp, raddr);
		if(ipforme(laddr) == Runi)
		if(ipforme(f, laddr) == Runi)
			ipmove(bp->rp+IPaddrlen, laddr);
		else
			ipmove(bp->rp+IPaddrlen, ia);
		hnputs(bp->rp+2*IPaddrlen, rport);
		hnputs(bp->rp+2*IPaddrlen+2, lport);
	} else {
		break;
	case 4:
		/* pass the src address */
		bp = padblock(bp, UDP_USEAD4);
		memmove(bp->rp, raddr, IPv4addrlen);
		if(ipforme(f, laddr) == Runi)
			memmove(bp->rp+IPv4addrlen, laddr, IPv4addrlen);
		else
			memmove(bp->rp+IPv4addrlen, ia, IPv4addrlen);
		hnputs(bp->rp + 2*IPv4addrlen, rport);
		hnputs(bp->rp + 2*IPv4addrlen + 2, lport);
		break;
	default:
		/* connection oriented udp */
		if(c->raddr == 0){
			/* save the src address in the conversation */


@@ 279,17 350,18 @@ udpiput(uchar *ia, Block *bp)
			c->rport = rport;

			/* reply with the same ip address (if not broadcast) */
			if(ipforme(laddr) == Runi)
			if(ipforme(f, laddr) == Runi)
				ipmove(c->laddr, laddr);
			else
				ipmove(c->laddr, ia);
				v4tov6(c->laddr, ia);
		}
		break;
	}
	if(bp->next)
		bp = concatblock(bp);

	if(qfull(c->rq)){
		netlog(Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
		netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
			laddr, lport);
		freeblist(bp);
	}else


@@ 302,19 374,20 @@ udpctl(Conv *c, char **f, int n)
	Udpcb *ucb;

	ucb = (Udpcb*)c->ptcl;
	if(n == 1 && strcmp(f[0], "headers") == 0){
		ucb->headers = 1;
		return nil;
	}
	if(n == 1 && strcmp(f[0], "debug") == 0){
		udpdebug = 1;
		return nil;
	if(n == 1){
		if(strcmp(f[0], "headers4") == 0){
			ucb->headers = 4;
			return nil;
		} else if(strcmp(f[0], "headers") == 0){
			ucb->headers = 6;
			return nil;
		}
	}
	return "unknown control request";
}

void
udpadvise(Block *bp, char *msg)
udpadvise(Proto *udp, Block *bp, char *msg)
{
	Udphdr *h;
	uchar source[IPaddrlen], dest[IPaddrlen];


@@ 329,7 402,7 @@ udpadvise(Block *bp, char *msg)
	pdest = nhgets(h->udpdport);

	/* Look for a connection */
	for(p = udp.conv; *p; p++) {
	for(p = udp->conv; *p; p++) {
		s = *p;
		if(s->rport == pdest)
		if(s->lport == psource)


@@ 344,30 417,39 @@ udpadvise(Block *bp, char *msg)
}

int
udpstats(char *buf, int len)
udpstats(Proto *udp, char *buf, int len)
{
	return snprint(buf, len,
		"udp: csum %d hlen %d len %d order %d rexmit %d\n",
		udp.csumerr, udp.hlenerr, udp.lenerr, udp.order, udp.rexmit);
	Udppriv *upriv;

	upriv = udp->priv;
	return snprint(buf, len, "%d %d %d %d",
		upriv->ustats.udpInDatagrams,
		upriv->ustats.udpNoPorts,
		upriv->ustats.udpInErrors,
		upriv->ustats.udpOutDatagrams);
}

void
udpinit(Fs *fs)
{
	udp.name = "udp";
	udp.kick = udpkick;
	udp.connect = udpconnect;
	udp.announce = udpannounce;
	udp.ctl = udpctl;
	udp.state = udpstate;
	udp.create = udpcreate;
	udp.close = udpclose;
	udp.rcv = udpiput;
	udp.advise = udpadvise;
	udp.stats = udpstats;
	udp.ipproto = IP_UDPPROTO;
	udp.nc = 16;
	udp.ptclsize = sizeof(Udpcb);

	Fsproto(fs, &udp);
	Proto *udp;

	udp = smalloc(sizeof(Proto));
	udp->priv = smalloc(sizeof(Udppriv));
	udp->name = "udp";
	udp->kick = udpkick;
	udp->connect = udpconnect;
	udp->announce = udpannounce;
	udp->ctl = udpctl;
	udp->state = udpstate;
	udp->create = udpcreate;
	udp->close = udpclose;
	udp->rcv = udpiput;
	udp->advise = udpadvise;
	udp->stats = udpstats;
	udp->ipproto = IP_UDPPROTO;
	udp->nc = 16;
	udp->ptclsize = sizeof(Udpcb);

	Fsproto(fs, udp);
}