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

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


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

Fs fs;
Queue* qlog;

enum
{
	Qtopdir=	1,		/* top level directory */
	Qtopbase,
	Qarp=		Qtopbase,
	Qipifc,
	Qiproute,
	Qlog,

	Qprotodir,			/* directory for a protocol */
	Qprotobase,
	Qclone=		Qprotobase,

	Qconvdir,			/* directory for a conversation */
	Qconvbase,
	Qctl=		Qconvbase,
	Qdata,
	Qerr,
	Qlisten,
	Qlocal,
	Qremote,
	Qstatus,
};
#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))

static char network[] = "network";

static int
ip3gen(Chan *c, int i, Dir *dp)
{
	Qid q;
	Conv *cv;
	char *p;

	cv = fs.p[PROTO(c->qid)]->conv[CONV(c->qid)];
	switch(i) {
	default:
		return -1;
	case Qctl:
		q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qctl), 0};
		devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
		return 1;
	case Qdata:
		q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qdata), 0};
		devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp);
		return 1;
	case Qerr:
		q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qerr), 0};
		devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp);
		return 1;
	case Qlisten:
		p = "listen";
		q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qlisten), 0};
		break;
	case Qlocal:
		p = "local";
		q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qlocal), 0};
		break;
	case Qremote:
		p = "remote";
		q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qremote), 0};
		break;
	case Qstatus:
		p = "status";
		q = (Qid){QID(PROTO(c->qid), CONV(c->qid), Qstatus), 0};
		break;
	}
	devdir(c, q, p, 0, cv->owner, 0444, dp);
	return 1;
}

static int
ip2gen(Chan *c, int i, Dir *dp)
{
	Qid q;

	switch(i) {
	case Qclone:
		q = (Qid){QID(PROTO(c->qid), 0, Qclone), 0};
		devdir(c, q, "clone", 0, network, 0444, dp);
		return 1;
	}	
	return -1;
}

static int
ip1gen(Chan *c, int i, Dir *dp)
{
	Qid q;
	char *p;

	switch(i) {
	default:
		return -1;
	case Qarp:
		p = "arp";
		q = (Qid){QID(0, 0, Qarp), 0};
		break;
	case Qipifc:
		p = "ipifc";
		q = (Qid){QID(0, 0, Qipifc), 0};
		break;
	case Qiproute:
		p = "iproute";
		q = (Qid){QID(0, 0, Qiproute), 0};
		break;
	case Qlog:
		p = "log";
		q = (Qid){QID(0, 0, Qlog), 0};
		break;
	}
	devdir(c, q, p, 0, network, 0444, dp);
	return 1;
}

static int
ipgen(Chan *c, Dirtab*, int, int s, Dir *dp)
{
	Qid q;
	Conv *cv;
	char name[16];

	switch(TYPE(c->qid)) {
	case Qtopdir:
		if(s < fs.np) {
			q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0};
			devdir(c, q, fs.p[s]->name, 0, network, CHDIR|0555, dp);
			return 1;
		}
		s -= fs.np;
		return ip1gen(c, s+Qtopbase, dp);
	case Qarp:
	case Qipifc:
	case Qlog:
	case Qiproute:
		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];
			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;
		return ip2gen(c, s+Qprotobase, dp);
	case Qclone:
		return ip2gen(c, TYPE(c->qid), dp);
	case Qconvdir:
		return ip3gen(c, s+Qconvbase, dp);
	case Qctl:
	case Qdata:
	case Qerr:
	case Qlisten:
	case Qlocal:
	case Qremote:
	case Qstatus:
		return ip3gen(c, TYPE(c->qid), dp);
	}
	return -1;
}

static void
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);
}

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

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

	return c;
}

static Chan*
ipclone(Chan* c, Chan* nc)
{
	return devclone(c, nc);
}

static int
ipwalk(Chan* c, char* name)
{
	Path *op;

	if(strcmp(name, "..") == 0){
		switch(TYPE(c->qid)){
		case Qtopdir:
		case Qprotodir:
			c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
			break;
		case Qconvdir:
			c->qid = (Qid){QID(0, 0, Qprotodir)|CHDIR, 0};
			break;
		default:
			panic("ipwalk %lux", c->qid.path);
		}
		op = c->path;
		c->path = ptenter(&syspt, op, name);
		decref(op);
		return 1;
	}

	return devwalk(c, name, nil, 0, ipgen);
}

static void
ipstat(Chan* c, char* db)
{
	devstat(c, db, nil, 0, ipgen);
}

static int
incoming(void* arg)
{
	Conv *conv;

	conv = arg;
	return conv->incall != nil;
}

static int m2p[] = {
	[OREAD]		4,
	[OWRITE]	2,
	[ORDWR]		6
};

static Chan*
ipopen(Chan* c, int omode)
{
	Conv *cv, *nc;
	Proto *p;
	int perm;

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

	switch(TYPE(c->qid)) {
	default:
		break;
	case Qlog:
		netlogopen();
		break;
	case Qtopdir:
	case Qprotodir:
	case Qconvdir:
	case Qstatus:
	case Qremote:
	case Qlocal:
		if(omode != OREAD)
			error(Eperm);
		break;
	case Qclone:
		p = fs.p[PROTO(c->qid)];
		cv = Fsprotoclone(p, up->user);
		if(cv == nil) {
			error(Enodev);
			break;
		}
		c->qid = (Qid){QID(p->x, cv->x, Qctl), 0};
		break;
	case Qdata:
	case Qctl:
	case Qerr:
		p = fs.p[PROTO(c->qid)];
		lock(p);
		cv = p->conv[CONV(c->qid)];
		lock(cv);
		if(waserror()) {
			unlock(cv);
			unlock(p);
			nexterror();
		}
		if((perm & (cv->perm>>6)) != perm) {
			if(strcmp(up->user, cv->owner) != 0)
				error(Eperm);
		 	if((perm & cv->perm) != perm)
				error(Eperm); 

		}
		cv->inuse++;
		if(cv->inuse == 1){
			memmove(cv->owner, up->user, NAMELEN);
			cv->perm = 0660;
		}
		unlock(cv);
		unlock(p);
		poperror();
		break;
	case Qlisten:
		cv = fs.p[PROTO(c->qid)]->conv[CONV(c->qid)];
		if(cv->state != Announced)
			error("not announced");

		nc = nil;
		while(nc == nil) {
			qlock(&cv->listenq);
			if(waserror()) {
				qunlock(&cv->listenq);
				nexterror();
			}

			sleep(&cv->listenr, incoming, cv);

			lock(cv);
			nc = cv->incall;
			if(nc != nil){
				cv->incall = nc->next;
				c->qid = (Qid){QID(PROTO(c->qid), nc->x, Qctl), 0};
				memmove(cv->owner, up->user, NAMELEN);
			}
			unlock(cv);

			qunlock(&cv->listenq);
			poperror();
		}
		break;
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

static void
ipcreate(Chan*, char*, int, ulong)
{
	error(Eperm);
}

static void
ipremove(Chan*)
{
	error(Eperm);
}

static void
ipwstat(Chan*, char*)
{
	error(Eperm);
}

static void
closeconv(Conv *cv)
{
	Conv *nc;

	lock(cv);
	if(--cv->inuse > 0) {
		unlock(cv);
		return;
	}

	/* close all incoming calls since no listen will ever happen */
	for(nc = cv->incall; nc; nc = cv->incall){
		cv->incall = nc->next;
		closeconv(nc);
	}

	strcpy(cv->owner, network);
	cv->perm = 0660;

	/* The close routine will unlock the conv */
	cv->p->close(cv);
}

static void
ipclose(Chan* c)
{
	switch(TYPE(c->qid)) {
	default:
		break;
	case Qlog:
		netlogclose();
		break;
	case Qdata:
	case Qctl:
	case Qerr:
		if(c->flag & COPEN)
			closeconv(fs.p[PROTO(c->qid)]->conv[CONV(c->qid)]);
	}
}

static long
ipread(Chan *ch, void *a, long n, ulong offset)
{
	Conv *c;
	Proto *x;
	byte ip[4];
	char buf[256], *p, *statename;

	p = a;
	switch(TYPE(ch->qid)) {
	default:
		error(Eperm);
	case Qtopdir:
	case Qprotodir:
	case Qconvdir:
		return devdirread(ch, a, n, 0, 0, ipgen);
	case Qarp:
		return arpread(a, offset, n);
	case Qipifc:
		return Mediaifcread(a, offset, n);
	case Qiproute:
		return routeread(a, offset, n);
	case Qlog:
		return netlogread(a, offset, n);
	case Qctl:
		sprint(buf, "%d", CONV(ch->qid));
		return readstr(offset, p, n, buf);
	case Qremote:
		c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
		hnputl(ip, c->raddr);
		sprint(buf, "%I!%d\n", ip, c->rport);
		return readstr(offset, p, n, buf);
	case Qlocal:
		c = fs.p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
		if(media != nil && c->laddr == 0)
			hnputl(ip, Mediagetaddr(media));
		else
			hnputl(ip, c->laddr);
		sprint(buf, "%I!%d\n", ip, c->lport);
		return readstr(offset, p, n, buf);
	case Qstatus:
		x = fs.p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];
		x->state(&statename, c);
		sprint(buf, "%s/%d %d %s \n", c->p->name, c->x, c->inuse, statename);
		return readstr(offset, p, n, buf);
	case Qdata:
		c = fs.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)];
		return qread(c->eq, a, n);
	}
}

