plan 9 kernel history: overview | file list | diff list

2001/0527/ip/devip.c (diff list | history)

2001/0527/sys/src/9/ip/devip.c:1,13462001/0922/sys/src/9/ip/devip.c:1,1354 (short | long | prev | next)
1997/0327    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
#include	"../ip/ip.h" 
 
enum 
{ 
	Qtopdir=	1,		/* top level directory */ 
	Qtopbase, 
	Qarp=		Qtopbase, 
1998/0313    
	Qbootp, 
2000/0116    
	Qndb, 
1997/0327    
	Qiproute, 
1998/0310    
	Qipselftab, 
1997/0327    
	Qlog, 
 
	Qprotodir,			/* directory for a protocol */ 
	Qprotobase, 
	Qclone=		Qprotobase, 
1998/0306    
	Qstats, 
1997/0327    
 
	Qconvdir,			/* directory for a conversation */ 
	Qconvbase, 
	Qctl=		Qconvbase, 
	Qdata, 
	Qerr, 
	Qlisten, 
	Qlocal, 
	Qremote, 
	Qstatus, 
1998/0313    
 
	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, 
1997/0327    
}; 
2001/0527    
#define TYPE(x) 	( ((ulong)(x).path) & Masktype ) 
#define CONV(x) 	( (((ulong)(x).path) >> Shiftconv) & Maskconv ) 
#define PROTO(x) 	( (((ulong)(x).path) >> Shiftproto) & Maskproto ) 
1998/0313    
#define QID(p, c, y) 	( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) ) 
1997/0327    
 
static char network[] = "network"; 
 
1998/0313    
QLock	fslock; 
Fs	*ipfs[Nfs];	/* attached fs's */ 
Queue	*qlog; 
 
2000/0116    
extern	void nullmediumlink(void); 
extern	void pktmediumlink(void); 
	long ndbwrite(Fs *f, char *a, ulong off, int n); 
1998/0423    
 
1997/0327    
static int 
ip3gen(Chan *c, int i, Dir *dp) 
{ 
	Qid q; 
	Conv *cv; 
	char *p; 
 
1998/0313    
	cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)]; 
2001/0527    
	if(cv->owner == nil) 
		kstrdup(&cv->owner, eve); 
	mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE); 
 
1997/0327    
	switch(i) { 
	default: 
		return -1; 
	case Qctl: 
		devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp); 
		return 1; 
	case Qdata: 
		devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp); 
		return 1; 
	case Qerr: 
		devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp); 
		return 1; 
	case Qlisten: 
2001/0403    
		devdir(c, q, "listen", qlen(cv->eq), cv->owner, cv->perm, dp); 
		return 1; 
1997/0327    
	case Qlocal: 
		p = "local"; 
		break; 
	case Qremote: 
		p = "remote"; 
		break; 
	case Qstatus: 
		p = "status"; 
		break; 
	} 
2001/0403    
	devdir(c, q, p, 0, cv->owner, 0444, dp); 
1997/0327    
	return 1; 
} 
 
static int 
ip2gen(Chan *c, int i, Dir *dp) 
{ 
	Qid q; 
 
	switch(i) { 
	case Qclone: 
2001/0527    
		mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE); 
1998/0306    
		devdir(c, q, "clone", 0, network, 0666, dp); 
1997/0327    
		return 1; 
1998/0306    
	case Qstats: 
2001/0527    
		mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE); 
1998/0306    
		devdir(c, q, "stats", 0, network, 0444, dp); 
		return 1; 
1997/0327    
	}	 
	return -1; 
} 
 
static int 
ip1gen(Chan *c, int i, Dir *dp) 
{ 
	Qid q; 
	char *p; 
1998/0310    
	int prot; 
2000/0126    
	int len = 0; 
	Fs *f; 
1997/0327    
 
2000/0126    
	f = ipfs[c->dev]; 
 
1998/0310    
	prot = 0666; 
2001/0527    
	mkqid(&q, QID(0, 0, i), 0, QTFILE); 
1997/0327    
	switch(i) { 
	default: 
		return -1; 
	case Qarp: 
		p = "arp"; 
		break; 
1998/0313    
	case Qbootp: 
		p = "bootp"; 
		break; 
2000/0116    
	case Qndb: 
		p = "ndb"; 
2000/0126    
		len = strlen(f->ndb); 
2000/0116    
		break; 
1997/0327    
	case Qiproute: 
		p = "iproute"; 
		break; 
1998/0310    
	case Qipselftab: 
		p = "ipselftab"; 
		prot = 0444; 
		break; 
1997/0327    
	case Qlog: 
		p = "log"; 
		break; 
	} 
2000/0126    
	devdir(c, q, p, len, network, prot, dp); 
1997/0327    
	return 1; 
} 
 
