forsyth20121205-174063a80cc13 years agoHistory
1119 lines · 19.5 KB · C
RawDownload
#include	"dat.h"#include	"fns.h"#include	"error.h"#include	"ip.h" enum{	Qtopdir		= 1,	/* top level directory */	Qtopbase,	Qarp=	Qtopbase,/*	Qiproute, *//*	Qipselftab,	*/	Qndb, 	Qprotodir,		/* directory for a protocol */	Qprotobase,	Qclone=	Qprotobase,	Qstats, 	Qconvdir,		/* directory for a conversation */	Qconvbase,	Qctl=	Qconvbase,	Qdata,	Qlisten,	Qlocal,	Qremote,	Qstatus, 	Logtype=	5,	Masktype=	(1<<Logtype)-1,	Logconv=	12,	Maskconv=	(1<<Logconv)-1,	Shiftconv=	Logtype,	Logproto=	8,	Maskproto=	(1<<Logproto)-1,	Shiftproto=	Logtype + Logconv, 	Statelen = 256, 	Nfs=	1, 	Maxproto	= 4,	MAXCONV		= 4096};#define TYPE(x) 	( ((ulong)(x).path) & Masktype )#define CONV(x) 	( (((ulong)(x).path) >> Shiftconv) & Maskconv )#define PROTO(x) 	( (((ulong)(x).path) >> Shiftproto) & Maskproto )#define QID(p, c, y) 	( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) ) enum{	Idle=		0,	Announcing=	1,	Announced=	2,	Connecting=	3,	Connected=	4,	Hungup=	5,}; struct Conv{	QLock	l; 	int	x;	/* conversation index */	Proto*	p; 	uchar	laddr[IPaddrlen];	/* local IP address */	uchar	raddr[IPaddrlen];	/* remote IP address */	int	restricted;	/* remote port is restricted */	ushort	lport;	/* local port number */	ushort	rport;	/* remote port number */ 	char*	owner;	/* protections */	int	perm;	int	inuse;	/* opens of listen/data/ctl */	int	state; 	/* udp specific */	int	headers;	/* data src/dst headers in udp */ 	char	cerr[ERRMAX]; 	QLock	listenq; 	void*	ptcl;	/* protocol specific stuff */ 	int	sfd;	QLock	wlock;	/* prevent data from being split by concurrent writes */}; struct Proto{	QLock	l;	int	x;	int	ipproto;	int	stype;	char*	name;	int	maxconv;	Fs*	f;	/* file system this proto is part of */	Conv**	conv;	/* array of conversations */	int	pctlsize;	/* size of per protocol ctl block */	int	nc;	/* number of conversations */	int	ac;	Qid	qid;	/* qid for protocol directory */	/* port allocation isn't done here when hosted */ 	void*	priv;}; /* * one per IP protocol stack */struct Fs{	RWlock	l;	int	dev; 	int	np;	Proto*	p[Maxproto+1];	/* list of supported protocols */	Proto*	t2p[256];	/* vector of all protocols */ 	char	ndb[1024];	/* an ndb entry for this interface */	int	ndbvers;	long	ndbmtime;}; static	Fs	*ipfs[Nfs];	/* attached fs's */static	char	network[] = "network";static	char* ipstates[] = {	"Closed",	/* Idle */	"Announcing",	"Announced",	"Connecting",	"Established",	/* Connected */	"Closed",	/* Hungup */}; static	Conv*	protoclone(Proto*, char*, int);static	Conv*	newconv(Proto*, Conv **);static	void	setladdr(Conv*); static intip3gen(Chan *c, int i, Dir *dp){	Qid q;	Conv *cv;	char *p; 	cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];	if(cv->owner == nil)		kstrdup(&cv->owner, eve);	mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE); 	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", 0, cv->owner, cv->perm, dp);		return 1;	case Qlisten:		devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);		return 1;	case Qlocal:		p = "local";		break;	case Qremote:		p = "remote";		break;	case Qstatus:		p = "status";		break;	}	devdir(c, q, p, 0, cv->owner, 0444, dp);	return 1;} static intip2gen(Chan *c, int i, Dir *dp){	Qid q; 	switch(i) {	case Qclone:		mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);		devdir(c, q, "clone", 0, network, 0666, dp);		return 1;	case Qstats:		mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE);		devdir(c, q, "stats", 0, network, 0444, dp);		return 1;	}		return -1;} static intip1gen(Chan *c, int i, Dir *dp){	Qid q;	char *p;	int prot;	int len = 0;	Fs *f;	extern ulong	kerndate; 	f = ipfs[c->dev]; 	prot = 0664;	mkqid(&q, QID(0, 0, i), 0, QTFILE);	switch(i) {	default:		return -1;	case Qarp:		p = "arp";		break;	case Qndb:		p = "ndb";		len = strlen(ipfs[c->dev]->ndb);		break;/*	case Qiproute:		p = "iproute";		break;	case Qipselftab:		p = "ipselftab";		prot = 0444;		break;	case Qiprouter:		p = "iprouter";		break;	case Qlog:		p = "log";		break;*/	}	devdir(c, q, p, len, network, prot, dp);	if(i == Qndb && f->ndbmtime > kerndate)		dp->mtime = f->ndbmtime;	return 1;} static intipgen(Chan *c, char *name, Dirtab *tab, int x, int s, Dir *dp){	Qid q;	Conv *cv;	Fs *f; 	USED(name);	USED(tab);	USED(x);	f = ipfs[c->dev]; 	switch(TYPE(c->qid)) {	case Qtopdir:		if(s == DEVDOTDOT){			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);			sprint(up->genbuf, "#I%lud", c->dev);			devdir(c, q, up->genbuf, 0, network, 0555, dp);			return 1;		}		if(s < f->np) {/*			if(f->p[s]->connect == nil)				return 0;	/* protocol with no user interface */			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);			return 1;		}		s -= f->np;		return ip1gen(c, s+Qtopbase, dp);	case Qarp:	case Qndb:/*	case Qiproute:	case Qiprouter:	case Qipselftab:	*/		return ip1gen(c, TYPE(c->qid), dp);	case Qprotodir:		if(s == DEVDOTDOT){			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);			sprint(up->genbuf, "#I%lud", c->dev);			devdir(c, q, up->genbuf, 0, network, 0555, dp);			return 1;		}		if(s < f->p[PROTO(c->qid)]->ac) {			cv = f->p[PROTO(c->qid)]->conv[s];			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);			return 1;		}		s -= f->p[PROTO(c->qid)]->ac;		return ip2gen(c, s+Qprotobase, dp);	case Qclone:	case Qstats:		return ip2gen(c, TYPE(c->qid), dp);	case Qconvdir:		if(s == DEVDOTDOT){			s = PROTO(c->qid);			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);			return 1;		}		return ip3gen(c, s+Qconvbase, dp);	case Qctl:	case Qdata:	case Qlisten:	case Qlocal:	case Qremote:	case Qstatus:		return ip3gen(c, TYPE(c->qid), dp);	}	return -1;} static voidnewproto(char *name, int type, int maxconv){	Proto *p; 	p = smalloc(sizeof(*p));	p->name = name;	p->stype = type;	p->ipproto = type+1;	/* temporary */	p->nc = maxconv;	if(Fsproto(ipfs[0], p))		panic("can't newproto %s", name);} voidipinit(void){	ipfs[0] = malloc(sizeof(Fs));	if(ipfs[0] == nil)		panic("no memory for IP stack"); 	newproto("udp", S_UDP, 64);	newproto("tcp", S_TCP, 2048); 	fmtinstall('i', eipfmt);	fmtinstall('I', eipfmt);	fmtinstall('E', eipfmt);	fmtinstall('V', eipfmt);	fmtinstall('M', eipfmt);} Chan *ipattach(char *spec){	Chan *c; 	if(atoi(spec) != 0)		error("bad specification"); 	c = devattach('I', spec);	mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);	c->dev = 0; 	return c;} static Walkqid*ipwalk(Chan* c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, nil, 0, ipgen);} static intipstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, 0, 0, ipgen);} static int m2p[] = {	4,	2,	6,}; static Chan *ipopen(Chan *c, int omode){	Conv *cv, *nc;	Proto *p;	uchar raddr[IPaddrlen];	ushort rport;	int perm, sfd;	Fs *f; 	perm = m2p[omode&3]; 	f = ipfs[c->dev]; 	switch(TYPE(c->qid)) {	default:		break;	case Qtopdir:	case Qprotodir:	case Qconvdir:	case Qstatus:	case Qremote:	case Qlocal:	case Qstats:	/* case Qipselftab: */		if(omode != OREAD)			error(Eperm);		break;	case Qndb:		if(omode & (OWRITE|OTRUNC) && !iseve())			error(Eperm);		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC)){			f->ndb[0] = 0;			f->ndbvers++;		}		break;	case Qclone:		p = f->p[PROTO(c->qid)];		cv = protoclone(p, up->env->user, -1);		if(cv == 0)			error(Enodev);		mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);		break;	case Qdata:	case Qctl:		p = f->p[PROTO(c->qid)];		qlock(&p->l);		cv = p->conv[CONV(c->qid)];		qlock(&cv->l);		if(waserror()){			qunlock(&cv->l);			qunlock(&p->l);			nexterror();		}		if((perm & (cv->perm>>6)) != perm) {			if(strcmp(up->env->user, cv->owner) != 0)				error(Eperm);			if((perm & cv->perm) != perm)				error(Eperm);		}		cv->inuse++;		if(cv->inuse == 1) {			kstrdup(&cv->owner, up->env->user);			cv->perm = 0660;			if(cv->sfd < 0)				cv->sfd = so_socket(p->stype);		}		poperror();		qunlock(&cv->l);		qunlock(&p->l);		break;	case Qlisten:		p = f->p[PROTO(c->qid)];		cv = p->conv[CONV(c->qid)];		if((perm & (cv->perm>>6)) != perm){			if(strcmp(up->env->user, cv->owner) != 0)				error(Eperm);			if((perm & cv->perm) != perm)				error(Eperm);		} 		if(cv->state != Announced)			error("not announced"); 		qlock(&cv->listenq);		if(waserror()){			qunlock(&cv->listenq);			nexterror();		} 		sfd = so_accept(cv->sfd, raddr, &rport); 		nc = protoclone(p, up->env->user, sfd);		if(nc == 0) {			so_close(sfd);			error(Enodev);		}		memmove(nc->raddr, raddr, IPaddrlen);		nc->rport = rport;		setladdr(nc);		nc->state = Connected;		mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE); 		poperror();		qunlock(&cv->listenq);		break;	}	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;} static voidcloseconv(Conv *cv){	int fd; 	qlock(&cv->l); 	if(--cv->inuse > 0) {

Lines 1–500 of 1119.