static Block*
ipbread(Chan* c, long n, ulong offset)
{
	return devbread(c, n, offset);
}

static void
setladdr(Conv* c)
{
	byte rem[4];

	hnputl(rem, c->raddr);
	c->laddr = Mediagetsrc(rem);
}

static void
setlport(Conv* c)
{
	Proto *p;
	ushort *pp;
	int x, found;

	p = c->p;
	/*
	 * For compatibility with old Plan9/Brazil systems restrict
	 * the port number for now such that it can't sign-extend on
	 * the other end.
	 */
	while(p->nextport < 5000 || p->nextport >= (1<<15))
		p->nextport = nrand(1<<16);

	if(c->restricted)
		pp = &p->nextrport;
	else
		pp = &p->nextport;
	lock(p);
	for(;;(*pp)++){
		if(*pp == 0 || *pp >= (1<<15)) {	/* BSD hack */
			if(c->restricted)
				*pp = 600;
			else
				*pp = 5000;
		}
		found = 0;
		for(x = 0; x < p->nc; x++){
			if(p->conv[x] == nil)
				break;
			if(p->conv[x]->lport == *pp){
				found = 1;
				break;
			}
		}
		if(!found)
			break;
	}
	c->lport = (*pp)++;
	unlock(p);
}

static void
setladdrport(Conv* c, char* str)
{
	char *p, addr[4];

	p = strchr(str, '!');
	if(p == nil) {
		p = str;
		c->laddr = 0;
	}
	else {
		*p++ = 0;
		parseip(addr, str);
		c->laddr = nhgetl((byte*)addr);
	}
	if(*p == '*')
		c->lport = 0;
	else {
		c->lport = atoi(p);
		if(c->lport == 0)
			setlport(c);
	}
}

static char*
setraddrport(Conv* c, char* str)
{
	char *p, addr[4];

	p = strchr(str, '!');
	if(p == nil)
		return "malformed address";
	*p++ = 0;
	parseip(addr, str);
	c->raddr = nhgetl((byte*)addr);
	c->rport = atoi(p);
	p = strchr(p, '!');
	if(p){
		if(strcmp(p, "!r") == 0)
			c->restricted = 1;
	}
	return nil;
}

static int
connected(void* a)
{
	return ((Conv*)a)->state == Connected;
}

static int
announced(void* a)
{
	return ((Conv*)a)->state == Announced;
}

static long
ipwrite(Chan* ch, char* a, long n, ulong)
{
	Conv *c;
	Proto *x;
	int nfield;
	char *p, *fields[10], buf[128];

	switch(TYPE(ch->qid)){
	default:
		error(Eperm);
	case Qarp:
		p = arpwrite(a, n);
		if(p != nil)
			error(p);
		return n;
	case Qipifc:
		p = Mediaifcwrite(a, n);
		if(p != nil)
			error(p);
		return n;
	case Qiproute:
		p = routewrite(a, n);
		if(p != nil)
			error(p);
		return n;
	case Qlog:
		p = netlogctl(a, n);
		if(p != nil)
			error(p);
		return n;
	case Qctl:
		x = fs.p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];
		if(n > sizeof(buf)-1)
			n = sizeof(buf)-1;
		memmove(buf, a, n);
		buf[n] = '\0';
		nfield = parsefields(buf, fields, 10, " ");
		if(strcmp(fields[0], "connect") == 0){
			if(canqlock(&c->car) == 0)
				error("connect/announce in progress");
			if(waserror()) {
				qunlock(&c->car);
				nexterror();
			}
			c->state = Connecting;
			c->cerr[0] = '\0';
			p = x->connect(c, fields, nfield);
			if(p != nil)
				error(p);
			sleep(&c->cr, connected, c);
			if(c->cerr[0] != '\0')
				error(c->cerr);
			qunlock(&c->car);
			poperror();
			return n;
		}
		if(strcmp(fields[0], "announce") == 0){
			if(canqlock(&c->car) == 0)
				error("connect/announce in progress");
			if(waserror()) {
				qunlock(&c->car);
				nexterror();
			}
			switch(nfield){
			default:
				error("bad args to announce");
			case 2:
				setladdrport(c, fields[1]);
				break;
			}
			c->state = Announcing;
			c->cerr[0] = '\0';
			x->announce(c);
			sleep(&c->cr, announced, c);
			if(c->cerr[0] != '\0')
				error(c->cerr);
			qunlock(&c->car);
			poperror();
			return n;
		}
		if(strcmp(fields[0], "bind") == 0){
			if(canqlock(&c->car) == 0)
				error("connect/announce in progress");
			if(waserror()) {
				qunlock(&c->car);
				nexterror();
			}
			switch(nfield){
			default:
				error("bad args to bind");
			case 2:
				setladdr(c);
				c->lport = atoi(fields[1]);
				if(c->lport == 0)
					setlport(c);
				break;
			}
			qunlock(&c->car);
			poperror();
			return n;
		}
		if(strcmp(fields[0], "ttl") == 0){
			if(nfield < 2)
				c->ttl = MAXTTL;
			else
				c->ttl = atoi(fields[1]);
			return n;
		}
		if(x->ctl != nil) {
			p = x->ctl(c, fields, nfield);
			if(p != nil)
				error(p);
			return n;
		}
		error("unknown control request");
	case Qdata:
		x = fs.p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];

		qwrite(c->wq, a, n);
		x->kick(c, n);
	}
	return n;
}

static long
ipbwrite(Chan* c, Block* bp, ulong offset)
{
	return devbwrite(c, bp, offset);
}

Dev ipdevtab = {
	ipreset,
	ipinit,
	ipattach,
	ipclone,
	ipwalk,
	ipstat,
	ipopen,
	ipcreate,
	ipclose,
	ipread,
	ipbread,
	ipwrite,
	ipbwrite,
	ipremove,
	ipwstat,
};

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

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

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

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

/*
 *  return true if this protocol is
 *  built in
 */
int
Fsbuiltinproto(Fs* fs, byte proto)
{
	return fs->t2p[proto] != nil;
}

Conv*
Fsprotoclone(Proto *p, char *user)
{
	char *junk;
	int unused;
	Conv *c, **pp, **ep;

	c = nil;
	lock(p);
	if(waserror()) {
		unlock(p);
		nexterror();
	}
	ep = &p->conv[p->nc];
	for(pp = p->conv; pp < ep; pp++) {
		c = *pp;
		if(c == nil){
			c = malloc(sizeof(Conv));
			if(c == nil)
				error(Enomem);
			lock(c);
			c->p = p;
			c->x = pp - p->conv;
			c->ptcl = malloc(p->ptclsize);
			if(c->ptcl == nil) {
				free(c);
				error(Enomem);
			}
			*pp = c;
			p->ac++;
			c->eq = qopen(1024, 1, 0, 0);
			(*p->create)(c);
			break;
		}
		if(canlock(c)){
			unused = p->state(&junk, c);
			if(c->inuse == 0 && unused)
				break;

			unlock(c);
		}
	}
	if(pp >= ep) {
		unlock(p);
		poperror();
		return nil;
	}

	c->inuse = 1;
	strcpy(c->owner, user);
	c->perm = 0660;
	c->state = 0;
	c->laddr = 0;
	c->raddr = 0;
	c->lport = 0;
	c->rport = 0;
	c->restricted = 0;
	c->ttl = MAXTTL;
	qreopen(c->rq);
	qreopen(c->wq);
	qreopen(c->eq);

	unlock(c);
	unlock(p);
	poperror();
	return c;
}

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

	switch(c->state){

	case Announcing:
		c->state = Announced;
		break;

	case Connecting:
		c->state = Connected;
		break;
	}

	wakeup(&c->cr);
	return 0;
}

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

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

	lock(c);
	i = 0;
	for(l = &c->incall; *l; l = &(*l)->next)
		i++;
	if(i >= Maxincall) {
		unlock(c);
		return nil;
	}

	/* find a free conversation */
	nc = Fsprotoclone(c->p, network);
	if(nc == nil) {
		unlock(c);
		return nil;
	}
	nc->raddr = raddr;
	nc->rport = rport;
	nc->laddr = laddr;
	nc->lport = lport;
	nc->next = nil;
	*l = nc;
	unlock(c);

	wakeup(&c->listenr);

	return nc;
}

int
Fspcolstats(char *buf, int len)
{
	Proto **p;
	int n;

	n = 0;
	for(p = fs.p; *p; p++)
		n += snprint(buf + n, len - n,
			"%s: csum %d hlen %d len %d order %d rexmit %d\n",
			(*p)->name, (*p)->csumerr, (*p)->hlenerr, (*p)->lenerr,
			(*p)->order, (*p)->rexmit);
	return n;
}