static int 
2001/0527    
ipgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp) 
1997/0327    
{ 
	Qid q; 
	Conv *cv; 
1998/0313    
	Fs *f; 
1997/0327    
 
1998/0313    
	f = ipfs[c->dev]; 
 
1997/0327    
	switch(TYPE(c->qid)) { 
	case Qtopdir: 
1999/1230    
		if(s == DEVDOTDOT){ 
2001/0527    
			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); 
			sprint(up->genbuf, "#I%lud", c->dev); 
			devdir(c, q, up->genbuf, 0, network, 0555, dp); 
1999/1230    
			return 1; 
		} 
1998/0313    
		if(s < f->np) { 
			if(f->p[s]->connect == nil) 
1997/0423    
				return 0;	/* protocol with no user interface */ 
2001/0527    
			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); 
1999/1230    
			devdir(c, q, f->p[s]->name, 0, network, 0555, dp); 
1997/0327    
			return 1; 
		} 
1998/0313    
		s -= f->np; 
1997/0327    
		return ip1gen(c, s+Qtopbase, dp); 
	case Qarp: 
1998/0313    
	case Qbootp: 
2000/0116    
	case Qndb: 
1997/0327    
	case Qlog: 
	case Qiproute: 
1998/0310    
	case Qipselftab: 
1997/0327    
		return ip1gen(c, TYPE(c->qid), dp); 
	case Qprotodir: 
1999/1230    
		if(s == DEVDOTDOT){ 
2001/0527    
			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR); 
			sprint(up->genbuf, "#I%lud", c->dev); 
			devdir(c, q, up->genbuf, 0, network, 0555, dp); 
1999/1230    
			return 1; 
		} 
1998/0313    
		if(s < f->p[PROTO(c->qid)]->ac) { 
			cv = f->p[PROTO(c->qid)]->conv[s]; 
2001/0527    
			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); 
1997/0327    
			return 1; 
		} 
1998/0313    
		s -= f->p[PROTO(c->qid)]->ac; 
1997/0327    
		return ip2gen(c, s+Qprotobase, dp); 
	case Qclone: 
1998/0306    
	case Qstats: 
1997/0327    
		return ip2gen(c, TYPE(c->qid), dp); 
	case Qconvdir: 
1999/1230    
		if(s == DEVDOTDOT){ 
			s = PROTO(c->qid); 
2001/0527    
			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR); 
1999/1230    
			devdir(c, q, f->p[s]->name, 0, network, 0555, dp); 
			return 1; 
		} 
1997/0327    
		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) 
{ 
1998/0423    
	nullmediumlink(); 
	pktmediumlink(); 
1997/0327    
} 
 
static void 
ipinit(void) 
{ 
	fmtinstall('i', eipconv); 
	fmtinstall('I', eipconv); 
	fmtinstall('E', eipconv); 
1998/0306    
	fmtinstall('V', eipconv); 
	fmtinstall('M', eipconv); 
1997/0327    
} 
 
1998/0313    
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); 
1998/0924    
		f->dev = dev; 
1998/0313    
		ipfs[dev] = f; 
	} 
	qunlock(&fslock); 
 
	return ipfs[dev]; 
} 
 
2001/0405    
IPaux* 
newipaux(char *owner, char *tag) 
{ 
	IPaux *a; 
	int n; 
 
	a = smalloc(sizeof(*a)); 
2001/0527    
	kstrdup(&a->owner, owner); 
2001/0405    
	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) 
 
1997/0327    
static Chan* 
ipattach(char* spec) 
{ 
	Chan *c; 
1998/0313    
	int dev; 
1997/0327    
 
1998/0313    
	dev = atoi(spec); 
	if(dev >= 16) 
		error("bad specification"); 
 
	ipgetfs(dev); 
1997/0327    
	c = devattach('I', spec); 
2001/0527    
	mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR); 
1998/0313    
	c->dev = dev; 
1997/0327    
 
2001/0405    
	c->aux = newipaux(commonuser(), "none"); 
 
1997/0327    
	return c; 
} 
 
