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

1999/0711/ip/devip.c (diff list | history)

ip/devip.c on 1997/0327
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, 
1997/0327    
	Qiproute, 
1998/0306    
	Qiprouter, 
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    
}; 
1998/0313    
#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) ) 
1997/0327    
 
static char network[] = "network"; 
 
1998/0313    
QLock	fslock; 
Fs	*ipfs[Nfs];	/* attached fs's */ 
Queue	*qlog; 
 
1998/0423    
extern void nullmediumlink(void); 
extern void pktmediumlink(void); 
 
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)]; 
1997/0327    
	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; 
	} 
1998/0306    
	devdir(c, q, p, 0, cv->owner, 0666, dp); 
1997/0327    
	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}; 
1998/0306    
		devdir(c, q, "clone", 0, network, 0666, dp); 
1997/0327    
		return 1; 
1998/0306    
	case Qstats: 
		q = (Qid){QID(PROTO(c->qid), 0, Qstats), 0}; 
		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; 
1997/0327    
 
1998/0310    
	prot = 0666; 
1997/0327    
	switch(i) { 
	default: 
		return -1; 
	case Qarp: 
		p = "arp"; 
		q = (Qid){QID(0, 0, Qarp), 0}; 
		break; 
1998/0313    
	case Qbootp: 
		p = "bootp"; 
		q = (Qid){QID(0, 0, Qbootp), 0}; 
		break; 
1997/0327    
	case Qiproute: 
		p = "iproute"; 
		q = (Qid){QID(0, 0, Qiproute), 0}; 
		break; 
1998/0310    
	case Qipselftab: 
		p = "ipselftab"; 
		prot = 0444; 
		q = (Qid){QID(0, 0, Qipselftab), 0}; 
		break; 
1998/0306    
	case Qiprouter: 
		p = "iprouter"; 
		q = (Qid){QID(0, 0, Qiprouter), 0}; 
		break; 
1997/0327    
	case Qlog: 
		p = "log"; 
		q = (Qid){QID(0, 0, Qlog), 0}; 
		break; 
	} 
1998/0310    
	devdir(c, q, p, 0, network, prot, dp); 
1997/0327    
	return 1; 
} 
 
static int 
ipgen(Chan *c, Dirtab*, int, int s, Dir *dp) 
{ 
	Qid q; 
	Conv *cv; 
	char name[16]; 
1998/0313    
	Fs *f; 
1997/0327    
 
1998/0313    
	f = ipfs[c->dev]; 
 
1997/0327    
	switch(TYPE(c->qid)) { 
	case Qtopdir: 
1998/0313    
		if(s < f->np) { 
			if(f->p[s]->connect == nil) 
1997/0423    
				return 0;	/* protocol with no user interface */ 
1997/0327    
			q = (Qid){QID(s, 0, Qprotodir)|CHDIR, 0}; 
1998/0313    
			devdir(c, q, f->p[s]->name, 0, network, CHDIR|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: 
1997/0327    
	case Qlog: 
	case Qiproute: 
1998/0306    
	case Qiprouter: 
1998/0310    
	case Qipselftab: 
1997/0327    
		return ip1gen(c, TYPE(c->qid), dp); 
	case Qprotodir: 
1998/0313    
		if(s < f->p[PROTO(c->qid)]->ac) { 
			cv = f->p[PROTO(c->qid)]->conv[s]; 
1997/0327    
			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; 
		} 
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: 
		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]; 
} 
 
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); 
	c->qid = (Qid){QID(0, 0, Qtopdir)|CHDIR, 0}; 
1998/0313    
	c->dev = dev; 
1997/0327    
 
	return c; 
} 
 
static Chan* 
ipclone(Chan* c, Chan* nc) 
{ 
	return devclone(c, nc); 
} 
 
static int 
ipwalk(Chan* c, char* name) 
{ 
1998/0306    
	if(strcmp(name, "..") != 0) 
		return devwalk(c, name, nil, 0, ipgen); 
1997/0327    
 
1998/0306    
	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); 
	} 
	return 1; 
1997/0327    
} 
 
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; 
1998/0313    
	Fs *f; 
1997/0327    
 
	omode &= 3; 
	perm = m2p[omode]; 
 
1998/0313    
	f = ipfs[c->dev]; 
 
1997/0327    
	switch(TYPE(c->qid)) { 
	default: 
		break; 
	case Qlog: 
1998/0313    
		netlogopen(f); 
1997/0327    
		break; 
1998/0306    
	case Qiprouter: 
1998/0313    
		iprouteropen(f); 
1998/0306    
		break; 
	case Qiproute: 
		memmove(c->tag, "none", sizeof(c->tag)); 
		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(); 
		} 