char*
Fsstdconnect(Conv *c, char *argv[], int argc)
{
	char *p;

	switch(argc) {
	default:
		return "bad args to connect";
	case 2:
		p = setraddrport(c, argv[1]);
		if(p != nil)
			return p;
		setladdr(c);
		setlport(c);
		break;
	case 3:
		p = setraddrport(c, argv[1]);
		if(p != nil)
			return p;
		setladdr(c);
		c->lport = atoi(argv[2]);
		break;
	}
	return nil;
}
.
## diffname ip/devip.c 1997/0403
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0403/sys/src/brazil/ip/devip.c
936a
		break;
	}
	return nil;
}

char*
Fsstdannounce(Conv* c, char* argv[], int argc)
{
	switch(argc){
	default:
		return "bad args to announce";
	case 2:
		setladdrport(c, argv[1]);
.
660c
			p = x->announce(c, fields, nfield);
			if(p != nil)
				error(p);
.
651,657d
## diffname ip/devip.c 1997/0408
## diff -e /n/emeliedump/1997/0403/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0408/sys/src/brazil/ip/devip.c
714a
	'I',
	"ip",

.
## diffname ip/devip.c 1997/0423
## diff -e /n/emeliedump/1997/0408/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0423/sys/src/brazil/ip/devip.c
603c
		p = Mediaifcwrite(ch->aux, a, n);
.
564c
	c->raddr = nhgetl(addr);
.
557c
	char *p;
	uchar addr[Ipaddrlen];
.
543c
		c->laddr = nhgetl(addr);
.
533c
	char *p;
	uchar addr[Ipaddrlen];
.
404a
	case Qipifc:
		closeifcconv(c->aux);
		c->aux = nil;
		break;
.
272a
	case Qipifc:
		c->aux = newifcconv();
		break;
.
139a
			if(fs.p[s]->connect == nil)
				return 0;	/* protocol with no user interface */
.
## diffname ip/devip.c 1997/0508
## diff -e /n/emeliedump/1997/0423/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0508/sys/src/brazil/ip/devip.c
522a
		else while(*pp < 5000)
			*pp = nrand(1<<16);

.
520,521d
517,518c
		/*
		 * Fsproto initialises p->nextport to 0 and the restricted
		 * ports (p->nextrport) to 600.
		 * Restricted ports must lie between 600 and 1024.
		 * For the initial condition or if the unrestricted port number
		 * has wrapped round, select a random port between 5000 and 1<<16
		 * to start at.
		 */
		if(c->restricted){
			if(*pp >= 1024)
.
503,510d
## diffname ip/devip.c 1997/0531
## diff -e /n/emeliedump/1997/0508/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0531/sys/src/brazil/ip/devip.c
411c
		if(c->flag & COPEN)
			closeifcconv(c->aux);
.
## diffname ip/devip.c 1997/0806
## diff -e /n/emeliedump/1997/0531/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0806/sys/src/brazil/ip/devip.c
923c
			(*p)->order, (*p)->rexmit, (*p)->wclosed);
.
921c
			"%s: csum %d hlen %d len %d order %d rexmit %d wc %d\n",
.
## diffname ip/devip.c 1997/0811
## diff -e /n/emeliedump/1997/0806/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0811/sys/src/brazil/ip/devip.c
523c
			*pp = nrand(1<<15);
.
515c
		 * has wrapped round, select a random port between 5000 and 1<<15
.
## diffname ip/devip.c 1997/0815
## diff -e /n/emeliedump/1997/0811/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0815/sys/src/brazil/ip/devip.c
570c
	uchar addr[IPaddrlen];
.
545c
	uchar addr[IPaddrlen];
.
## diffname ip/devip.c 1997/0823
## diff -e /n/emeliedump/1997/0815/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0823/sys/src/brazil/ip/devip.c
227c
			c->qid = (Qid){QID(PROTO(c->qid), 0, Qprotodir)|CHDIR, 0};
.
## diffname ip/devip.c 1997/0916
## diff -e /n/emeliedump/1997/0823/sys/src/brazil/ip/devip.c /n/emeliedump/1997/0916/sys/src/brazil/ip/devip.c
923c
			(*p)->order, (*p)->rexmit);
		if((*p)->stats)
			n += (*(*p)->stats)(buf + n, len - n);
	}
.
921c
			"%s: csum %d hlen %d len %d order %d rexmit %d\n",
.
919c
	for(p = fs.p; *p; p++){
.
## diffname ip/devip.c 1997/1030
## diff -e /n/emeliedump/1997/0916/sys/src/brazil/ip/devip.c /n/emeliedump/1997/1030/sys/src/brazil/ip/devip.c
963c
		setladdrport(c, argv[1], 0);
.
949,950c
		setladdrport(c, argv[2], 1);
.
550c
		if(nodefault)
			setladdr(c);
		else
			c->laddr = 0;
.
542c
setladdrport(Conv* c, char* str, int nodefault)
.
## diffname ip/devip.c 1997/1104
## diff -e /n/emeliedump/1997/1030/sys/src/brazil/ip/devip.c /n/emeliedump/1997/1104/sys/src/brazil/ip/devip.c
809a
				unlock(c);
.
474c
//		return qread(c->rq, a, n);
		xxx = qread(c->rq, a, n);
poot("ipread 2", 0);
		return xxx;
}
.
472a
{int xxx;
poot("ipread 1", 0);
.
## diffname ip/devip.c 1997/1105
## diff -e /n/emeliedump/1997/1104/sys/src/brazil/ip/devip.c /n/emeliedump/1997/1105/sys/src/brazil/ip/devip.c
476,480c
		return qread(c->rq, a, n);

.
473,474d
## diffname ip/devip.c 1997/1128
## diff -e /n/emeliedump/1997/1105/sys/src/brazil/ip/devip.c /n/emeliedump/1997/1128/sys/src/brazil/ip/devip.c
549c
	if(p == nil || strcmp(p, "!r") == 0) {
.
547a
	/*
	 *  ignore restricted part if it exists.  it's
	 *  meaningless on local ports.
	 */
.
## diffname ip/devip.c 1998/0306
## diff -e /n/emeliedump/1997/1128/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0306/sys/src/brazil/ip/devip.c
919,974d
910c
	ipmove(nc->laddr, laddr);
.
908c
	ipmove(nc->raddr, raddr);
.
887c
Fsnewcall(Fs*, Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport)
.
881c
Fsrcvpcol(Fs* fs, uchar proto)
.
854c
	qunlock(p);
.
843,844c
	ipmove(c->laddr, IPnoaddr);
	ipmove(c->raddr, IPnoaddr);
.
834c
		qunlock(p);
.
826,827c
			/*
			 *  make sure both processes and protocol
			 *  are done with this Conv
			 */
			if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0))
.
815d
800c
		qunlock(p);
.
798c
	qlock(p);
.
793,794d
785c
Fsbuiltinproto(Fs* fs, uchar proto)
.
716,724c
		} else
			error("unknown control request");
		qunlock(&c->car);
		free(cb);
		poperror();
.
684,713c
		if(strcmp(cb->f[0], "connect") == 0)
			connectctlmsg(x, c, cb);
		else if(strcmp(cb->f[0], "announce") == 0)
			announcectlmsg(x, c, cb);
		else if(strcmp(cb->f[0], "bind") == 0)
			bindctlmsg(x, c, cb);
		else if(strcmp(cb->f[0], "ttl") == 0)
			ttlctlmsg(c, cb);
		else if(strcmp(cb->f[0], "addmulti") == 0){
			if(cb->nf < 2)
				error("addmulti needs interface address");
			if(!ipismulticast(c->raddr))
				error("addmulti for a non multicast address");
			parseip(ia, cb->f[1]);
			ipifcaddmulti(c, c->raddr, ia);
		} else if(strcmp(cb->f[0], "remmulti") == 0){
			if(cb->nf < 2)
				error("remmulti needs interface address");
			if(!ipismulticast(c->raddr))
				error("remmulti for a non multicast address");
			parseip(ia, cb->f[1]);
			ipifcremmulti(c, c->raddr, ia);
		} else if(x->ctl != nil) {
			p = x->ctl(c, cb->f, cb->nf);
.
681,682c
			free(cb);
			nexterror();
.
665,679c
		if(waserror()) {
.
641,663c
		cb = parsecmd(a, n);

		if(canqlock(&c->car) == 0){
			free(cb);
			error("connect/announce in progress");
.
629,632c
		return routewrite(ch, a, n);
.
619,627c
		return arpwrite(a, n);
.
617a
	case Qdata:
		x = fs.p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];

		if(c->wq == nil)
			error(Eperm);

		qwrite(c->wq, a, n);
		x->kick(c, n);
		break;
.
612,613c
	char *p;
	Cmdbuf *cb;
	uchar ia[IPaddrlen];
.
606a
	c->state = Announcing;
	c->cerr[0] = '\0';
	if(x->announce == nil)
		error("announce not supported");
	p = x->announce(c, cb->f, cb->nf);
	if(p != nil)
		error(p);
	sleep(&c->cr, announced, c);
	if(c->cerr[0] != '\0')
		error(c->cerr);
}

/*
 *  called by protocol bide routine to set addresses
 */
char*
Fsstdbind(Conv* c, char* argv[], int argc)
{
	switch(argc){
	default:
		return "bad args to bind";
	case 2:
		setladdrport(c, argv[1], 0);
		break;
	}
	return nil;
}

static void
bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
{
	char *p;

	if(x->bind == nil)
		p = Fsstdbind(c, cb->f, cb->nf);
	else
		p = x->bind(c, cb->f, cb->nf);
	if(p != nil)
		error(p);
}

static void
ttlctlmsg(Conv *c, Cmdbuf *cb)
{
	if(cb->nf < 2)
		c->ttl = MAXTTL;
	else
		c->ttl = atoi(cb->f[1]);
}

.
605a
static void
announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb)
{
	char *p;
.
600a
	c->state = Connecting;
	c->cerr[0] = '\0';
	if(x->connect == nil)
		error("connect not supported");
	p = x->connect(c, cb->f, cb->nf);
	if(p != nil)
		error(p);
	sleep(&c->cr, connected, c);
	if(c->cerr[0] != '\0')
		error(c->cerr);
}