2001/0527    
static Walkqid* 
ipwalk(Chan* c, Chan *nc, char **name, int nname) 
1997/0327    
{ 
2001/0405    
	IPaux *a = c->aux; 
2001/0527    
	Walkqid* w; 
2001/0405    
 
2001/0527    
	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; 
1997/0327    
} 
 
static int 
2001/0527    
ipstat(Chan* c, uchar* db, int n) 
1997/0327    
{ 
2001/0527    
	return devstat(c, db, n, nil, 0, ipgen); 
1997/0327    
} 
 
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; 
1998/0313    
	Fs *f; 
1997/0327    
 
2001/0527    
	omode &= 3; 
	perm = m2p[omode]; 
1997/0327    
 
1998/0313    
	f = ipfs[c->dev]; 
 
1997/0327    
	switch(TYPE(c->qid)) { 
	default: 
		break; 
2000/0126    
	case Qndb: 
		if(omode & (OWRITE|OTRUNC) && !iseve()) 
			error(Eperm); 
		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)) 
			f->ndb[0] = 0; 
		break; 
1997/0327    
	case Qlog: 
1998/0313    
		netlogopen(f); 
1997/0327    
		break; 
1998/0306    
	case Qiproute: 
		break; 
1997/0327    
	case Qtopdir: 
	case Qprotodir: 
	case Qconvdir: 
	case Qstatus: 
	case Qremote: 
	case Qlocal: 
1998/0306    
	case Qstats: 
1998/0313    
	case Qbootp: 
1998/0310    
	case Qipselftab: 
1997/0327    
		if(omode != OREAD) 
			error(Eperm); 
		break; 
	case Qclone: 
1998/0313    
		p = f->p[PROTO(c->qid)]; 
1999/0302    
		qlock(p); 
		if(waserror()){ 
			qunlock(p); 
			nexterror(); 
		} 
2001/0405    
		cv = Fsprotoclone(p, ATTACHER(c)); 
1999/0302    
		qunlock(p); 
		poperror(); 
1997/0327    
		if(cv == nil) { 
			error(Enodev); 
			break; 
		} 
2001/0527    
		mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE); 
1997/0327    
		break; 
	case Qdata: 
	case Qctl: 
	case Qerr: 
1998/0313    
		p = f->p[PROTO(c->qid)]; 
1998/0306    
		qlock(p); 
1997/0327    
		cv = p->conv[CONV(c->qid)]; 
1999/0302    
		qlock(cv); 
1997/0327    
		if(waserror()) { 
1999/0302    
			qunlock(cv); 
1998/0306    
			qunlock(p); 
1997/0327    
			nexterror(); 
		} 
		if((perm & (cv->perm>>6)) != perm) { 
2001/0405    
			if(strcmp(ATTACHER(c), cv->owner) != 0) 
1997/0327    
				error(Eperm); 
		 	if((perm & cv->perm) != perm) 
				error(Eperm);  
 
		} 
		cv->inuse++; 
		if(cv->inuse == 1){ 
2001/0527    
			kstrdup(&cv->owner, ATTACHER(c)); 
1997/0327    
			cv->perm = 0660; 
		} 
1999/0302    
		qunlock(cv); 
1998/0306    
		qunlock(p); 
1997/0327    
		poperror(); 
		break; 
	case Qlisten: 
1998/0313    
		cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)]; 
2001/0403    
		if((perm & (cv->perm>>6)) != perm) { 
2001/0405    
			if(strcmp(ATTACHER(c), cv->owner) != 0) 
2001/0403    
				error(Eperm); 
		 	if((perm & cv->perm) != perm) 
				error(Eperm);  
 
		} 
 
1997/0327    
		if(cv->state != Announced) 
			error("not announced"); 
 
		nc = nil; 
		while(nc == nil) { 
1998/1127    
			/* give up if we got a hangup */ 
			if(qisclosed(cv->rq)) 
				error("listen hungup"); 
 
1997/0327    
			qlock(&cv->listenq); 
			if(waserror()) { 
				qunlock(&cv->listenq); 
				nexterror(); 
			} 
 
1998/1127    
			/* wait for a connect */ 
1997/0327    
			sleep(&cv->listenr, incoming, cv); 
 
1999/0302    
			qlock(cv); 
1997/0327    
			nc = cv->incall; 
			if(nc != nil){ 
				cv->incall = nc->next; 
2001/0527    
				mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE); 
				kstrdup(&cv->owner, ATTACHER(c)); 
1997/0327    
			} 
