xref: /plan9/sys/src/9/ip/devip.c (revision ea58ad6fbee60d5a3fca57ac646881779dd8f0ea)
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
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
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
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
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);
1869a747e4fSDavid du Colombier 			sprint(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);
2099a747e4fSDavid du Colombier 			sprint(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];
2159a747e4fSDavid du Colombier 			sprint(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
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*
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*
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*
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*
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
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
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*
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
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
5163ff48bf5SDavid du Colombier ipremove(Chan*)
5173ff48bf5SDavid du Colombier {
5183ff48bf5SDavid du Colombier 	error(Eperm);
5193ff48bf5SDavid du Colombier }
5203ff48bf5SDavid du Colombier 
5219a747e4fSDavid du Colombier static int
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
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
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
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);
6527dd7cddfSDavid du Colombier 		sprint(buf, "%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) {
6617dd7cddfSDavid du Colombier 			sprint(buf, "%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) {
6737dd7cddfSDavid du Colombier 			sprint(buf, "%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*
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
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*
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 
7693ff48bf5SDavid du Colombier 
77080ee5cbfSDavid du Colombier /*
7717dd7cddfSDavid du Colombier  *  pick a local port and set it
7727dd7cddfSDavid du Colombier  */
773e288d156SDavid du Colombier void
7747dd7cddfSDavid du Colombier setlport(Conv* c)
7757dd7cddfSDavid du Colombier {
7767dd7cddfSDavid du Colombier 	Proto *p;
7777dd7cddfSDavid du Colombier 	ushort *pp;
7787dd7cddfSDavid du Colombier 	int x, found;
7797dd7cddfSDavid du Colombier 
7807dd7cddfSDavid du Colombier 	p = c->p;
7817dd7cddfSDavid du Colombier 	if(c->restricted)
7827dd7cddfSDavid du Colombier 		pp = &p->nextrport;
7837dd7cddfSDavid du Colombier 	else
7847dd7cddfSDavid du Colombier 		pp = &p->nextport;
7857dd7cddfSDavid du Colombier 	qlock(p);
7867dd7cddfSDavid du Colombier 	for(;;(*pp)++){
7877dd7cddfSDavid du Colombier 		/*
7887dd7cddfSDavid du Colombier 		 * Fsproto initialises p->nextport to 0 and the restricted
7897dd7cddfSDavid du Colombier 		 * ports (p->nextrport) to 600.
7907dd7cddfSDavid du Colombier 		 * Restricted ports must lie between 600 and 1024.
7917dd7cddfSDavid du Colombier 		 * For the initial condition or if the unrestricted port number
7927dd7cddfSDavid du Colombier 		 * has wrapped round, select a random port between 5000 and 1<<15
7937dd7cddfSDavid du Colombier 		 * to start at.
7947dd7cddfSDavid du Colombier 		 */
7957dd7cddfSDavid du Colombier 		if(c->restricted){
7967dd7cddfSDavid du Colombier 			if(*pp >= 1024)
7977dd7cddfSDavid du Colombier 				*pp = 600;
7987dd7cddfSDavid du Colombier 		}
7997dd7cddfSDavid du Colombier 		else while(*pp < 5000)
8007dd7cddfSDavid du Colombier 			*pp = nrand(1<<15);
8017dd7cddfSDavid du Colombier 
8027dd7cddfSDavid du Colombier 		found = 0;
8037dd7cddfSDavid du Colombier 		for(x = 0; x < p->nc; x++){
8047dd7cddfSDavid du Colombier 			if(p->conv[x] == nil)
8057dd7cddfSDavid du Colombier 				break;
8067dd7cddfSDavid du Colombier 			if(p->conv[x]->lport == *pp){
8077dd7cddfSDavid du Colombier 				found = 1;
8087dd7cddfSDavid du Colombier 				break;
8097dd7cddfSDavid du Colombier 			}
8107dd7cddfSDavid du Colombier 		}
8117dd7cddfSDavid du Colombier 		if(!found)
8127dd7cddfSDavid du Colombier 			break;
8137dd7cddfSDavid du Colombier 	}
8147dd7cddfSDavid du Colombier 	c->lport = (*pp)++;
8157dd7cddfSDavid du Colombier 	qunlock(p);
8167dd7cddfSDavid du Colombier }
8177dd7cddfSDavid du Colombier 
8187dd7cddfSDavid du Colombier /*
8197dd7cddfSDavid du Colombier  *  set a local address and port from a string of the form
82080ee5cbfSDavid du Colombier  *	[address!]port[!r]
8217dd7cddfSDavid du Colombier  */
822e288d156SDavid du Colombier char*
8237dd7cddfSDavid du Colombier setladdrport(Conv* c, char* str, int announcing)
8247dd7cddfSDavid du Colombier {
8257dd7cddfSDavid du Colombier 	char *p;
82680ee5cbfSDavid du Colombier 	char *rv;
82780ee5cbfSDavid du Colombier 	ushort lport;
8281b0a7c7eSDavid du Colombier 	uchar addr[IPaddrlen];
82980ee5cbfSDavid du Colombier 
83080ee5cbfSDavid du Colombier 	rv = nil;
8317dd7cddfSDavid du Colombier 
8327dd7cddfSDavid du Colombier 	/*
8337dd7cddfSDavid du Colombier 	 *  ignore restricted part if it exists.  it's
8347dd7cddfSDavid du Colombier 	 *  meaningless on local ports.
8357dd7cddfSDavid du Colombier 	 */
8367dd7cddfSDavid du Colombier 	p = strchr(str, '!');
83780ee5cbfSDavid du Colombier 	if(p != nil){
8387dd7cddfSDavid du Colombier 		*p++ = 0;
83980ee5cbfSDavid du Colombier 		if(strcmp(p, "r") == 0)
84080ee5cbfSDavid du Colombier 			p = nil;
8417dd7cddfSDavid du Colombier 	}
8427dd7cddfSDavid du Colombier 
8437dd7cddfSDavid du Colombier 	c->lport = 0;
84480ee5cbfSDavid du Colombier 	if(p == nil){
84580ee5cbfSDavid du Colombier 		if(announcing)
84680ee5cbfSDavid du Colombier 			ipmove(c->laddr, IPnoaddr);
84780ee5cbfSDavid du Colombier 		else
84880ee5cbfSDavid du Colombier 			setladdr(c);
84980ee5cbfSDavid du Colombier 		p = str;
85080ee5cbfSDavid du Colombier 	} else {
85180ee5cbfSDavid du Colombier 		if(strcmp(str, "*") == 0)
85280ee5cbfSDavid du Colombier 			ipmove(c->laddr, IPnoaddr);
8531b0a7c7eSDavid du Colombier 		else {
854*ea58ad6fSDavid du Colombier 			if(parseip(addr, str) == -1)
855*ea58ad6fSDavid du Colombier 				return Ebadip;
8561b0a7c7eSDavid du Colombier 			if(ipforme(c->p->f, addr))
8571b0a7c7eSDavid du Colombier 				ipmove(c->laddr, addr);
85880ee5cbfSDavid du Colombier 			else
8591b0a7c7eSDavid du Colombier 				return "not a local IP address";
8601b0a7c7eSDavid du Colombier 		}
8617dd7cddfSDavid du Colombier 	}
86280ee5cbfSDavid du Colombier 
86380ee5cbfSDavid du Colombier 	/* one process can get all connections */
86480ee5cbfSDavid du Colombier 	if(announcing && strcmp(p, "*") == 0){
86580ee5cbfSDavid du Colombier 		if(!iseve())
86680ee5cbfSDavid du Colombier 			error(Eperm);
86780ee5cbfSDavid du Colombier 		return setluniqueport(c, 0);
86880ee5cbfSDavid du Colombier 	}
86980ee5cbfSDavid du Colombier 
87080ee5cbfSDavid du Colombier 	lport = atoi(p);
87180ee5cbfSDavid du Colombier 	if(lport <= 0)
87280ee5cbfSDavid du Colombier 		setlport(c);
87380ee5cbfSDavid du Colombier 	else
87480ee5cbfSDavid du Colombier 		rv = setluniqueport(c, lport);
87580ee5cbfSDavid du Colombier 	return rv;
8767dd7cddfSDavid du Colombier }
8777dd7cddfSDavid du Colombier 
8787dd7cddfSDavid du Colombier static char*
8797dd7cddfSDavid du Colombier setraddrport(Conv* c, char* str)
8807dd7cddfSDavid du Colombier {
8817dd7cddfSDavid du Colombier 	char *p;
8827dd7cddfSDavid du Colombier 
8837dd7cddfSDavid du Colombier 	p = strchr(str, '!');
8847dd7cddfSDavid du Colombier 	if(p == nil)
8857dd7cddfSDavid du Colombier 		return "malformed address";
8867dd7cddfSDavid du Colombier 	*p++ = 0;
887*ea58ad6fSDavid du Colombier 	if (parseip(c->raddr, str) == -1)
888*ea58ad6fSDavid du Colombier 		return Ebadip;
8897dd7cddfSDavid du Colombier 	c->rport = atoi(p);
8907dd7cddfSDavid du Colombier 	p = strchr(p, '!');
8917dd7cddfSDavid du Colombier 	if(p){
89280ee5cbfSDavid du Colombier 		if(strstr(p, "!r") != nil)
8937dd7cddfSDavid du Colombier 			c->restricted = 1;
8947dd7cddfSDavid du Colombier 	}
8957dd7cddfSDavid du Colombier 	return nil;
8967dd7cddfSDavid du Colombier }
8977dd7cddfSDavid du Colombier 
8987dd7cddfSDavid du Colombier /*
8997dd7cddfSDavid du Colombier  *  called by protocol connect routine to set addresses
9007dd7cddfSDavid du Colombier  */
9017dd7cddfSDavid du Colombier char*
9027dd7cddfSDavid du Colombier Fsstdconnect(Conv *c, char *argv[], int argc)
9037dd7cddfSDavid du Colombier {
9047dd7cddfSDavid du Colombier 	char *p;
9057dd7cddfSDavid du Colombier 
9067dd7cddfSDavid du Colombier 	switch(argc) {
9077dd7cddfSDavid du Colombier 	default:
9087dd7cddfSDavid du Colombier 		return "bad args to connect";
9097dd7cddfSDavid du Colombier 	case 2:
9107dd7cddfSDavid du Colombier 		p = setraddrport(c, argv[1]);
9117dd7cddfSDavid du Colombier 		if(p != nil)
9127dd7cddfSDavid du Colombier 			return p;
9137dd7cddfSDavid du Colombier 		setladdr(c);
9147dd7cddfSDavid du Colombier 		setlport(c);
9157dd7cddfSDavid du Colombier 		break;
9167dd7cddfSDavid du Colombier 	case 3:
9177dd7cddfSDavid du Colombier 		p = setraddrport(c, argv[1]);
9187dd7cddfSDavid du Colombier 		if(p != nil)
9197dd7cddfSDavid du Colombier 			return p;
9203ff48bf5SDavid du Colombier 		p = setladdrport(c, argv[2], 0);
9213ff48bf5SDavid du Colombier 		if(p != nil)
9223ff48bf5SDavid du Colombier 			return p;
9237dd7cddfSDavid du Colombier 	}
9243ff48bf5SDavid du Colombier 
9253ff48bf5SDavid du Colombier 	if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
9263ff48bf5SDavid du Colombier 		memcmp(c->laddr, v4prefix, IPv4off) == 0)
9273ff48bf5SDavid du Colombier 		|| ipcmp(c->raddr, IPnoaddr) == 0)
9283ff48bf5SDavid du Colombier 		c->ipversion = V4;
9293ff48bf5SDavid du Colombier 	else
9303ff48bf5SDavid du Colombier 		c->ipversion = V6;
9313ff48bf5SDavid du Colombier 
9327dd7cddfSDavid du Colombier 	return nil;
9337dd7cddfSDavid du Colombier }
9347dd7cddfSDavid du Colombier /*
9357dd7cddfSDavid du Colombier  *  initiate connection and sleep till its set up
9367dd7cddfSDavid du Colombier  */
9377dd7cddfSDavid du Colombier static int
9387dd7cddfSDavid du Colombier connected(void* a)
9397dd7cddfSDavid du Colombier {
9407dd7cddfSDavid du Colombier 	return ((Conv*)a)->state == Connected;
9417dd7cddfSDavid du Colombier }
9427dd7cddfSDavid du Colombier static void
9437dd7cddfSDavid du Colombier connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
9447dd7cddfSDavid du Colombier {
9457dd7cddfSDavid du Colombier 	char *p;
9467dd7cddfSDavid du Colombier 
94780ee5cbfSDavid du Colombier 	if(c->state != 0)
94880ee5cbfSDavid du Colombier 		error(Econinuse);
9497dd7cddfSDavid du Colombier 	c->state = Connecting;
9507dd7cddfSDavid du Colombier 	c->cerr[0] = '\0';
9517dd7cddfSDavid du Colombier 	if(x->connect == nil)
9527dd7cddfSDavid du Colombier 		error("connect not supported");
9537dd7cddfSDavid du Colombier 	p = x->connect(c, cb->f, cb->nf);
9547dd7cddfSDavid du Colombier 	if(p != nil)
9557dd7cddfSDavid du Colombier 		error(p);
95680ee5cbfSDavid du Colombier 
95780ee5cbfSDavid du Colombier 	qunlock(c);
95880ee5cbfSDavid du Colombier 	if(waserror()){
95980ee5cbfSDavid du Colombier 		qlock(c);
96080ee5cbfSDavid du Colombier 		nexterror();
96180ee5cbfSDavid du Colombier 	}
9627dd7cddfSDavid du Colombier 	sleep(&c->cr, connected, c);
96380ee5cbfSDavid du Colombier 	qlock(c);
96480ee5cbfSDavid du Colombier 	poperror();
96580ee5cbfSDavid du Colombier 
9667dd7cddfSDavid du Colombier 	if(c->cerr[0] != '\0')
9677dd7cddfSDavid du Colombier 		error(c->cerr);
9687dd7cddfSDavid du Colombier }
9697dd7cddfSDavid du Colombier 
9707dd7cddfSDavid du Colombier /*
9717dd7cddfSDavid du Colombier  *  called by protocol announce routine to set addresses
9727dd7cddfSDavid du Colombier  */
9737dd7cddfSDavid du Colombier char*
9747dd7cddfSDavid du Colombier Fsstdannounce(Conv* c, char* argv[], int argc)
9757dd7cddfSDavid du Colombier {
97680ee5cbfSDavid du Colombier 	memset(c->raddr, 0, sizeof(c->raddr));
97780ee5cbfSDavid du Colombier 	c->rport = 0;
9787dd7cddfSDavid du Colombier 	switch(argc){
9797dd7cddfSDavid du Colombier 	default:
9809acf0835SDavid du Colombier 		break;
9817dd7cddfSDavid du Colombier 	case 2:
98280ee5cbfSDavid du Colombier 		return setladdrport(c, argv[1], 1);
9837dd7cddfSDavid du Colombier 	}
9849acf0835SDavid du Colombier 	return "bad args to announce";
9857dd7cddfSDavid du Colombier }
9867dd7cddfSDavid du Colombier 
9877dd7cddfSDavid du Colombier /*
9887dd7cddfSDavid du Colombier  *  initiate announcement and sleep till its set up
9897dd7cddfSDavid du Colombier  */
9907dd7cddfSDavid du Colombier static int
9917dd7cddfSDavid du Colombier announced(void* a)
9927dd7cddfSDavid du Colombier {
9937dd7cddfSDavid du Colombier 	return ((Conv*)a)->state == Announced;
9947dd7cddfSDavid du Colombier }
9957dd7cddfSDavid du Colombier static void
9967dd7cddfSDavid du Colombier announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb)
9977dd7cddfSDavid du Colombier {
9987dd7cddfSDavid du Colombier 	char *p;
9997dd7cddfSDavid du Colombier 
100080ee5cbfSDavid du Colombier 	if(c->state != 0)
100180ee5cbfSDavid du Colombier 		error(Econinuse);
10027dd7cddfSDavid du Colombier 	c->state = Announcing;
10037dd7cddfSDavid du Colombier 	c->cerr[0] = '\0';
10047dd7cddfSDavid du Colombier 	if(x->announce == nil)
10057dd7cddfSDavid du Colombier 		error("announce not supported");
10067dd7cddfSDavid du Colombier 	p = x->announce(c, cb->f, cb->nf);
10077dd7cddfSDavid du Colombier 	if(p != nil)
10087dd7cddfSDavid du Colombier 		error(p);
100980ee5cbfSDavid du Colombier 
101080ee5cbfSDavid du Colombier 	qunlock(c);
101180ee5cbfSDavid du Colombier 	if(waserror()){
101280ee5cbfSDavid du Colombier 		qlock(c);
101380ee5cbfSDavid du Colombier 		nexterror();
101480ee5cbfSDavid du Colombier 	}
10157dd7cddfSDavid du Colombier 	sleep(&c->cr, announced, c);
101680ee5cbfSDavid du Colombier 	qlock(c);
101780ee5cbfSDavid du Colombier 	poperror();
101880ee5cbfSDavid du Colombier 
10197dd7cddfSDavid du Colombier 	if(c->cerr[0] != '\0')
10207dd7cddfSDavid du Colombier 		error(c->cerr);
10217dd7cddfSDavid du Colombier }
10227dd7cddfSDavid du Colombier 
10237dd7cddfSDavid du Colombier /*
102480ee5cbfSDavid du Colombier  *  called by protocol bind routine to set addresses
10257dd7cddfSDavid du Colombier  */
10267dd7cddfSDavid du Colombier char*
10277dd7cddfSDavid du Colombier Fsstdbind(Conv* c, char* argv[], int argc)
10287dd7cddfSDavid du Colombier {
10297dd7cddfSDavid du Colombier 	switch(argc){
10307dd7cddfSDavid du Colombier 	default:
10319acf0835SDavid du Colombier 		break;
10327dd7cddfSDavid du Colombier 	case 2:
103380ee5cbfSDavid du Colombier 		return setladdrport(c, argv[1], 0);
10347dd7cddfSDavid du Colombier 	}
10359acf0835SDavid du Colombier 	return "bad args to bind";
10367dd7cddfSDavid du Colombier }
10377dd7cddfSDavid du Colombier 
10387dd7cddfSDavid du Colombier static void
10397dd7cddfSDavid du Colombier bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
10407dd7cddfSDavid du Colombier {
10417dd7cddfSDavid du Colombier 	char *p;
10427dd7cddfSDavid du Colombier 
10437dd7cddfSDavid du Colombier 	if(x->bind == nil)
10447dd7cddfSDavid du Colombier 		p = Fsstdbind(c, cb->f, cb->nf);
10457dd7cddfSDavid du Colombier 	else
10467dd7cddfSDavid du Colombier 		p = x->bind(c, cb->f, cb->nf);
10477dd7cddfSDavid du Colombier 	if(p != nil)
10487dd7cddfSDavid du Colombier 		error(p);
10497dd7cddfSDavid du Colombier }
10507dd7cddfSDavid du Colombier 
10517dd7cddfSDavid du Colombier static void
10527dd7cddfSDavid du Colombier tosctlmsg(Conv *c, Cmdbuf *cb)
10537dd7cddfSDavid du Colombier {
10547dd7cddfSDavid du Colombier 	if(cb->nf < 2)
10557dd7cddfSDavid du Colombier 		c->tos = 0;
10567dd7cddfSDavid du Colombier 	else
10577dd7cddfSDavid du Colombier 		c->tos = atoi(cb->f[1]);
10587dd7cddfSDavid du Colombier }
10597dd7cddfSDavid du Colombier 
10607dd7cddfSDavid du Colombier static void
10617dd7cddfSDavid du Colombier ttlctlmsg(Conv *c, Cmdbuf *cb)
10627dd7cddfSDavid du Colombier {
10637dd7cddfSDavid du Colombier 	if(cb->nf < 2)
10647dd7cddfSDavid du Colombier 		c->ttl = MAXTTL;
10657dd7cddfSDavid du Colombier 	else
10667dd7cddfSDavid du Colombier 		c->ttl = atoi(cb->f[1]);
10677dd7cddfSDavid du Colombier }
10687dd7cddfSDavid du Colombier 
10697dd7cddfSDavid du Colombier static long
10707dd7cddfSDavid du Colombier ipwrite(Chan* ch, void *v, long n, vlong off)
10717dd7cddfSDavid du Colombier {
10727dd7cddfSDavid du Colombier 	Conv *c;
10737dd7cddfSDavid du Colombier 	Proto *x;
10747dd7cddfSDavid du Colombier 	char *p;
10757dd7cddfSDavid du Colombier 	Cmdbuf *cb;
10767dd7cddfSDavid du Colombier 	uchar ia[IPaddrlen], ma[IPaddrlen];
10777dd7cddfSDavid du Colombier 	Fs *f;
10787dd7cddfSDavid du Colombier 	char *a;
10797dd7cddfSDavid du Colombier 	ulong offset = off;
10807dd7cddfSDavid du Colombier 
10817dd7cddfSDavid du Colombier 	a = v;
10827dd7cddfSDavid du Colombier 	f = ipfs[ch->dev];
10837dd7cddfSDavid du Colombier 
10847dd7cddfSDavid du Colombier 	switch(TYPE(ch->qid)){
10857dd7cddfSDavid du Colombier 	default:
10867dd7cddfSDavid du Colombier 		error(Eperm);
10877dd7cddfSDavid du Colombier 	case Qdata:
10887dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
10897dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
10907dd7cddfSDavid du Colombier 
10917dd7cddfSDavid du Colombier 		if(c->wq == nil)
10927dd7cddfSDavid du Colombier 			error(Eperm);
10937dd7cddfSDavid du Colombier 
10947dd7cddfSDavid du Colombier 		qwrite(c->wq, a, n);
10957dd7cddfSDavid du Colombier 		break;
10967dd7cddfSDavid du Colombier 	case Qarp:
10977dd7cddfSDavid du Colombier 		return arpwrite(f, a, n);
10987dd7cddfSDavid du Colombier 	case Qiproute:
10997dd7cddfSDavid du Colombier 		return routewrite(f, ch, a, n);
11007dd7cddfSDavid du Colombier 	case Qlog:
11019a747e4fSDavid du Colombier 		netlogctl(f, a, n);
11027dd7cddfSDavid du Colombier 		return n;
11037dd7cddfSDavid du Colombier 	case Qndb:
11047dd7cddfSDavid du Colombier 		return ndbwrite(f, a, offset, n);
11057dd7cddfSDavid du Colombier 		break;
11067dd7cddfSDavid du Colombier 	case Qctl:
11077dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
11087dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
11097dd7cddfSDavid du Colombier 		cb = parsecmd(a, n);
11107dd7cddfSDavid du Colombier 
111180ee5cbfSDavid du Colombier 		qlock(c);
11127dd7cddfSDavid du Colombier 		if(waserror()) {
111380ee5cbfSDavid du Colombier 			qunlock(c);
11147dd7cddfSDavid du Colombier 			free(cb);
11157dd7cddfSDavid du Colombier 			nexterror();
11167dd7cddfSDavid du Colombier 		}
11173ff48bf5SDavid du Colombier 		if(cb->nf < 1)
11183ff48bf5SDavid du Colombier 			error("short control request");
11193ff48bf5SDavid du Colombier 		if(strcmp(cb->f[0], "connect") == 0)
11207dd7cddfSDavid du Colombier 			connectctlmsg(x, c, cb);
11213ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "announce") == 0)
11227dd7cddfSDavid du Colombier 			announcectlmsg(x, c, cb);
11233ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "bind") == 0)
11247dd7cddfSDavid du Colombier 			bindctlmsg(x, c, cb);
11253ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "ttl") == 0)
11267dd7cddfSDavid du Colombier 			ttlctlmsg(c, cb);
11273ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "tos") == 0)
11287dd7cddfSDavid du Colombier 			tosctlmsg(c, cb);
11293ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "ignoreadvice") == 0)
11303ff48bf5SDavid du Colombier 			c->ignoreadvice = 1;
11313ff48bf5SDavid du Colombier 		else if(strcmp(cb->f[0], "addmulti") == 0){
11323ff48bf5SDavid du Colombier 			if(cb->nf < 2)
11333ff48bf5SDavid du Colombier 				error("addmulti needs interface address");
11347dd7cddfSDavid du Colombier 			if(cb->nf == 2){
11357dd7cddfSDavid du Colombier 				if(!ipismulticast(c->raddr))
11367dd7cddfSDavid du Colombier 					error("addmulti for a non multicast address");
1137*ea58ad6fSDavid du Colombier 				if (parseip(ia, cb->f[1]) == -1)
1138*ea58ad6fSDavid du Colombier 					error(Ebadip);
11397dd7cddfSDavid du Colombier 				ipifcaddmulti(c, c->raddr, ia);
11407dd7cddfSDavid du Colombier 			} else {
1141*ea58ad6fSDavid du Colombier 				if (parseip(ia, cb->f[1]) == -1 ||
1142*ea58ad6fSDavid du Colombier 				    parseip(ma, cb->f[2]) == -1)
1143*ea58ad6fSDavid du Colombier 					error(Ebadip);
11447dd7cddfSDavid du Colombier 				if(!ipismulticast(ma))
11457dd7cddfSDavid du Colombier 					error("addmulti for a non multicast address");
11467dd7cddfSDavid du Colombier 				ipifcaddmulti(c, ma, ia);
11477dd7cddfSDavid du Colombier 			}
11483ff48bf5SDavid du Colombier 		} else if(strcmp(cb->f[0], "remmulti") == 0){
11497dd7cddfSDavid du Colombier 			if(cb->nf < 2)
11507dd7cddfSDavid du Colombier 				error("remmulti needs interface address");
11517dd7cddfSDavid du Colombier 			if(!ipismulticast(c->raddr))
11527dd7cddfSDavid du Colombier 				error("remmulti for a non multicast address");
1153*ea58ad6fSDavid du Colombier 			if (parseip(ia, cb->f[1]) == -1)
1154*ea58ad6fSDavid du Colombier 				error(Ebadip);
11557dd7cddfSDavid du Colombier 			ipifcremmulti(c, c->raddr, ia);
11563ff48bf5SDavid du Colombier 		} else if(x->ctl != nil) {
11577dd7cddfSDavid du Colombier 			p = x->ctl(c, cb->f, cb->nf);
11587dd7cddfSDavid du Colombier 			if(p != nil)
11597dd7cddfSDavid du Colombier 				error(p);
11603ff48bf5SDavid du Colombier 		} else
11613ff48bf5SDavid du Colombier 			error("unknown control request");
116280ee5cbfSDavid du Colombier 		qunlock(c);
11637dd7cddfSDavid du Colombier 		free(cb);
11647dd7cddfSDavid du Colombier 		poperror();
11657dd7cddfSDavid du Colombier 	}
11667dd7cddfSDavid du Colombier 	return n;
11677dd7cddfSDavid du Colombier }
11687dd7cddfSDavid du Colombier 
11697dd7cddfSDavid du Colombier static long
11707dd7cddfSDavid du Colombier ipbwrite(Chan* ch, Block* bp, ulong offset)
11717dd7cddfSDavid du Colombier {
11727dd7cddfSDavid du Colombier 	Conv *c;
11737dd7cddfSDavid du Colombier 	Proto *x;
11747dd7cddfSDavid du Colombier 	Fs *f;
11757dd7cddfSDavid du Colombier 	int n;
11767dd7cddfSDavid du Colombier 
11777dd7cddfSDavid du Colombier 	switch(TYPE(ch->qid)){
11787dd7cddfSDavid du Colombier 	case Qdata:
11797dd7cddfSDavid du Colombier 		f = ipfs[ch->dev];
11807dd7cddfSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
11817dd7cddfSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
11827dd7cddfSDavid du Colombier 
11837dd7cddfSDavid du Colombier 		if(c->wq == nil)
11847dd7cddfSDavid du Colombier 			error(Eperm);
11857dd7cddfSDavid du Colombier 
11867dd7cddfSDavid du Colombier 		if(bp->next)
11877dd7cddfSDavid du Colombier 			bp = concatblock(bp);
11887dd7cddfSDavid du Colombier 		n = BLEN(bp);
11897dd7cddfSDavid du Colombier 		qbwrite(c->wq, bp);
11907dd7cddfSDavid du Colombier 		return n;
11917dd7cddfSDavid du Colombier 	default:
11927dd7cddfSDavid du Colombier 		return devbwrite(ch, bp, offset);
11937dd7cddfSDavid du Colombier 	}
11947dd7cddfSDavid du Colombier }
11957dd7cddfSDavid du Colombier 
11967dd7cddfSDavid du Colombier Dev ipdevtab = {
11977dd7cddfSDavid du Colombier 	'I',
11987dd7cddfSDavid du Colombier 	"ip",
11997dd7cddfSDavid du Colombier 
12007dd7cddfSDavid du Colombier 	ipreset,
12019a747e4fSDavid du Colombier 	devinit,
12029a747e4fSDavid du Colombier 	devshutdown,
12037dd7cddfSDavid du Colombier 	ipattach,
12047dd7cddfSDavid du Colombier 	ipwalk,
12057dd7cddfSDavid du Colombier 	ipstat,
12067dd7cddfSDavid du Colombier 	ipopen,
12073ff48bf5SDavid du Colombier 	ipcreate,
12087dd7cddfSDavid du Colombier 	ipclose,
12097dd7cddfSDavid du Colombier 	ipread,
12107dd7cddfSDavid du Colombier 	ipbread,
12117dd7cddfSDavid du Colombier 	ipwrite,
12127dd7cddfSDavid du Colombier 	ipbwrite,
12133ff48bf5SDavid du Colombier 	ipremove,
12147dd7cddfSDavid du Colombier 	ipwstat,
12157dd7cddfSDavid du Colombier };
12167dd7cddfSDavid du Colombier 
12177dd7cddfSDavid du Colombier int
12187dd7cddfSDavid du Colombier Fsproto(Fs *f, Proto *p)
12197dd7cddfSDavid du Colombier {
12207dd7cddfSDavid du Colombier 	if(f->np >= Maxproto)
12217dd7cddfSDavid du Colombier 		return -1;
12227dd7cddfSDavid du Colombier 
12237dd7cddfSDavid du Colombier 	p->f = f;
12247dd7cddfSDavid du Colombier 
12257dd7cddfSDavid du Colombier 	if(p->ipproto > 0){
12267dd7cddfSDavid du Colombier 		if(f->t2p[p->ipproto] != nil)
12277dd7cddfSDavid du Colombier 			return -1;
12287dd7cddfSDavid du Colombier 		f->t2p[p->ipproto] = p;
12297dd7cddfSDavid du Colombier 	}
12307dd7cddfSDavid du Colombier 
12319a747e4fSDavid du Colombier 	p->qid.type = QTDIR;
12329a747e4fSDavid du Colombier 	p->qid.path = QID(f->np, 0, Qprotodir);
12337dd7cddfSDavid du Colombier 	p->conv = malloc(sizeof(Conv*)*(p->nc+1));
12347dd7cddfSDavid du Colombier 	if(p->conv == nil)
12357dd7cddfSDavid du Colombier 		panic("Fsproto");
12367dd7cddfSDavid du Colombier 
12377dd7cddfSDavid du Colombier 	p->x = f->np;
12387dd7cddfSDavid du Colombier 	p->nextport = 0;
12397dd7cddfSDavid du Colombier 	p->nextrport = 600;
12407dd7cddfSDavid du Colombier 	f->p[f->np++] = p;
12417dd7cddfSDavid du Colombier 
12427dd7cddfSDavid du Colombier 	return 0;
12437dd7cddfSDavid du Colombier }
12447dd7cddfSDavid du Colombier 
12457dd7cddfSDavid du Colombier /*
12467dd7cddfSDavid du Colombier  *  return true if this protocol is
12477dd7cddfSDavid du Colombier  *  built in
12487dd7cddfSDavid du Colombier  */
12497dd7cddfSDavid du Colombier int
12507dd7cddfSDavid du Colombier Fsbuiltinproto(Fs* f, uchar proto)
12517dd7cddfSDavid du Colombier {
12527dd7cddfSDavid du Colombier 	return f->t2p[proto] != nil;
12537dd7cddfSDavid du Colombier }
12547dd7cddfSDavid du Colombier 
12557dd7cddfSDavid du Colombier /*
12567dd7cddfSDavid du Colombier  *  called with protocol locked
12577dd7cddfSDavid du Colombier  */
12587dd7cddfSDavid du Colombier Conv*
12597dd7cddfSDavid du Colombier Fsprotoclone(Proto *p, char *user)
12607dd7cddfSDavid du Colombier {
12617dd7cddfSDavid du Colombier 	Conv *c, **pp, **ep;
12627dd7cddfSDavid du Colombier 
12637dd7cddfSDavid du Colombier retry:
12647dd7cddfSDavid du Colombier 	c = nil;
12657dd7cddfSDavid du Colombier 	ep = &p->conv[p->nc];
12667dd7cddfSDavid du Colombier 	for(pp = p->conv; pp < ep; pp++) {
12677dd7cddfSDavid du Colombier 		c = *pp;
12687dd7cddfSDavid du Colombier 		if(c == nil){
12697dd7cddfSDavid du Colombier 			c = malloc(sizeof(Conv));
12707dd7cddfSDavid du Colombier 			if(c == nil)
12717dd7cddfSDavid du Colombier 				error(Enomem);
12727dd7cddfSDavid du Colombier 			qlock(c);
12737dd7cddfSDavid du Colombier 			c->p = p;
12747dd7cddfSDavid du Colombier 			c->x = pp - p->conv;
12757dd7cddfSDavid du Colombier 			if(p->ptclsize != 0){
12767dd7cddfSDavid du Colombier 				c->ptcl = malloc(p->ptclsize);
12777dd7cddfSDavid du Colombier 				if(c->ptcl == nil) {
12787dd7cddfSDavid du Colombier 					free(c);
12797dd7cddfSDavid du Colombier 					error(Enomem);
12807dd7cddfSDavid du Colombier 				}
12817dd7cddfSDavid du Colombier 			}
12827dd7cddfSDavid du Colombier 			*pp = c;
12837dd7cddfSDavid du Colombier 			p->ac++;
12843ff48bf5SDavid du Colombier 			c->eq = qopen(1024, Qmsg, 0, 0);
12857dd7cddfSDavid du Colombier 			(*p->create)(c);
12867dd7cddfSDavid du Colombier 			break;
12877dd7cddfSDavid du Colombier 		}
12887dd7cddfSDavid du Colombier 		if(canqlock(c)){
12897dd7cddfSDavid du Colombier 			/*
12907dd7cddfSDavid du Colombier 			 *  make sure both processes and protocol
12917dd7cddfSDavid du Colombier 			 *  are done with this Conv
12927dd7cddfSDavid du Colombier 			 */
12937dd7cddfSDavid du Colombier 			if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0))
12947dd7cddfSDavid du Colombier 				break;
12957dd7cddfSDavid du Colombier 
12967dd7cddfSDavid du Colombier 			qunlock(c);
12977dd7cddfSDavid du Colombier 		}
12987dd7cddfSDavid du Colombier 	}
12997dd7cddfSDavid du Colombier 	if(pp >= ep) {
13007dd7cddfSDavid du Colombier 		if(p->gc != nil && (*p->gc)(p))
13017dd7cddfSDavid du Colombier 			goto retry;
13027dd7cddfSDavid du Colombier 		return nil;
13037dd7cddfSDavid du Colombier 	}
13047dd7cddfSDavid du Colombier 
13057dd7cddfSDavid du Colombier 	c->inuse = 1;
13069a747e4fSDavid du Colombier 	kstrdup(&c->owner, user);
13077dd7cddfSDavid du Colombier 	c->perm = 0660;
130880ee5cbfSDavid du Colombier 	c->state = Idle;
13097dd7cddfSDavid du Colombier 	ipmove(c->laddr, IPnoaddr);
13107dd7cddfSDavid du Colombier 	ipmove(c->raddr, IPnoaddr);
1311a6a9e072SDavid du Colombier 	c->r = nil;
1312a6a9e072SDavid du Colombier 	c->rgen = 0;
13137dd7cddfSDavid du Colombier 	c->lport = 0;
13147dd7cddfSDavid du Colombier 	c->rport = 0;
13157dd7cddfSDavid du Colombier 	c->restricted = 0;
13167dd7cddfSDavid du Colombier 	c->ttl = MAXTTL;
13177dd7cddfSDavid du Colombier 	qreopen(c->rq);
13187dd7cddfSDavid du Colombier 	qreopen(c->wq);
13197dd7cddfSDavid du Colombier 	qreopen(c->eq);
13207dd7cddfSDavid du Colombier 
13217dd7cddfSDavid du Colombier 	qunlock(c);
13227dd7cddfSDavid du Colombier 	return c;
13237dd7cddfSDavid du Colombier }
13247dd7cddfSDavid du Colombier 
13257dd7cddfSDavid du Colombier int
13267dd7cddfSDavid du Colombier Fsconnected(Conv* c, char* msg)
13277dd7cddfSDavid du Colombier {
13287dd7cddfSDavid du Colombier 	if(msg != nil && *msg != '\0')
13299a747e4fSDavid du Colombier 		strncpy(c->cerr, msg, ERRMAX-1);
13307dd7cddfSDavid du Colombier 
13317dd7cddfSDavid du Colombier 	switch(c->state){
13327dd7cddfSDavid du Colombier 
13337dd7cddfSDavid du Colombier 	case Announcing:
13347dd7cddfSDavid du Colombier 		c->state = Announced;
13357dd7cddfSDavid du Colombier 		break;
13367dd7cddfSDavid du Colombier 
13377dd7cddfSDavid du Colombier 	case Connecting:
13387dd7cddfSDavid du Colombier 		c->state = Connected;
13397dd7cddfSDavid du Colombier 		break;
13407dd7cddfSDavid du Colombier 	}
13417dd7cddfSDavid du Colombier 
13427dd7cddfSDavid du Colombier 	wakeup(&c->cr);
13437dd7cddfSDavid du Colombier 	return 0;
13447dd7cddfSDavid du Colombier }
13457dd7cddfSDavid du Colombier 
13467dd7cddfSDavid du Colombier Proto*
13477dd7cddfSDavid du Colombier Fsrcvpcol(Fs* f, uchar proto)
13487dd7cddfSDavid du Colombier {
13497dd7cddfSDavid du Colombier 	if(f->ipmux)
13507dd7cddfSDavid du Colombier 		return f->ipmux;
13517dd7cddfSDavid du Colombier 	else
13527dd7cddfSDavid du Colombier 		return f->t2p[proto];
13537dd7cddfSDavid du Colombier }
13547dd7cddfSDavid du Colombier 
13557dd7cddfSDavid du Colombier Proto*
13567dd7cddfSDavid du Colombier Fsrcvpcolx(Fs *f, uchar proto)
13577dd7cddfSDavid du Colombier {
13587dd7cddfSDavid du Colombier 	return f->t2p[proto];
13597dd7cddfSDavid du Colombier }
13607dd7cddfSDavid du Colombier 
13617dd7cddfSDavid du Colombier /*
13627dd7cddfSDavid du Colombier  *  called with protocol locked
13637dd7cddfSDavid du Colombier  */
13647dd7cddfSDavid du Colombier Conv*
13653ff48bf5SDavid du Colombier Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport, uchar version)
13667dd7cddfSDavid du Colombier {
13677dd7cddfSDavid du Colombier 	Conv *nc;
13687dd7cddfSDavid du Colombier 	Conv **l;
13697dd7cddfSDavid du Colombier 	int i;
13707dd7cddfSDavid du Colombier 
13717dd7cddfSDavid du Colombier 	qlock(c);
13727dd7cddfSDavid du Colombier 	i = 0;
13737dd7cddfSDavid du Colombier 	for(l = &c->incall; *l; l = &(*l)->next)
13747dd7cddfSDavid du Colombier 		i++;
13757dd7cddfSDavid du Colombier 	if(i >= Maxincall) {
13767dd7cddfSDavid du Colombier 		qunlock(c);
13777dd7cddfSDavid du Colombier 		return nil;
13787dd7cddfSDavid du Colombier 	}
13797dd7cddfSDavid du Colombier 
13807dd7cddfSDavid du Colombier 	/* find a free conversation */
13817dd7cddfSDavid du Colombier 	nc = Fsprotoclone(c->p, network);
13827dd7cddfSDavid du Colombier 	if(nc == nil) {
13837dd7cddfSDavid du Colombier 		qunlock(c);
13847dd7cddfSDavid du Colombier 		return nil;
13857dd7cddfSDavid du Colombier 	}
13867dd7cddfSDavid du Colombier 	ipmove(nc->raddr, raddr);
13877dd7cddfSDavid du Colombier 	nc->rport = rport;
13887dd7cddfSDavid du Colombier 	ipmove(nc->laddr, laddr);
13897dd7cddfSDavid du Colombier 	nc->lport = lport;
13907dd7cddfSDavid du Colombier 	nc->next = nil;
13917dd7cddfSDavid du Colombier 	*l = nc;
139280ee5cbfSDavid du Colombier 	nc->state = Connected;
13933ff48bf5SDavid du Colombier 	nc->ipversion = version;
13943ff48bf5SDavid du Colombier 
13957dd7cddfSDavid du Colombier 	qunlock(c);
13967dd7cddfSDavid du Colombier 
13977dd7cddfSDavid du Colombier 	wakeup(&c->listenr);
13987dd7cddfSDavid du Colombier 
13997dd7cddfSDavid du Colombier 	return nc;
14007dd7cddfSDavid du Colombier }
14017dd7cddfSDavid du Colombier 
14027dd7cddfSDavid du Colombier long
14037dd7cddfSDavid du Colombier ndbwrite(Fs *f, char *a, ulong off, int n)
14047dd7cddfSDavid du Colombier {
14057dd7cddfSDavid du Colombier 	if(off > strlen(f->ndb))
14067dd7cddfSDavid du Colombier 		error(Eio);
14077dd7cddfSDavid du Colombier 	if(off+n >= sizeof(f->ndb))
14087dd7cddfSDavid du Colombier 		error(Eio);
14097dd7cddfSDavid du Colombier 	memmove(f->ndb+off, a, n);
14107dd7cddfSDavid du Colombier 	f->ndb[off+n] = 0;
14119a747e4fSDavid du Colombier 	f->ndbvers++;
14129a747e4fSDavid du Colombier 	f->ndbmtime = seconds();
14137dd7cddfSDavid du Colombier 	return n;
14147dd7cddfSDavid du Colombier }
14159a747e4fSDavid du Colombier 
14169a747e4fSDavid du Colombier ulong
14179a747e4fSDavid du Colombier scalednconv(void)
14189a747e4fSDavid du Colombier {
14199a747e4fSDavid du Colombier 	if(cpuserver && conf.npage*BY2PG >= 128*MB)
14209a747e4fSDavid du Colombier 		return Nchans*4;
14219a747e4fSDavid du Colombier 	return Nchans;
14229a747e4fSDavid du Colombier }
1423