/*
 *  called by protocol announce routine to set addresses
 */
char*
Fsstdannounce(Conv* c, char* argv[], int argc)
{
	switch(argc){
	default:
		return "bad args to announce";
	case 2:
		setladdrport(c, argv[1], 1);
		break;
	}
	return nil;
}

/*
 *  initiate announcement and sleep till its set up
 */
.
599a
static void
connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
{
	char *p;
.
594a
/*
 *  called by protocol connect routine to set addresses
 */
char*
Fsstdconnect(Conv *c, char *argv[], int argc)
{
	char *p;

	switch(argc) {
	default:
		return "bad args to connect";
	case 2:
		p = setraddrport(c, argv[1]);
		if(p != nil)
			return p;
		setladdr(c);
		setlport(c);
		break;
	case 3:
		p = setraddrport(c, argv[1]);
		if(p != nil)
			return p;
		setladdrport(c, argv[2], 0);
		break;
	}
	return nil;
}
/*
 *  initiate connection and sleep till its set up
 */
.
584,585c
	parseip(c->raddr, str);
.
578d
565,567c

	c->lport = 0;
	if(*p != '*'){
.
562,563c
		parseip(c->laddr, str);
.
557,560c
	} else {
.
555c
		memset(c->laddr, 0, sizeof(c->laddr));
		if(!announcing)
.
546d
543c
setladdrport(Conv* c, char* str, int announcing)
.
541a
/*
 *  set a local address and port from a string of the form
 *	address!port
 *  if address is missing and not announcing, pick one
 *  if address is missing and announcing, leave address as zero (i.e. matches anything)
 *  if port is 0, pick a free one
 *  if port is '*', leave port as zero (i.e. matches anything)
 */
.
539c
	qunlock(p);
.
509c
	qlock(p);
.
496a
/*
 *  pick a local port and set it
 */
.
491,494c
	findlocalip(c->laddr, c->raddr);
.
487a
/*
 *  set local address to be that of the ifc closest to remote address
 */
.
478a
	case Qstats:
		x = fs.p[PROTO(ch->qid)];
		if(x->stats == nil)
			error("stats not implemented");
		buf = smalloc(Statelen);
		(*x->stats)(buf, Statelen);
		rv = readstr(offset, p, n, buf);
		free(buf);
		return rv;
.
475d
469,471c
		m = sprint(buf, "%s/%d %d ", c->p->name, c->x, c->inuse);
		(*x->state)(c, buf, Statelen-m-2);
		rv = readstr(offset, p, n, buf);
		free(buf);
		return rv;
.
466a
		buf = smalloc(Statelen);
.
459,465c
		buf = smalloc(Statelen);
		x = fs.p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];
		if(x->local == nil) {
			sprint(buf, "%I!%d\n", c->laddr, c->lport);
		} else {
			(*x->local)(c, buf, Statelen-2);
		}
		rv = readstr(offset, p, n, buf);
		free(buf);
		return rv;
.
455,457c
		sprint(buf, "%I!%d\n", c->raddr, c->rport);
		rv = readstr(offset, p, n, buf);
		free(buf);
		return rv;
.
453a
		buf = smalloc(Statelen);
.
452c
		rv = readstr(offset, p, n, buf);
		free(buf);
		return rv;
.
450a
		buf = smalloc(16);
.
447a
	case Qiprouter:
		return iprouterread(a, n);
.
444,445d
431,432c
	char *buf, *p;
	long m, rv;
.
425a
enum
{
	Statelen=	1024,
};

.
415,416c
	case Qiprouter:
		if(c->flag & COPEN)
			iprouterclose();
.
412,413c
			netlogclose();
.
410c
	case Qlog:
.
399a
	while((mp = cv->multi) != nil)
		ipifcremmulti(cv, mp->ma, mp->ia);

.
385a

.
383a
	Ipmulti *mp;
.
324c
		qunlock(p);
.
308c
			qunlock(p);
.
303c
		qlock(p);
.
286a
	case Qstats:
.
280a
	case Qiprouter:
		iprouteropen();
		break;
	case Qiproute:
		memmove(c->tag, "none", sizeof(c->tag));
		break;
.
275,277d
238c
	switch(TYPE(c->qid)){
	case Qtopdir:
	case Qprotodir:
		c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
		break;
	case Qconvdir:
		c->qid = (Qid){QID(PROTO(c->qid), 0, Qprotodir)|CHDIR, 0};
		break;
	default:
		panic("ipwalk %lux", c->qid.path);
	}
	op = c->path;
	c->path = ptenter(&syspt, op, name);
	decref(op);
	return 1;
.
220,236c
	if(strcmp(name, "..") != 0)
		return devwalk(c, name, nil, 0, ipgen);
.
195a
	fmtinstall('V', eipconv);
	fmtinstall('M', eipconv);
.
163a
	case Qstats:
.
151a
	case Qiprouter:
.
149d
126c
	devdir(c, q, p, 0, network, 0666, dp);
.
120a
	case Qiprouter:
		p = "iprouter";
		q = (Qid){QID(0, 0, Qiprouter), 0};
		break;
.
113,116d
95a
	case Qstats:
		q = (Qid){QID(PROTO(c->qid), 0, Qstats), 0};
		devdir(c, q, "stats", 0, network, 0444, dp);
		return 1;
.
94c
		devdir(c, q, "clone", 0, network, 0666, dp);
.
82c
	devdir(c, q, p, 0, cv->owner, 0666, dp);
.
23a
	Qstats,
.
18a
	Qiprouter,
.
17d
## diffname ip/devip.c 1998/0310
## diff -e /n/emeliedump/1998/0306/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0310/sys/src/brazil/ip/devip.c
467,468c
	case Qipselftab:
		return ipselftabread(a, offset, n);
.
297a
	case Qipselftab:
.
156a
	case Qipselftab:
.
131c
	devdir(c, q, p, 0, network, prot, dp);
.
121a
	case Qipselftab:
		p = "ipselftab";
		prot = 0444;
		q = (Qid){QID(0, 0, Qipselftab), 0};
		break;
.
110a
	prot = 0666;
.
109a
	int prot;
.
18a
	Qipselftab,
.
## diffname ip/devip.c 1998/0313
## diff -e /n/emeliedump/1998/0310/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0313/sys/src/brazil/ip/devip.c
1020c
Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport)
.
1016c
	return f->t2p[proto];
.
1014c
Fsrcvpcol(Fs* f, uchar proto)
.
993c
Fsconnected(Conv* c, char* msg)
.
920c
	return f->t2p[proto] != nil;
.
918c
Fsbuiltinproto(Fs* f, uchar proto)
.
909c
	f->p[f->np++] = p;

.
906c
	p->x = f->np;
.
901c
	p->qid.path = CHDIR|QID(f->np, 0, Qprotodir);
.
898c
		f->t2p[p->ipproto] = p;
.
896c
		if(f->t2p[p->ipproto] != nil)
.
894a
	p->f = f;

.
892c
	if(f->np >= Maxproto)
.
890c
Fsproto(Fs *f, Proto *p)
.
814c
		x = f->p[PROTO(ch->qid)];
.
809c
		p = netlogctl(f, a, n);
.
807c
		return routewrite(f, ch, a, n);
.
805c
		return arpwrite(f->arp, a, n);
.
795c
		x = f->p[PROTO(ch->qid)];
.
790a
	f = ipfs[ch->dev];

.
789a
	Fs *f;
.
545c
	findlocalip(c->p->f, c->laddr, c->raddr);
.
526c
		(*x->stats)(x, buf, Statelen);
.
522c
		x = f->p[PROTO(ch->qid)];
.
519c
		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
.
516c
		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
.
508c
		x = f->p[PROTO(ch->qid)];
.
496c
		x = f->p[PROTO(ch->qid)];
.
489c
		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
.
480c
		return netlogread(f, a, offset, n);
.
478c
		return ipselftabread(f, a, offset, n);
.
476c
		return routeread(f, a, offset, n);
.
474c
		return arpread(f->arp, a, offset, n);
 	case Qbootp:
 		return bootpread(a, offset, n);
.
464a
	f = ipfs[ch->dev];

.
463a
	Fs *f;
.
448c
			closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);
.
442c
			iprouterclose(f);
.
438c
			netlogclose(f);
.
432a
	Fs *f;

	f = ipfs[c->dev];
.
368c
				memmove(cv->owner, commonuser(), NAMELEN);