1999/0302    
			qunlock(cv); 
1997/0327    
 
			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); 
} 
 
2001/0527    
static int 
ipwstat(Chan *c, uchar *dp, int n) 
1997/0327    
{ 
2001/0403    
	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; 
	} 
 
2001/0527    
	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; 
2001/0403    
	} 
2001/0527    
	return n; 
1997/0327    
} 
 
1999/0910    
void 
1997/0327    
closeconv(Conv *cv) 
{ 
	Conv *nc; 
1998/0306    
	Ipmulti *mp; 
1997/0327    
 
1999/0302    
	qlock(cv); 
1998/0306    
 
1997/0327    
	if(--cv->inuse > 0) { 
1999/0302    
		qunlock(cv); 
1997/0327    
		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); 
	} 
1998/0321    
	cv->incall = nil; 
1997/0327    
 
2001/0527    
	kstrdup(&cv->owner, network); 
1997/0327    
	cv->perm = 0660; 
 
1998/0306    
	while((mp = cv->multi) != nil) 
		ipifcremmulti(cv, mp->ma, mp->ia); 
 
1997/0327    
	cv->p->close(cv); 
2000/1220    
	cv->state = Idle; 
	qunlock(cv); 
1997/0327    
} 
 
static void 
ipclose(Chan* c) 
{ 
1998/0313    
	Fs *f; 
 
	f = ipfs[c->dev]; 
1997/0327    
	switch(TYPE(c->qid)) { 
	default: 
		break; 
1998/0306    
	case Qlog: 
1997/0531    
		if(c->flag & COPEN) 
1998/0313    
			netlogclose(f); 
1997/0327    
		break; 
	case Qdata: 
	case Qctl: 
	case Qerr: 
		if(c->flag & COPEN) 
1998/0313    
			closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]); 
1997/0327    
	} 
2001/0527    
	free(((IPaux*)c->aux)->owner); 
2001/0405    
	free(c->aux); 
1997/0327    
} 
 
1998/0306    
enum 
{ 
1998/0717    
	Statelen=	32*1024, 
1998/0306    
}; 
 
1997/0327    
static long 
1998/0319    
ipread(Chan *ch, void *a, long n, vlong off) 
1997/0327    
{ 
	Conv *c; 
	Proto *x; 
1998/0306    
	char *buf, *p; 
1998/0710    
	long rv; 
1998/0313    
	Fs *f; 
1998/0319    
	ulong offset = off; 
1997/0327    
 
1998/0313    
	f = ipfs[ch->dev]; 
 
1997/0327    
	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: 
1998/0313    
		return arpread(f->arp, a, offset, n); 
 	case Qbootp: 
 		return bootpread(a, offset, n); 
2000/0116    
 	case Qndb: 
		return readstr(offset, a, n, f->ndb); 
1997/0327    
	case Qiproute: 
1998/0313    
		return routeread(f, a, offset, n); 
1998/0310    
	case Qipselftab: 
1998/0313    
		return ipselftabread(f, a, offset, n); 
1997/0327    
	case Qlog: 
1998/0313    
		return netlogread(f, a, offset, n); 
1997/0327    
	case Qctl: 
1998/0306    
		buf = smalloc(16); 
1998/0825    
		sprint(buf, "%lud", CONV(ch->qid)); 
1998/0306    
		rv = readstr(offset, p, n, buf); 
		free(buf); 
		return rv; 
1997/0327    
	case Qremote: 
1998/0306    
		buf = smalloc(Statelen); 
1999/0316    
		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); 
		} 
1998/0306    
		rv = readstr(offset, p, n, buf); 
		free(buf); 
		return rv; 
1997/0327    
	case Qlocal: 
1998/0306    
		buf = smalloc(Statelen); 
1998/0313    
		x = f->p[PROTO(ch->qid)]; 
1998/0306    
		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; 
1997/0327    
	case Qstatus: 
1998/0306    
		buf = smalloc(Statelen); 
1998/0313    
		x = f->p[PROTO(ch->qid)]; 
1997/0327    
		c = x->conv[CONV(ch->qid)]; 
1998/0709    
		(*x->state)(c, buf, Statelen-2); 
1998/0306    
		rv = readstr(offset, p, n, buf); 
		free(buf); 
		return rv; 
1997/0327    
	case Qdata: 
1998/0313    
		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; 