1998/0313    
		cv = Fsprotoclone(p, commonuser()); 
1999/0302    
		qunlock(p); 
		poperror(); 
1997/0327    
		if(cv == nil) { 
			error(Enodev); 
			break; 
		} 
		c->qid = (Qid){QID(p->x, cv->x, Qctl), 0}; 
		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) { 
1998/0313    
			if(strcmp(commonuser(), cv->owner) != 0) 
1997/0327    
				error(Eperm); 
		 	if((perm & cv->perm) != perm) 
				error(Eperm);  
 
		} 
		cv->inuse++; 
		if(cv->inuse == 1){ 
1998/0313    
			memmove(cv->owner, commonuser(), NAMELEN); 
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)]; 
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; 
				c->qid = (Qid){QID(PROTO(c->qid), nc->x, Qctl), 0}; 
1998/0313    
				memmove(cv->owner, commonuser(), NAMELEN); 
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); 
} 
 
static void 
ipwstat(Chan*, char*) 
{ 
	error(Eperm); 
} 
 
static void 
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    
 
	strcpy(cv->owner, network); 
	cv->perm = 0660; 
 
1998/0306    
	while((mp = cv->multi) != nil) 
		ipifcremmulti(cv, mp->ma, mp->ia); 
 
1997/0327    
	/* The close routine will unlock the conv */ 
	cv->p->close(cv); 
} 
 
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/0423    
		break; 
1998/0306    
	case Qiprouter: 
		if(c->flag & COPEN) 
1998/0313    
			iprouterclose(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    
	} 
} 
 
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); 
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* 
ipbread(Chan* c, long n, ulong offset) 
{ 
	return devbread(c, n, offset); 
} 
 
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    
/* 
 *  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 
 *	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) 
 */ 
1997/0327    
static void 
1998/0306    
setladdrport(Conv* c, char* str, int announcing) 
1997/0327    
{ 
1997/0423    
	char *p; 
1997/0327    
 
1997/1128    
	/* 
	 *  ignore restricted part if it exists.  it's 
	 *  meaningless on local ports. 
	 */ 
1997/0327    
	p = strchr(str, '!'); 
1997/1128    
	if(p == nil || strcmp(p, "!r") == 0) { 
1997/0327    
		p = str; 
1998/0306    
		memset(c->laddr, 0, sizeof(c->laddr)); 
		if(!announcing) 
1997/1030    
			setladdr(c); 
1998/0306    
	} else { 
1997/0327    
		*p++ = 0; 
1998/0306    
		parseip(c->laddr, str); 
1997/0327    
	} 
1998/0306    
 
	c->lport = 0; 
	if(*p != '*'){ 
1997/0327    
		c->lport = atoi(p); 
		if(c->lport == 0) 
			setlport(c); 
	} 
} 
 
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){ 
		if(strcmp(p, "!r") == 0) 
			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; 
		setladdrport(c, argv[2], 0); 
		break; 
	} 
	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    
 
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); 
	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 
 */ 
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    
 
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); 
	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]); 
} 
 
1997/0327    
static long 
1999/0320    
ipwrite(Chan* ch, void *v, long n, vlong) 
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; 
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); 
		x->kick(c, n); 
		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; 
	case Qctl: 
1998/0313    
		x = f->p[PROTO(ch->qid)]; 
1997/0327    
		c = x->conv[CONV(ch->qid)]; 
1998/0306    
		cb = parsecmd(a, n); 
 
		if(canqlock(&c->car) == 0){ 
			free(cb); 
			error("connect/announce in progress"); 
1997/0327    
		} 
1998/0306    
		if(waserror()) { 
1997/0327    
			qunlock(&c->car); 
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); 
		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"); 
		qunlock(&c->car); 
		free(cb); 
		poperror(); 
1997/0327    
	} 
	return n; 
} 
 
static long 
ipbwrite(Chan* c, Block* bp, ulong offset) 
{ 
	return devbwrite(c, bp, offset); 
} 
 
Dev ipdevtab = { 
1997/0408    
	'I', 
	"ip", 
 
1997/0327    
	ipreset, 
	ipinit, 
	ipattach, 
	ipclone, 
	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    
	} 
 
1998/0313    
	p->qid.path = CHDIR|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; 
 
	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) { 
		return nil; 
	} 
 
	c->inuse = 1; 
	strcpy(c->owner, user); 
	c->perm = 0660; 
	c->state = 0; 
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') 
		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* 
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; 
1999/0302    
	qunlock(c); 
1997/0327    
 
	wakeup(&c->listenr); 
 
	return nc; 
} 


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