.
349c
		cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
.
341c
			memmove(cv->owner, commonuser(), NAMELEN);
.
333c
			if(strcmp(commonuser(), cv->owner) != 0)
.
323c
		p = f->p[PROTO(c->qid)];
.
312,313c
		p = f->p[PROTO(c->qid)];
		cv = Fsprotoclone(p, commonuser());
.
306a
	case Qbootp:
.
295c
		iprouteropen(f);
.
292c
		netlogopen(f);
.
287a
	f = ipfs[c->dev];

.
283a
	Fs *f;
.
221a
	c->dev = dev;
.
219a
	dev = atoi(spec);
	if(dev >= 16)
		error("bad specification");

	ipgetfs(dev);
.
218a
	int dev;
.
214a
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];
}

.
202,207d
175c
		s -= f->p[PROTO(c->qid)]->ac;
.
168,169c
		if(s < f->p[PROTO(c->qid)]->ac) {
			cv = f->p[PROTO(c->qid)]->conv[s];
.
161a
	case Qbootp:
.
159c
		s -= f->np;
.
156c
			devdir(c, q, f->p[s]->name, 0, network, CHDIR|0555, dp);
.
152,153c
		if(s < f->np) {
			if(f->p[s]->connect == nil)
.
149a
	f = ipfs[c->dev];

.
148a
	Fs *f;
.
120a
	case Qbootp:
		p = "bootp";
		q = (Qid){QID(0, 0, Qbootp), 0};
		break;
.
51c
	cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
.
43a
QLock	fslock;
Fs	*ipfs[Nfs];	/* attached fs's */
Queue	*qlog;

.
37,40c
#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) )
.
35a

	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,
.
16a
	Qbootp,
.
9,11d
## diffname ip/devip.c 1998/0319
## diff -e /n/emeliedump/1998/0313/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0319/sys/src/brazil/ip/devip.c
842c
ipwrite(Chan* ch, char* a, long n, vlong)
.
518a
	ulong offset = off;
.
512c
ipread(Chan *ch, void *a, long n, vlong off)
.
## diffname ip/devip.c 1998/0321
## diff -e /n/emeliedump/1998/0319/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0321/sys/src/brazil/ip/devip.c
469a
	cv->incall = nil;
.
## diffname ip/devip.c 1998/0324
## diff -e /n/emeliedump/1998/0321/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0324/sys/src/brazil/ip/devip.c
1083c
	if(f->t2m[proto] && f->ipmux)
		return f->ipmux;
	else
		return f->t2p[proto];
.
## diffname ip/devip.c 1998/0327
## diff -e /n/emeliedump/1998/0324/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0327/sys/src/brazil/ip/devip.c
1083c
	if(f->ipmux)
.
## diffname ip/devip.c 1998/0423
## diff -e /n/emeliedump/1998/0327/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0423/sys/src/brazil/ip/devip.c
217a
	nullmediumlink();
	pktmediumlink();
.
56a
extern void nullmediumlink(void);
extern void pktmediumlink(void);

.
## diffname ip/devip.c 1998/0502
## diff -e /n/emeliedump/1998/0423/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0502/sys/src/brazil/ip/devip.c
907,910c
			if(cb->nf == 2){
				if(!ipismulticast(c->raddr))
					error("addmulti for a non multicast address");
				parseip(ia, cb->f[1]);
				ipifcaddmulti(c, c->raddr, ia);
			} else {
				parseip(ma, cb->f[2]);
				if(!ipismulticast(ma))
					error("addmulti for a non multicast address");
				parseip(ia, cb->f[1]);
				ipifcaddmulti(c, ma, ia);
			}
.
855c
	uchar ia[IPaddrlen], ma[IPaddrlen];
.
## diffname ip/devip.c 1998/0509
## diff -e /n/emeliedump/1998/0502/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0509/sys/src/brazil/ip/devip.c
1101a
Proto*
Fsrcvpcolx(Fs *f, uchar proto)
{
	return f->t2p[proto];
}

.
## diffname ip/devip.c 1998/0630
## diff -e /n/emeliedump/1998/0509/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0630/sys/src/brazil/ip/devip.c
874c
		return arpwrite(f, a, n);
.
## diffname ip/devip.c 1998/0709
## diff -e /n/emeliedump/1998/0630/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0709/sys/src/brazil/ip/devip.c
576,577c
		(*x->state)(c, buf, Statelen-2);
.
## diffname ip/devip.c 1998/0710
## diff -e /n/emeliedump/1998/0709/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0710/sys/src/brazil/ip/devip.c
523c
	long rv;
.
## diffname ip/devip.c 1998/0717
## diff -e /n/emeliedump/1998/0710/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0717/sys/src/brazil/ip/devip.c
514c
	Statelen=	32*1024,
.
## diffname ip/devip.c 1998/0825
## diff -e /n/emeliedump/1998/0717/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0825/sys/src/brazil/ip/devip.c
549c
		sprint(buf, "%lud", CONV(ch->qid));
.
## diffname ip/devip.c 1998/0924
## diff -e /n/emeliedump/1998/0825/sys/src/brazil/ip/devip.c /n/emeliedump/1998/0924/sys/src/brazil/ip/devip.c
252a
		f->dev = dev;
.
## diffname ip/devip.c 1998/1127
## diff -e /n/emeliedump/1998/0924/sys/src/brazil/ip/devip.c /n/emeliedump/1998/1127/sys/src/brazil/ip/devip.c
417a
			/* wait for a connect */
.
411a
			/* give up if we got a hangup */
			if(qisclosed(cv->rq))
				error("listen hungup");

.
## diffname ip/devip.c 1999/0302
## diff -e /n/emeliedump/1998/1127/sys/src/brazil/ip/devip.c /n/emeliedump/1999/0302/sys/src/brazil/ip/devip.c
1141c
	qunlock(c);
.
1132c
		qunlock(c);
.
1125c
		qunlock(c);
.
1120c
	qlock(c);
.
1112a
/*
 *  called with protocol locked
 */
.
1071,1073c
	qunlock(c);
.
1052,1053d
1048c
			qunlock(c);
.
1040c
		if(canqlock(c)){
.
1026c
			qlock(c);
.
1014,1018d
1007a
/*
 *  called with protocol locked
 */
.
472c
		qunlock(cv);
.
469c
	qlock(cv);
.
432c
			qunlock(cv);
.
425c
			qlock(cv);
.
401c
		qunlock(cv);
.
385c
			qunlock(cv);
.
383c
		qlock(cv);
.
370a
		qunlock(p);
		poperror();
.
369a
		qlock(p);
		if(waserror()){
			qunlock(p);
			nexterror();
		}
.
## diffname ip/devip.c 1999/0316
## diff -e /n/emeliedump/1999/0302/sys/src/brazil/ip/devip.c /n/emeliedump/1999/0316/sys/src/brazil/ip/devip.c
907a
		if(cb->nf < 1)
			error("short control request");
.
568,569c
		x = f->p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];
		if(x->remote == nil) {
			sprint(buf, "%I!%d\n", c->raddr, c->rport);
		} else {
			(*x->remote)(c, buf, Statelen-2);
		}
.
## diffname ip/devip.c 1999/0320
## diff -e /n/emeliedump/1999/0316/sys/src/brazil/ip/devip.c /n/emeliedump/1999/0320/sys/src/brazil/ip/devip.c
874a
	a = v;
.
873a
	char *a;
.
866c
ipwrite(Chan* ch, void *v, long n, vlong)
.
## diffname ip/devip.c 1999/0629
## diff -e /n/emeliedump/1999/0320/sys/src/brazil/ip/devip.c /n/emeliedump/1999/0629/sys/src/brazil/ip/devip.c
304,306d
288,289d
## diffname ip/devip.c 1999/0711
## diff -e /n/emeliedump/1999/0629/sys/src/brazil/ip/devip.c /n/emeliedump/1999/0711/sys/src/brazil/ip/devip.c
1038,1041c
			if(p->ptclsize != 0){
				c->ptcl = malloc(p->ptclsize);
				if(c->ptcl == nil) {
					free(c);
					error(Enomem);
				}
.
## diffname ip/devip.c 1999/0817
## diff -e /n/emeliedump/1999/0711/sys/src/brazil/ip/devip.c /n/emeliedump/1999/0817/sys/src/brazil/ip/devip.c
919a
		else if(strcmp(cb->f[0], "tos") == 0)
			tosctlmsg(c, cb);
.
851a
tosctlmsg(Conv *c, Cmdbuf *cb)
{
	if(cb->nf < 2)
		c->tos = 0;
	else
		c->tos = atoi(cb->f[1]);
}

static void
.
## diffname ip/devip.c 1999/0901
## diff -e /n/emeliedump/1999/0817/sys/src/brazil/ip/devip.c /n/emeliedump/1999/0901/sys/src/brazil/ip/devip.c
969c
	Conv *c;
	Proto *x;
	Fs *f;
	int n;

	switch(TYPE(ch->qid)){
	case Qdata:
		f = ipfs[ch->dev];
		x = f->p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];

		if(c->wq == nil)
			error(Eperm);

		if(bp->next)
			bp = concatblock(bp);
		n = BLEN(bp);
		qbwrite(c->wq, bp);
		x->kick(c, n);
		return n;
	default:
		return devbwrite(ch, bp, offset);
	}
.
967c
ipbwrite(Chan* ch, Block* bp, ulong offset)
.
614c
	Conv *c;
	Proto *x;
	Fs *f;

	switch(TYPE(ch->qid)){
	case Qdata:
		f = ipfs[ch->dev];
		x = f->p[PROTO(ch->qid)];
		c = x->conv[CONV(ch->qid)];
		return qbread(c->rq, n);
	default:
		return devbread(ch, n, offset);
	}
.
612c
ipbread(Chan* ch, long n, ulong offset)
.
## diffname ip/devip.c 1999/0910
## diff -e /n/emeliedump/1999/0901/sys/src/brazil/ip/devip.c /n/emeliedump/1999/0910/sys/src/brazil/ip/devip.c
465c
void
.
## diffname ip/devip.c 1999/1230
## diff -e /n/emeliedump/1999/0910/sys/src/brazil/ip/devip.c /n/emeliedump/1999/1230/sys/src/9/ip/devip.c
288,302c
	return devwalk(c, name, nil, 0, ipgen);
.
204a
		if(s == DEVDOTDOT){
			s = PROTO(c->qid);
			q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0};
			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
			return 1;
		}
.
196c
			devdir(c, q, name, 0, cv->owner, 0555, dp);
.
191a
		if(s == DEVDOTDOT){
			q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
			sprint(name, "#I%lud", c->dev);
			devdir(c, q, name, 0, network, 0555, dp);
			return 1;
		}
.
179c
			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
.
174a
		if(s == DEVDOTDOT){
			q = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0};
			sprint(name, "#I%lud", c->dev);
			devdir(c, q, name, 0, network, 0555, dp);
			return 1;
		}