1997/1105    
		return qread(c->rq, a, n); 
1997/0327    
	case Qerr: 
1998/0313    
		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)]; 
1997/0327    
		return qread(c->eq, a, n); 
1998/0306    
	case Qstats: 
1998/0313    
		x = f->p[PROTO(ch->qid)]; 
1998/0306    
		if(x->stats == nil) 
			error("stats not implemented"); 
		buf = smalloc(Statelen); 
1998/0313    
		(*x->stats)(x, buf, Statelen); 
1998/0306    
		rv = readstr(offset, p, n, buf); 
		free(buf); 
		return rv; 
1997/0327    
	} 
} 
 
static Block* 
1999/0901    
ipbread(Chan* ch, long n, ulong offset) 
1997/0327    
{ 
1999/0901    
	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); 
	} 
1997/0327    
} 
 
1998/0306    
/* 
 *  set local address to be that of the ifc closest to remote address 
 */ 
1997/0327    
static void 
setladdr(Conv* c) 
{ 
1998/0313    
	findlocalip(c->p->f, c->laddr, c->raddr); 
1997/0327    
} 
 
1998/0306    
/* 
2001/0118    
 *  set a local port making sure the quad of raddr,rport,laddr,lport is unique 
 */ 
2001/0126    
static char* 
2001/0118    
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; 
2001/0126    
		if(xp == c) 
			continue; 
2001/0118    
		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); 
2001/0126    
			return "address in use"; 
2001/0118    
		} 
	} 
	c->lport = lport; 
	qunlock(p); 
2001/0126    
	return nil; 
2001/0118    
} 
 
/* 
1998/0306    
 *  pick a local port and set it 
 */ 
1997/0327    
static void 
setlport(Conv* c) 
{ 
	Proto *p; 
	ushort *pp; 
	int x, found; 
 
	p = c->p; 
	if(c->restricted) 
		pp = &p->nextrport; 
	else 
		pp = &p->nextport; 
1998/0306    
	qlock(p); 
1997/0327    
	for(;;(*pp)++){ 
1997/0508    
		/* 
		 * 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 
1997/0811    
		 * has wrapped round, select a random port between 5000 and 1<<15 
1997/0508    
		 * to start at. 
		 */ 
		if(c->restricted){ 
			if(*pp >= 1024) 
1997/0327    
				*pp = 600; 
		} 
1997/0508    
		else while(*pp < 5000) 
1997/0811    
			*pp = nrand(1<<15); 
1997/0508    
 
1997/0327    
		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)++; 
1998/0306    
	qunlock(p); 
1997/0327    
} 
 
1998/0306    
/* 
 *  set a local address and port from a string of the form 
2001/0209    
 *	[address!]port[!r] 
1998/0306    
 */ 
2001/0126    
static char* 
1998/0306    
setladdrport(Conv* c, char* str, int announcing) 
1997/0327    
{ 
1997/0423    
	char *p; 
2001/0126    
	char *rv; 
2001/0118    
	ushort lport; 
1997/0327    
 
2001/0126    
	rv = nil; 
 
1997/1128    
	/* 
	 *  ignore restricted part if it exists.  it's 
	 *  meaningless on local ports. 
	 */ 
1997/0327    
	p = strchr(str, '!'); 
2001/0209    
	if(p != nil){ 
1997/0327    
		*p++ = 0; 
2001/0209    
		if(strcmp(p, "r") == 0) 
			p = nil; 
1997/0327    
	} 
1998/0306    
 
	c->lport = 0; 
2001/0301    
	if(p == nil){ 
		if(announcing) 
2001/0209    
			ipmove(c->laddr, IPnoaddr); 
2001/0301    
		else 
2001/0209    
			setladdr(c); 
2001/0301    
		p = str; 
	} else { 
		if(strcmp(str, "*") == 0) 
			ipmove(c->laddr, IPnoaddr); 
		else 
			parseip(c->laddr, str); 
2001/0209    
	} 
2001/0301    
 
	/* one process can get all connections */ 
	if(announcing && strcmp(p, "*") == 0){ 
		if(!iseve()) 
			error(Eperm); 
		return setluniqueport(c, 0); 
	} 
 
	lport = atoi(p); 
2001/0210    
	if(lport <= 0) 
		setlport(c); 
	else 
		rv = setluniqueport(c, lport); 
2001/0126    
	return rv; 
1997/0327    
} 
 
