xref: /plan9/sys/src/9/ip/devip.c (revision 3e87cd09ffd62dbb30f89f86caa5a8aa696a53bb)
17dd7cddfSDavid du Colombier #include	"u.h"
27dd7cddfSDavid du Colombier #include	"../port/lib.h"
37dd7cddfSDavid du Colombier #include	"mem.h"
47dd7cddfSDavid du Colombier #include	"dat.h"
57dd7cddfSDavid du Colombier #include	"fns.h"
67dd7cddfSDavid du Colombier #include	"../port/error.h"
77dd7cddfSDavid du Colombier #include	"../ip/ip.h"
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier enum
107dd7cddfSDavid du Colombier {
117dd7cddfSDavid du Colombier 	Qtopdir=	1,		/* top level directory */
127dd7cddfSDavid du Colombier 	Qtopbase,
137dd7cddfSDavid du Colombier 	Qarp=		Qtopbase,
147dd7cddfSDavid du Colombier 	Qbootp,
157dd7cddfSDavid du Colombier 	Qndb,
167dd7cddfSDavid du Colombier 	Qiproute,
177dd7cddfSDavid du Colombier 	Qipselftab,
187dd7cddfSDavid du Colombier 	Qlog,
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier 	Qprotodir,			/* directory for a protocol */
217dd7cddfSDavid du Colombier 	Qprotobase,
227dd7cddfSDavid du Colombier 	Qclone=		Qprotobase,
237dd7cddfSDavid du Colombier 	Qstats,
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier 	Qconvdir,			/* directory for a conversation */
267dd7cddfSDavid du Colombier 	Qconvbase,
277dd7cddfSDavid du Colombier 	Qctl=		Qconvbase,
287dd7cddfSDavid du Colombier 	Qdata,
297dd7cddfSDavid du Colombier 	Qerr,
307dd7cddfSDavid du Colombier 	Qlisten,
317dd7cddfSDavid du Colombier 	Qlocal,
327dd7cddfSDavid du Colombier 	Qremote,
337dd7cddfSDavid du Colombier 	Qstatus,
34ef9eff0bSDavid du Colombier 	Qsnoop,
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier 	Logtype=	5,
377dd7cddfSDavid du Colombier 	Masktype=	(1<<Logtype)-1,
387dd7cddfSDavid du Colombier 	Logconv=	12,
397dd7cddfSDavid du Colombier 	Maskconv=	(1<<Logconv)-1,
407dd7cddfSDavid du Colombier 	Shiftconv=	Logtype,
417dd7cddfSDavid du Colombier 	Logproto=	8,
427dd7cddfSDavid du Colombier 	Maskproto=	(1<<Logproto)-1,
437dd7cddfSDavid du Colombier 	Shiftproto=	Logtype + Logconv,
447dd7cddfSDavid du Colombier 
458c1c8807SDavid du Colombier 	Nfs=		128,
467dd7cddfSDavid du Colombier };
479a747e4fSDavid du Colombier #define TYPE(x) 	( ((ulong)(x).path) & Masktype )
489a747e4fSDavid du Colombier #define CONV(x) 	( (((ulong)(x).path) >> Shiftconv) & Maskconv )
499a747e4fSDavid du Colombier #define PROTO(x) 	( (((ulong)(x).path) >> Shiftproto) & Maskproto )
507dd7cddfSDavid du Colombier #define QID(p, c, y) 	( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) )
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier static char network[] = "network";
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier QLock	fslock;
557dd7cddfSDavid du Colombier Fs	*ipfs[Nfs];	/* attached fs's */
567dd7cddfSDavid du Colombier Queue	*qlog;
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier extern	void nullmediumlink(void);
597dd7cddfSDavid du Colombier extern	void pktmediumlink(void);
607dd7cddfSDavid du Colombier 	long ndbwrite(Fs *f, char *a, ulong off, int n);
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier static int
ip3gen(Chan * c,int i,Dir * dp)637dd7cddfSDavid du Colombier ip3gen(Chan *c, int i, Dir *dp)
647dd7cddfSDavid du Colombier {
657dd7cddfSDavid du Colombier 	Qid q;
667dd7cddfSDavid du Colombier 	Conv *cv;
677dd7cddfSDavid du Colombier 	char *p;
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier 	cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
709a747e4fSDavid du Colombier 	if(cv->owner == nil)
719a747e4fSDavid du Colombier 		kstrdup(&cv->owner, eve);
729a747e4fSDavid du Colombier 	mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
739a747e4fSDavid du Colombier 
747dd7cddfSDavid du Colombier 	switch(i) {
757dd7cddfSDavid du Colombier 	default:
767dd7cddfSDavid du Colombier 		return -1;
777dd7cddfSDavid du Colombier 	case Qctl:
787dd7cddfSDavid du Colombier 		devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
797dd7cddfSDavid du Colombier 		return 1;
807dd7cddfSDavid du Colombier 	case Qdata:
8136d3592fSDavid du Colombier 		devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp);
827dd7cddfSDavid du Colombier 		return 1;
837dd7cddfSDavid du Colombier 	case Qerr:
8436d3592fSDavid du Colombier 		devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp);
857dd7cddfSDavid du Colombier 		return 1;
867dd7cddfSDavid du Colombier 	case Qlisten:
87ef9eff0bSDavid du Colombier 		devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
889a747e4fSDavid du Colombier 		return 1;
897dd7cddfSDavid du Colombier 	case Qlocal:
907dd7cddfSDavid du Colombier 		p = "local";
917dd7cddfSDavid du Colombier 		break;
927dd7cddfSDavid du Colombier 	case Qremote:
937dd7cddfSDavid du Colombier 		p = "remote";
947dd7cddfSDavid du Colombier 		break;
95ef9eff0bSDavid du Colombier 	case Qsnoop:
96ef9eff0bSDavid du Colombier 		if(strcmp(cv->p->name, "ipifc") != 0)
97ef9eff0bSDavid du Colombier 			return -1;
9836d3592fSDavid du Colombier 		devdir(c, q, "snoop", qlen(cv->sq), cv->owner, 0400, dp);
99ef9eff0bSDavid du Colombier 		return 1;
1007dd7cddfSDavid du Colombier 	case Qstatus:
1017dd7cddfSDavid du Colombier 		p = "status";
1027dd7cddfSDavid du Colombier 		break;
1037dd7cddfSDavid du Colombier 	}
1049a747e4fSDavid du Colombier 	devdir(c, q, p, 0, cv->owner, 0444, dp);
1057dd7cddfSDavid du Colombier 	return 1;
1067dd7cddfSDavid du Colombier }
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier static int
ip2gen(Chan * c,int i,Dir * dp)1097dd7cddfSDavid du Colombier ip2gen(Chan *c, int i, Dir *dp)
1107dd7cddfSDavid du Colombier {
1117dd7cddfSDavid du Colombier 	Qid q;
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier 	switch(i) {
1147dd7cddfSDavid du Colombier 	case Qclone:
1159a747e4fSDavid du Colombier 		mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);
1167dd7cddfSDavid du Colombier 		devdir(c, q, "clone", 0, network, 0666, dp);
1177dd7cddfSDavid du Colombier 		return 1;
1187dd7cddfSDavid du Colombier 	case Qstats:
1199a747e4fSDavid du Colombier 		mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE);
1207dd7cddfSDavid du Colombier 		devdir(c, q, "stats", 0, network, 0444, dp);
1217dd7cddfSDavid du Colombier 		return 1;
1227dd7cddfSDavid du Colombier 	}
1237dd7cddfSDavid du Colombier 	return -1;
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier static int
ip1gen(Chan * c,int i,Dir * dp)1277dd7cddfSDavid du Colombier ip1gen(Chan *c, int i, Dir *dp)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier 	Qid q;
1307dd7cddfSDavid du Colombier 	char *p;
1317dd7cddfSDavid du Colombier 	int prot;
1327dd7cddfSDavid du Colombier 	int len = 0;
1337dd7cddfSDavid du Colombier 	Fs *f;
1343ff48bf5SDavid du Colombier 	extern ulong	kerndate;
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier 	f = ipfs[c->dev];
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier 	prot = 0666;
1399a747e4fSDavid du Colombier 	mkqid(&q, QID(0, 0, i), 0, QTFILE);
1407dd7cddfSDavid du Colombier 	switch(i) {
1417dd7cddfSDavid du Colombier 	default:
1427dd7cddfSDavid du Colombier 		return -1;
1437dd7cddfSDavid du Colombier 	case Qarp:
1447dd7cddfSDavid du Colombier 		p = "arp";
14537c8dc8dSDavid du Colombier 		prot = 0664;
1467dd7cddfSDavid du Colombier 		break;
1477dd7cddfSDavid du Colombier 	case Qbootp:
1487dd7cddfSDavid du Colombier 		p = "bootp";
1497dd7cddfSDavid du Colombier 		break;
1507dd7cddfSDavid du Colombier 	case Qndb:
1517dd7cddfSDavid du Colombier 		p = "ndb";
1527dd7cddfSDavid du Colombier 		len = strlen(f->ndb);
1539a747e4fSDavid du Colombier 		q.vers = f->ndbvers;
1547dd7cddfSDavid du Colombier 		break;
1557dd7cddfSDavid du Colombier 	case Qiproute:
1567dd7cddfSDavid du Colombier 		p = "iproute";
15737c8dc8dSDavid du Colombier 		prot = 0664;
1587dd7cddfSDavid du Colombier 		break;
1597dd7cddfSDavid du Colombier 	case Qipselftab:
1607dd7cddfSDavid du Colombier 		p = "ipselftab";
1617dd7cddfSDavid du Colombier 		prot = 0444;
1627dd7cddfSDavid du Colombier 		break;
1637dd7cddfSDavid du Colombier 	case Qlog:
1647dd7cddfSDavid du Colombier 		p = "log";
1657dd7cddfSDavid du Colombier 		break;
1667dd7cddfSDavid du Colombier 	}
1677dd7cddfSDavid du Colombier 	devdir(c, q, p, len, network, prot, dp);
1683ff48bf5SDavid du Colombier 	if(i == Qndb && f->ndbmtime > kerndate)
1699a747e4fSDavid du Colombier 		dp->mtime = f->ndbmtime;
1707dd7cddfSDavid du Colombier 	return 1;
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier static int
ipgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)1749a747e4fSDavid du Colombier ipgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
1757dd7cddfSDavid du Colombier {
1767dd7cddfSDavid du Colombier 	Qid q;
1777dd7cddfSDavid du Colombier 	Conv *cv;
1787dd7cddfSDavid du Colombier 	Fs *f;
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier 	f = ipfs[c->dev];
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)) {
1837dd7cddfSDavid du Colombier 	case Qtopdir:
1847dd7cddfSDavid du Colombier 		if(s == DEVDOTDOT){
1859a747e4fSDavid du Colombier 			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
186*57d98441SDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev);
1879a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, network, 0555, dp);
1887dd7cddfSDavid du Colombier 			return 1;
1897dd7cddfSDavid du Colombier 		}
1907dd7cddfSDavid du Colombier 		if(s < f->np) {
1917dd7cddfSDavid du Colombier 			if(f->p[s]->connect == nil)
1927dd7cddfSDavid du Colombier 				return 0;	/* protocol with no user interface */
1939a747e4fSDavid du Colombier 			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
1947dd7cddfSDavid du Colombier 			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
1957dd7cddfSDavid du Colombier 			return 1;
1967dd7cddfSDavid du Colombier 		}
1977dd7cddfSDavid du Colombier 		s -= f->np;
1987dd7cddfSDavid du Colombier 		return ip1gen(c, s+Qtopbase, dp);
1997dd7cddfSDavid du Colombier 	case Qarp:
2007dd7cddfSDavid du Colombier 	case Qbootp:
2017dd7cddfSDavid du Colombier 	case Qndb:
2027dd7cddfSDavid du Colombier 	case Qlog:
2037dd7cddfSDavid du Colombier 	case Qiproute:
2047dd7cddfSDavid du Colombier 	case Qipselftab:
2057dd7cddfSDavid du Colombier 		return ip1gen(c, TYPE(c->qid), dp);
2067dd7cddfSDavid du Colombier 	case Qprotodir:
2077dd7cddfSDavid du Colombier 		if(s == DEVDOTDOT){
2089a747e4fSDavid du Colombier 			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
209*57d98441SDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#I%lud", c->dev);
2109a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, network, 0555, dp);
2117dd7cddfSDavid du Colombier 			return 1;
2127dd7cddfSDavid du Colombier 		}
2137dd7cddfSDavid du Colombier 		if(s < f->p[PROTO(c->qid)]->ac) {
2147dd7cddfSDavid du Colombier 			cv = f->p[PROTO(c->qid)]->conv[s];
215*57d98441SDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "%d", s);
2169a747e4fSDavid du Colombier 			mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);
2179a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);
2187dd7cddfSDavid du Colombier 			return 1;
2197dd7cddfSDavid du Colombier 		}
2207dd7cddfSDavid du Colombier 		s -= f->p[PROTO(c->qid)]->ac;
2217dd7cddfSDavid du Colombier 		return ip2gen(c, s+Qprotobase, dp);
2227dd7cddfSDavid du Colombier 	case Qclone:
2237dd7cddfSDavid du Colombier 	case Qstats:
2247dd7cddfSDavid du Colombier 		return ip2gen(c, TYPE(c->qid), dp);
2257dd7cddfSDavid du Colombier 	case Qconvdir:
2267dd7cddfSDavid du Colombier 		if(s == DEVDOTDOT){
2277dd7cddfSDavid du Colombier 			s = PROTO(c->qid);
2289a747e4fSDavid du Colombier 			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
2297dd7cddfSDavid du Colombier 			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
2307dd7cddfSDavid du Colombier 			return 1;
2317dd7cddfSDavid du Colombier 		}
2327dd7cddfSDavid du Colombier 		return ip3gen(c, s+Qconvbase, dp);
2337dd7cddfSDavid du Colombier 	case Qctl:
2347dd7cddfSDavid du Colombier 	case Qdata:
2357dd7cddfSDavid du Colombier 	case Qerr:
2367dd7cddfSDavid du Colombier 	case Qlisten:
2377dd7cddfSDavid du Colombier 	case Qlocal:
2387dd7cddfSDavid du Colombier 	case Qremote:
2397dd7cddfSDavid du Colombier 	case Qstatus:
240ef9eff0bSDavid du Colombier 	case Qsnoop:
2417dd7cddfSDavid du Colombier 		return ip3gen(c, TYPE(c->qid), dp);
2427dd7cddfSDavid du Colombier 	}
2437dd7cddfSDavid du Colombier 	return -1;
2447dd7cddfSDavid du Colombier }
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier static void
ipreset(void)2477dd7cddfSDavid du Colombier ipreset(void)
2487dd7cddfSDavid du Colombier {
2497dd7cddfSDavid du Colombier 	nullmediumlink();
2507dd7cddfSDavid du Colombier 	pktmediumlink();
2517dd7cddfSDavid du Colombier 
2529a747e4fSDavid du Colombier 	fmtinstall('i', eipfmt);
2539a747e4fSDavid du Colombier 	fmtinstall('I', eipfmt);
2549a747e4fSDavid du Colombier 	fmtinstall('E', eipfmt);
2559a747e4fSDavid du Colombier 	fmtinstall('V', eipfmt);
2569a747e4fSDavid du Colombier 	fmtinstall('M', eipfmt);
2577dd7cddfSDavid du Colombier }
2587dd7cddfSDavid du Colombier 
2597dd7cddfSDavid du Colombier static Fs*
ipgetfs(int dev)2607dd7cddfSDavid du Colombier ipgetfs(int dev)
2617dd7cddfSDavid du Colombier {
2627dd7cddfSDavid du Colombier 	extern void (*ipprotoinit[])(Fs*);
2637dd7cddfSDavid du Colombier 	Fs *f;
2647dd7cddfSDavid du Colombier 	int i;
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier 	if(dev >= Nfs)
2677dd7cddfSDavid du Colombier 		return nil;
2687dd7cddfSDavid du Colombier 
2697dd7cddfSDavid du Colombier 	qlock(&fslock);
2707dd7cddfSDavid du Colombier 	if(ipfs[dev] == nil){
2717dd7cddfSDavid du Colombier 		f = smalloc(sizeof(Fs));
2727dd7cddfSDavid du Colombier 		ip_init(f);
2737dd7cddfSDavid du Colombier 		arpinit(f);
2747dd7cddfSDavid du Colombier 		netloginit(f);
2757dd7cddfSDavid du Colombier 		for(i = 0; ipprotoinit[i]; i++)
2767dd7cddfSDavid du Colombier 			ipprotoinit[i](f);
2777dd7cddfSDavid du Colombier 		f->dev = dev;
2787dd7cddfSDavid du Colombier 		ipfs[dev] = f;
2797dd7cddfSDavid du Colombier 	}
2807dd7cddfSDavid du Colombier 	qunlock(&fslock);
2817dd7cddfSDavid du Colombier 
2827dd7cddfSDavid du Colombier 	return ipfs[dev];
2837dd7cddfSDavid du Colombier }
2847dd7cddfSDavid du Colombier 
2859a747e4fSDavid du Colombier IPaux*
newipaux(char * owner,char * tag)2869a747e4fSDavid du Colombier newipaux(char *owner, char *tag)
2879a747e4fSDavid du Colombier {
2889a747e4fSDavid du Colombier 	IPaux *a;
2899a747e4fSDavid du Colombier 	int n;
2909a747e4fSDavid du Colombier 
2919a747e4fSDavid du Colombier 	a = smalloc(sizeof(*a));
2929a747e4fSDavid du Colombier 	kstrdup(&a->owner, owner);
2939a747e4fSDavid du Colombier 	memset(a->tag, ' ', sizeof(a->tag));
2949a747e4fSDavid du Colombier 	n = strlen(tag);
2959a747e4fSDavid du Colombier 	if(n > sizeof(a->tag))
2969a747e4fSDavid du Colombier 		n = sizeof(a->tag);
2979a747e4fSDavid du Colombier 	memmove(a->tag, tag, n);
2989a747e4fSDavid du Colombier 	return a;
2999a747e4fSDavid du Colombier }
3009a747e4fSDavid du Colombier 
3019a747e4fSDavid du Colombier #define ATTACHER(c) (((IPaux*)((c)->aux))->owner)
3029a747e4fSDavid du Colombier 
3037dd7cddfSDavid du Colombier static Chan*
ipattach(char * spec)3047dd7cddfSDavid du Colombier ipattach(char* spec)
3057dd7cddfSDavid du Colombier {
3067dd7cddfSDavid du Colombier 	Chan *c;
3077dd7cddfSDavid du Colombier 	int dev;
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier 	dev = atoi(spec);
3108c1c8807SDavid du Colombier 	if(dev >= Nfs)
3117dd7cddfSDavid du Colombier 		error("bad specification");
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier 	ipgetfs(dev);
3147dd7cddfSDavid du Colombier 	c = devattach('I', spec);
3159a747e4fSDavid du Colombier 	mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);
3167dd7cddfSDavid du Colombier 	c->dev = dev;
3177dd7cddfSDavid du Colombier 
3189a747e4fSDavid du Colombier 	c->aux = newipaux(commonuser(), "none");
3199a747e4fSDavid du Colombier 
3207dd7cddfSDavid du Colombier 	return c;
3217dd7cddfSDavid du Colombier }
3227dd7cddfSDavid du Colombier 
3239a747e4fSDavid du Colombier static Walkqid*
ipwalk(Chan * c,Chan * nc,char ** name,int nname)3249a747e4fSDavid du Colombier ipwalk(Chan* c, Chan *nc, char **name, int nname)
3257dd7cddfSDavid du Colombier {
3269a747e4fSDavid du Colombier 	IPaux *a = c->aux;
3279a747e4fSDavid du Colombier 	Walkqid* w;
3289a747e4fSDavid du Colombier 
3299a747e4fSDavid du Colombier 	w = devwalk(c, nc, name, nname, nil, 0, ipgen);
3309a747e4fSDavid du Colombier 	if(w != nil && w->clone != nil)
3319a747e4fSDavid du Colombier 		w->clone->aux = newipaux(a->owner, a->tag);
3329a747e4fSDavid du Colombier 	return w;
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier 
3353ff48bf5SDavid du Colombier 
3367dd7cddfSDavid du Colombier static int
ipstat(Chan * c,uchar * db,int n)3379a747e4fSDavid du Colombier ipstat(Chan* c, uchar* db, int n)
3387dd7cddfSDavid du Colombier {
3399a747e4fSDavid du Colombier 	return devstat(c, db, n, nil, 0, ipgen);
3407dd7cddfSDavid du Colombier }
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier static int
incoming(void * arg)3437dd7cddfSDavid du Colombier incoming(void* arg)
3447dd7cddfSDavid du Colombier {
3457dd7cddfSDavid du Colombier 	Conv *conv;
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier 	conv = arg;
3487dd7cddfSDavid du Colombier 	return conv->incall != nil;
3497dd7cddfSDavid du Colombier }
3507dd7cddfSDavid du Colombier 
3517dd7cddfSDavid du Colombier static int m2p[] = {
3527dd7cddfSDavid du Colombier 	[OREAD]		4,
3537dd7cddfSDavid du Colombier 	[OWRITE]	2,
3547dd7cddfSDavid du Colombier 	[ORDWR]		6
3557dd7cddfSDavid du Colombier };
3567dd7cddfSDavid du Colombier 
3577dd7cddfSDavid du Colombier static Chan*
ipopen(Chan * c,int omode)3587dd7cddfSDavid du Colombier ipopen(Chan* c, int omode)
3597dd7cddfSDavid du Colombier {
3607dd7cddfSDavid du Colombier 	Conv *cv, *nc;
3617dd7cddfSDavid du Colombier 	Proto *p;
3627dd7cddfSDavid du Colombier 	int perm;
3637dd7cddfSDavid du Colombier 	Fs *f;
3647dd7cddfSDavid du Colombier 
3651b0a7c7eSDavid du Colombier 	perm = m2p[omode&3];
3667dd7cddfSDavid du Colombier 
3677dd7cddfSDavid du Colombier 	f = ipfs[c->dev];
3687dd7cddfSDavid du Colombier 
3697dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)) {
3707dd7cddfSDavid du Colombier 	default:
3717dd7cddfSDavid du Colombier 		break;
3727dd7cddfSDavid du Colombier 	case Qndb:
3733ff48bf5SDavid du Colombier 		if(omode & (OWRITE|OTRUNC) && !iseve())
3747dd7cddfSDavid du Colombier 			error(Eperm);
3753ff48bf5SDavid du Colombier 		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))
3767dd7cddfSDavid du Colombier 			f->ndb[0] = 0;
3777dd7cddfSDavid du Colombier 		break;
3787dd7cddfSDavid du Colombier 	case Qlog:
3797dd7cddfSDavid du Colombier 		netlogopen(f);
3807dd7cddfSDavid du Colombier 		break;
3817dd7cddfSDavid du Colombier 	case Qiproute:
38237c8dc8dSDavid du Colombier 	case Qarp:
38337c8dc8dSDavid du Colombier 		if(omode != OREAD && !iseve())
38437c8dc8dSDavid du Colombier 			error(Eperm);
3857dd7cddfSDavid du Colombier 		break;
3867dd7cddfSDavid du Colombier 	case Qtopdir:
3877dd7cddfSDavid du Colombier 	case Qprotodir:
3887dd7cddfSDavid du Colombier 	case Qconvdir:
3897dd7cddfSDavid du Colombier 	case Qstatus:
3907dd7cddfSDavid du Colombier 	case Qremote:
3917dd7cddfSDavid du Colombier 	case Qlocal:
3927dd7cddfSDavid du Colombier 	case Qstats:
3937dd7cddfSDavid du Colombier 	case Qbootp:
3947dd7cddfSDavid du Colombier 	case Qipselftab:
3957dd7cddfSDavid du Colombier 		if(omode != OREAD)
3967dd7cddfSDavid du Colombier 			error(Eperm);
3977dd7cddfSDavid du Colombier 		break;
398ef9eff0bSDavid du Colombier 	case Qsnoop:
399ef9eff0bSDavid du Colombier 		if(omode != OREAD)
400ef9eff0bSDavid du Colombier 			error(Eperm);
401ef9eff0bSDavid du Colombier 		p = f->p[PROTO(c->qid)];
402ef9eff0bSDavid du Colombier 		cv = p->conv[CONV(c->qid)];
403ef9eff0bSDavid du Colombier 		if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())
404ef9eff0bSDavid du Colombier 			error(Eperm);
405ef9eff0bSDavid du Colombier 		incref(&cv->snoopers);
406ef9eff0bSDavid du Colombier 		break;
4077dd7cddfSDavid du Colombier 	case Qclone:
4087dd7cddfSDavid du Colombier 		p = f->p[PROTO(c->qid)];
4097dd7cddfSDavid du Colombier 		qlock(p);
4107dd7cddfSDavid du Colombier 		if(waserror()){
4117dd7cddfSDavid du Colombier 			qunlock(p);
4127dd7cddfSDavid du Colombier 			nexterror();
4137dd7cddfSDavid du Colombier 		}
4149a747e4fSDavid du Colombier 		cv = Fsprotoclone(p, ATTACHER(c));
4157dd7cddfSDavid du Colombier 		qunlock(p);
4167dd7cddfSDavid du Colombier 		poperror();
4177dd7cddfSDavid du Colombier 		if(cv == nil) {
4187dd7cddfSDavid du Colombier 			error(Enodev);
4197dd7cddfSDavid du Colombier 			break;
4207dd7cddfSDavid du Colombier 		}
4219a747e4fSDavid du Colombier 		mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
4227dd7cddfSDavid du Colombier 		break;
4237dd7cddfSDavid du Colombier 	case Qdata:
4247dd7cddfSDavid du Colombier 	case Qctl:
4257dd7cddfSDavid du Colombier 	case Qerr:
4267dd7cddfSDavid du Colombier 		p = f->p[PROTO(c->qid)];
4277dd7cddfSDavid du Colombier 		qlock(p);
4287dd7cddfSDavid du Colombier 		cv = p->conv[CONV(c->qid)];
4297dd7cddfSDavid du Colombier 		qlock(cv);
4307dd7cddfSDavid du Colombier 		if(waserror()) {
4317dd7cddfSDavid du Colombier 			qunlock(cv);
4327dd7cddfSDavid du Colombier 			qunlock(p);
4337dd7cddfSDavid du Colombier 			nexterror();
4347dd7cddfSDavid du Colombier 		}
4357dd7cddfSDavid du Colombier 		if((perm & (cv->perm>>6)) != perm) {
4369a747e4fSDavid du Colombier 			if(strcmp(ATTACHER(c), cv->owner) != 0)
4377dd7cddfSDavid du Colombier 				error(Eperm);
4387dd7cddfSDavid du Colombier 		 	if((perm & cv->perm) != perm)
4397dd7cddfSDavid du Colombier 				error(Eperm);
4407dd7cddfSDavid du Colombier 
4417dd7cddfSDavid du Colombier 		}
4427dd7cddfSDavid du Colombier 		cv->inuse++;
4437dd7cddfSDavid du Colombier 		if(cv->inuse == 1){
4449a747e4fSDavid du Colombier 			kstrdup(&cv->owner, ATTACHER(c));
4457dd7cddfSDavid du Colombier 			cv->perm = 0660;
4467dd7cddfSDavid du Colombier 		}
4477dd7cddfSDavid du Colombier 		qunlock(cv);
4487dd7cddfSDavid du Colombier 		qunlock(p);
4497dd7cddfSDavid du Colombier 		poperror();
4507dd7cddfSDavid du Colombier 		break;
4517dd7cddfSDavid du Colombier 	case Qlisten:
4527dd7cddfSDavid du Colombier 		cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
4539a747e4fSDavid du Colombier 		if((perm & (cv->perm>>6)) != perm) {
4549a747e4fSDavid du Colombier 			if(strcmp(ATTACHER(c), cv->owner) != 0)
4559a747e4fSDavid du Colombier 				error(Eperm);
4569a747e4fSDavid du Colombier 		 	if((perm & cv->perm) != perm)
4579a747e4fSDavid du Colombier 				error(Eperm);
4589a747e4fSDavid du Colombier 
4599a747e4fSDavid du Colombier 		}
4609a747e4fSDavid du Colombier 
4617dd7cddfSDavid du Colombier 		if(cv->state != Announced)
4627dd7cddfSDavid du Colombier 			error("not announced");
4637dd7cddfSDavid du Colombier 
46451711cb6SDavid du Colombier 		if(waserror()){
46551711cb6SDavid du Colombier 			closeconv(cv);
46651711cb6SDavid du Colombier 			nexterror();
46751711cb6SDavid du Colombier 		}
46851711cb6SDavid du Colombier 		qlock(cv);
46951711cb6SDavid du Colombier 		cv->inuse++;
47051711cb6SDavid du Colombier 		qunlock(cv);
47151711cb6SDavid du Colombier 
4727dd7cddfSDavid du Colombier 		nc = nil;
4737dd7cddfSDavid du Colombier 		while(nc == nil) {
4747dd7cddfSDavid du Colombier 			/* give up if we got a hangup */
4757dd7cddfSDavid du Colombier 			if(qisclosed(cv->rq))
4767dd7cddfSDavid du Colombier 				error("listen hungup");
4777dd7cddfSDavid du Colombier 
4787dd7cddfSDavid du Colombier 			qlock(&cv->listenq);
4797dd7cddfSDavid du Colombier 			if(waserror()) {
4807dd7cddfSDavid du Colombier 				qunlock(&cv->listenq);
4817dd7cddfSDavid du Colombier 				nexterror();
4827dd7cddfSDavid du Colombier 			}
4837dd7cddfSDavid du Colombier 
4847dd7cddfSDavid du Colombier 			/* wait for a connect */
4857dd7cddfSDavid du Colombier 			sleep(&cv->listenr, incoming, cv);
4867dd7cddfSDavid du Colombier 
4877dd7cddfSDavid du Colombier 			qlock(cv);
4887dd7cddfSDavid du Colombier 			nc = cv->incall;
4897dd7cddfSDavid du Colombier 			if(nc != nil){
4907dd7cddfSDavid du Colombier 				cv->incall = nc->next;
4919a747e4fSDavid du Colombier 				mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
4929a747e4fSDavid du Colombier 				kstrdup(&cv->owner, ATTACHER(c));
4937dd7cddfSDavid du Colombier 			}
4947dd7cddfSDavid du Colombier 			qunlock(cv);
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier 			qunlock(&cv->listenq);
4977dd7cddfSDavid du Colombier 			poperror();
4987dd7cddfSDavid du Colombier 		}
49951711cb6SDavid du Colombier 		closeconv(cv);
50051711cb6SDavid du Colombier 		poperror();
5017dd7cddfSDavid du Colombier 		break;
5027dd7cddfSDavid du Colombier 	}
5037dd7cddfSDavid du Colombier 	c->mode = openmode(omode);
5047dd7cddfSDavid du Colombier 	c->flag |= COPEN;
5057dd7cddfSDavid du Colombier 	c->offset = 0;
5067dd7cddfSDavid du Colombier 	return c;
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier 
5093ff48bf5SDavid du Colombier static void
ipcreate(Chan *,char *,int,ulong)5103ff48bf5SDavid du Colombier ipcreate(Chan*, char*, int, ulong)
5113ff48bf5SDavid du Colombier {
5123ff48bf5SDavid du Colombier 	error(Eperm);
5133ff48bf5SDavid du Colombier }
5143ff48bf5SDavid du Colombier 
5153ff48bf5SDavid du Colombier static void
ipremove(Chan *)5163ff48bf5SDavid du Colombier ipremove(Chan*)
5173ff48bf5SDavid du Colombier {
5183ff48bf5SDavid du Colombier 	error(Eperm);
5193ff48bf5SDavid du Colombier }
5203ff48bf5SDavid du Colombier 
5219a747e4fSDavid du Colombier static int
ipwstat(Chan * c,uchar * dp,int n)5229a747e4fSDavid du Colombier ipwstat(Chan *c, uchar *dp, int n)
5237dd7cddfSDavid du Colombier {
5243ff48bf5SDavid du Colombier 	Dir d;
5259a747e4fSDavid du Colombier 	Conv *cv;
5269a747e4fSDavid du Colombier 	Fs *f;
5279a747e4fSDavid du Colombier 	Proto *p;
5289a747e4fSDavid du Colombier 
5299a747e4fSDavid du Colombier 	f = ipfs[c->dev];
5309a747e4fSDavid du Colombier 	switch(TYPE(c->qid)) {
5319a747e4fSDavid du Colombier 	default:
5327dd7cddfSDavid du Colombier 		error(Eperm);
5339a747e4fSDavid du Colombier 		break;
5349a747e4fSDavid du Colombier 	case Qctl:
5359a747e4fSDavid du Colombier 	case Qdata:
5369a747e4fSDavid du Colombier 		break;
5377dd7cddfSDavid du Colombier 	}
5387dd7cddfSDavid du Colombier 
5393ff48bf5SDavid du Colombier 	n = convM2D(dp, n, &d, nil);
5403ff48bf5SDavid du Colombier 	if(n > 0){
5419a747e4fSDavid du Colombier 		p = f->p[PROTO(c->qid)];
5429a747e4fSDavid du Colombier 		cv = p->conv[CONV(c->qid)];
5439a747e4fSDavid du Colombier 		if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
5447dd7cddfSDavid du Colombier 			error(Eperm);
5453ff48bf5SDavid du Colombier 		if(d.uid[0])
5463ff48bf5SDavid du Colombier 			kstrdup(&cv->owner, d.uid);
5473ff48bf5SDavid du Colombier 		cv->perm = d.mode & 0777;
5483ff48bf5SDavid du Colombier 	}
5499a747e4fSDavid du Colombier 	return n;
5507dd7cddfSDavid du Colombier }
5517dd7cddfSDavid du Colombier 
5527dd7cddfSDavid du Colombier void
closeconv(Conv * cv)5537dd7cddfSDavid du Colombier closeconv(Conv *cv)
5547dd7cddfSDavid du Colombier {
5557dd7cddfSDavid du Colombier 	Conv *nc;
5567dd7cddfSDavid du Colombier 	Ipmulti *mp;
5577dd7cddfSDavid du Colombier 
5587dd7cddfSDavid du Colombier 	qlock(cv);
5597dd7cddfSDavid du Colombier 
5607dd7cddfSDavid du Colombier 	if(--cv->inuse > 0) {
5617dd7cddfSDavid du Colombier 		qunlock(cv);
5627dd7cddfSDavid du Colombier 		return;
5637dd7cddfSDavid du Colombier 	}
5647dd7cddfSDavid du Colombier 
5657dd7cddfSDavid du Colombier 	/* close all incoming calls since no listen will ever happen */
5667dd7cddfSDavid du Colombier 	for(nc = cv->incall; nc; nc = cv->incall){
5677dd7cddfSDavid du Colombier 		cv->incall = nc->next;
5687dd7cddfSDavid du Colombier 		closeconv(nc);
5697dd7cddfSDavid du Colombier 	}
5707dd7cddfSDavid du Colombier 	cv->incall = nil;
5717dd7cddfSDavid du Colombier 
5729a747e4fSDavid du Colombier 	kstrdup(&cv->owner, network);
5737dd7cddfSDavid du Colombier 	cv->perm = 0660;
5747dd7cddfSDavid du Colombier 
5757dd7cddfSDavid du Colombier 	while((mp = cv->multi) != nil)
5767dd7cddfSDavid du Colombier 		ipifcremmulti(cv, mp->ma, mp->ia);
5777dd7cddfSDavid du Colombier 
578a6a9e072SDavid du Colombier 	cv->r = nil;
579a6a9e072SDavid du Colombier 	cv->rgen = 0;
5807dd7cddfSDavid du Colombier 	cv->p->close(cv);
58180ee5cbfSDavid du Colombier 	cv->state = Idle;
58280ee5cbfSDavid du Colombier 	qunlock(cv);
5837dd7cddfSDavid du Colombier }
5847dd7cddfSDavid du Colombier 
5857dd7cddfSDavid du Colombier static void
ipclose(Chan * c)5867dd7cddfSDavid du Colombier ipclose(Chan* c)
5877dd7cddfSDavid du Colombier {
5887dd7cddfSDavid du Colombier 	Fs *f;
5897dd7cddfSDavid du Colombier 
5907dd7cddfSDavid du Colombier 	f = ipfs[c->dev];
5917dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)) {
5927dd7cddfSDavid du Colombier 	default:
5937dd7cddfSDavid du Colombier 		break;
5947dd7cddfSDavid du Colombier 	case Qlog:
5957dd7cddfSDavid du Colombier 		if(c->flag & COPEN)
5967dd7cddfSDavid du Colombier 			netlogclose(f);
5977dd7cddfSDavid du Colombier 		break;
5987dd7cddfSDavid du Colombier 	case Qdata:
5997dd7cddfSDavid du Colombier 	case Qctl:
6007dd7cddfSDavid du Colombier 	case Qerr:
6017dd7cddfSDavid du Colombier 		if(c->flag & COPEN)
6027dd7cddfSDavid du Colombier 			closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);
603ef9eff0bSDavid du Colombier 		break;
604ef9eff0bSDavid du Colombier 	case Qsnoop:
605ef9eff0bSDavid du Colombier 		if(c->flag & COPEN)
606ef9eff0bSDavid du Colombier 			decref(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers);
607ef9eff0bSDavid du Colombier 		break;
6087dd7cddfSDavid du Colombier 	}
6099a747e4fSDavid du Colombier 	free(((IPaux*)c->aux)->owner);
6109a747e4fSDavid du Colombier 	free(c->aux);
6117dd7cddfSDavid du Colombier }
6127dd7cddfSDavid du Colombier 
6137dd7cddfSDavid du Colombier enum
6147dd7cddfSDavid du Colombier {
6157dd7cddfSDavid du Colombier 	Statelen=	32*1024,
6167dd7cddfSDavid du Colombier };
6177dd7cddfSDavid du Colombier 
6187dd7cddfSDavid du Colombier static long
ipread(Chan * ch,void * a,long n,vlong off)6197dd7cddfSDavid du Colombier ipread(Chan *ch, void *a, long n, vlong off)
6207dd7cddfSDavid du Colombier {
6217dd7cddfSDavid du Colombier 	Conv *c;
6227dd7cddfSDavid du Colombier 	Proto *x;
6237dd7cddfSDavid du Colombier 	char *buf, *p;
6247dd7cddfSDavid du Colombier 	long rv;
6257dd7cddfSDavid du Colombier 	Fs *f;
6267dd7cddfSDavid du Colombier 	ulong offset = off;
6277dd7cddfSDavid du Colombier 
6287dd7cddfSDavid du Colombier 	f = ipfs[ch->dev];
6297dd7cddfSDavid du Colombier 
6307dd7cddfSDavid du Colombier 	p = a;
6317dd7cddfSDavid du Colombier 	switch(TYPE(ch->qid)) {
6327dd7cddfSDavid du Colombier 	default:
6337dd7cddfSDavid du Colombier 		error(Eperm);
6347dd7cddfSDavid du Colombier 	case Qtopdir:
6357dd7cddfSDavid du Colombier 	case Qprotodir:
6367dd7cddfSDavid du Colombier 	case Qconvdir:
6377dd7cddfSDavid du Colombier 		return devdirread(ch, a, n, 0, 0, ipgen);
6387dd7cddfSDavid du Colombier 	case Qarp:
6397dd7cddfSDavid du Colombier 		return arpread(f->arp, a, offset, n);
6407dd7cddfSDavid du Colombier  	case Qbootp:
6417dd7cddfSDavid du Colombier  		return bootpread(a, offset, n);
6427dd7cddfSDavid du Colombier  	case Qndb:
6437dd7cddfSDavid du Colombier 		return readstr(offset, a, n, f->ndb);
6447dd7cddfSDavid du Colombier 	case Qiproute:
6457dd7cddfSDavid du Colombier 		return routeread(f, a, offset, n);
6467dd7cddfSDavid du Colombier 	case Qipselftab:
6477dd7cddfSDavid du Colombier 		return ipselftabread(f, a, offset, n);
6487dd7cddfSDavid du Colombier 	case Qlog:
6497dd7cddfSDavid du Colombier 		return netlogread(f, a, offset, n);
6507dd7cddfSDavid du Colombier 	case Qctl:
6517dd7cddfSDavid du Colombier 		buf = smalloc(16);
652*57d98441SDavid du Colombier 		snprint(buf, 16, "%lud", CONV(ch->qid));
6537dd7cddfSDavid du Colombier 		rv = readstr(offset, p, n, buf);
6547dd7cddfSDavid du Colombier 		free(buf);
6557dd7cddfSDavid du Colombier 		return rv;
6567dd7cddfSDavid du Colombier 	case Qremote:
6577dd7cddfSDavid du Colombier 		buf = smalloc(Statelen);
6587dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
6597dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
6607dd7cddfSDavid du Colombier 		if(x->remote == nil) {
661*57d98441SDavid du Colombier 			snprint(buf, Statelen, "%I!%d\n", c->raddr, c->rport);
6627dd7cddfSDavid du Colombier 		} else {
6637dd7cddfSDavid du Colombier 			(*x->remote)(c, buf, Statelen-2);
6647dd7cddfSDavid du Colombier 		}
6657dd7cddfSDavid du Colombier 		rv = readstr(offset, p, n, buf);
6667dd7cddfSDavid du Colombier 		free(buf);
6677dd7cddfSDavid du Colombier 		return rv;
6687dd7cddfSDavid du Colombier 	case Qlocal:
6697dd7cddfSDavid du Colombier 		buf = smalloc(Statelen);
6707dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
6717dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
6727dd7cddfSDavid du Colombier 		if(x->local == nil) {
673*57d98441SDavid du Colombier 			snprint(buf, Statelen, "%I!%d\n", c->laddr, c->lport);
6747dd7cddfSDavid du Colombier 		} else {
6757dd7cddfSDavid du Colombier 			(*x->local)(c, buf, Statelen-2);
6767dd7cddfSDavid du Colombier 		}
6777dd7cddfSDavid du Colombier 		rv = readstr(offset, p, n, buf);
6787dd7cddfSDavid du Colombier 		free(buf);
6797dd7cddfSDavid du Colombier 		return rv;
6807dd7cddfSDavid du Colombier 	case Qstatus:
6817dd7cddfSDavid du Colombier 		buf = smalloc(Statelen);
6827dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
6837dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
6847dd7cddfSDavid du Colombier 		(*x->state)(c, buf, Statelen-2);
6857dd7cddfSDavid du Colombier 		rv = readstr(offset, p, n, buf);
6867dd7cddfSDavid du Colombier 		free(buf);
6877dd7cddfSDavid du Colombier 		return rv;
6887dd7cddfSDavid du Colombier 	case Qdata:
6897dd7cddfSDavid du Colombier 		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
6907dd7cddfSDavid du Colombier 		return qread(c->rq, a, n);
6917dd7cddfSDavid du Colombier 	case Qerr:
6927dd7cddfSDavid du Colombier 		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
6937dd7cddfSDavid du Colombier 		return qread(c->eq, a, n);
694ef9eff0bSDavid du Colombier 	case Qsnoop:
695ef9eff0bSDavid du Colombier 		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
696ef9eff0bSDavid du Colombier 		return qread(c->sq, a, n);
6977dd7cddfSDavid du Colombier 	case Qstats:
6987dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
6997dd7cddfSDavid du Colombier 		if(x->stats == nil)
7007dd7cddfSDavid du Colombier 			error("stats not implemented");
7017dd7cddfSDavid du Colombier 		buf = smalloc(Statelen);
7027dd7cddfSDavid du Colombier 		(*x->stats)(x, buf, Statelen);
7037dd7cddfSDavid du Colombier 		rv = readstr(offset, p, n, buf);
7047dd7cddfSDavid du Colombier 		free(buf);
7057dd7cddfSDavid du Colombier 		return rv;
7067dd7cddfSDavid du Colombier 	}
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier 
7097dd7cddfSDavid du Colombier static Block*
ipbread(Chan * ch,long n,ulong offset)7107dd7cddfSDavid du Colombier ipbread(Chan* ch, long n, ulong offset)
7117dd7cddfSDavid du Colombier {
7127dd7cddfSDavid du Colombier 	Conv *c;
7137dd7cddfSDavid du Colombier 	Proto *x;
7147dd7cddfSDavid du Colombier 	Fs *f;
7157dd7cddfSDavid du Colombier 
7167dd7cddfSDavid du Colombier 	switch(TYPE(ch->qid)){
7177dd7cddfSDavid du Colombier 	case Qdata:
7187dd7cddfSDavid du Colombier 		f = ipfs[ch->dev];
7197dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
7207dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
7217dd7cddfSDavid du Colombier 		return qbread(c->rq, n);
7227dd7cddfSDavid du Colombier 	default:
7237dd7cddfSDavid du Colombier 		return devbread(ch, n, offset);
7247dd7cddfSDavid du Colombier 	}
7257dd7cddfSDavid du Colombier }
7267dd7cddfSDavid du Colombier 
7277dd7cddfSDavid du Colombier /*
7287dd7cddfSDavid du Colombier  *  set local address to be that of the ifc closest to remote address
7297dd7cddfSDavid du Colombier  */
7307dd7cddfSDavid du Colombier static void
setladdr(Conv * c)7317dd7cddfSDavid du Colombier setladdr(Conv* c)
7327dd7cddfSDavid du Colombier {
7337dd7cddfSDavid du Colombier 	findlocalip(c->p->f, c->laddr, c->raddr);
7347dd7cddfSDavid du Colombier }
7357dd7cddfSDavid du Colombier 
7367dd7cddfSDavid du Colombier /*
73780ee5cbfSDavid du Colombier  *  set a local port making sure the quad of raddr,rport,laddr,lport is unique
73880ee5cbfSDavid du Colombier  */
739e288d156SDavid du Colombier char*
setluniqueport(Conv * c,int lport)74080ee5cbfSDavid du Colombier setluniqueport(Conv* c, int lport)
74180ee5cbfSDavid du Colombier {
74280ee5cbfSDavid du Colombier 	Proto *p;
74380ee5cbfSDavid du Colombier 	Conv *xp;
74480ee5cbfSDavid du Colombier 	int x;
74580ee5cbfSDavid du Colombier 
74680ee5cbfSDavid du Colombier 	p = c->p;
74780ee5cbfSDavid du Colombier 
74880ee5cbfSDavid du Colombier 	qlock(p);
74980ee5cbfSDavid du Colombier 	for(x = 0; x < p->nc; x++){
75080ee5cbfSDavid du Colombier 		xp = p->conv[x];
75180ee5cbfSDavid du Colombier 		if(xp == nil)
75280ee5cbfSDavid du Colombier 			break;
75380ee5cbfSDavid du Colombier 		if(xp == c)
75480ee5cbfSDavid du Colombier 			continue;
75580ee5cbfSDavid du Colombier 		if((xp->state == Connected || xp->state == Announced)
75680ee5cbfSDavid du Colombier 		&& xp->lport == lport
75780ee5cbfSDavid du Colombier 		&& xp->rport == c->rport
75880ee5cbfSDavid du Colombier 		&& ipcmp(xp->raddr, c->raddr) == 0
75980ee5cbfSDavid du Colombier 		&& ipcmp(xp->laddr, c->laddr) == 0){
76080ee5cbfSDavid du Colombier 			qunlock(p);
76180ee5cbfSDavid du Colombier 			return "address in use";
76280ee5cbfSDavid du Colombier 		}
76380ee5cbfSDavid du Colombier 	}
76480ee5cbfSDavid du Colombier 	c->lport = lport;
76580ee5cbfSDavid du Colombier 	qunlock(p);
76680ee5cbfSDavid du Colombier 	return nil;
76780ee5cbfSDavid du Colombier }
76880ee5cbfSDavid du Colombier 
7692b5cb72cSDavid du Colombier /*
7702b5cb72cSDavid du Colombier  * is lport in use by anyone?
7712b5cb72cSDavid du Colombier  */
7722b5cb72cSDavid du Colombier static int
lportinuse(Proto * p,ushort lport)7732b5cb72cSDavid du Colombier lportinuse(Proto *p, ushort lport)
7742b5cb72cSDavid du Colombier {
7752b5cb72cSDavid du Colombier 	int x;
7762b5cb72cSDavid du Colombier 
7772b5cb72cSDavid du Colombier 	for(x = 0; x < p->nc && p->conv[x]; x++)
7782b5cb72cSDavid du Colombier 		if(p->conv[x]->lport == lport)
7792b5cb72cSDavid du Colombier 			return 1;
7802b5cb72cSDavid du Colombier 	return 0;
7812b5cb72cSDavid du Colombier }
7823ff48bf5SDavid du Colombier 
78380ee5cbfSDavid du Colombier /*
7847dd7cddfSDavid du Colombier  *  pick a local port and set it
7857dd7cddfSDavid du Colombier  */
7862b5cb72cSDavid du Colombier char *
setlport(Conv * c)7877dd7cddfSDavid du Colombier setlport(Conv* c)
7887dd7cddfSDavid du Colombier {
7897dd7cddfSDavid du Colombier 	Proto *p;
7902b5cb72cSDavid du Colombier 	int i, port;
7917dd7cddfSDavid du Colombier 
7927dd7cddfSDavid du Colombier 	p = c->p;
7937dd7cddfSDavid du Colombier 	qlock(p);
7947dd7cddfSDavid du Colombier 	if(c->restricted){
7952b5cb72cSDavid du Colombier 		/* Restricted ports cycle between 600 and 1024. */
7962b5cb72cSDavid du Colombier 		for(i=0; i<1024-600; i++){
7972b5cb72cSDavid du Colombier 			if(p->nextrport >= 1024 || p->nextrport < 600)
7982b5cb72cSDavid du Colombier 				p->nextrport = 600;
7992b5cb72cSDavid du Colombier 			port = p->nextrport++;
8002b5cb72cSDavid du Colombier 			if(!lportinuse(p, port))
8012b5cb72cSDavid du Colombier 				goto chosen;
8027dd7cddfSDavid du Colombier 		}
8032b5cb72cSDavid du Colombier 	}else{
8042b5cb72cSDavid du Colombier 		/*
8052b5cb72cSDavid du Colombier 		 * Unrestricted ports are chosen randomly
8062b5cb72cSDavid du Colombier 		 * between 2^15 and 2^16.  There are at most
8072b5cb72cSDavid du Colombier 		 * 4*Nchan = 4096 ports in use at any given time,
8082b5cb72cSDavid du Colombier 		 * so even in the worst case, a random probe has a
8092b5cb72cSDavid du Colombier 		 * 1 - 4096/2^15 = 87% chance of success.
8102b5cb72cSDavid du Colombier 		 * If 64 successive probes fail, there is a bug somewhere
8112b5cb72cSDavid du Colombier 		 * (or a once in 10^58 event has happened, but that's
8122b5cb72cSDavid du Colombier 		 * less likely than a venti collision).
8132b5cb72cSDavid du Colombier 		 */
8142b5cb72cSDavid du Colombier 		for(i=0; i<64; i++){
8152b5cb72cSDavid du Colombier 			port = (1<<15) + nrand(1<<15);
8162b5cb72cSDavid du Colombier 			if(!lportinuse(p, port))
8172b5cb72cSDavid du Colombier 				goto chosen;
8187dd7cddfSDavid du Colombier 		}
8197dd7cddfSDavid du Colombier 	}
8207dd7cddfSDavid du Colombier 	qunlock(p);
821c6569576SDavid du Colombier 	/*
822c6569576SDavid du Colombier 	 * debugging: let's see if we ever get this.
823c6569576SDavid du Colombier 	 * if we do (and we're a cpu server), we might as well restart
824c6569576SDavid du Colombier 	 * since we're now unable to service new connections.
825c6569576SDavid du Colombier 	 */
826c6569576SDavid du Colombier 	panic("setlport: out of ports");
8272b5cb72cSDavid du Colombier 	return "no ports available";
8282b5cb72cSDavid du Colombier 
8292b5cb72cSDavid du Colombier chosen:
8302b5cb72cSDavid du Colombier 	c->lport = port;
8312b5cb72cSDavid du Colombier 	qunlock(p);
8322b5cb72cSDavid du Colombier 	return nil;
8337dd7cddfSDavid du Colombier }
8347dd7cddfSDavid du Colombier 
8357dd7cddfSDavid du Colombier /*
8367dd7cddfSDavid du Colombier  *  set a local address and port from a string of the form
83780ee5cbfSDavid du Colombier  *	[address!]port[!r]
8387dd7cddfSDavid du Colombier  */
839e288d156SDavid du Colombier char*
setladdrport(Conv * c,char * str,int announcing)8407dd7cddfSDavid du Colombier setladdrport(Conv* c, char* str, int announcing)
8417dd7cddfSDavid du Colombier {
8427dd7cddfSDavid du Colombier 	char *p;
84380ee5cbfSDavid du Colombier 	char *rv;
84480ee5cbfSDavid du Colombier 	ushort lport;
8451b0a7c7eSDavid du Colombier 	uchar addr[IPaddrlen];
84680ee5cbfSDavid du Colombier 
8477dd7cddfSDavid du Colombier 	/*
8487dd7cddfSDavid du Colombier 	 *  ignore restricted part if it exists.  it's
8497dd7cddfSDavid du Colombier 	 *  meaningless on local ports.
8507dd7cddfSDavid du Colombier 	 */
8517dd7cddfSDavid du Colombier 	p = strchr(str, '!');
85280ee5cbfSDavid du Colombier 	if(p != nil){
8537dd7cddfSDavid du Colombier 		*p++ = 0;
85480ee5cbfSDavid du Colombier 		if(strcmp(p, "r") == 0)
85580ee5cbfSDavid du Colombier 			p = nil;
8567dd7cddfSDavid du Colombier 	}
8577dd7cddfSDavid du Colombier 
8587dd7cddfSDavid du Colombier 	c->lport = 0;
85980ee5cbfSDavid du Colombier 	if(p == nil){
86080ee5cbfSDavid du Colombier 		if(announcing)
86180ee5cbfSDavid du Colombier 			ipmove(c->laddr, IPnoaddr);
86280ee5cbfSDavid du Colombier 		else
86380ee5cbfSDavid du Colombier 			setladdr(c);
86480ee5cbfSDavid du Colombier 		p = str;
86580ee5cbfSDavid du Colombier 	} else {
86680ee5cbfSDavid du Colombier 		if(strcmp(str, "*") == 0)
86780ee5cbfSDavid du Colombier 			ipmove(c->laddr, IPnoaddr);
8681b0a7c7eSDavid du Colombier 		else {
869ea58ad6fSDavid du Colombier 			if(parseip(addr, str) == -1)
870ea58ad6fSDavid du Colombier 				return Ebadip;
8711b0a7c7eSDavid du Colombier 			if(ipforme(c->p->f, addr))
8721b0a7c7eSDavid du Colombier 				ipmove(c->laddr, addr);
87380ee5cbfSDavid du Colombier 			else
8741b0a7c7eSDavid du Colombier 				return "not a local IP address";
8751b0a7c7eSDavid du Colombier 		}
8767dd7cddfSDavid du Colombier 	}
87780ee5cbfSDavid du Colombier 
87880ee5cbfSDavid du Colombier 	/* one process can get all connections */
87980ee5cbfSDavid du Colombier 	if(announcing && strcmp(p, "*") == 0){
88080ee5cbfSDavid du Colombier 		if(!iseve())
88180ee5cbfSDavid du Colombier 			error(Eperm);
88280ee5cbfSDavid du Colombier 		return setluniqueport(c, 0);
88380ee5cbfSDavid du Colombier 	}
88480ee5cbfSDavid du Colombier 
88580ee5cbfSDavid du Colombier 	lport = atoi(p);
88680ee5cbfSDavid du Colombier 	if(lport <= 0)
8872b5cb72cSDavid du Colombier 		rv = setlport(c);
88880ee5cbfSDavid du Colombier 	else
88980ee5cbfSDavid du Colombier 		rv = setluniqueport(c, lport);
89080ee5cbfSDavid du Colombier 	return rv;
8917dd7cddfSDavid du Colombier }
8927dd7cddfSDavid du Colombier 
8937dd7cddfSDavid du Colombier static char*
setraddrport(Conv * c,char * str)8947dd7cddfSDavid du Colombier setraddrport(Conv* c, char* str)
8957dd7cddfSDavid du Colombier {
8967dd7cddfSDavid du Colombier 	char *p;
8977dd7cddfSDavid du Colombier 
8987dd7cddfSDavid du Colombier 	p = strchr(str, '!');
8997dd7cddfSDavid du Colombier 	if(p == nil)
9007dd7cddfSDavid du Colombier 		return "malformed address";
9017dd7cddfSDavid du Colombier 	*p++ = 0;
902ea58ad6fSDavid du Colombier 	if (parseip(c->raddr, str) == -1)
903ea58ad6fSDavid du Colombier 		return Ebadip;
9047dd7cddfSDavid du Colombier 	c->rport = atoi(p);
9057dd7cddfSDavid du Colombier 	p = strchr(p, '!');
9067dd7cddfSDavid du Colombier 	if(p){
90780ee5cbfSDavid du Colombier 		if(strstr(p, "!r") != nil)
9087dd7cddfSDavid du Colombier 			c->restricted = 1;
9097dd7cddfSDavid du Colombier 	}
9107dd7cddfSDavid du Colombier 	return nil;
9117dd7cddfSDavid du Colombier }
9127dd7cddfSDavid du Colombier 
9137dd7cddfSDavid du Colombier /*
9147dd7cddfSDavid du Colombier  *  called by protocol connect routine to set addresses
9157dd7cddfSDavid du Colombier  */
9167dd7cddfSDavid du Colombier char*
Fsstdconnect(Conv * c,char * argv[],int argc)9177dd7cddfSDavid du Colombier Fsstdconnect(Conv *c, char *argv[], int argc)
9187dd7cddfSDavid du Colombier {
9197dd7cddfSDavid du Colombier 	char *p;
9207dd7cddfSDavid du Colombier 
9217dd7cddfSDavid du Colombier 	switch(argc) {
9227dd7cddfSDavid du Colombier 	default:
9237dd7cddfSDavid du Colombier 		return "bad args to connect";
9247dd7cddfSDavid du Colombier 	case 2:
9257dd7cddfSDavid du Colombier 		p = setraddrport(c, argv[1]);
9267dd7cddfSDavid du Colombier 		if(p != nil)
9277dd7cddfSDavid du Colombier 			return p;
9287dd7cddfSDavid du Colombier 		setladdr(c);
9292b5cb72cSDavid du Colombier 		p = setlport(c);
9302b5cb72cSDavid du Colombier 		if (p != nil)
9312b5cb72cSDavid du Colombier 			return p;
9327dd7cddfSDavid du Colombier 		break;
9337dd7cddfSDavid du Colombier 	case 3:
9347dd7cddfSDavid du Colombier 		p = setraddrport(c, argv[1]);
9357dd7cddfSDavid du Colombier 		if(p != nil)
9367dd7cddfSDavid du Colombier 			return p;
9373ff48bf5SDavid du Colombier 		p = setladdrport(c, argv[2], 0);
9383ff48bf5SDavid du Colombier 		if(p != nil)
9393ff48bf5SDavid du Colombier 			return p;
9407dd7cddfSDavid du Colombier 	}
9413ff48bf5SDavid du Colombier 
9423ff48bf5SDavid du Colombier 	if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
9433ff48bf5SDavid du Colombier 		memcmp(c->laddr, v4prefix, IPv4off) == 0)
9443ff48bf5SDavid du Colombier 		|| ipcmp(c->raddr, IPnoaddr) == 0)
9453ff48bf5SDavid du Colombier 		c->ipversion = V4;
9463ff48bf5SDavid du Colombier 	else
9473ff48bf5SDavid du Colombier 		c->ipversion = V6;
9483ff48bf5SDavid du Colombier 
9497dd7cddfSDavid du Colombier 	return nil;
9507dd7cddfSDavid du Colombier }
9517dd7cddfSDavid du Colombier /*
9527dd7cddfSDavid du Colombier  *  initiate connection and sleep till its set up
9537dd7cddfSDavid du Colombier  */
9547dd7cddfSDavid du Colombier static int
connected(void * a)9557dd7cddfSDavid du Colombier connected(void* a)
9567dd7cddfSDavid du Colombier {
9577dd7cddfSDavid du Colombier 	return ((Conv*)a)->state == Connected;
9587dd7cddfSDavid du Colombier }
9597dd7cddfSDavid du Colombier static void
connectctlmsg(Proto * x,Conv * c,Cmdbuf * cb)9607dd7cddfSDavid du Colombier connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
9617dd7cddfSDavid du Colombier {
9627dd7cddfSDavid du Colombier 	char *p;
9637dd7cddfSDavid du Colombier 
96480ee5cbfSDavid du Colombier 	if(c->state != 0)
96580ee5cbfSDavid du Colombier 		error(Econinuse);
9667dd7cddfSDavid du Colombier 	c->state = Connecting;
9677dd7cddfSDavid du Colombier 	c->cerr[0] = '\0';
9687dd7cddfSDavid du Colombier 	if(x->connect == nil)
9697dd7cddfSDavid du Colombier 		error("connect not supported");
9707dd7cddfSDavid du Colombier 	p = x->connect(c, cb->f, cb->nf);
9717dd7cddfSDavid du Colombier 	if(p != nil)
9727dd7cddfSDavid du Colombier 		error(p);
97380ee5cbfSDavid du Colombier 
97480ee5cbfSDavid du Colombier 	qunlock(c);
97580ee5cbfSDavid du Colombier 	if(waserror()){
97680ee5cbfSDavid du Colombier 		qlock(c);
97780ee5cbfSDavid du Colombier 		nexterror();
97880ee5cbfSDavid du Colombier 	}
9797dd7cddfSDavid du Colombier 	sleep(&c->cr, connected, c);
98080ee5cbfSDavid du Colombier 	qlock(c);
98180ee5cbfSDavid du Colombier 	poperror();
98280ee5cbfSDavid du Colombier 
9837dd7cddfSDavid du Colombier 	if(c->cerr[0] != '\0')
9847dd7cddfSDavid du Colombier 		error(c->cerr);
9857dd7cddfSDavid du Colombier }
9867dd7cddfSDavid du Colombier 
9877dd7cddfSDavid du Colombier /*
9887dd7cddfSDavid du Colombier  *  called by protocol announce routine to set addresses
9897dd7cddfSDavid du Colombier  */
9907dd7cddfSDavid du Colombier char*
Fsstdannounce(Conv * c,char * argv[],int argc)9917dd7cddfSDavid du Colombier Fsstdannounce(Conv* c, char* argv[], int argc)
9927dd7cddfSDavid du Colombier {
99380ee5cbfSDavid du Colombier 	memset(c->raddr, 0, sizeof(c->raddr));
99480ee5cbfSDavid du Colombier 	c->rport = 0;
9957dd7cddfSDavid du Colombier 	switch(argc){
9967dd7cddfSDavid du Colombier 	default:
9979acf0835SDavid du Colombier 		break;
9987dd7cddfSDavid du Colombier 	case 2:
99980ee5cbfSDavid du Colombier 		return setladdrport(c, argv[1], 1);
10007dd7cddfSDavid du Colombier 	}
10019acf0835SDavid du Colombier 	return "bad args to announce";
10027dd7cddfSDavid du Colombier }
10037dd7cddfSDavid du Colombier 
10047dd7cddfSDavid du Colombier /*
10057dd7cddfSDavid du Colombier  *  initiate announcement and sleep till its set up
10067dd7cddfSDavid du Colombier  */
10077dd7cddfSDavid du Colombier static int
announced(void * a)10087dd7cddfSDavid du Colombier announced(void* a)
10097dd7cddfSDavid du Colombier {
10107dd7cddfSDavid du Colombier 	return ((Conv*)a)->state == Announced;
10117dd7cddfSDavid du Colombier }
10127dd7cddfSDavid du Colombier static void
announcectlmsg(Proto * x,Conv * c,Cmdbuf * cb)10137dd7cddfSDavid du Colombier announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb)
10147dd7cddfSDavid du Colombier {
10157dd7cddfSDavid du Colombier 	char *p;
10167dd7cddfSDavid du Colombier 
101780ee5cbfSDavid du Colombier 	if(c->state != 0)
101880ee5cbfSDavid du Colombier 		error(Econinuse);
10197dd7cddfSDavid du Colombier 	c->state = Announcing;
10207dd7cddfSDavid du Colombier 	c->cerr[0] = '\0';
10217dd7cddfSDavid du Colombier 	if(x->announce == nil)
10227dd7cddfSDavid du Colombier 		error("announce not supported");
10237dd7cddfSDavid du Colombier 	p = x->announce(c, cb->f, cb->nf);
10247dd7cddfSDavid du Colombier 	if(p != nil)
10257dd7cddfSDavid du Colombier 		error(p);
102680ee5cbfSDavid du Colombier 
102780ee5cbfSDavid du Colombier 	qunlock(c);
102880ee5cbfSDavid du Colombier 	if(waserror()){
102980ee5cbfSDavid du Colombier 		qlock(c);
103080ee5cbfSDavid du Colombier 		nexterror();
103180ee5cbfSDavid du Colombier 	}
10327dd7cddfSDavid du Colombier 	sleep(&c->cr, announced, c);
103380ee5cbfSDavid du Colombier 	qlock(c);
103480ee5cbfSDavid du Colombier 	poperror();
103580ee5cbfSDavid du Colombier 
10367dd7cddfSDavid du Colombier 	if(c->cerr[0] != '\0')
10377dd7cddfSDavid du Colombier 		error(c->cerr);
10387dd7cddfSDavid du Colombier }
10397dd7cddfSDavid du Colombier 
10407dd7cddfSDavid du Colombier /*
104180ee5cbfSDavid du Colombier  *  called by protocol bind routine to set addresses
10427dd7cddfSDavid du Colombier  */
10437dd7cddfSDavid du Colombier char*
Fsstdbind(Conv * c,char * argv[],int argc)10447dd7cddfSDavid du Colombier Fsstdbind(Conv* c, char* argv[], int argc)
10457dd7cddfSDavid du Colombier {
10467dd7cddfSDavid du Colombier 	switch(argc){
10477dd7cddfSDavid du Colombier 	default:
10489acf0835SDavid du Colombier 		break;
10497dd7cddfSDavid du Colombier 	case 2:
105080ee5cbfSDavid du Colombier 		return setladdrport(c, argv[1], 0);
10517dd7cddfSDavid du Colombier 	}
10529acf0835SDavid du Colombier 	return "bad args to bind";
10537dd7cddfSDavid du Colombier }
10547dd7cddfSDavid du Colombier 
10557dd7cddfSDavid du Colombier static void
bindctlmsg(Proto * x,Conv * c,Cmdbuf * cb)10567dd7cddfSDavid du Colombier bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
10577dd7cddfSDavid du Colombier {
10587dd7cddfSDavid du Colombier 	char *p;
10597dd7cddfSDavid du Colombier 
10607dd7cddfSDavid du Colombier 	if(x->bind == nil)
10617dd7cddfSDavid du Colombier 		p = Fsstdbind(c, cb->f, cb->nf);
10627dd7cddfSDavid du Colombier 	else
10637dd7cddfSDavid du Colombier 		p = x->bind(c, cb->f, cb->nf);
10647dd7cddfSDavid du Colombier 	if(p != nil)
10657dd7cddfSDavid du Colombier 		error(p);
10667dd7cddfSDavid du Colombier }
10677dd7cddfSDavid du Colombier 
10687dd7cddfSDavid du Colombier static void
tosctlmsg(Conv * c,Cmdbuf * cb)10697dd7cddfSDavid du Colombier tosctlmsg(Conv *c, Cmdbuf *cb)
10707dd7cddfSDavid du Colombier {
10717dd7cddfSDavid du Colombier 	if(cb->nf < 2)
10727dd7cddfSDavid du Colombier 		c->tos = 0;
10737dd7cddfSDavid du Colombier 	else
10747dd7cddfSDavid du Colombier 		c->tos = atoi(cb->f[1]);
10757dd7cddfSDavid du Colombier }
10767dd7cddfSDavid du Colombier 
10777dd7cddfSDavid du Colombier static void
ttlctlmsg(Conv * c,Cmdbuf * cb)10787dd7cddfSDavid du Colombier ttlctlmsg(Conv *c, Cmdbuf *cb)
10797dd7cddfSDavid du Colombier {
10807dd7cddfSDavid du Colombier 	if(cb->nf < 2)
10817dd7cddfSDavid du Colombier 		c->ttl = MAXTTL;
10827dd7cddfSDavid du Colombier 	else
10837dd7cddfSDavid du Colombier 		c->ttl = atoi(cb->f[1]);
10847dd7cddfSDavid du Colombier }
10857dd7cddfSDavid du Colombier 
10867dd7cddfSDavid du Colombier static long
ipwrite(Chan * ch,void * v,long n,vlong off)10877dd7cddfSDavid du Colombier ipwrite(Chan* ch, void *v, long n, vlong off)
10887dd7cddfSDavid du Colombier {
10897dd7cddfSDavid du Colombier 	Conv *c;
10907dd7cddfSDavid du Colombier 	Proto *x;
10917dd7cddfSDavid du Colombier 	char *p;
10927dd7cddfSDavid du Colombier 	Cmdbuf *cb;
10937dd7cddfSDavid du Colombier 	uchar ia[IPaddrlen], ma[IPaddrlen];
10947dd7cddfSDavid du Colombier 	Fs *f;
10957dd7cddfSDavid du Colombier 	char *a;
10967dd7cddfSDavid du Colombier 	ulong offset = off;
10977dd7cddfSDavid du Colombier 
10987dd7cddfSDavid du Colombier 	a = v;
10997dd7cddfSDavid du Colombier 	f = ipfs[ch->dev];
11007dd7cddfSDavid du Colombier 
11017dd7cddfSDavid du Colombier 	switch(TYPE(ch->qid)){
11027dd7cddfSDavid du Colombier 	default:
11037dd7cddfSDavid du Colombier 		error(Eperm);
11047dd7cddfSDavid du Colombier 	case Qdata:
11057dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
11067dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
11077dd7cddfSDavid du Colombier 
11087dd7cddfSDavid du Colombier 		if(c->wq == nil)
11097dd7cddfSDavid du Colombier 			error(Eperm);
11107dd7cddfSDavid du Colombier 
11117dd7cddfSDavid du Colombier 		qwrite(c->wq, a, n);
11127dd7cddfSDavid du Colombier 		break;
11137dd7cddfSDavid du Colombier 	case Qarp:
11147dd7cddfSDavid du Colombier 		return arpwrite(f, a, n);
11157dd7cddfSDavid du Colombier 	case Qiproute:
11167dd7cddfSDavid du Colombier 		return routewrite(f, ch, a, n);
11177dd7cddfSDavid du Colombier 	case Qlog:
11189a747e4fSDavid du Colombier 		netlogctl(f, a, n);
11197dd7cddfSDavid du Colombier 		return n;
11207dd7cddfSDavid du Colombier 	case Qndb:
11217dd7cddfSDavid du Colombier 		return ndbwrite(f, a, offset, n);
11227dd7cddfSDavid du Colombier 		break;
11237dd7cddfSDavid du Colombier 	case Qctl:
11247dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
11257dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
11267dd7cddfSDavid du Colombier 		cb = parsecmd(a, n);
11277dd7cddfSDavid du Colombier 
112880ee5cbfSDavid du Colombier 		qlock(c);
11297dd7cddfSDavid du Colombier 		if(waserror()) {
113080ee5cbfSDavid du Colombier 			qunlock(c);
11317dd7cddfSDavid du Colombier 			free(cb);
11327dd7cddfSDavid du Colombier 			nexterror();
11337dd7cddfSDavid du Colombier 		}
11343ff48bf5SDavid du Colombier 		if(cb->nf < 1)
11353ff48bf5SDavid du Colombier 			error("short control request");
11363ff48bf5SDavid du Colombier 		if(strcmp(cb->f[0], "connect") == 0)
11377dd7cddfSDavid du Colombier 			connectctlmsg(x, c, cb);
11383ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "announce") == 0)
11397dd7cddfSDavid du Colombier 			announcectlmsg(x, c, cb);
11403ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "bind") == 0)
11417dd7cddfSDavid du Colombier 			bindctlmsg(x, c, cb);
11423ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "ttl") == 0)
11437dd7cddfSDavid du Colombier 			ttlctlmsg(c, cb);
11443ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "tos") == 0)
11457dd7cddfSDavid du Colombier 			tosctlmsg(c, cb);
11463ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "ignoreadvice") == 0)
11473ff48bf5SDavid du Colombier 			c->ignoreadvice = 1;
11483ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "addmulti") == 0){
11493ff48bf5SDavid du Colombier 			if(cb->nf < 2)
11503ff48bf5SDavid du Colombier 				error("addmulti needs interface address");
11517dd7cddfSDavid du Colombier 			if(cb->nf == 2){
11527dd7cddfSDavid du Colombier 				if(!ipismulticast(c->raddr))
11537dd7cddfSDavid du Colombier 					error("addmulti for a non multicast address");
1154ea58ad6fSDavid du Colombier 				if (parseip(ia, cb->f[1]) == -1)
1155ea58ad6fSDavid du Colombier 					error(Ebadip);
11567dd7cddfSDavid du Colombier 				ipifcaddmulti(c, c->raddr, ia);
11577dd7cddfSDavid du Colombier 			} else {
1158ea58ad6fSDavid du Colombier 				if (parseip(ia, cb->f[1]) == -1 ||
1159ea58ad6fSDavid du Colombier 				    parseip(ma, cb->f[2]) == -1)
1160ea58ad6fSDavid du Colombier 					error(Ebadip);
11617dd7cddfSDavid du Colombier 				if(!ipismulticast(ma))
11627dd7cddfSDavid du Colombier 					error("addmulti for a non multicast address");
11637dd7cddfSDavid du Colombier 				ipifcaddmulti(c, ma, ia);
11647dd7cddfSDavid du Colombier 			}
11653ff48bf5SDavid du Colombier 		} else if(strcmp(cb->f[0], "remmulti") == 0){
11667dd7cddfSDavid du Colombier 			if(cb->nf < 2)
11677dd7cddfSDavid du Colombier 				error("remmulti needs interface address");
11687dd7cddfSDavid du Colombier 			if(!ipismulticast(c->raddr))
11697dd7cddfSDavid du Colombier 				error("remmulti for a non multicast address");
1170ea58ad6fSDavid du Colombier 			if (parseip(ia, cb->f[1]) == -1)
1171ea58ad6fSDavid du Colombier 				error(Ebadip);
11727dd7cddfSDavid du Colombier 			ipifcremmulti(c, c->raddr, ia);
11732b5cb72cSDavid du Colombier 		} else if(strcmp(cb->f[0], "maxfragsize") == 0){
11742b5cb72cSDavid du Colombier 			if(cb->nf < 2)
11752b5cb72cSDavid du Colombier 				error("maxfragsize needs size");
11762b5cb72cSDavid du Colombier 
11772b5cb72cSDavid du Colombier 			c->maxfragsize = (int)strtol(cb->f[1], nil, 0);
11782b5cb72cSDavid du Colombier 
11793ff48bf5SDavid du Colombier 		} else if(x->ctl != nil) {
11807dd7cddfSDavid du Colombier 			p = x->ctl(c, cb->f, cb->nf);
11817dd7cddfSDavid du Colombier 			if(p != nil)
11827dd7cddfSDavid du Colombier 				error(p);
11833ff48bf5SDavid du Colombier 		} else
11843ff48bf5SDavid du Colombier 			error("unknown control request");
118580ee5cbfSDavid du Colombier 		qunlock(c);
11867dd7cddfSDavid du Colombier 		free(cb);
11877dd7cddfSDavid du Colombier 		poperror();
11887dd7cddfSDavid du Colombier 	}
11897dd7cddfSDavid du Colombier 	return n;
11907dd7cddfSDavid du Colombier }
11917dd7cddfSDavid du Colombier 
11927dd7cddfSDavid du Colombier static long
ipbwrite(Chan * ch,Block * bp,ulong offset)11937dd7cddfSDavid du Colombier ipbwrite(Chan* ch, Block* bp, ulong offset)
11947dd7cddfSDavid du Colombier {
11957dd7cddfSDavid du Colombier 	Conv *c;
11967dd7cddfSDavid du Colombier 	Proto *x;
11977dd7cddfSDavid du Colombier 	Fs *f;
11987dd7cddfSDavid du Colombier 	int n;
11997dd7cddfSDavid du Colombier 
12007dd7cddfSDavid du Colombier 	switch(TYPE(ch->qid)){
12017dd7cddfSDavid du Colombier 	case Qdata:
12027dd7cddfSDavid du Colombier 		f = ipfs[ch->dev];
12037dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
12047dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
12057dd7cddfSDavid du Colombier 
12067dd7cddfSDavid du Colombier 		if(c->wq == nil)
12077dd7cddfSDavid du Colombier 			error(Eperm);
12087dd7cddfSDavid du Colombier 
12097dd7cddfSDavid du Colombier 		if(bp->next)
12107dd7cddfSDavid du Colombier 			bp = concatblock(bp);
12117dd7cddfSDavid du Colombier 		n = BLEN(bp);
12127dd7cddfSDavid du Colombier 		qbwrite(c->wq, bp);
12137dd7cddfSDavid du Colombier 		return n;
12147dd7cddfSDavid du Colombier 	default:
12157dd7cddfSDavid du Colombier 		return devbwrite(ch, bp, offset);
12167dd7cddfSDavid du Colombier 	}
12177dd7cddfSDavid du Colombier }
12187dd7cddfSDavid du Colombier 
12197dd7cddfSDavid du Colombier Dev ipdevtab = {
12207dd7cddfSDavid du Colombier 	'I',
12217dd7cddfSDavid du Colombier 	"ip",
12227dd7cddfSDavid du Colombier 
12237dd7cddfSDavid du Colombier 	ipreset,
12249a747e4fSDavid du Colombier 	devinit,
12259a747e4fSDavid du Colombier 	devshutdown,
12267dd7cddfSDavid du Colombier 	ipattach,
12277dd7cddfSDavid du Colombier 	ipwalk,
12287dd7cddfSDavid du Colombier 	ipstat,
12297dd7cddfSDavid du Colombier 	ipopen,
12303ff48bf5SDavid du Colombier 	ipcreate,
12317dd7cddfSDavid du Colombier 	ipclose,
12327dd7cddfSDavid du Colombier 	ipread,
12337dd7cddfSDavid du Colombier 	ipbread,
12347dd7cddfSDavid du Colombier 	ipwrite,
12357dd7cddfSDavid du Colombier 	ipbwrite,
12363ff48bf5SDavid du Colombier 	ipremove,
12377dd7cddfSDavid du Colombier 	ipwstat,
12387dd7cddfSDavid du Colombier };
12397dd7cddfSDavid du Colombier 
12407dd7cddfSDavid du Colombier int
Fsproto(Fs * f,Proto * p)12417dd7cddfSDavid du Colombier Fsproto(Fs *f, Proto *p)
12427dd7cddfSDavid du Colombier {
12437dd7cddfSDavid du Colombier 	if(f->np >= Maxproto)
12447dd7cddfSDavid du Colombier 		return -1;
12457dd7cddfSDavid du Colombier 
12467dd7cddfSDavid du Colombier 	p->f = f;
12477dd7cddfSDavid du Colombier 
12487dd7cddfSDavid du Colombier 	if(p->ipproto > 0){
12497dd7cddfSDavid du Colombier 		if(f->t2p[p->ipproto] != nil)
12507dd7cddfSDavid du Colombier 			return -1;
12517dd7cddfSDavid du Colombier 		f->t2p[p->ipproto] = p;
12527dd7cddfSDavid du Colombier 	}
12537dd7cddfSDavid du Colombier 
12549a747e4fSDavid du Colombier 	p->qid.type = QTDIR;
12559a747e4fSDavid du Colombier 	p->qid.path = QID(f->np, 0, Qprotodir);
12567dd7cddfSDavid du Colombier 	p->conv = malloc(sizeof(Conv*)*(p->nc+1));
12577dd7cddfSDavid du Colombier 	if(p->conv == nil)
12587dd7cddfSDavid du Colombier 		panic("Fsproto");
12597dd7cddfSDavid du Colombier 
12607dd7cddfSDavid du Colombier 	p->x = f->np;
12617dd7cddfSDavid du Colombier 	p->nextrport = 600;
12627dd7cddfSDavid du Colombier 	f->p[f->np++] = p;
12637dd7cddfSDavid du Colombier 
12647dd7cddfSDavid du Colombier 	return 0;
12657dd7cddfSDavid du Colombier }
12667dd7cddfSDavid du Colombier 
12677dd7cddfSDavid du Colombier /*
12687dd7cddfSDavid du Colombier  *  return true if this protocol is
12697dd7cddfSDavid du Colombier  *  built in
12707dd7cddfSDavid du Colombier  */
12717dd7cddfSDavid du Colombier int
Fsbuiltinproto(Fs * f,uchar proto)12727dd7cddfSDavid du Colombier Fsbuiltinproto(Fs* f, uchar proto)
12737dd7cddfSDavid du Colombier {
12747dd7cddfSDavid du Colombier 	return f->t2p[proto] != nil;
12757dd7cddfSDavid du Colombier }
12767dd7cddfSDavid du Colombier 
12777dd7cddfSDavid du Colombier /*
12787dd7cddfSDavid du Colombier  *  called with protocol locked
12797dd7cddfSDavid du Colombier  */
12807dd7cddfSDavid du Colombier Conv*
Fsprotoclone(Proto * p,char * user)12817dd7cddfSDavid du Colombier Fsprotoclone(Proto *p, char *user)
12827dd7cddfSDavid du Colombier {
12837dd7cddfSDavid du Colombier 	Conv *c, **pp, **ep;
12847dd7cddfSDavid du Colombier 
12857dd7cddfSDavid du Colombier retry:
12867dd7cddfSDavid du Colombier 	c = nil;
12877dd7cddfSDavid du Colombier 	ep = &p->conv[p->nc];
12887dd7cddfSDavid du Colombier 	for(pp = p->conv; pp < ep; pp++) {
12897dd7cddfSDavid du Colombier 		c = *pp;
12907dd7cddfSDavid du Colombier 		if(c == nil){
12917dd7cddfSDavid du Colombier 			c = malloc(sizeof(Conv));
12927dd7cddfSDavid du Colombier 			if(c == nil)
12937dd7cddfSDavid du Colombier 				error(Enomem);
12947dd7cddfSDavid du Colombier 			qlock(c);
12957dd7cddfSDavid du Colombier 			c->p = p;
12967dd7cddfSDavid du Colombier 			c->x = pp - p->conv;
12977dd7cddfSDavid du Colombier 			if(p->ptclsize != 0){
12987dd7cddfSDavid du Colombier 				c->ptcl = malloc(p->ptclsize);
12997dd7cddfSDavid du Colombier 				if(c->ptcl == nil) {
13007dd7cddfSDavid du Colombier 					free(c);
13017dd7cddfSDavid du Colombier 					error(Enomem);
13027dd7cddfSDavid du Colombier 				}
13037dd7cddfSDavid du Colombier 			}
13047dd7cddfSDavid du Colombier 			*pp = c;
13057dd7cddfSDavid du Colombier 			p->ac++;
13063ff48bf5SDavid du Colombier 			c->eq = qopen(1024, Qmsg, 0, 0);
13077dd7cddfSDavid du Colombier 			(*p->create)(c);
13087dd7cddfSDavid du Colombier 			break;
13097dd7cddfSDavid du Colombier 		}
13107dd7cddfSDavid du Colombier 		if(canqlock(c)){
13117dd7cddfSDavid du Colombier 			/*
13127dd7cddfSDavid du Colombier 			 *  make sure both processes and protocol
13137dd7cddfSDavid du Colombier 			 *  are done with this Conv
13147dd7cddfSDavid du Colombier 			 */
13157dd7cddfSDavid du Colombier 			if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0))
13167dd7cddfSDavid du Colombier 				break;
13177dd7cddfSDavid du Colombier 
13187dd7cddfSDavid du Colombier 			qunlock(c);
13197dd7cddfSDavid du Colombier 		}
13207dd7cddfSDavid du Colombier 	}
13217dd7cddfSDavid du Colombier 	if(pp >= ep) {
1322c6569576SDavid du Colombier 		if(p->gc)
1323c6569576SDavid du Colombier 			print("Fsprotoclone: garbage collecting Convs\n");
13247dd7cddfSDavid du Colombier 		if(p->gc != nil && (*p->gc)(p))
13257dd7cddfSDavid du Colombier 			goto retry;
1326c6569576SDavid du Colombier 		/* debugging: do we ever get here? */
1327ac10c8dbSDavid du Colombier 		if (cpuserver)
1328c6569576SDavid du Colombier 			panic("Fsprotoclone: all conversations in use");
13297dd7cddfSDavid du Colombier 		return nil;
13307dd7cddfSDavid du Colombier 	}
13317dd7cddfSDavid du Colombier 
13327dd7cddfSDavid du Colombier 	c->inuse = 1;
13339a747e4fSDavid du Colombier 	kstrdup(&c->owner, user);
13347dd7cddfSDavid du Colombier 	c->perm = 0660;
133580ee5cbfSDavid du Colombier 	c->state = Idle;
13367dd7cddfSDavid du Colombier 	ipmove(c->laddr, IPnoaddr);
13377dd7cddfSDavid du Colombier 	ipmove(c->raddr, IPnoaddr);
1338a6a9e072SDavid du Colombier 	c->r = nil;
1339a6a9e072SDavid du Colombier 	c->rgen = 0;
13407dd7cddfSDavid du Colombier 	c->lport = 0;
13417dd7cddfSDavid du Colombier 	c->rport = 0;
13427dd7cddfSDavid du Colombier 	c->restricted = 0;
13432b5cb72cSDavid du Colombier 	c->maxfragsize = 0;
13447dd7cddfSDavid du Colombier 	c->ttl = MAXTTL;
13457dd7cddfSDavid du Colombier 	qreopen(c->rq);
13467dd7cddfSDavid du Colombier 	qreopen(c->wq);
13477dd7cddfSDavid du Colombier 	qreopen(c->eq);
13487dd7cddfSDavid du Colombier 
13497dd7cddfSDavid du Colombier 	qunlock(c);
13507dd7cddfSDavid du Colombier 	return c;
13517dd7cddfSDavid du Colombier }
13527dd7cddfSDavid du Colombier 
13537dd7cddfSDavid du Colombier int
Fsconnected(Conv * c,char * msg)13547dd7cddfSDavid du Colombier Fsconnected(Conv* c, char* msg)
13557dd7cddfSDavid du Colombier {
13567dd7cddfSDavid du Colombier 	if(msg != nil && *msg != '\0')
13579a747e4fSDavid du Colombier 		strncpy(c->cerr, msg, ERRMAX-1);
13587dd7cddfSDavid du Colombier 
13597dd7cddfSDavid du Colombier 	switch(c->state){
13607dd7cddfSDavid du Colombier 
13617dd7cddfSDavid du Colombier 	case Announcing:
13627dd7cddfSDavid du Colombier 		c->state = Announced;
13637dd7cddfSDavid du Colombier 		break;
13647dd7cddfSDavid du Colombier 
13657dd7cddfSDavid du Colombier 	case Connecting:
13667dd7cddfSDavid du Colombier 		c->state = Connected;
13677dd7cddfSDavid du Colombier 		break;
13687dd7cddfSDavid du Colombier 	}
13697dd7cddfSDavid du Colombier 
13707dd7cddfSDavid du Colombier 	wakeup(&c->cr);
13717dd7cddfSDavid du Colombier 	return 0;
13727dd7cddfSDavid du Colombier }
13737dd7cddfSDavid du Colombier 
13747dd7cddfSDavid du Colombier Proto*
Fsrcvpcol(Fs * f,uchar proto)13757dd7cddfSDavid du Colombier Fsrcvpcol(Fs* f, uchar proto)
13767dd7cddfSDavid du Colombier {
13777dd7cddfSDavid du Colombier 	if(f->ipmux)
13787dd7cddfSDavid du Colombier 		return f->ipmux;
13797dd7cddfSDavid du Colombier 	else
13807dd7cddfSDavid du Colombier 		return f->t2p[proto];
13817dd7cddfSDavid du Colombier }
13827dd7cddfSDavid du Colombier 
13837dd7cddfSDavid du Colombier Proto*
Fsrcvpcolx(Fs * f,uchar proto)13847dd7cddfSDavid du Colombier Fsrcvpcolx(Fs *f, uchar proto)
13857dd7cddfSDavid du Colombier {
13867dd7cddfSDavid du Colombier 	return f->t2p[proto];
13877dd7cddfSDavid du Colombier }
13887dd7cddfSDavid du Colombier 
13897dd7cddfSDavid du Colombier /*
13907dd7cddfSDavid du Colombier  *  called with protocol locked
13917dd7cddfSDavid du Colombier  */
13927dd7cddfSDavid du Colombier Conv*
Fsnewcall(Conv * c,uchar * raddr,ushort rport,uchar * laddr,ushort lport,uchar version)13933ff48bf5SDavid du Colombier Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport, uchar version)
13947dd7cddfSDavid du Colombier {
13957dd7cddfSDavid du Colombier 	Conv *nc;
13967dd7cddfSDavid du Colombier 	Conv **l;
13977dd7cddfSDavid du Colombier 	int i;
13987dd7cddfSDavid du Colombier 
13997dd7cddfSDavid du Colombier 	qlock(c);
14007dd7cddfSDavid du Colombier 	i = 0;
14017dd7cddfSDavid du Colombier 	for(l = &c->incall; *l; l = &(*l)->next)
14027dd7cddfSDavid du Colombier 		i++;
14037dd7cddfSDavid du Colombier 	if(i >= Maxincall) {
1404c6569576SDavid du Colombier 		static int beenhere;
1405c6569576SDavid du Colombier 
14067dd7cddfSDavid du Colombier 		qunlock(c);
1407c6569576SDavid du Colombier 		if (!beenhere) {
1408c6569576SDavid du Colombier 			beenhere = 1;
1409c6569576SDavid du Colombier 			print("Fsnewcall: incall queue full (%d) on port %d\n",
1410c6569576SDavid du Colombier 				i, c->lport);
1411c6569576SDavid du Colombier 		}
14127dd7cddfSDavid du Colombier 		return nil;
14137dd7cddfSDavid du Colombier 	}
14147dd7cddfSDavid du Colombier 
14157dd7cddfSDavid du Colombier 	/* find a free conversation */
14167dd7cddfSDavid du Colombier 	nc = Fsprotoclone(c->p, network);
14177dd7cddfSDavid du Colombier 	if(nc == nil) {
14187dd7cddfSDavid du Colombier 		qunlock(c);
14197dd7cddfSDavid du Colombier 		return nil;
14207dd7cddfSDavid du Colombier 	}
14217dd7cddfSDavid du Colombier 	ipmove(nc->raddr, raddr);
14227dd7cddfSDavid du Colombier 	nc->rport = rport;
14237dd7cddfSDavid du Colombier 	ipmove(nc->laddr, laddr);
14247dd7cddfSDavid du Colombier 	nc->lport = lport;
14257dd7cddfSDavid du Colombier 	nc->next = nil;
14267dd7cddfSDavid du Colombier 	*l = nc;
142780ee5cbfSDavid du Colombier 	nc->state = Connected;
14283ff48bf5SDavid du Colombier 	nc->ipversion = version;
14293ff48bf5SDavid du Colombier 
14307dd7cddfSDavid du Colombier 	qunlock(c);
14317dd7cddfSDavid du Colombier 
14327dd7cddfSDavid du Colombier 	wakeup(&c->listenr);
14337dd7cddfSDavid du Colombier 
14347dd7cddfSDavid du Colombier 	return nc;
14357dd7cddfSDavid du Colombier }
14367dd7cddfSDavid du Colombier 
14377dd7cddfSDavid du Colombier long
ndbwrite(Fs * f,char * a,ulong off,int n)14387dd7cddfSDavid du Colombier ndbwrite(Fs *f, char *a, ulong off, int n)
14397dd7cddfSDavid du Colombier {
14407dd7cddfSDavid du Colombier 	if(off > strlen(f->ndb))
14417dd7cddfSDavid du Colombier 		error(Eio);
14427dd7cddfSDavid du Colombier 	if(off+n >= sizeof(f->ndb))
14437dd7cddfSDavid du Colombier 		error(Eio);
14447dd7cddfSDavid du Colombier 	memmove(f->ndb+off, a, n);
14457dd7cddfSDavid du Colombier 	f->ndb[off+n] = 0;
14469a747e4fSDavid du Colombier 	f->ndbvers++;
14479a747e4fSDavid du Colombier 	f->ndbmtime = seconds();
14487dd7cddfSDavid du Colombier 	return n;
14497dd7cddfSDavid du Colombier }
14509a747e4fSDavid du Colombier 
14519a747e4fSDavid du Colombier ulong
scalednconv(void)14529a747e4fSDavid du Colombier scalednconv(void)
14539a747e4fSDavid du Colombier {
14549a747e4fSDavid du Colombier 	if(cpuserver && conf.npage*BY2PG >= 128*MB)
14559a747e4fSDavid du Colombier 		return Nchans*4;
14569a747e4fSDavid du Colombier 	return Nchans;
14579a747e4fSDavid du Colombier }
1458