.
## diffname ip/devip.c 2000/0116
## diff -e /n/emeliedump/1999/1230/sys/src/9/ip/devip.c /n/emeliedump/2000/0116/sys/src/9/ip/devip.c
1204a
}

long
ndbwrite(Fs *f, char *a, ulong off, int n)
{
	if(off != 0)
		error(Eio);
	if(n >= sizeof(f->ndb))
		error(Eio);
	memmove(f->ndb, a, n);
	f->ndb[n] = 0;
	return n;
.
920a
	case Qndb:
		return ndbwrite(f, a, offset, n);
		break;
.
894a
	ulong offset = off;
.
886c
ipwrite(Chan* ch, void *v, long n, vlong off)
.
552a
 	case Qndb:
		return readstr(offset, a, n, f->ndb);
.
191a
	case Qndb:
.
140a
	case Qndb:
		p = "ndb";
		q = (Qid){QID(0, 0, Qndb), 0};
		break;
.
57,58c
extern	void nullmediumlink(void);
extern	void pktmediumlink(void);
	long ndbwrite(Fs *f, char *a, ulong off, int n);
.
14a
	Qndb,
.
## diffname ip/devip.c 2000/0126
## diff -e /n/emeliedump/2000/0116/sys/src/9/ip/devip.c /n/emeliedump/2000/0126/sys/src/9/ip/devip.c
1227,1228c
	memmove(f->ndb+off, a, n);
	f->ndb[off+n] = 0;
.
1225c
	if(off+n >= sizeof(f->ndb))
.
1223c
	if(off > strlen(f->ndb))
.
352a
	case Qndb:
		if(omode & (OWRITE|OTRUNC) && !iseve())
			error(Eperm);
		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))
			f->ndb[0] = 0;
		break;
.
165c
	devdir(c, q, p, len, network, prot, dp);
.
145a
		len = strlen(f->ndb);
.
130a
	f = ipfs[c->dev];

.
129a
	int len = 0;
	Fs *f;
.
## diffname ip/devip.c 2000/0220
## diff -e /n/emeliedump/2000/0126/sys/src/9/ip/devip.c /n/emeliedump/2000/0220/sys/src/9/ip/devip.c
529,532d
367,369d
206d
161,164d
17d
## diffname ip/devip.c 2000/0424
## diff -e /n/emeliedump/2000/0220/sys/src/9/ip/devip.c /n/emeliedump/2000/0424/sys/src/9/ip/devip.c
1122a
		if(p->gc != nil && (*p->gc)(p))
			goto retry;
.
1086a
retry:
.
## diffname ip/devip.c 2000/1220
## diff -e /n/emeliedump/2000/0424/sys/src/9/ip/devip.c /n/emeliedump/2000/1220/sys/src/9/ip/devip.c
1213a
	c->state = Connected;
.
1132c
	c->state = Idle;
.
986c
		qunlock(c);
.
942c
			qunlock(c);
.
937,940c
		qlock(c);
.
840a

	qlock(c);
.
839a
	qunlock(c);

.
832a
	if(c->state != 0)
		error(Econinuse);
.
799a

	qlock(c);
.
798a
	qunlock(c);

.
791a
	if(c->state != 0)
		error(Econinuse);
.
505a
	cv->state = Idle;
	qunlock(cv);
.
504d
## diffname ip/devip.c 2000/1221
## diff -e /n/emeliedump/2000/1220/sys/src/9/ip/devip.c /n/emeliedump/2000/1221/sys/src/9/ip/devip.c
853a
	poperror();

.
852d
850a
	qunlock(c);
	if(waserror()){
		qlock(c);
		nexterror();
	}
.
849d
806a
	poperror();

.
805d
803a
	qunlock(c);
	if(waserror()){
		qlock(c);
		nexterror();
	}
.
802d
## diffname ip/devip.c 2000/1227
## diff -e /n/emeliedump/2000/1221/sys/src/9/ip/devip.c /n/emeliedump/2000/1227/sys/src/9/ip/devip.c
1234c
	nc->state = Connected;
.
## diffname ip/devip.c 2001/0118
## diff -e /n/emeliedump/2000/1227/sys/src/9/ip/devip.c /n/emeliedump/2001/0118/sys/src/9/ip/devip.c
869c
 *  called by protocol bind routine to set addresses
.
821a
	memset(c->raddr, 0, sizeof(c->raddr));
	c->rport = 0;
.
728,729c
		lport = atoi(p);
		if(lport != 0)
			setluniqueport(c, lport);
		else
.
709a
	ushort lport;
.
650a
 *  set a local port making sure the quad of raddr,rport,laddr,lport is unique
 */
static void
setluniqueport(Conv* c, int lport)
{
	Proto *p;
	Conv *xp;
	int x;

	p = c->p;

	qlock(p);
	for(x = 0; x < p->nc; x++){
		xp = p->conv[x];
		if(xp == nil)
			break;
		if((xp->state == Connected || xp->state == Announced)
		&& xp->lport == lport
		&& xp->rport == c->rport
		&& ipcmp(xp->raddr, c->raddr) == 0
		&& ipcmp(xp->laddr, c->laddr) == 0){
			qunlock(p);
			error("address in use");
		}
	}
	c->lport = lport;
	qunlock(p);
}


/*
.
## diffname ip/devip.c 2001/0126
## diff -e /n/emeliedump/2001/0118/sys/src/9/ip/devip.c /n/emeliedump/2001/0126/sys/src/9/ip/devip.c
914,915c
		return setladdrport(c, argv[1], 0);
.
862,863c
		return setladdrport(c, argv[1], 1);
.
809,810c
		return setladdrport(c, argv[2], 0);
.
765c
	} else
		rv = setluniqueport(c, 0);
	return rv;
.
761,762c
		if(lport > 0)
			rv = setluniqueport(c, lport);
.
742a
	rv = nil;

.
740a
	char *rv;
.
737c
static char*
.
677a
	return nil;
.
673c
			return "address in use";
.
666a
		if(xp == c)
			continue;
.
653c
static char*
.
## diffname ip/devip.c 2001/0209
## diff -e /n/emeliedump/2001/0126/sys/src/9/ip/devip.c /n/emeliedump/2001/0209/sys/src/9/ip/devip.c
771,772c
		else
			rv = setluniqueport(c, lport);
	}
.
765,769c
	if(announcing){
		if(p == nil){
			ipmove(c->laddr, IPnoaddr);
			lport = atoi(str);
		} else {
			if(strcmp(str, "*") == 0)
				ipmove(c->laddr, IPnoaddr);
			else
				parseip(c->laddr, str);
			lport = atoi(p);
		}
		rv = setluniqueport(c, lport);
	} else {
		if(p == nil){
			setladdr(c);
			lport = atoi(str);
		} else {
			if(strcmp(str, "*") == 0)
				setladdr(c);
			else
				parseip(c->laddr, str);
			lport = atoi(p);
		}
		if(lport <= 0)
.
761c
		if(strcmp(p, "r") == 0)
			p = nil;
.
754,759c
	if(p != nil){
.
734,738c
 *	[address!]port[!r]
.
## diffname ip/devip.c 2001/0210
## diff -e /n/emeliedump/2001/0209/sys/src/9/ip/devip.c /n/emeliedump/2001/0210/sys/src/9/ip/devip.c
784a
	if(lport <= 0)
		setlport(c);
	else
		rv = setluniqueport(c, lport);
.
780,783d
768d
## diffname ip/devip.c 2001/0227
## diff -e /n/emeliedump/2001/0210/sys/src/9/ip/devip.c /n/emeliedump/2001/0227/sys/src/9/ip/devip.c
800c
		if(strstr(p, "!r") != nil)
.
## diffname ip/devip.c 2001/0301
## diff -e /n/emeliedump/2001/0227/sys/src/9/ip/devip.c /n/emeliedump/2001/0301/sys/src/9/ip/devip.c
779a

	/* one process can get all connections */
	if(announcing && strcmp(p, "*") == 0){
		if(!iseve())
			error(Eperm);
		return setluniqueport(c, 0);
	}

	lport = atoi(p);