static char* 
setraddrport(Conv* c, char* str) 
{ 
1997/0423    
	char *p; 
1997/0327    
 
	p = strchr(str, '!'); 
	if(p == nil) 
		return "malformed address"; 
	*p++ = 0; 
1998/0306    
	parseip(c->raddr, str); 
1997/0327    
	c->rport = atoi(p); 
	p = strchr(p, '!'); 
	if(p){ 
2001/0227    
		if(strstr(p, "!r") != nil) 
1997/0327    
			c->restricted = 1; 
	} 
	return nil; 
} 
 
1998/0306    
/* 
 *  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; 
2001/0126    
		return setladdrport(c, argv[2], 0); 
1998/0306    
	} 
	return nil; 
} 
/* 
 *  initiate connection and sleep till its set up 
 */ 
1997/0327    
static int 
connected(void* a) 
{ 
	return ((Conv*)a)->state == Connected; 
} 
1998/0306    
static void 
connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb) 
{ 
	char *p; 
1997/0327    
 
2000/1220    
	if(c->state != 0) 
		error(Econinuse); 
1998/0306    
	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); 
2000/1220    
 
2000/1221    
	qunlock(c); 
	if(waserror()){ 
		qlock(c); 
		nexterror(); 
	} 
1998/0306    
	sleep(&c->cr, connected, c); 
2000/1220    
	qlock(c); 
2000/1221    
	poperror(); 
 
1998/0306    
	if(c->cerr[0] != '\0') 
		error(c->cerr); 
} 
 
/* 
 *  called by protocol announce routine to set addresses 
 */ 
char* 
Fsstdannounce(Conv* c, char* argv[], int argc) 
{ 
2001/0118    
	memset(c->raddr, 0, sizeof(c->raddr)); 
	c->rport = 0; 
1998/0306    
	switch(argc){ 
	default: 
		return "bad args to announce"; 
	case 2: 
2001/0126    
		return setladdrport(c, argv[1], 1); 
1998/0306    
	} 
	return nil; 
} 
 
/* 
 *  initiate announcement and sleep till its set up 
 */ 
1997/0327    
static int 
announced(void* a) 
{ 
	return ((Conv*)a)->state == Announced; 
} 
1998/0306    
static void 
announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb) 
{ 
	char *p; 
1997/0327    
 
2000/1220    
	if(c->state != 0) 
		error(Econinuse); 
1998/0306    
	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); 
2000/1220    
 
2000/1221    
	qunlock(c); 
	if(waserror()){ 
		qlock(c); 
		nexterror(); 
	} 
1998/0306    
	sleep(&c->cr, announced, c); 
2000/1220    
	qlock(c); 
2000/1221    
	poperror(); 
 
1998/0306    
	if(c->cerr[0] != '\0') 
		error(c->cerr); 
} 
 
/* 
2001/0118    
 *  called by protocol bind routine to set addresses 
1998/0306    
 */ 
