1417 lines · 23.9 KB · C
RawDownload
#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,	Qbootp,	Qndb,	Qiproute,	Qiprouter,	Qipselftab,	Qlog, 	Qprotodir,			/* directory for a protocol */	Qprotobase,	Qclone=		Qprotobase,	Qstats, 	Qconvdir,			/* directory for a conversation */	Qconvbase,	Qctl=		Qconvbase,	Qdata,	Qerr,	Qlisten,	Qlocal,	Qremote,	Qstatus,	Qsnoop, 	Logtype=	5,	Masktype=	(1<<Logtype)-1,	Logconv=	12,	Maskconv=	(1<<Logconv)-1,	Shiftconv=	Logtype,	Logproto=	8,	Maskproto=	(1<<Logproto)-1,	Shiftproto=	Logtype + Logconv, 	Nfs=		32,};#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) ) static char network[] = "network"; QLock	fslock;Fs	*ipfs[Nfs];	/* attached fs's */Queue	*qlog; extern	void nullmediumlink(void);extern	void pktmediumlink(void);static	long ndbwrite(Fs*, char*, ulong, int);static	void	closeconv(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", 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:		devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);		return 1;	case Qlocal:		p = "local";		break;	case Qremote:		p = "remote";		break;	case Qsnoop:		if(strcmp(cv->p->name, "ipifc") != 0)			return -1;		devdir(c, q, "snoop", qlen(cv->sq), cv->owner, 0400, dp);		return 1;	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 = 0666;	mkqid(&q, QID(0, 0, i), 0, QTFILE);	switch(i) {	default:		return -1;	case Qarp:		p = "arp";		break;	case Qbootp:		p = "bootp";		if(bootp == nil)			return 0;		break;	case Qndb:		p = "ndb";		len = strlen(f->ndb);		q.vers = f->ndbvers;		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*, Dirtab*, int, int s, Dir *dp){	Qid q;	Conv *cv;	Fs *f; 	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 Qbootp:	case Qndb:	case Qlog:	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 Qerr:	case Qlisten:	case Qlocal:	case Qremote:	case Qstatus:	case Qsnoop:		return ip3gen(c, TYPE(c->qid), dp);	}	return -1;} static voidipreset(void){	nullmediumlink();	pktmediumlink(); 	fmtinstall('i', eipfmt);	fmtinstall('I', eipfmt);	fmtinstall('E', eipfmt);	fmtinstall('V', eipfmt);	fmtinstall('M', eipfmt);} 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);		f->dev = dev;		ipfs[dev] = f;	}	qunlock(&fslock); 	return ipfs[dev];} IPaux*newipaux(char *owner, char *tag){	IPaux *a;	int n; 	a = smalloc(sizeof(*a));	kstrdup(&a->owner, owner);	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) static Chan*ipattach(char* spec){	Chan *c;	int dev; 	dev = atoi(spec);	if(dev >= Nfs)		error("bad specification"); 	ipgetfs(dev);	c = devattach('I', spec);	mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);	c->dev = dev; 	c->aux = newipaux(commonuser(), "none"); 	return c;} static Walkqid*ipwalk(Chan* c, Chan *nc, char **name, int nname){	IPaux *a = c->aux;	Walkqid* w; 	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;} static intipstat(Chan* c, uchar* db, int n){	return devstat(c, db, n, nil, 0, ipgen);} static intincoming(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;	Fs *f; 	perm = m2p[omode&3]; 	f = ipfs[c->dev]; 	switch(TYPE(c->qid)) {	default:		break;	case Qndb:		if(omode & (OWRITE|OTRUNC) && !iseve())			error(Eperm);		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))			f->ndb[0] = 0;		break;	case Qlog:		netlogopen(f);		break;	case Qiprouter:		iprouteropen(f);		break;	case Qiproute:		break;	case Qtopdir:	case Qprotodir:	case Qconvdir:	case Qstatus:	case Qremote:	case Qlocal:	case Qstats:	case Qbootp:	case Qipselftab:		if(omode != OREAD)			error(Eperm);		break;	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;	case Qclone:		p = f->p[PROTO(c->qid)];		qlock(p);		if(waserror()){			qunlock(p);			nexterror();		}		cv = Fsprotoclone(p, ATTACHER(c));		qunlock(p);		poperror();		if(cv == nil) {			error(Enodev);			break;		}		mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);		break;	case Qdata:	case Qctl:	case Qerr:		p = f->p[PROTO(c->qid)];		qlock(p);		cv = p->conv[CONV(c->qid)];		qlock(cv);		if(waserror()) {			qunlock(cv);			qunlock(p);			nexterror();		}		if((perm & (cv->perm>>6)) != perm) {			if(strcmp(ATTACHER(c), cv->owner) != 0)				error(Eperm);		 	if((perm & cv->perm) != perm)				error(Eperm);  		}		cv->inuse++;		if(cv->inuse == 1){			kstrdup(&cv->owner, ATTACHER(c));			cv->perm = 0660;		}		qunlock(cv);		qunlock(p);		poperror();		break;	case Qlisten:		cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];		if((perm & (cv->perm>>6)) != perm) {			if(strcmp(ATTACHER(c), cv->owner) != 0)				error(Eperm);		 	if((perm & cv->perm) != perm)				error(Eperm);  		} 		if(cv->state != Announced)			error("not announced"); 		if(waserror()){			closeconv(cv);			nexterror();		}		qlock(cv);		cv->inuse++;		qunlock(cv); 		nc = nil;		while(nc == nil) {			/* give up if we got a hangup */			if(qisclosed(cv->rq))				error("listen hungup"); 			qlock(&cv->listenq);			if(waserror()) {				qunlock(&cv->listenq);				nexterror();			} 			/* wait for a connect */			sleep(&cv->listenr, incoming, cv); 			qlock(cv);			nc = cv->incall;			if(nc != nil){				cv->incall = nc->next;				mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);				kstrdup(&cv->owner, ATTACHER(c));			}			qunlock(cv); 

Lines 1–500 of 1417.