.
771,778c
		p = str;
	} else {
		if(strcmp(str, "*") == 0)
			ipmove(c->laddr, IPnoaddr);
		else
			parseip(c->laddr, str);
.
760,769c
		else
.
757,758c
	if(p == nil){
		if(announcing)
.
## diffname ip/devip.c 2001/0306
## diff -e /n/emeliedump/2001/0301/sys/src/9/ip/devip.c /n/emeliedump/2001/0306/sys/src/9/ip/devip.c
1084c
		x->kick(c);
.
991c
		x->kick(c);
.
## diffname ip/devip.c 2001/0403
## diff -e /n/emeliedump/2001/0306/sys/src/9/ip/devip.c /n/emeliedump/2001/0403/sys/src/9/ip/devip.c
475c
	Dir d;
	Conv *cv;
	Fs *f;
	Proto *p;

	f = ipfs[c->dev];
	switch(TYPE(c->qid)) {
	default:
		error(Eperm);
		break;
	case Qctl:
	case Qdata:
		break;
	}

	convM2D(dp, &d);

	p = f->p[PROTO(c->qid)];
	cv = p->conv[CONV(c->qid)];
	if(!iseve() && strcmp(commonuser(), cv->owner) != 0)
		error(Eperm);
	if(d.uid[0]){
		strncpy(cv->owner, d.uid, sizeof(cv->owner));
		cv->owner[sizeof(cv->owner)-1] = 0;
	}
	cv->perm = d.mode & 0777;
.
473c
ipwstat(Chan *c, char *dp)
.
421a
		if((perm & (cv->perm>>6)) != perm) {
			if(strcmp(commonuser(), cv->owner) != 0)
				error(Eperm);
		 	if((perm & cv->perm) != perm)
				error(Eperm); 

		}

.
101c
	devdir(c, q, p, 0, cv->owner, 0444, dp);
.
87c
		devdir(c, q, "listen", qlen(cv->eq), cv->owner, cv->perm, dp);
		return 1;
.
85d
## diffname ip/devip.c 2001/0405
## diff -e /n/emeliedump/2001/0403/sys/src/9/ip/devip.c /n/emeliedump/2001/0405/sys/src/9/ip/devip.c
560a
	free(c->aux);
.
502c
	if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
.
453c
				memmove(nc->owner, ATTACHER(c), NAMELEN);
.
423c
			if(strcmp(ATTACHER(c), cv->owner) != 0)
.
413c
			memmove(cv->owner, ATTACHER(c), NAMELEN);
.
405c
			if(strcmp(ATTACHER(c), cv->owner) != 0)
.
383c
		cv = Fsprotoclone(p, ATTACHER(c));
.
362d
306c
	IPaux *a = c->aux;

	nc = devclone(c, nc);
	nc->aux = newipaux(a->owner, a->tag);
	return nc;
.
299a
	c->aux = newipaux(commonuser(), "none");

.
284a
IPaux*
newipaux(char *owner, char *tag)
{
	IPaux *a;
	int n;

	a = smalloc(sizeof(*a));
	memmove(a->owner, owner, NAMELEN);
	memset(a->tag, ' ', sizeof(a->tag));
	n = strlen(tag);
	if(n > sizeof(a->tag))
		n = sizeof(a->tag);
	memmove(a->tag, tag, n);
	return a;
}

#define ATTACHER(c) (((IPaux*)((c)->aux))->owner)

.
68a
	if(cv->owner[0] == 0)
		memmove(cv->owner, eve, NAMELEN);
.
## diffname ip/devip.c 2001/0430
## diff -e /n/emeliedump/2001/0405/sys/src/9/ip/devip.c /n/emeliedump/2001/0430/sys/src/9/ip/devip.c
370,371c
	perm = m2p[omode&3];
.
## diffname ip/devip.c 2001/0527
## diff -e /n/emeliedump/2001/0430/sys/src/9/ip/devip.c /n/emeliedump/2001/0527/sys/src/9/ip/devip.c
1279c
		strncpy(c->cerr, msg, ERRMAX-1);
.
1258c
	kstrdup(&c->owner, user);
.
1184c
	p->qid.type = QTDIR;
	p->qid.path = QID(f->np, 0, Qprotodir);
.
1156d
741d
584a
	free(((IPaux*)c->aux)->owner);
.
555c
	kstrdup(&cv->owner, network);
.
532c
	return n;
.
522,530c
	n = convM2D(dp, n, &d, nil);
	if(n > 0){
		p = f->p[PROTO(c->qid)];
		cv = p->conv[CONV(c->qid)];
		if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
			error(Eperm);
		if(d.uid[0])
			kstrdup(&cv->owner, d.uid);
		cv->perm = d.mode & 0777;
.
504,505c
static int
ipwstat(Chan *c, uchar *dp, int n)
.
476,477c
				mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
				kstrdup(&cv->owner, ATTACHER(c));
.
437c
			kstrdup(&cv->owner, ATTACHER(c));
.
414c
		mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
.
370c
	omode &= 3;
	perm = m2p[omode];
.
341,346d
338c
	return devstat(c, db, n, nil, 0, ipgen);
.
336c
ipstat(Chan* c, uchar* db, int n)
.
330,332c
	w = devwalk(c, nc, name, nname, nil, 0, ipgen);
	if(w != nil && w->clone != nil)
		w->clone->aux = newipaux(a->owner, a->tag);
	return w;
.
328a
	Walkqid* w;
.
325,326c
static Walkqid*
ipwalk(Chan* c, Chan *nc, char **name, int nname)
.
317c
	mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);
.
294c
	kstrdup(&a->owner, owner);
.
227c
			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
.
214,216c
			sprint(up->genbuf, "%d", s);
			mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);
			devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);
.
207,209c
			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
			sprint(up->genbuf, "#I%lud", c->dev);
			devdir(c, q, up->genbuf, 0, network, 0555, dp);
.
192c
			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
.
184,186c
			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
			sprint(up->genbuf, "#I%lud", c->dev);
			devdir(c, q, up->genbuf, 0, network, 0555, dp);
.
176d
172c
ipgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
.
164d
160d
155d
150d
146d
142d
136a
	mkqid(&q, QID(0, 0, i), 0, QTFILE);
.
118c
		mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE);
.
114c
		mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);
.
100d
96d
92d
87d
83d
79d
75d
69,70c
	if(cv->owner == nil)
		kstrdup(&cv->owner, eve);
	mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);

.
46,48c
#define TYPE(x) 	( ((ulong)(x).path) & Masktype )
#define CONV(x) 	( (((ulong)(x).path) >> Shiftconv) & Maskconv )
#define PROTO(x) 	( (((ulong)(x).path) >> Shiftproto) & Maskproto )
.
## diffname ip/devip.c 2001/0922
## diff -e /n/emeliedump/2001/0527/sys/src/9/ip/devip.c /n/emeliedump/2001/0922/sys/src/9/ip/devip.c
1346a

ulong
scalednconv(void)
{
	if(cpuserver && conf.npage*BY2PG >= 128*MB)
		return Nchans*4;
	return Nchans;
}
.
## diffname ip/devip.c 2001/1106
## diff -e /n/emeliedump/2001/0922/sys/src/9/ip/devip.c /n/emeliedump/2001/1106/sys/src/9/ip/devip.c
517a
	n = convM2D(dp, n, d, nil);
	if(n == 0)
		error(Eshortstat);

	p = f->p[PROTO(c->qid)];
	cv = p->conv[CONV(c->qid)];
	if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
		error(Eperm);
	if(!emptystr(d->uid))
		kstrdup(&cv->owner, d->uid);
	if(d->mode != ~0UL)
		cv->perm = d->mode & 0777;

	poperror();
	free(d);
.
508,516c
	d = smalloc(n + sizeof(Dir));
	if(waserror()){
		free(d);
		nexterror();
.
493c
	Dir *d;
.
## diffname ip/devip.c 2001/1120
## diff -e /n/emeliedump/2001/1106/sys/src/9/ip/devip.c /n/emeliedump/2001/1120/sys/src/9/ip/devip.c
1108,1109c
		}

.
1104c
			break;
		case CMwildcard:
			if(x->ctl == nil)
				cmderror(cb, "unknown control request");
.
1097c
			break;
		case CMremmulti:
.
1082,1084c
			break;
		case CMaddmulti:
			if(cb->nf != 2 && cb->nf != 3)
				cmderror(cb, Ecmdargs);
.
1080c
			break;
		case CMtos:
.
1078c
			break;
		case CMttl:
.
1076c
			break;
		case CMbind:
.
1074c
			break;
		case CMannounce:
.
1072c

		ct = lookupcmd(cb, ipctlmsg, nelem(ipctlmsg));
		switch(ct->index){
		case CMconnect:
.
1052,1054c
		netlogctl(f, a, n);
.
1025a
	Cmdtab *ct;
.
56a
enum
{
	CMaddmulti,
	CMannounce,
	CMbind,
	CMconnect,
	CMremmulti,
	CMtos,
	CMttl,
	CMwildcard,
};

Cmdtab ipctlmsg[] =
{
	CMaddmulti,	"addmulti",	0,
	CMannounce,	"announce",	0,
	CMbind,		"bind",		0,
	CMconnect,	"connect",	0,
	CMremmulti,	"remmulti",	0,
	CMtos,		"tos",		0,
	CMttl,		"ttl",			0,
	CMwildcard,	"*",			0,
};

.
## diffname ip/devip.c 2001/1204
## diff -e /n/emeliedump/2001/1120/sys/src/9/ip/devip.c /n/emeliedump/2001/1204/sys/src/9/ip/devip.c
1196c
	devremove,
.
1190c
	devcreate,
.
502,513d
## diffname ip/devip.c 2001/1207
## diff -e /n/emeliedump/2001/1204/sys/src/9/ip/devip.c /n/emeliedump/2001/1207/sys/src/9/ip/devip.c
498a
	c->iounit = qiomaxatomic;
.
## diffname ip/devip.c 2002/0109
## diff -e /n/emeliedump/2001/1207/sys/src/9/ip/devip.c /n/emeliedump/2002/0109/sys/src/9/ip/devip.c
1174c
	devinit,
	devshutdown,
.
1082,1084d
264,266d
262d
## diffname ip/devip.c 2002/0217
## diff -e /n/emeliedump/2002/0109/sys/src/9/ip/devip.c /n/emeliedump/2002/0217/sys/src/9/ip/devip.c
263,267c
	fmtinstall('i', eipfmt);
	fmtinstall('I', eipfmt);
	fmtinstall('E', eipfmt);
	fmtinstall('V', eipfmt);
	fmtinstall('M', eipfmt);
.
## diffname ip/devip.c 2002/0324
## diff -e /n/emeliedump/2002/0217/sys/src/9/ip/devip.c /n/emeliedump/2002/0324/sys/src/9/ip/devip.c
1372a
	f->ndbvers++;
.
387a
			f->ndbvers++;
		}
.
386c
		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)){
.
384c
		if((omode & (OWRITE|OTRUNC)) && !iseve())
.
168a
		q.vers = f->ndbvers;
.
## diffname ip/devip.c 2002/0325
## diff -e /n/emeliedump/2002/0324/sys/src/9/ip/devip.c /n/emeliedump/2002/0325/sys/src/9/ip/devip.c
1376a
	f->ndbmtime = seconds();
.
182a
	if(i == Qndb)
		dp->mtime = f->ndbmtime;
.
## diffname ip/devip.c 2002/0507
## diff -e /n/emeliedump/2002/0325/sys/src/9/ip/devip.c /n/emeliedump/2002/0507/sys/src/9/ip/devip.c
1378,1379d
1184c
	ipremove,
.
1178c
	ipcreate,
.
1130,1131c
		} else 
			error("unknown control request");
.
1123,1126c
		} else if(x->ctl != nil) {
.
1115,1116c
		} else if(strcmp(cb->f[0], "remmulti") == 0){
.
1099,1102c
		else if(strcmp(cb->f[0], "addmulti") == 0){
			if(cb->nf < 2)
				error("addmulti needs interface address");
.
1096,1097c
		else if(strcmp(cb->f[0], "tos") == 0)
.
1093,1094c
		else if(strcmp(cb->f[0], "ttl") == 0)
.
1090,1091c
		else if(strcmp(cb->f[0], "bind") == 0)
.
1087,1088c
		else if(strcmp(cb->f[0], "announce") == 0)
.
1083,1085c
		if(cb->nf < 1)
			error("short control request");
		if(strcmp(cb->f[0], "connect") == 0)
.
1040d
751a

.
633a
	case Qipgate6:
		return ipgateread6(f, a, offset, n);
.
527,541d
522,525c
	n = convM2D(dp, n, &d, nil);
	if(n > 0){
		p = f->p[PROTO(c->qid)];
		cv = p->conv[CONV(c->qid)];
		if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
			error(Eperm);
		if(d.uid[0])
			kstrdup(&cv->owner, d.uid);
		cv->perm = d.mode & 0777;
.
507c
	Dir d;
.
503a
static void
ipcreate(Chan*, char*, int, ulong)
{
	error(Eperm);
}

static void
ipremove(Chan*)
{
	error(Eperm);
}

.
500d
407a
	case Qipgate6:
.
391,392d
389c
		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))
.
387c
		if(omode & (OWRITE|OTRUNC) && !iseve())
.
348a

.
219a
	case Qipgate6:
.
183,184d
177a
	case Qipgate6:
		p = "ipgate6";
		prot = 0444;
		break;
.
169d
57,80d
17a
	Qipgate6,
.
## diffname ip/devip.c 2002/0514
## diff -e /n/emeliedump/2002/0507/sys/src/9/ip/devip.c /n/emeliedump/2002/0514/sys/src/9/ip/devip.c
1350a
	f->ndbvers++;
	f->ndbmtime = seconds();
.
162a
	if(i == Qndb)
		dp->mtime = f->ndbmtime;
.
145a
		q.vers = f->ndbvers;
.
## diffname ip/devip.c 2002/0516
## diff -e /n/emeliedump/2002/0514/sys/src/9/ip/devip.c /n/emeliedump/2002/0516/sys/src/9/ip/devip.c
164c
	if(i == Qndb && f->ndbmtime > kerndate)
.
128a
	extern ulong	kerndate;
.
## diffname ip/devip.c 2002/0601
## diff -e /n/emeliedump/2002/0516/sys/src/9/ip/devip.c /n/emeliedump/2002/0601/sys/src/9/ip/devip.c
1338a
	nc->ipversion = version;

.
1311c
Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport, uchar version)
.
882a

	if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
		memcmp(c->laddr, v4prefix, IPv4off) == 0)
		|| ipcmp(c->raddr, IPnoaddr) == 0)
		c->ipversion = V4;
	else
		c->ipversion = V6;

.
881c
		p = setladdrport(c, argv[2], 0);
		if(p != nil)
			return p;
.
## diffname ip/devip.c 2002/0625
## diff -e /n/emeliedump/2002/0601/sys/src/9/ip/devip.c /n/emeliedump/2002/0625/sys/src/9/ip/devip.c
1090a
		else if(strcmp(cb->f[0], "ignoreadvice") == 0)
			c->ignoreadvice = 1;
.
## diffname ip/devip.c 2002/0711
## diff -e /n/emeliedump/2002/0625/sys/src/9/ip/devip.c /n/emeliedump/2002/0711/sys/src/9/ip/devip.c
1244c
			c->eq = qopen(1024, Qmsg, 0, 0);
.
1149c
		if(x->kick != nil)
			x->kick(c);
.
1056c
		if(x->kick != nil)
			x->kick(c);
.
## diffname ip/devip.c 2002/0712
## diff -e /n/emeliedump/2002/0711/sys/src/9/ip/devip.c /n/emeliedump/2002/0712/sys/src/9/ip/devip.c
1150,1151d
1056,1057d
## diffname ip/devip.c 2002/1110
## diff -e /n/emeliedump/2002/0712/sys/src/9/ip/devip.c /n/emeliedump/2002/1110/sys/src/9/ip/devip.c
665a
	case Qsnoop:
		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
		return qread(c->sq, a, n);
.
577a
		break;
	case Qsnoop:
		if(c->flag & COPEN)
			decref(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers);
		break;
.
393a
	case Qsnoop:
		if(omode != OREAD)
			error(Eperm);
		p = f->p[PROTO(c->qid)];
		cv = p->conv[CONV(c->qid)];
		if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())
			error(Eperm);
		incref(&cv->snoopers);
		break;
.
237a
	case Qsnoop:
.
94a
	case Qsnoop:
		if(strcmp(cv->p->name, "ipifc") != 0)
			return -1;
		devdir(c, q, "snoop", qlen(cv->sq), cv->owner, 0400, dp);
		return 1;
.
87c
		devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
.
34a
	Qsnoop,
.
## diffname ip/devip.c 2003/0308
## diff -e /n/emeliedump/2002/1110/sys/src/9/ip/devip.c /n/emeliedump/2003/0308/sys/src/9/ip/devip.c
1292a
	c->r = nil;
	c->rgen = 0;
.
570a
	cv->r = nil;
	cv->rgen = 0;
.
## diffname ip/devip.c 2003/0423
## diff -e /n/emeliedump/2003/0308/sys/src/9/ip/devip.c /n/emeliedump/2003/0423/sys/src/9/ip/devip.c
847,848c
		else {
			parseip(addr, str);
			if(ipforme(c->p->f, addr))
				ipmove(c->laddr, addr);
			else
				return "not a local IP address";
		}
.
822a
	uchar addr[IPaddrlen];
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.