char* 
Fsstdbind(Conv* c, char* argv[], int argc) 
{ 
	switch(argc){ 
	default: 
		return "bad args to bind"; 
	case 2: 
2001/0126    
		return setladdrport(c, argv[1], 0); 
1998/0306    
	} 
	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 
1999/0817    
tosctlmsg(Conv *c, Cmdbuf *cb) 
{ 
	if(cb->nf < 2) 
		c->tos = 0; 
	else 
		c->tos = atoi(cb->f[1]); 
} 
 
static void 
1998/0306    
ttlctlmsg(Conv *c, Cmdbuf *cb) 
{ 
	if(cb->nf < 2) 
		c->ttl = MAXTTL; 
	else 
		c->ttl = atoi(cb->f[1]); 
} 
 
1997/0327    
static long 
2000/0116    
ipwrite(Chan* ch, void *v, long n, vlong off) 
1997/0327    
{ 
	Conv *c; 
	Proto *x; 
1998/0306    
	char *p; 
	Cmdbuf *cb; 
1998/0502    
	uchar ia[IPaddrlen], ma[IPaddrlen]; 
1998/0313    
	Fs *f; 
1999/0320    
	char *a; 
2000/0116    
	ulong offset = off; 
1997/0327    
 
1999/0320    
	a = v; 
1998/0313    
	f = ipfs[ch->dev]; 
 
1997/0327    
	switch(TYPE(ch->qid)){ 
	default: 
		error(Eperm); 
1998/0306    
	case Qdata: 
1998/0313    
		x = f->p[PROTO(ch->qid)]; 
1998/0306    
		c = x->conv[CONV(ch->qid)]; 
 
		if(c->wq == nil) 
			error(Eperm); 
 
		qwrite(c->wq, a, n); 
2001/0306    
		x->kick(c); 
1998/0306    
		break; 
1997/0327    
	case Qarp: 
1998/0630    
		return arpwrite(f, a, n); 
1997/0327    
	case Qiproute: 
1998/0313    
		return routewrite(f, ch, a, n); 
1997/0327    
	case Qlog: 
1998/0313    
		p = netlogctl(f, a, n); 
1997/0327    
		if(p != nil) 
			error(p); 
		return n; 
2000/0116    
	case Qndb: 
		return ndbwrite(f, a, offset, n); 
		break; 
1997/0327    
	case Qctl: 
1998/0313    
		x = f->p[PROTO(ch->qid)]; 
1997/0327    
		c = x->conv[CONV(ch->qid)]; 
1998/0306    
		cb = parsecmd(a, n); 
 
2000/1220    
		qlock(c); 
1998/0306    
		if(waserror()) { 
2000/1220    
			qunlock(c); 
1998/0306    
			free(cb); 
			nexterror(); 
1997/0327    
		} 
1999/0316    
		if(cb->nf < 1) 
			error("short control request"); 
1998/0306    
		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); 
1999/0817    
		else if(strcmp(cb->f[0], "tos") == 0) 
			tosctlmsg(c, cb); 
1998/0306    
		else if(strcmp(cb->f[0], "addmulti") == 0){ 
			if(cb->nf < 2) 
				error("addmulti needs interface address"); 
1998/0502    
			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); 
			} 
1998/0306    
		} 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); 
1997/0327    
			if(p != nil) 
				error(p); 
1998/0306    
		} else 
			error("unknown control request"); 
2000/1220    
		qunlock(c); 
1998/0306    
		free(cb); 
		poperror(); 
1997/0327    
	} 
	return n; 
} 
 
static long 
1999/0901    
ipbwrite(Chan* ch, Block* bp, ulong offset) 
1997/0327    
{ 
1999/0901    
	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); 
2001/0306    
		x->kick(c); 
1999/0901    
		return n; 
	default: 
		return devbwrite(ch, bp, offset); 
	} 
1997/0327    
} 
 
Dev ipdevtab = { 
1997/0408    
	'I', 
	"ip", 
 
1997/0327    
	ipreset, 
	ipinit, 
	ipattach, 
	ipwalk, 
	ipstat, 
	ipopen, 
	ipcreate, 
	ipclose, 
	ipread, 
	ipbread, 
	ipwrite, 
	ipbwrite, 
	ipremove, 
	ipwstat, 
}; 
 
int 
1998/0313    
Fsproto(Fs *f, Proto *p) 
1997/0327    
{ 
1998/0313    
	if(f->np >= Maxproto) 
1997/0327    
		return -1; 
 
1998/0313    
	p->f = f; 
 
1997/0327    
	if(p->ipproto > 0){ 
1998/0313    
		if(f->t2p[p->ipproto] != nil) 
1997/0327    
			return -1; 
1998/0313    
		f->t2p[p->ipproto] = p; 
1997/0327    
	} 
 
2001/0527    
	p->qid.type = QTDIR; 
	p->qid.path = QID(f->np, 0, Qprotodir); 
1997/0327    
	p->conv = malloc(sizeof(Conv*)*(p->nc+1)); 
	if(p->conv == nil) 
		panic("Fsproto"); 
 
1998/0313    
	p->x = f->np; 
1997/0327    
	p->nextport = 0; 
	p->nextrport = 600; 
1998/0313    
	f->p[f->np++] = p; 
 
1997/0327    
	return 0; 
} 
 
/* 
 *  return true if this protocol is 
 *  built in 
 */ 
int 
1998/0313    
Fsbuiltinproto(Fs* f, uchar proto) 
1997/0327    
{ 
1998/0313    
	return f->t2p[proto] != nil; 
1997/0327    
} 
 
1999/0302    
/* 
 *  called with protocol locked 
 */ 
1997/0327    
Conv* 
Fsprotoclone(Proto *p, char *user) 
{ 
	Conv *c, **pp, **ep; 
 
2000/0424    
retry: 
1997/0327    
	c = nil; 
	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); 
1999/0302    
			qlock(c); 
1997/0327    
			c->p = p; 
			c->x = pp - p->conv; 
1999/0711    
			if(p->ptclsize != 0){ 
				c->ptcl = malloc(p->ptclsize); 
				if(c->ptcl == nil) { 
					free(c); 
					error(Enomem); 
				} 
1997/0327    
			} 
			*pp = c; 
			p->ac++; 
			c->eq = qopen(1024, 1, 0, 0); 
			(*p->create)(c); 
			break; 
		} 
1999/0302    
		if(canqlock(c)){ 
1998/0306    
			/* 
			 *  make sure both processes and protocol 
			 *  are done with this Conv 
			 */ 
			if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0)) 
1997/0327    
				break; 
 
1999/0302    
			qunlock(c); 
1997/0327    
		} 
	} 
	if(pp >= ep) { 
2000/0424    
		if(p->gc != nil && (*p->gc)(p)) 
			goto retry; 
1997/0327    
		return nil; 
	} 
 
	c->inuse = 1; 
2001/0527    
	kstrdup(&c->owner, user); 
1997/0327    
	c->perm = 0660; 
2000/1220    
	c->state = Idle; 
1998/0306    
	ipmove(c->laddr, IPnoaddr); 
	ipmove(c->raddr, IPnoaddr); 
1997/0327    
	c->lport = 0; 
	c->rport = 0; 
	c->restricted = 0; 
	c->ttl = MAXTTL; 
	qreopen(c->rq); 
	qreopen(c->wq); 
	qreopen(c->eq); 
 
1999/0302    
	qunlock(c); 
1997/0327    
	return c; 
} 
 
int 
1998/0313    
Fsconnected(Conv* c, char* msg) 
1997/0327    
{ 
	if(msg != nil && *msg != '\0') 
2001/0527    
		strncpy(c->cerr, msg, ERRMAX-1); 
1997/0327    
 
	switch(c->state){ 
 
	case Announcing: 
		c->state = Announced; 
		break; 
 
	case Connecting: 
		c->state = Connected; 
		break; 
	} 
 
	wakeup(&c->cr); 
	return 0; 
} 
 
Proto* 
1998/0313    
Fsrcvpcol(Fs* f, uchar proto) 
1997/0327    
{ 
1998/0327    
	if(f->ipmux) 
1998/0324    
		return f->ipmux; 
	else 
		return f->t2p[proto]; 
1997/0327    
} 
 
1998/0509    
Proto* 
Fsrcvpcolx(Fs *f, uchar proto) 
{ 
	return f->t2p[proto]; 
} 
 
1999/0302    
/* 
 *  called with protocol locked 
 */ 
1997/0327    
Conv* 
1998/0313    
Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport) 
1997/0327    
{ 
	Conv *nc; 
	Conv **l; 
	int i; 
 
1999/0302    
	qlock(c); 
1997/0327    
	i = 0; 
	for(l = &c->incall; *l; l = &(*l)->next) 
		i++; 
	if(i >= Maxincall) { 
1999/0302    
		qunlock(c); 
1997/0327    
		return nil; 
	} 
 
	/* find a free conversation */ 
	nc = Fsprotoclone(c->p, network); 
	if(nc == nil) { 
1999/0302    
		qunlock(c); 
1997/0327    
		return nil; 
	} 
1998/0306    
	ipmove(nc->raddr, raddr); 
1997/0327    
	nc->rport = rport; 
1998/0306    
	ipmove(nc->laddr, laddr); 
1997/0327    
	nc->lport = lport; 
	nc->next = nil; 
	*l = nc; 
2000/1227    
	nc->state = Connected; 
1999/0302    
	qunlock(c); 
1997/0327    
 
	wakeup(&c->listenr); 
 
	return nc; 
2000/0116    
} 
 
long 
ndbwrite(Fs *f, char *a, ulong off, int n) 
{ 
2000/0126    
	if(off > strlen(f->ndb)) 
2000/0116    
		error(Eio); 
2000/0126    
	if(off+n >= sizeof(f->ndb)) 
2000/0116    
		error(Eio); 
2000/0126    
	memmove(f->ndb+off, a, n); 
	f->ndb[off+n] = 0; 
2000/0116    
	return n; 
1997/0327    
} 
2001/0922    
 
ulong 
scalednconv(void) 
{ 
	if(cpuserver && conf.npage*BY2PG >= 128*MB) 
		return Nchans*4; 
	return Nchans; 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)