xref: /plan9-contrib/sys/src/9k/ip/devip.c (revision 9ef1f84b659abcb917c5c090acbce0772e494f21)
1*9ef1f84bSDavid du Colombier #include	"u.h"
2*9ef1f84bSDavid du Colombier #include	"../port/lib.h"
3*9ef1f84bSDavid du Colombier #include	"mem.h"
4*9ef1f84bSDavid du Colombier #include	"dat.h"
5*9ef1f84bSDavid du Colombier #include	"fns.h"
6*9ef1f84bSDavid du Colombier #include	"../port/error.h"
7*9ef1f84bSDavid du Colombier #include	"../ip/ip.h"
8*9ef1f84bSDavid du Colombier 
9*9ef1f84bSDavid du Colombier enum
10*9ef1f84bSDavid du Colombier {
11*9ef1f84bSDavid du Colombier 	Qtopdir=	1,		/* top level directory */
12*9ef1f84bSDavid du Colombier 	Qtopbase,
13*9ef1f84bSDavid du Colombier 	Qarp=		Qtopbase,
14*9ef1f84bSDavid du Colombier 	Qndb,
15*9ef1f84bSDavid du Colombier 	Qiproute,
16*9ef1f84bSDavid du Colombier 	Qipselftab,
17*9ef1f84bSDavid du Colombier 	Qlog,
18*9ef1f84bSDavid du Colombier 
19*9ef1f84bSDavid du Colombier 	Qprotodir,			/* directory for a protocol */
20*9ef1f84bSDavid du Colombier 	Qprotobase,
21*9ef1f84bSDavid du Colombier 	Qclone=		Qprotobase,
22*9ef1f84bSDavid du Colombier 	Qstats,
23*9ef1f84bSDavid du Colombier 
24*9ef1f84bSDavid du Colombier 	Qconvdir,			/* directory for a conversation */
25*9ef1f84bSDavid du Colombier 	Qconvbase,
26*9ef1f84bSDavid du Colombier 	Qctl=		Qconvbase,
27*9ef1f84bSDavid du Colombier 	Qdata,
28*9ef1f84bSDavid du Colombier 	Qerr,
29*9ef1f84bSDavid du Colombier 	Qlisten,
30*9ef1f84bSDavid du Colombier 	Qlocal,
31*9ef1f84bSDavid du Colombier 	Qremote,
32*9ef1f84bSDavid du Colombier 	Qstatus,
33*9ef1f84bSDavid du Colombier 	Qsnoop,
34*9ef1f84bSDavid du Colombier 
35*9ef1f84bSDavid du Colombier 	Logtype=	5,
36*9ef1f84bSDavid du Colombier 	Masktype=	(1<<Logtype)-1,
37*9ef1f84bSDavid du Colombier 	Logconv=	12,
38*9ef1f84bSDavid du Colombier 	Maskconv=	(1<<Logconv)-1,
39*9ef1f84bSDavid du Colombier 	Shiftconv=	Logtype,
40*9ef1f84bSDavid du Colombier 	Logproto=	8,
41*9ef1f84bSDavid du Colombier 	Maskproto=	(1<<Logproto)-1,
42*9ef1f84bSDavid du Colombier 	Shiftproto=	Logtype + Logconv,
43*9ef1f84bSDavid du Colombier 
44*9ef1f84bSDavid du Colombier 	Nfs=		128,
45*9ef1f84bSDavid du Colombier };
46*9ef1f84bSDavid du Colombier #define TYPE(x)		( ((ulong)(x).path) & Masktype )
47*9ef1f84bSDavid du Colombier #define CONV(x)		( (((ulong)(x).path) >> Shiftconv) & Maskconv )
48*9ef1f84bSDavid du Colombier #define PROTO(x)	( (((ulong)(x).path) >> Shiftproto) & Maskproto )
49*9ef1f84bSDavid du Colombier #define QID(p, c, y)	( ((p)<<(Shiftproto)) | ((c)<<Shiftconv) | (y) )
50*9ef1f84bSDavid du Colombier 
51*9ef1f84bSDavid du Colombier static char network[] = "network";
52*9ef1f84bSDavid du Colombier 
53*9ef1f84bSDavid du Colombier QLock	fslock;
54*9ef1f84bSDavid du Colombier Fs	*ipfs[Nfs];	/* attached fs's */
55*9ef1f84bSDavid du Colombier Queue	*qlog;
56*9ef1f84bSDavid du Colombier 
57*9ef1f84bSDavid du Colombier extern	void nullmediumlink(void);
58*9ef1f84bSDavid du Colombier extern	void pktmediumlink(void);
59*9ef1f84bSDavid du Colombier 	long ndbwrite(Fs *f, char *a, ulong off, int n);
60*9ef1f84bSDavid du Colombier 
61*9ef1f84bSDavid du Colombier static int
ip3gen(Chan * c,int i,Dir * dp)62*9ef1f84bSDavid du Colombier ip3gen(Chan *c, int i, Dir *dp)
63*9ef1f84bSDavid du Colombier {
64*9ef1f84bSDavid du Colombier 	Qid q;
65*9ef1f84bSDavid du Colombier 	Conv *cv;
66*9ef1f84bSDavid du Colombier 	char *p;
67*9ef1f84bSDavid du Colombier 
68*9ef1f84bSDavid du Colombier 	cv = ipfs[c->devno]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
69*9ef1f84bSDavid du Colombier 	if(cv->owner == nil)
70*9ef1f84bSDavid du Colombier 		kstrdup(&cv->owner, eve);
71*9ef1f84bSDavid du Colombier 	mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
72*9ef1f84bSDavid du Colombier 
73*9ef1f84bSDavid du Colombier 	switch(i) {
74*9ef1f84bSDavid du Colombier 	default:
75*9ef1f84bSDavid du Colombier 		return -1;
76*9ef1f84bSDavid du Colombier 	case Qctl:
77*9ef1f84bSDavid du Colombier 		devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
78*9ef1f84bSDavid du Colombier 		return 1;
79*9ef1f84bSDavid du Colombier 	case Qdata:
80*9ef1f84bSDavid du Colombier 		devdir(c, q, "data", qlen(cv->rq), cv->owner, cv->perm, dp);
81*9ef1f84bSDavid du Colombier 		return 1;
82*9ef1f84bSDavid du Colombier 	case Qerr:
83*9ef1f84bSDavid du Colombier 		devdir(c, q, "err", qlen(cv->eq), cv->owner, cv->perm, dp);
84*9ef1f84bSDavid du Colombier 		return 1;
85*9ef1f84bSDavid du Colombier 	case Qlisten:
86*9ef1f84bSDavid du Colombier 		devdir(c, q, "listen", 0, cv->owner, cv->perm, dp);
87*9ef1f84bSDavid du Colombier 		return 1;
88*9ef1f84bSDavid du Colombier 	case Qlocal:
89*9ef1f84bSDavid du Colombier 		p = "local";
90*9ef1f84bSDavid du Colombier 		break;
91*9ef1f84bSDavid du Colombier 	case Qremote:
92*9ef1f84bSDavid du Colombier 		p = "remote";
93*9ef1f84bSDavid du Colombier 		break;
94*9ef1f84bSDavid du Colombier 	case Qsnoop:
95*9ef1f84bSDavid du Colombier 		if(strcmp(cv->p->name, "ipifc") != 0)
96*9ef1f84bSDavid du Colombier 			return -1;
97*9ef1f84bSDavid du Colombier 		devdir(c, q, "snoop", qlen(cv->sq), cv->owner, 0400, dp);
98*9ef1f84bSDavid du Colombier 		return 1;
99*9ef1f84bSDavid du Colombier 	case Qstatus:
100*9ef1f84bSDavid du Colombier 		p = "status";
101*9ef1f84bSDavid du Colombier 		break;
102*9ef1f84bSDavid du Colombier 	}
103*9ef1f84bSDavid du Colombier 	devdir(c, q, p, 0, cv->owner, 0444, dp);
104*9ef1f84bSDavid du Colombier 	return 1;
105*9ef1f84bSDavid du Colombier }
106*9ef1f84bSDavid du Colombier 
107*9ef1f84bSDavid du Colombier static int
ip2gen(Chan * c,int i,Dir * dp)108*9ef1f84bSDavid du Colombier ip2gen(Chan *c, int i, Dir *dp)
109*9ef1f84bSDavid du Colombier {
110*9ef1f84bSDavid du Colombier 	Qid q;
111*9ef1f84bSDavid du Colombier 
112*9ef1f84bSDavid du Colombier 	switch(i) {
113*9ef1f84bSDavid du Colombier 	case Qclone:
114*9ef1f84bSDavid du Colombier 		mkqid(&q, QID(PROTO(c->qid), 0, Qclone), 0, QTFILE);
115*9ef1f84bSDavid du Colombier 		devdir(c, q, "clone", 0, network, 0666, dp);
116*9ef1f84bSDavid du Colombier 		return 1;
117*9ef1f84bSDavid du Colombier 	case Qstats:
118*9ef1f84bSDavid du Colombier 		mkqid(&q, QID(PROTO(c->qid), 0, Qstats), 0, QTFILE);
119*9ef1f84bSDavid du Colombier 		devdir(c, q, "stats", 0, network, 0444, dp);
120*9ef1f84bSDavid du Colombier 		return 1;
121*9ef1f84bSDavid du Colombier 	}
122*9ef1f84bSDavid du Colombier 	return -1;
123*9ef1f84bSDavid du Colombier }
124*9ef1f84bSDavid du Colombier 
125*9ef1f84bSDavid du Colombier static int
ip1gen(Chan * c,int i,Dir * dp)126*9ef1f84bSDavid du Colombier ip1gen(Chan *c, int i, Dir *dp)
127*9ef1f84bSDavid du Colombier {
128*9ef1f84bSDavid du Colombier 	Qid q;
129*9ef1f84bSDavid du Colombier 	char *p;
130*9ef1f84bSDavid du Colombier 	int prot;
131*9ef1f84bSDavid du Colombier 	int len = 0;
132*9ef1f84bSDavid du Colombier 	Fs *f;
133*9ef1f84bSDavid du Colombier 	extern ulong	kerndate;
134*9ef1f84bSDavid du Colombier 
135*9ef1f84bSDavid du Colombier 	f = ipfs[c->devno];
136*9ef1f84bSDavid du Colombier 
137*9ef1f84bSDavid du Colombier 	prot = 0666;
138*9ef1f84bSDavid du Colombier 	mkqid(&q, QID(0, 0, i), 0, QTFILE);
139*9ef1f84bSDavid du Colombier 	switch(i) {
140*9ef1f84bSDavid du Colombier 	default:
141*9ef1f84bSDavid du Colombier 		return -1;
142*9ef1f84bSDavid du Colombier 	case Qarp:
143*9ef1f84bSDavid du Colombier 		p = "arp";
144*9ef1f84bSDavid du Colombier 		prot = 0664;
145*9ef1f84bSDavid du Colombier 		break;
146*9ef1f84bSDavid du Colombier 	case Qndb:
147*9ef1f84bSDavid du Colombier 		p = "ndb";
148*9ef1f84bSDavid du Colombier 		len = strlen(f->ndb);
149*9ef1f84bSDavid du Colombier 		q.vers = f->ndbvers;
150*9ef1f84bSDavid du Colombier 		break;
151*9ef1f84bSDavid du Colombier 	case Qiproute:
152*9ef1f84bSDavid du Colombier 		p = "iproute";
153*9ef1f84bSDavid du Colombier 		prot = 0664;
154*9ef1f84bSDavid du Colombier 		break;
155*9ef1f84bSDavid du Colombier 	case Qipselftab:
156*9ef1f84bSDavid du Colombier 		p = "ipselftab";
157*9ef1f84bSDavid du Colombier 		prot = 0444;
158*9ef1f84bSDavid du Colombier 		break;
159*9ef1f84bSDavid du Colombier 	case Qlog:
160*9ef1f84bSDavid du Colombier 		p = "log";
161*9ef1f84bSDavid du Colombier 		break;
162*9ef1f84bSDavid du Colombier 	}
163*9ef1f84bSDavid du Colombier 	devdir(c, q, p, len, network, prot, dp);
164*9ef1f84bSDavid du Colombier 	if(i == Qndb && f->ndbmtime > kerndate)
165*9ef1f84bSDavid du Colombier 		dp->mtime = f->ndbmtime;
166*9ef1f84bSDavid du Colombier 	return 1;
167*9ef1f84bSDavid du Colombier }
168*9ef1f84bSDavid du Colombier 
169*9ef1f84bSDavid du Colombier static int
ipgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)170*9ef1f84bSDavid du Colombier ipgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
171*9ef1f84bSDavid du Colombier {
172*9ef1f84bSDavid du Colombier 	Qid q;
173*9ef1f84bSDavid du Colombier 	Conv *cv;
174*9ef1f84bSDavid du Colombier 	Fs *f;
175*9ef1f84bSDavid du Colombier 
176*9ef1f84bSDavid du Colombier 	f = ipfs[c->devno];
177*9ef1f84bSDavid du Colombier 
178*9ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)) {
179*9ef1f84bSDavid du Colombier 	case Qtopdir:
180*9ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
181*9ef1f84bSDavid du Colombier 			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
182*9ef1f84bSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#I%ud", c->devno);
183*9ef1f84bSDavid du Colombier 			devdir(c, q, up->genbuf, 0, network, 0555, dp);
184*9ef1f84bSDavid du Colombier 			return 1;
185*9ef1f84bSDavid du Colombier 		}
186*9ef1f84bSDavid du Colombier 		if(s < f->np) {
187*9ef1f84bSDavid du Colombier 			if(f->p[s]->connect == nil)
188*9ef1f84bSDavid du Colombier 				return 0;	/* protocol with no user interface */
189*9ef1f84bSDavid du Colombier 			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
190*9ef1f84bSDavid du Colombier 			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
191*9ef1f84bSDavid du Colombier 			return 1;
192*9ef1f84bSDavid du Colombier 		}
193*9ef1f84bSDavid du Colombier 		s -= f->np;
194*9ef1f84bSDavid du Colombier 		return ip1gen(c, s+Qtopbase, dp);
195*9ef1f84bSDavid du Colombier 	case Qarp:
196*9ef1f84bSDavid du Colombier 	case Qndb:
197*9ef1f84bSDavid du Colombier 	case Qlog:
198*9ef1f84bSDavid du Colombier 	case Qiproute:
199*9ef1f84bSDavid du Colombier 	case Qipselftab:
200*9ef1f84bSDavid du Colombier 		return ip1gen(c, TYPE(c->qid), dp);
201*9ef1f84bSDavid du Colombier 	case Qprotodir:
202*9ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
203*9ef1f84bSDavid du Colombier 			mkqid(&q, QID(0, 0, Qtopdir), 0, QTDIR);
204*9ef1f84bSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#I%ud", c->devno);
205*9ef1f84bSDavid du Colombier 			devdir(c, q, up->genbuf, 0, network, 0555, dp);
206*9ef1f84bSDavid du Colombier 			return 1;
207*9ef1f84bSDavid du Colombier 		}
208*9ef1f84bSDavid du Colombier 		if(s < f->p[PROTO(c->qid)]->ac) {
209*9ef1f84bSDavid du Colombier 			cv = f->p[PROTO(c->qid)]->conv[s];
210*9ef1f84bSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "%d", s);
211*9ef1f84bSDavid du Colombier 			mkqid(&q, QID(PROTO(c->qid), s, Qconvdir), 0, QTDIR);
212*9ef1f84bSDavid du Colombier 			devdir(c, q, up->genbuf, 0, cv->owner, 0555, dp);
213*9ef1f84bSDavid du Colombier 			return 1;
214*9ef1f84bSDavid du Colombier 		}
215*9ef1f84bSDavid du Colombier 		s -= f->p[PROTO(c->qid)]->ac;
216*9ef1f84bSDavid du Colombier 		return ip2gen(c, s+Qprotobase, dp);
217*9ef1f84bSDavid du Colombier 	case Qclone:
218*9ef1f84bSDavid du Colombier 	case Qstats:
219*9ef1f84bSDavid du Colombier 		return ip2gen(c, TYPE(c->qid), dp);
220*9ef1f84bSDavid du Colombier 	case Qconvdir:
221*9ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
222*9ef1f84bSDavid du Colombier 			s = PROTO(c->qid);
223*9ef1f84bSDavid du Colombier 			mkqid(&q, QID(s, 0, Qprotodir), 0, QTDIR);
224*9ef1f84bSDavid du Colombier 			devdir(c, q, f->p[s]->name, 0, network, 0555, dp);
225*9ef1f84bSDavid du Colombier 			return 1;
226*9ef1f84bSDavid du Colombier 		}
227*9ef1f84bSDavid du Colombier 		return ip3gen(c, s+Qconvbase, dp);
228*9ef1f84bSDavid du Colombier 	case Qctl:
229*9ef1f84bSDavid du Colombier 	case Qdata:
230*9ef1f84bSDavid du Colombier 	case Qerr:
231*9ef1f84bSDavid du Colombier 	case Qlisten:
232*9ef1f84bSDavid du Colombier 	case Qlocal:
233*9ef1f84bSDavid du Colombier 	case Qremote:
234*9ef1f84bSDavid du Colombier 	case Qstatus:
235*9ef1f84bSDavid du Colombier 	case Qsnoop:
236*9ef1f84bSDavid du Colombier 		return ip3gen(c, TYPE(c->qid), dp);
237*9ef1f84bSDavid du Colombier 	}
238*9ef1f84bSDavid du Colombier 	return -1;
239*9ef1f84bSDavid du Colombier }
240*9ef1f84bSDavid du Colombier 
241*9ef1f84bSDavid du Colombier static void
ipreset(void)242*9ef1f84bSDavid du Colombier ipreset(void)
243*9ef1f84bSDavid du Colombier {
244*9ef1f84bSDavid du Colombier 	nullmediumlink();
245*9ef1f84bSDavid du Colombier 	pktmediumlink();
246*9ef1f84bSDavid du Colombier 
247*9ef1f84bSDavid du Colombier 	fmtinstall('i', eipfmt);
248*9ef1f84bSDavid du Colombier 	fmtinstall('I', eipfmt);
249*9ef1f84bSDavid du Colombier 	fmtinstall('E', eipfmt);
250*9ef1f84bSDavid du Colombier 	fmtinstall('V', eipfmt);
251*9ef1f84bSDavid du Colombier 	fmtinstall('M', eipfmt);
252*9ef1f84bSDavid du Colombier }
253*9ef1f84bSDavid du Colombier 
254*9ef1f84bSDavid du Colombier static Fs*
ipgetfs(int dev)255*9ef1f84bSDavid du Colombier ipgetfs(int dev)
256*9ef1f84bSDavid du Colombier {
257*9ef1f84bSDavid du Colombier 	extern void (*ipprotoinit[])(Fs*);
258*9ef1f84bSDavid du Colombier 	Fs *f;
259*9ef1f84bSDavid du Colombier 	int i;
260*9ef1f84bSDavid du Colombier 
261*9ef1f84bSDavid du Colombier 	if(dev >= Nfs)
262*9ef1f84bSDavid du Colombier 		return nil;
263*9ef1f84bSDavid du Colombier 
264*9ef1f84bSDavid du Colombier 	qlock(&fslock);
265*9ef1f84bSDavid du Colombier 	if(ipfs[dev] == nil){
266*9ef1f84bSDavid du Colombier 		f = smalloc(sizeof(Fs));
267*9ef1f84bSDavid du Colombier 		ip_init(f);
268*9ef1f84bSDavid du Colombier 		arpinit(f);
269*9ef1f84bSDavid du Colombier 		netloginit(f);
270*9ef1f84bSDavid du Colombier 		for(i = 0; ipprotoinit[i]; i++)
271*9ef1f84bSDavid du Colombier 			ipprotoinit[i](f);
272*9ef1f84bSDavid du Colombier 		f->dev = dev;
273*9ef1f84bSDavid du Colombier 		ipfs[dev] = f;
274*9ef1f84bSDavid du Colombier 	}
275*9ef1f84bSDavid du Colombier 	qunlock(&fslock);
276*9ef1f84bSDavid du Colombier 
277*9ef1f84bSDavid du Colombier 	return ipfs[dev];
278*9ef1f84bSDavid du Colombier }
279*9ef1f84bSDavid du Colombier 
280*9ef1f84bSDavid du Colombier IPaux*
newipaux(char * owner,char * tag)281*9ef1f84bSDavid du Colombier newipaux(char *owner, char *tag)
282*9ef1f84bSDavid du Colombier {
283*9ef1f84bSDavid du Colombier 	IPaux *a;
284*9ef1f84bSDavid du Colombier 	int n;
285*9ef1f84bSDavid du Colombier 
286*9ef1f84bSDavid du Colombier 	a = smalloc(sizeof(*a));
287*9ef1f84bSDavid du Colombier 	kstrdup(&a->owner, owner);
288*9ef1f84bSDavid du Colombier 	memset(a->tag, ' ', sizeof(a->tag));
289*9ef1f84bSDavid du Colombier 	n = strlen(tag);
290*9ef1f84bSDavid du Colombier 	if(n > sizeof(a->tag))
291*9ef1f84bSDavid du Colombier 		n = sizeof(a->tag);
292*9ef1f84bSDavid du Colombier 	memmove(a->tag, tag, n);
293*9ef1f84bSDavid du Colombier 	return a;
294*9ef1f84bSDavid du Colombier }
295*9ef1f84bSDavid du Colombier 
296*9ef1f84bSDavid du Colombier #define ATTACHER(c) (((IPaux*)((c)->aux))->owner)
297*9ef1f84bSDavid du Colombier 
298*9ef1f84bSDavid du Colombier static Chan*
ipattach(char * spec)299*9ef1f84bSDavid du Colombier ipattach(char* spec)
300*9ef1f84bSDavid du Colombier {
301*9ef1f84bSDavid du Colombier 	Chan *c;
302*9ef1f84bSDavid du Colombier 	int devno;
303*9ef1f84bSDavid du Colombier 
304*9ef1f84bSDavid du Colombier 	devno = atoi(spec);
305*9ef1f84bSDavid du Colombier 	if(devno >= Nfs)
306*9ef1f84bSDavid du Colombier 		error("bad specification");
307*9ef1f84bSDavid du Colombier 
308*9ef1f84bSDavid du Colombier 	ipgetfs(devno);
309*9ef1f84bSDavid du Colombier 	c = devattach('I', spec);
310*9ef1f84bSDavid du Colombier 	mkqid(&c->qid, QID(0, 0, Qtopdir), 0, QTDIR);
311*9ef1f84bSDavid du Colombier 	c->devno = devno;
312*9ef1f84bSDavid du Colombier 
313*9ef1f84bSDavid du Colombier 	c->aux = newipaux(up->user, "none");
314*9ef1f84bSDavid du Colombier 
315*9ef1f84bSDavid du Colombier 	return c;
316*9ef1f84bSDavid du Colombier }
317*9ef1f84bSDavid du Colombier 
318*9ef1f84bSDavid du Colombier static Walkqid*
ipwalk(Chan * c,Chan * nc,char ** name,int nname)319*9ef1f84bSDavid du Colombier ipwalk(Chan* c, Chan *nc, char **name, int nname)
320*9ef1f84bSDavid du Colombier {
321*9ef1f84bSDavid du Colombier 	IPaux *a = c->aux;
322*9ef1f84bSDavid du Colombier 	Walkqid* w;
323*9ef1f84bSDavid du Colombier 
324*9ef1f84bSDavid du Colombier 	w = devwalk(c, nc, name, nname, nil, 0, ipgen);
325*9ef1f84bSDavid du Colombier 	if(w != nil && w->clone != nil)
326*9ef1f84bSDavid du Colombier 		w->clone->aux = newipaux(a->owner, a->tag);
327*9ef1f84bSDavid du Colombier 	return w;
328*9ef1f84bSDavid du Colombier }
329*9ef1f84bSDavid du Colombier 
330*9ef1f84bSDavid du Colombier 
331*9ef1f84bSDavid du Colombier static long
ipstat(Chan * c,uchar * db,long n)332*9ef1f84bSDavid du Colombier ipstat(Chan* c, uchar* db, long n)
333*9ef1f84bSDavid du Colombier {
334*9ef1f84bSDavid du Colombier 	return devstat(c, db, n, nil, 0, ipgen);
335*9ef1f84bSDavid du Colombier }
336*9ef1f84bSDavid du Colombier 
337*9ef1f84bSDavid du Colombier static int
incoming(void * arg)338*9ef1f84bSDavid du Colombier incoming(void* arg)
339*9ef1f84bSDavid du Colombier {
340*9ef1f84bSDavid du Colombier 	Conv *conv;
341*9ef1f84bSDavid du Colombier 
342*9ef1f84bSDavid du Colombier 	conv = arg;
343*9ef1f84bSDavid du Colombier 	return conv->incall != nil;
344*9ef1f84bSDavid du Colombier }
345*9ef1f84bSDavid du Colombier 
346*9ef1f84bSDavid du Colombier static int m2p[] = {
347*9ef1f84bSDavid du Colombier 	[OREAD]		4,
348*9ef1f84bSDavid du Colombier 	[OWRITE]	2,
349*9ef1f84bSDavid du Colombier 	[ORDWR]		6
350*9ef1f84bSDavid du Colombier };
351*9ef1f84bSDavid du Colombier 
352*9ef1f84bSDavid du Colombier static Chan*
ipopen(Chan * c,int omode)353*9ef1f84bSDavid du Colombier ipopen(Chan* c, int omode)
354*9ef1f84bSDavid du Colombier {
355*9ef1f84bSDavid du Colombier 	Conv *cv, *nc;
356*9ef1f84bSDavid du Colombier 	Proto *p;
357*9ef1f84bSDavid du Colombier 	int perm;
358*9ef1f84bSDavid du Colombier 	Fs *f;
359*9ef1f84bSDavid du Colombier 
360*9ef1f84bSDavid du Colombier 	perm = m2p[omode&3];
361*9ef1f84bSDavid du Colombier 
362*9ef1f84bSDavid du Colombier 	f = ipfs[c->devno];
363*9ef1f84bSDavid du Colombier 
364*9ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)) {
365*9ef1f84bSDavid du Colombier 	default:
366*9ef1f84bSDavid du Colombier 		break;
367*9ef1f84bSDavid du Colombier 	case Qndb:
368*9ef1f84bSDavid du Colombier 		if(omode & (OWRITE|OTRUNC) && !iseve())
369*9ef1f84bSDavid du Colombier 			error(Eperm);
370*9ef1f84bSDavid du Colombier 		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))
371*9ef1f84bSDavid du Colombier 			f->ndb[0] = 0;
372*9ef1f84bSDavid du Colombier 		break;
373*9ef1f84bSDavid du Colombier 	case Qlog:
374*9ef1f84bSDavid du Colombier 		netlogopen(f);
375*9ef1f84bSDavid du Colombier 		break;
376*9ef1f84bSDavid du Colombier 	case Qiproute:
377*9ef1f84bSDavid du Colombier 	case Qarp:
378*9ef1f84bSDavid du Colombier 		if(omode != OREAD && !iseve())
379*9ef1f84bSDavid du Colombier 			error(Eperm);
380*9ef1f84bSDavid du Colombier 		break;
381*9ef1f84bSDavid du Colombier 	case Qtopdir:
382*9ef1f84bSDavid du Colombier 	case Qprotodir:
383*9ef1f84bSDavid du Colombier 	case Qconvdir:
384*9ef1f84bSDavid du Colombier 	case Qstatus:
385*9ef1f84bSDavid du Colombier 	case Qremote:
386*9ef1f84bSDavid du Colombier 	case Qlocal:
387*9ef1f84bSDavid du Colombier 	case Qstats:
388*9ef1f84bSDavid du Colombier 	case Qipselftab:
389*9ef1f84bSDavid du Colombier 		if(omode != OREAD)
390*9ef1f84bSDavid du Colombier 			error(Eperm);
391*9ef1f84bSDavid du Colombier 		break;
392*9ef1f84bSDavid du Colombier 	case Qsnoop:
393*9ef1f84bSDavid du Colombier 		if(omode != OREAD)
394*9ef1f84bSDavid du Colombier 			error(Eperm);
395*9ef1f84bSDavid du Colombier 		p = f->p[PROTO(c->qid)];
396*9ef1f84bSDavid du Colombier 		cv = p->conv[CONV(c->qid)];
397*9ef1f84bSDavid du Colombier 		if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())
398*9ef1f84bSDavid du Colombier 			error(Eperm);
399*9ef1f84bSDavid du Colombier 		incref(&cv->snoopers);
400*9ef1f84bSDavid du Colombier 		break;
401*9ef1f84bSDavid du Colombier 	case Qclone:
402*9ef1f84bSDavid du Colombier 		p = f->p[PROTO(c->qid)];
403*9ef1f84bSDavid du Colombier 		qlock(p);
404*9ef1f84bSDavid du Colombier 		if(waserror()){
405*9ef1f84bSDavid du Colombier 			qunlock(p);
406*9ef1f84bSDavid du Colombier 			nexterror();
407*9ef1f84bSDavid du Colombier 		}
408*9ef1f84bSDavid du Colombier 		cv = Fsprotoclone(p, ATTACHER(c));
409*9ef1f84bSDavid du Colombier 		qunlock(p);
410*9ef1f84bSDavid du Colombier 		poperror();
411*9ef1f84bSDavid du Colombier 		if(cv == nil) {
412*9ef1f84bSDavid du Colombier 			error(Enodev);
413*9ef1f84bSDavid du Colombier 			break;
414*9ef1f84bSDavid du Colombier 		}
415*9ef1f84bSDavid du Colombier 		mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
416*9ef1f84bSDavid du Colombier 		break;
417*9ef1f84bSDavid du Colombier 	case Qdata:
418*9ef1f84bSDavid du Colombier 	case Qctl:
419*9ef1f84bSDavid du Colombier 	case Qerr:
420*9ef1f84bSDavid du Colombier 		p = f->p[PROTO(c->qid)];
421*9ef1f84bSDavid du Colombier 		qlock(p);
422*9ef1f84bSDavid du Colombier 		cv = p->conv[CONV(c->qid)];
423*9ef1f84bSDavid du Colombier 		qlock(cv);
424*9ef1f84bSDavid du Colombier 		if(waserror()) {
425*9ef1f84bSDavid du Colombier 			qunlock(cv);
426*9ef1f84bSDavid du Colombier 			qunlock(p);
427*9ef1f84bSDavid du Colombier 			nexterror();
428*9ef1f84bSDavid du Colombier 		}
429*9ef1f84bSDavid du Colombier 		if((perm & (cv->perm>>6)) != perm) {
430*9ef1f84bSDavid du Colombier 			if(strcmp(ATTACHER(c), cv->owner) != 0)
431*9ef1f84bSDavid du Colombier 				error(Eperm);
432*9ef1f84bSDavid du Colombier 			if((perm & cv->perm) != perm)
433*9ef1f84bSDavid du Colombier 				error(Eperm);
434*9ef1f84bSDavid du Colombier 
435*9ef1f84bSDavid du Colombier 		}
436*9ef1f84bSDavid du Colombier 		cv->inuse++;
437*9ef1f84bSDavid du Colombier 		if(cv->inuse == 1){
438*9ef1f84bSDavid du Colombier 			kstrdup(&cv->owner, ATTACHER(c));
439*9ef1f84bSDavid du Colombier 			cv->perm = 0660;
440*9ef1f84bSDavid du Colombier 		}
441*9ef1f84bSDavid du Colombier 		qunlock(cv);
442*9ef1f84bSDavid du Colombier 		qunlock(p);
443*9ef1f84bSDavid du Colombier 		poperror();
444*9ef1f84bSDavid du Colombier 		break;
445*9ef1f84bSDavid du Colombier 	case Qlisten:
446*9ef1f84bSDavid du Colombier 		cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
447*9ef1f84bSDavid du Colombier 		if((perm & (cv->perm>>6)) != perm) {
448*9ef1f84bSDavid du Colombier 			if(strcmp(ATTACHER(c), cv->owner) != 0)
449*9ef1f84bSDavid du Colombier 				error(Eperm);
450*9ef1f84bSDavid du Colombier 			if((perm & cv->perm) != perm)
451*9ef1f84bSDavid du Colombier 				error(Eperm);
452*9ef1f84bSDavid du Colombier 
453*9ef1f84bSDavid du Colombier 		}
454*9ef1f84bSDavid du Colombier 
455*9ef1f84bSDavid du Colombier 		if(cv->state != Announced)
456*9ef1f84bSDavid du Colombier 			error("not announced");
457*9ef1f84bSDavid du Colombier 
458*9ef1f84bSDavid du Colombier 		if(waserror()){
459*9ef1f84bSDavid du Colombier 			closeconv(cv);
460*9ef1f84bSDavid du Colombier 			nexterror();
461*9ef1f84bSDavid du Colombier 		}
462*9ef1f84bSDavid du Colombier 		qlock(cv);
463*9ef1f84bSDavid du Colombier 		cv->inuse++;
464*9ef1f84bSDavid du Colombier 		qunlock(cv);
465*9ef1f84bSDavid du Colombier 
466*9ef1f84bSDavid du Colombier 		nc = nil;
467*9ef1f84bSDavid du Colombier 		while(nc == nil) {
468*9ef1f84bSDavid du Colombier 			/* give up if we got a hangup */
469*9ef1f84bSDavid du Colombier 			if(qisclosed(cv->rq))
470*9ef1f84bSDavid du Colombier 				error("listen hungup");
471*9ef1f84bSDavid du Colombier 
472*9ef1f84bSDavid du Colombier 			qlock(&cv->listenq);
473*9ef1f84bSDavid du Colombier 			if(waserror()) {
474*9ef1f84bSDavid du Colombier 				qunlock(&cv->listenq);
475*9ef1f84bSDavid du Colombier 				nexterror();
476*9ef1f84bSDavid du Colombier 			}
477*9ef1f84bSDavid du Colombier 
478*9ef1f84bSDavid du Colombier 			/* wait for a connect */
479*9ef1f84bSDavid du Colombier 			sleep(&cv->listenr, incoming, cv);
480*9ef1f84bSDavid du Colombier 
481*9ef1f84bSDavid du Colombier 			qlock(cv);
482*9ef1f84bSDavid du Colombier 			nc = cv->incall;
483*9ef1f84bSDavid du Colombier 			if(nc != nil){
484*9ef1f84bSDavid du Colombier 				cv->incall = nc->next;
485*9ef1f84bSDavid du Colombier 				mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
486*9ef1f84bSDavid du Colombier 				kstrdup(&cv->owner, ATTACHER(c));
487*9ef1f84bSDavid du Colombier 			}
488*9ef1f84bSDavid du Colombier 			qunlock(cv);
489*9ef1f84bSDavid du Colombier 
490*9ef1f84bSDavid du Colombier 			qunlock(&cv->listenq);
491*9ef1f84bSDavid du Colombier 			poperror();
492*9ef1f84bSDavid du Colombier 		}
493*9ef1f84bSDavid du Colombier 		closeconv(cv);
494*9ef1f84bSDavid du Colombier 		poperror();
495*9ef1f84bSDavid du Colombier 		break;
496*9ef1f84bSDavid du Colombier 	}
497*9ef1f84bSDavid du Colombier 	c->mode = openmode(omode);
498*9ef1f84bSDavid du Colombier 	c->flag |= COPEN;
499*9ef1f84bSDavid du Colombier 	c->offset = 0;
500*9ef1f84bSDavid du Colombier 	return c;
501*9ef1f84bSDavid du Colombier }
502*9ef1f84bSDavid du Colombier 
503*9ef1f84bSDavid du Colombier static void
ipcreate(Chan *,char *,int,int)504*9ef1f84bSDavid du Colombier ipcreate(Chan*, char*, int, int)
505*9ef1f84bSDavid du Colombier {
506*9ef1f84bSDavid du Colombier 	error(Eperm);
507*9ef1f84bSDavid du Colombier }
508*9ef1f84bSDavid du Colombier 
509*9ef1f84bSDavid du Colombier static void
ipremove(Chan *)510*9ef1f84bSDavid du Colombier ipremove(Chan*)
511*9ef1f84bSDavid du Colombier {
512*9ef1f84bSDavid du Colombier 	error(Eperm);
513*9ef1f84bSDavid du Colombier }
514*9ef1f84bSDavid du Colombier 
515*9ef1f84bSDavid du Colombier static long
ipwstat(Chan * c,uchar * dp,long n)516*9ef1f84bSDavid du Colombier ipwstat(Chan *c, uchar *dp, long n)
517*9ef1f84bSDavid du Colombier {
518*9ef1f84bSDavid du Colombier 	Dir d;
519*9ef1f84bSDavid du Colombier 	Conv *cv;
520*9ef1f84bSDavid du Colombier 	Fs *f;
521*9ef1f84bSDavid du Colombier 	Proto *p;
522*9ef1f84bSDavid du Colombier 
523*9ef1f84bSDavid du Colombier 	f = ipfs[c->devno];
524*9ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)) {
525*9ef1f84bSDavid du Colombier 	default:
526*9ef1f84bSDavid du Colombier 		error(Eperm);
527*9ef1f84bSDavid du Colombier 		break;
528*9ef1f84bSDavid du Colombier 	case Qctl:
529*9ef1f84bSDavid du Colombier 	case Qdata:
530*9ef1f84bSDavid du Colombier 		break;
531*9ef1f84bSDavid du Colombier 	}
532*9ef1f84bSDavid du Colombier 
533*9ef1f84bSDavid du Colombier 	n = convM2D(dp, n, &d, nil);
534*9ef1f84bSDavid du Colombier 	if(n > 0){
535*9ef1f84bSDavid du Colombier 		p = f->p[PROTO(c->qid)];
536*9ef1f84bSDavid du Colombier 		cv = p->conv[CONV(c->qid)];
537*9ef1f84bSDavid du Colombier 		if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
538*9ef1f84bSDavid du Colombier 			error(Eperm);
539*9ef1f84bSDavid du Colombier 		if(d.uid[0])
540*9ef1f84bSDavid du Colombier 			kstrdup(&cv->owner, d.uid);
541*9ef1f84bSDavid du Colombier 		cv->perm = d.mode & 0777;
542*9ef1f84bSDavid du Colombier 	}
543*9ef1f84bSDavid du Colombier 	return n;
544*9ef1f84bSDavid du Colombier }
545*9ef1f84bSDavid du Colombier 
546*9ef1f84bSDavid du Colombier void
closeconv(Conv * cv)547*9ef1f84bSDavid du Colombier closeconv(Conv *cv)
548*9ef1f84bSDavid du Colombier {
549*9ef1f84bSDavid du Colombier 	Conv *nc;
550*9ef1f84bSDavid du Colombier 	Ipmulti *mp;
551*9ef1f84bSDavid du Colombier 
552*9ef1f84bSDavid du Colombier 	qlock(cv);
553*9ef1f84bSDavid du Colombier 
554*9ef1f84bSDavid du Colombier 	if(--cv->inuse > 0) {
555*9ef1f84bSDavid du Colombier 		qunlock(cv);
556*9ef1f84bSDavid du Colombier 		return;
557*9ef1f84bSDavid du Colombier 	}
558*9ef1f84bSDavid du Colombier 
559*9ef1f84bSDavid du Colombier 	/* close all incoming calls since no listen will ever happen */
560*9ef1f84bSDavid du Colombier 	for(nc = cv->incall; nc; nc = cv->incall){
561*9ef1f84bSDavid du Colombier 		cv->incall = nc->next;
562*9ef1f84bSDavid du Colombier 		closeconv(nc);
563*9ef1f84bSDavid du Colombier 	}
564*9ef1f84bSDavid du Colombier 	cv->incall = nil;
565*9ef1f84bSDavid du Colombier 
566*9ef1f84bSDavid du Colombier 	kstrdup(&cv->owner, network);
567*9ef1f84bSDavid du Colombier 	cv->perm = 0660;
568*9ef1f84bSDavid du Colombier 
569*9ef1f84bSDavid du Colombier 	while((mp = cv->multi) != nil)
570*9ef1f84bSDavid du Colombier 		ipifcremmulti(cv, mp->ma, mp->ia);
571*9ef1f84bSDavid du Colombier 
572*9ef1f84bSDavid du Colombier 	cv->r = nil;
573*9ef1f84bSDavid du Colombier 	cv->rgen = 0;
574*9ef1f84bSDavid du Colombier 	cv->p->close(cv);
575*9ef1f84bSDavid du Colombier 	cv->state = Idle;
576*9ef1f84bSDavid du Colombier 	qunlock(cv);
577*9ef1f84bSDavid du Colombier }
578*9ef1f84bSDavid du Colombier 
579*9ef1f84bSDavid du Colombier static void
ipclose(Chan * c)580*9ef1f84bSDavid du Colombier ipclose(Chan* c)
581*9ef1f84bSDavid du Colombier {
582*9ef1f84bSDavid du Colombier 	Fs *f;
583*9ef1f84bSDavid du Colombier 
584*9ef1f84bSDavid du Colombier 	f = ipfs[c->devno];
585*9ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)) {
586*9ef1f84bSDavid du Colombier 	default:
587*9ef1f84bSDavid du Colombier 		break;
588*9ef1f84bSDavid du Colombier 	case Qlog:
589*9ef1f84bSDavid du Colombier 		if(c->flag & COPEN)
590*9ef1f84bSDavid du Colombier 			netlogclose(f);
591*9ef1f84bSDavid du Colombier 		break;
592*9ef1f84bSDavid du Colombier 	case Qdata:
593*9ef1f84bSDavid du Colombier 	case Qctl:
594*9ef1f84bSDavid du Colombier 	case Qerr:
595*9ef1f84bSDavid du Colombier 		if(c->flag & COPEN)
596*9ef1f84bSDavid du Colombier 			closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);
597*9ef1f84bSDavid du Colombier 		break;
598*9ef1f84bSDavid du Colombier 	case Qsnoop:
599*9ef1f84bSDavid du Colombier 		if(c->flag & COPEN)
600*9ef1f84bSDavid du Colombier 			decref(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers);
601*9ef1f84bSDavid du Colombier 		break;
602*9ef1f84bSDavid du Colombier 	}
603*9ef1f84bSDavid du Colombier 	free(((IPaux*)c->aux)->owner);
604*9ef1f84bSDavid du Colombier 	free(c->aux);
605*9ef1f84bSDavid du Colombier }
606*9ef1f84bSDavid du Colombier 
607*9ef1f84bSDavid du Colombier enum
608*9ef1f84bSDavid du Colombier {
609*9ef1f84bSDavid du Colombier 	Statelen=	32*1024,
610*9ef1f84bSDavid du Colombier };
611*9ef1f84bSDavid du Colombier 
612*9ef1f84bSDavid du Colombier static long
ipread(Chan * ch,void * a,long n,vlong off)613*9ef1f84bSDavid du Colombier ipread(Chan *ch, void *a, long n, vlong off)
614*9ef1f84bSDavid du Colombier {
615*9ef1f84bSDavid du Colombier 	Conv *c;
616*9ef1f84bSDavid du Colombier 	Proto *x;
617*9ef1f84bSDavid du Colombier 	char *buf, *p;
618*9ef1f84bSDavid du Colombier 	long rv;
619*9ef1f84bSDavid du Colombier 	Fs *f;
620*9ef1f84bSDavid du Colombier 	ulong offset = off;
621*9ef1f84bSDavid du Colombier 
622*9ef1f84bSDavid du Colombier 	f = ipfs[ch->devno];
623*9ef1f84bSDavid du Colombier 
624*9ef1f84bSDavid du Colombier 	p = a;
625*9ef1f84bSDavid du Colombier 	switch(TYPE(ch->qid)) {
626*9ef1f84bSDavid du Colombier 	default:
627*9ef1f84bSDavid du Colombier 		error(Eperm);
628*9ef1f84bSDavid du Colombier 	case Qtopdir:
629*9ef1f84bSDavid du Colombier 	case Qprotodir:
630*9ef1f84bSDavid du Colombier 	case Qconvdir:
631*9ef1f84bSDavid du Colombier 		return devdirread(ch, a, n, 0, 0, ipgen);
632*9ef1f84bSDavid du Colombier 	case Qarp:
633*9ef1f84bSDavid du Colombier 		return arpread(f->arp, a, offset, n);
634*9ef1f84bSDavid du Colombier 	case Qndb:
635*9ef1f84bSDavid du Colombier 		return readstr(offset, a, n, f->ndb);
636*9ef1f84bSDavid du Colombier 	case Qiproute:
637*9ef1f84bSDavid du Colombier 		return routeread(f, a, offset, n);
638*9ef1f84bSDavid du Colombier 	case Qipselftab:
639*9ef1f84bSDavid du Colombier 		return ipselftabread(f, a, offset, n);
640*9ef1f84bSDavid du Colombier 	case Qlog:
641*9ef1f84bSDavid du Colombier 		return netlogread(f, a, offset, n);
642*9ef1f84bSDavid du Colombier 	case Qctl:
643*9ef1f84bSDavid du Colombier 		buf = smalloc(16);
644*9ef1f84bSDavid du Colombier 		snprint(buf, 16, "%lud", CONV(ch->qid));
645*9ef1f84bSDavid du Colombier 		rv = readstr(offset, p, n, buf);
646*9ef1f84bSDavid du Colombier 		free(buf);
647*9ef1f84bSDavid du Colombier 		return rv;
648*9ef1f84bSDavid du Colombier 	case Qremote:
649*9ef1f84bSDavid du Colombier 		buf = smalloc(Statelen);
650*9ef1f84bSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
651*9ef1f84bSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
652*9ef1f84bSDavid du Colombier 		if(x->remote == nil) {
653*9ef1f84bSDavid du Colombier 			snprint(buf, Statelen, "%I!%d\n", c->raddr, c->rport);
654*9ef1f84bSDavid du Colombier 		} else {
655*9ef1f84bSDavid du Colombier 			(*x->remote)(c, buf, Statelen-2);
656*9ef1f84bSDavid du Colombier 		}
657*9ef1f84bSDavid du Colombier 		rv = readstr(offset, p, n, buf);
658*9ef1f84bSDavid du Colombier 		free(buf);
659*9ef1f84bSDavid du Colombier 		return rv;
660*9ef1f84bSDavid du Colombier 	case Qlocal:
661*9ef1f84bSDavid du Colombier 		buf = smalloc(Statelen);
662*9ef1f84bSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
663*9ef1f84bSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
664*9ef1f84bSDavid du Colombier 		if(x->local == nil) {
665*9ef1f84bSDavid du Colombier 			snprint(buf, Statelen, "%I!%d\n", c->laddr, c->lport);
666*9ef1f84bSDavid du Colombier 		} else {
667*9ef1f84bSDavid du Colombier 			(*x->local)(c, buf, Statelen-2);
668*9ef1f84bSDavid du Colombier 		}
669*9ef1f84bSDavid du Colombier 		rv = readstr(offset, p, n, buf);
670*9ef1f84bSDavid du Colombier 		free(buf);
671*9ef1f84bSDavid du Colombier 		return rv;
672*9ef1f84bSDavid du Colombier 	case Qstatus:
673*9ef1f84bSDavid du Colombier 		buf = smalloc(Statelen);
674*9ef1f84bSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
675*9ef1f84bSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
676*9ef1f84bSDavid du Colombier 		(*x->state)(c, buf, Statelen-2);
677*9ef1f84bSDavid du Colombier 		rv = readstr(offset, p, n, buf);
678*9ef1f84bSDavid du Colombier 		free(buf);
679*9ef1f84bSDavid du Colombier 		return rv;
680*9ef1f84bSDavid du Colombier 	case Qdata:
681*9ef1f84bSDavid du Colombier 		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
682*9ef1f84bSDavid du Colombier 		return qread(c->rq, a, n);
683*9ef1f84bSDavid du Colombier 	case Qerr:
684*9ef1f84bSDavid du Colombier 		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
685*9ef1f84bSDavid du Colombier 		return qread(c->eq, a, n);
686*9ef1f84bSDavid du Colombier 	case Qsnoop:
687*9ef1f84bSDavid du Colombier 		c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
688*9ef1f84bSDavid du Colombier 		return qread(c->sq, a, n);
689*9ef1f84bSDavid du Colombier 	case Qstats:
690*9ef1f84bSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
691*9ef1f84bSDavid du Colombier 		if(x->stats == nil)
692*9ef1f84bSDavid du Colombier 			error("stats not implemented");
693*9ef1f84bSDavid du Colombier 		buf = smalloc(Statelen);
694*9ef1f84bSDavid du Colombier 		(*x->stats)(x, buf, Statelen);
695*9ef1f84bSDavid du Colombier 		rv = readstr(offset, p, n, buf);
696*9ef1f84bSDavid du Colombier 		free(buf);
697*9ef1f84bSDavid du Colombier 		return rv;
698*9ef1f84bSDavid du Colombier 	}
699*9ef1f84bSDavid du Colombier }
700*9ef1f84bSDavid du Colombier 
701*9ef1f84bSDavid du Colombier static Block*
ipbread(Chan * ch,long n,vlong offset)702*9ef1f84bSDavid du Colombier ipbread(Chan* ch, long n, vlong offset)
703*9ef1f84bSDavid du Colombier {
704*9ef1f84bSDavid du Colombier 	Conv *c;
705*9ef1f84bSDavid du Colombier 	Proto *x;
706*9ef1f84bSDavid du Colombier 	Fs *f;
707*9ef1f84bSDavid du Colombier 
708*9ef1f84bSDavid du Colombier 	switch(TYPE(ch->qid)){
709*9ef1f84bSDavid du Colombier 	case Qdata:
710*9ef1f84bSDavid du Colombier 		f = ipfs[ch->devno];
711*9ef1f84bSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
712*9ef1f84bSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
713*9ef1f84bSDavid du Colombier 		return qbread(c->rq, n);
714*9ef1f84bSDavid du Colombier 	default:
715*9ef1f84bSDavid du Colombier 		return devbread(ch, n, offset);
716*9ef1f84bSDavid du Colombier 	}
717*9ef1f84bSDavid du Colombier }
718*9ef1f84bSDavid du Colombier 
719*9ef1f84bSDavid du Colombier /*
720*9ef1f84bSDavid du Colombier  *  set local address to be that of the ifc closest to remote address
721*9ef1f84bSDavid du Colombier  */
722*9ef1f84bSDavid du Colombier static void
setladdr(Conv * c)723*9ef1f84bSDavid du Colombier setladdr(Conv* c)
724*9ef1f84bSDavid du Colombier {
725*9ef1f84bSDavid du Colombier 	findlocalip(c->p->f, c->laddr, c->raddr);
726*9ef1f84bSDavid du Colombier }
727*9ef1f84bSDavid du Colombier 
728*9ef1f84bSDavid du Colombier /*
729*9ef1f84bSDavid du Colombier  *  set a local port making sure the quad of raddr,rport,laddr,lport is unique
730*9ef1f84bSDavid du Colombier  */
731*9ef1f84bSDavid du Colombier char*
setluniqueport(Conv * c,int lport)732*9ef1f84bSDavid du Colombier setluniqueport(Conv* c, int lport)
733*9ef1f84bSDavid du Colombier {
734*9ef1f84bSDavid du Colombier 	Proto *p;
735*9ef1f84bSDavid du Colombier 	Conv *xp;
736*9ef1f84bSDavid du Colombier 	int x;
737*9ef1f84bSDavid du Colombier 
738*9ef1f84bSDavid du Colombier 	p = c->p;
739*9ef1f84bSDavid du Colombier 
740*9ef1f84bSDavid du Colombier 	qlock(p);
741*9ef1f84bSDavid du Colombier 	for(x = 0; x < p->nc; x++){
742*9ef1f84bSDavid du Colombier 		xp = p->conv[x];
743*9ef1f84bSDavid du Colombier 		if(xp == nil)
744*9ef1f84bSDavid du Colombier 			break;
745*9ef1f84bSDavid du Colombier 		if(xp == c)
746*9ef1f84bSDavid du Colombier 			continue;
747*9ef1f84bSDavid du Colombier 		if((xp->state == Connected || xp->state == Announced)
748*9ef1f84bSDavid du Colombier 		&& xp->lport == lport
749*9ef1f84bSDavid du Colombier 		&& xp->rport == c->rport
750*9ef1f84bSDavid du Colombier 		&& ipcmp(xp->raddr, c->raddr) == 0
751*9ef1f84bSDavid du Colombier 		&& ipcmp(xp->laddr, c->laddr) == 0){
752*9ef1f84bSDavid du Colombier 			qunlock(p);
753*9ef1f84bSDavid du Colombier 			return "address in use";
754*9ef1f84bSDavid du Colombier 		}
755*9ef1f84bSDavid du Colombier 	}
756*9ef1f84bSDavid du Colombier 	c->lport = lport;
757*9ef1f84bSDavid du Colombier 	qunlock(p);
758*9ef1f84bSDavid du Colombier 	return nil;
759*9ef1f84bSDavid du Colombier }
760*9ef1f84bSDavid du Colombier 
761*9ef1f84bSDavid du Colombier /*
762*9ef1f84bSDavid du Colombier  * is lport in use by anyone?
763*9ef1f84bSDavid du Colombier  */
764*9ef1f84bSDavid du Colombier static int
lportinuse(Proto * p,ushort lport)765*9ef1f84bSDavid du Colombier lportinuse(Proto *p, ushort lport)
766*9ef1f84bSDavid du Colombier {
767*9ef1f84bSDavid du Colombier 	int x;
768*9ef1f84bSDavid du Colombier 
769*9ef1f84bSDavid du Colombier 	for(x = 0; x < p->nc && p->conv[x]; x++)
770*9ef1f84bSDavid du Colombier 		if(p->conv[x]->lport == lport)
771*9ef1f84bSDavid du Colombier 			return 1;
772*9ef1f84bSDavid du Colombier 	return 0;
773*9ef1f84bSDavid du Colombier }
774*9ef1f84bSDavid du Colombier 
775*9ef1f84bSDavid du Colombier /*
776*9ef1f84bSDavid du Colombier  *  pick a local port and set it
777*9ef1f84bSDavid du Colombier  */
778*9ef1f84bSDavid du Colombier char *
setlport(Conv * c)779*9ef1f84bSDavid du Colombier setlport(Conv* c)
780*9ef1f84bSDavid du Colombier {
781*9ef1f84bSDavid du Colombier 	Proto *p;
782*9ef1f84bSDavid du Colombier 	int i, port;
783*9ef1f84bSDavid du Colombier 
784*9ef1f84bSDavid du Colombier 	p = c->p;
785*9ef1f84bSDavid du Colombier 	qlock(p);
786*9ef1f84bSDavid du Colombier 	if(c->restricted){
787*9ef1f84bSDavid du Colombier 		/* Restricted ports cycle between 600 and 1024. */
788*9ef1f84bSDavid du Colombier 		for(i=0; i<1024-600; i++){
789*9ef1f84bSDavid du Colombier 			if(p->nextrport >= 1024 || p->nextrport < 600)
790*9ef1f84bSDavid du Colombier 				p->nextrport = 600;
791*9ef1f84bSDavid du Colombier 			port = p->nextrport++;
792*9ef1f84bSDavid du Colombier 			if(!lportinuse(p, port))
793*9ef1f84bSDavid du Colombier 				goto chosen;
794*9ef1f84bSDavid du Colombier 		}
795*9ef1f84bSDavid du Colombier 	}else{
796*9ef1f84bSDavid du Colombier 		/*
797*9ef1f84bSDavid du Colombier 		 * Unrestricted ports are chosen randomly
798*9ef1f84bSDavid du Colombier 		 * between 2^15 and 2^16.  There are at most
799*9ef1f84bSDavid du Colombier 		 * 4*Nchan = 4096 ports in use at any given time,
800*9ef1f84bSDavid du Colombier 		 * so even in the worst case, a random probe has a
801*9ef1f84bSDavid du Colombier 		 * 1 - 4096/2^15 = 87% chance of success.
802*9ef1f84bSDavid du Colombier 		 * If 64 successive probes fail, there is a bug somewhere
803*9ef1f84bSDavid du Colombier 		 * (or a once in 10^58 event has happened, but that's
804*9ef1f84bSDavid du Colombier 		 * less likely than a venti collision).
805*9ef1f84bSDavid du Colombier 		 */
806*9ef1f84bSDavid du Colombier 		for(i=0; i<64; i++){
807*9ef1f84bSDavid du Colombier 			port = (1<<15) + nrand(1<<15);
808*9ef1f84bSDavid du Colombier 			if(!lportinuse(p, port))
809*9ef1f84bSDavid du Colombier 				goto chosen;
810*9ef1f84bSDavid du Colombier 		}
811*9ef1f84bSDavid du Colombier 	}
812*9ef1f84bSDavid du Colombier 	qunlock(p);
813*9ef1f84bSDavid du Colombier 	/*
814*9ef1f84bSDavid du Colombier 	 * debugging: let's see if we ever get this.
815*9ef1f84bSDavid du Colombier 	 * if we do (and we're a cpu server), we might as well restart
816*9ef1f84bSDavid du Colombier 	 * since we're now unable to service new connections.
817*9ef1f84bSDavid du Colombier 	 */
818*9ef1f84bSDavid du Colombier 	panic("setlport: out of ports");
819*9ef1f84bSDavid du Colombier 	return "no ports available";
820*9ef1f84bSDavid du Colombier 
821*9ef1f84bSDavid du Colombier chosen:
822*9ef1f84bSDavid du Colombier 	c->lport = port;
823*9ef1f84bSDavid du Colombier 	qunlock(p);
824*9ef1f84bSDavid du Colombier 	return nil;
825*9ef1f84bSDavid du Colombier }
826*9ef1f84bSDavid du Colombier 
827*9ef1f84bSDavid du Colombier /*
828*9ef1f84bSDavid du Colombier  *  set a local address and port from a string of the form
829*9ef1f84bSDavid du Colombier  *	[address!]port[!r]
830*9ef1f84bSDavid du Colombier  */
831*9ef1f84bSDavid du Colombier char*
setladdrport(Conv * c,char * str,int announcing)832*9ef1f84bSDavid du Colombier setladdrport(Conv* c, char* str, int announcing)
833*9ef1f84bSDavid du Colombier {
834*9ef1f84bSDavid du Colombier 	char *p;
835*9ef1f84bSDavid du Colombier 	char *rv;
836*9ef1f84bSDavid du Colombier 	ushort lport;
837*9ef1f84bSDavid du Colombier 	uchar addr[IPaddrlen];
838*9ef1f84bSDavid du Colombier 
839*9ef1f84bSDavid du Colombier 	/*
840*9ef1f84bSDavid du Colombier 	 *  ignore restricted part if it exists.  it's
841*9ef1f84bSDavid du Colombier 	 *  meaningless on local ports.
842*9ef1f84bSDavid du Colombier 	 */
843*9ef1f84bSDavid du Colombier 	p = strchr(str, '!');
844*9ef1f84bSDavid du Colombier 	if(p != nil){
845*9ef1f84bSDavid du Colombier 		*p++ = 0;
846*9ef1f84bSDavid du Colombier 		if(strcmp(p, "r") == 0)
847*9ef1f84bSDavid du Colombier 			p = nil;
848*9ef1f84bSDavid du Colombier 	}
849*9ef1f84bSDavid du Colombier 
850*9ef1f84bSDavid du Colombier 	c->lport = 0;
851*9ef1f84bSDavid du Colombier 	if(p == nil){
852*9ef1f84bSDavid du Colombier 		if(announcing)
853*9ef1f84bSDavid du Colombier 			ipmove(c->laddr, IPnoaddr);
854*9ef1f84bSDavid du Colombier 		else
855*9ef1f84bSDavid du Colombier 			setladdr(c);
856*9ef1f84bSDavid du Colombier 		p = str;
857*9ef1f84bSDavid du Colombier 	} else {
858*9ef1f84bSDavid du Colombier 		if(strcmp(str, "*") == 0)
859*9ef1f84bSDavid du Colombier 			ipmove(c->laddr, IPnoaddr);
860*9ef1f84bSDavid du Colombier 		else {
861*9ef1f84bSDavid du Colombier 			if(parseip(addr, str) == -1)
862*9ef1f84bSDavid du Colombier 				return Ebadip;
863*9ef1f84bSDavid du Colombier 			if(ipforme(c->p->f, addr))
864*9ef1f84bSDavid du Colombier 				ipmove(c->laddr, addr);
865*9ef1f84bSDavid du Colombier 			else
866*9ef1f84bSDavid du Colombier 				return "not a local IP address";
867*9ef1f84bSDavid du Colombier 		}
868*9ef1f84bSDavid du Colombier 	}
869*9ef1f84bSDavid du Colombier 
870*9ef1f84bSDavid du Colombier 	/* one process can get all connections */
871*9ef1f84bSDavid du Colombier 	if(announcing && strcmp(p, "*") == 0){
872*9ef1f84bSDavid du Colombier 		if(!iseve())
873*9ef1f84bSDavid du Colombier 			error(Eperm);
874*9ef1f84bSDavid du Colombier 		return setluniqueport(c, 0);
875*9ef1f84bSDavid du Colombier 	}
876*9ef1f84bSDavid du Colombier 
877*9ef1f84bSDavid du Colombier 	lport = atoi(p);
878*9ef1f84bSDavid du Colombier 	if(lport <= 0)
879*9ef1f84bSDavid du Colombier 		rv = setlport(c);
880*9ef1f84bSDavid du Colombier 	else
881*9ef1f84bSDavid du Colombier 		rv = setluniqueport(c, lport);
882*9ef1f84bSDavid du Colombier 	return rv;
883*9ef1f84bSDavid du Colombier }
884*9ef1f84bSDavid du Colombier 
885*9ef1f84bSDavid du Colombier static char*
setraddrport(Conv * c,char * str)886*9ef1f84bSDavid du Colombier setraddrport(Conv* c, char* str)
887*9ef1f84bSDavid du Colombier {
888*9ef1f84bSDavid du Colombier 	char *p;
889*9ef1f84bSDavid du Colombier 
890*9ef1f84bSDavid du Colombier 	p = strchr(str, '!');
891*9ef1f84bSDavid du Colombier 	if(p == nil)
892*9ef1f84bSDavid du Colombier 		return "malformed address";
893*9ef1f84bSDavid du Colombier 	*p++ = 0;
894*9ef1f84bSDavid du Colombier 	if (parseip(c->raddr, str) == -1)
895*9ef1f84bSDavid du Colombier 		return Ebadip;
896*9ef1f84bSDavid du Colombier 	c->rport = atoi(p);
897*9ef1f84bSDavid du Colombier 	p = strchr(p, '!');
898*9ef1f84bSDavid du Colombier 	if(p){
899*9ef1f84bSDavid du Colombier 		if(strstr(p, "!r") != nil)
900*9ef1f84bSDavid du Colombier 			c->restricted = 1;
901*9ef1f84bSDavid du Colombier 	}
902*9ef1f84bSDavid du Colombier 	return nil;
903*9ef1f84bSDavid du Colombier }
904*9ef1f84bSDavid du Colombier 
905*9ef1f84bSDavid du Colombier /*
906*9ef1f84bSDavid du Colombier  *  called by protocol connect routine to set addresses
907*9ef1f84bSDavid du Colombier  */
908*9ef1f84bSDavid du Colombier char*
Fsstdconnect(Conv * c,char * argv[],int argc)909*9ef1f84bSDavid du Colombier Fsstdconnect(Conv *c, char *argv[], int argc)
910*9ef1f84bSDavid du Colombier {
911*9ef1f84bSDavid du Colombier 	char *p;
912*9ef1f84bSDavid du Colombier 
913*9ef1f84bSDavid du Colombier 	switch(argc) {
914*9ef1f84bSDavid du Colombier 	default:
915*9ef1f84bSDavid du Colombier 		return "bad args to connect";
916*9ef1f84bSDavid du Colombier 	case 2:
917*9ef1f84bSDavid du Colombier 		p = setraddrport(c, argv[1]);
918*9ef1f84bSDavid du Colombier 		if(p != nil)
919*9ef1f84bSDavid du Colombier 			return p;
920*9ef1f84bSDavid du Colombier 		setladdr(c);
921*9ef1f84bSDavid du Colombier 		p = setlport(c);
922*9ef1f84bSDavid du Colombier 		if (p != nil)
923*9ef1f84bSDavid du Colombier 			return p;
924*9ef1f84bSDavid du Colombier 		break;
925*9ef1f84bSDavid du Colombier 	case 3:
926*9ef1f84bSDavid du Colombier 		p = setraddrport(c, argv[1]);
927*9ef1f84bSDavid du Colombier 		if(p != nil)
928*9ef1f84bSDavid du Colombier 			return p;
929*9ef1f84bSDavid du Colombier 		p = setladdrport(c, argv[2], 0);
930*9ef1f84bSDavid du Colombier 		if(p != nil)
931*9ef1f84bSDavid du Colombier 			return p;
932*9ef1f84bSDavid du Colombier 	}
933*9ef1f84bSDavid du Colombier 
934*9ef1f84bSDavid du Colombier 	if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
935*9ef1f84bSDavid du Colombier 		memcmp(c->laddr, v4prefix, IPv4off) == 0)
936*9ef1f84bSDavid du Colombier 		|| ipcmp(c->raddr, IPnoaddr) == 0)
937*9ef1f84bSDavid du Colombier 		c->ipversion = V4;
938*9ef1f84bSDavid du Colombier 	else
939*9ef1f84bSDavid du Colombier 		c->ipversion = V6;
940*9ef1f84bSDavid du Colombier 
941*9ef1f84bSDavid du Colombier 	return nil;
942*9ef1f84bSDavid du Colombier }
943*9ef1f84bSDavid du Colombier /*
944*9ef1f84bSDavid du Colombier  *  initiate connection and sleep till its set up
945*9ef1f84bSDavid du Colombier  */
946*9ef1f84bSDavid du Colombier static int
connected(void * a)947*9ef1f84bSDavid du Colombier connected(void* a)
948*9ef1f84bSDavid du Colombier {
949*9ef1f84bSDavid du Colombier 	return ((Conv*)a)->state == Connected;
950*9ef1f84bSDavid du Colombier }
951*9ef1f84bSDavid du Colombier static void
connectctlmsg(Proto * x,Conv * c,Cmdbuf * cb)952*9ef1f84bSDavid du Colombier connectctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
953*9ef1f84bSDavid du Colombier {
954*9ef1f84bSDavid du Colombier 	char *p;
955*9ef1f84bSDavid du Colombier 
956*9ef1f84bSDavid du Colombier 	if(c->state != 0)
957*9ef1f84bSDavid du Colombier 		error(Econinuse);
958*9ef1f84bSDavid du Colombier 	c->state = Connecting;
959*9ef1f84bSDavid du Colombier 	c->cerr[0] = '\0';
960*9ef1f84bSDavid du Colombier 	if(x->connect == nil)
961*9ef1f84bSDavid du Colombier 		error("connect not supported");
962*9ef1f84bSDavid du Colombier 	p = x->connect(c, cb->f, cb->nf);
963*9ef1f84bSDavid du Colombier 	if(p != nil)
964*9ef1f84bSDavid du Colombier 		error(p);
965*9ef1f84bSDavid du Colombier 
966*9ef1f84bSDavid du Colombier 	qunlock(c);
967*9ef1f84bSDavid du Colombier 	if(waserror()){
968*9ef1f84bSDavid du Colombier 		qlock(c);
969*9ef1f84bSDavid du Colombier 		nexterror();
970*9ef1f84bSDavid du Colombier 	}
971*9ef1f84bSDavid du Colombier 	sleep(&c->cr, connected, c);
972*9ef1f84bSDavid du Colombier 	qlock(c);
973*9ef1f84bSDavid du Colombier 	poperror();
974*9ef1f84bSDavid du Colombier 
975*9ef1f84bSDavid du Colombier 	if(c->cerr[0] != '\0')
976*9ef1f84bSDavid du Colombier 		error(c->cerr);
977*9ef1f84bSDavid du Colombier }
978*9ef1f84bSDavid du Colombier 
979*9ef1f84bSDavid du Colombier /*
980*9ef1f84bSDavid du Colombier  *  called by protocol announce routine to set addresses
981*9ef1f84bSDavid du Colombier  */
982*9ef1f84bSDavid du Colombier char*
Fsstdannounce(Conv * c,char * argv[],int argc)983*9ef1f84bSDavid du Colombier Fsstdannounce(Conv* c, char* argv[], int argc)
984*9ef1f84bSDavid du Colombier {
985*9ef1f84bSDavid du Colombier 	memset(c->raddr, 0, sizeof(c->raddr));
986*9ef1f84bSDavid du Colombier 	c->rport = 0;
987*9ef1f84bSDavid du Colombier 	switch(argc){
988*9ef1f84bSDavid du Colombier 	default:
989*9ef1f84bSDavid du Colombier 		break;
990*9ef1f84bSDavid du Colombier 	case 2:
991*9ef1f84bSDavid du Colombier 		return setladdrport(c, argv[1], 1);
992*9ef1f84bSDavid du Colombier 	}
993*9ef1f84bSDavid du Colombier 	return "bad args to announce";
994*9ef1f84bSDavid du Colombier }
995*9ef1f84bSDavid du Colombier 
996*9ef1f84bSDavid du Colombier /*
997*9ef1f84bSDavid du Colombier  *  initiate announcement and sleep till its set up
998*9ef1f84bSDavid du Colombier  */
999*9ef1f84bSDavid du Colombier static int
announced(void * a)1000*9ef1f84bSDavid du Colombier announced(void* a)
1001*9ef1f84bSDavid du Colombier {
1002*9ef1f84bSDavid du Colombier 	return ((Conv*)a)->state == Announced;
1003*9ef1f84bSDavid du Colombier }
1004*9ef1f84bSDavid du Colombier static void
announcectlmsg(Proto * x,Conv * c,Cmdbuf * cb)1005*9ef1f84bSDavid du Colombier announcectlmsg(Proto *x, Conv *c, Cmdbuf *cb)
1006*9ef1f84bSDavid du Colombier {
1007*9ef1f84bSDavid du Colombier 	char *p;
1008*9ef1f84bSDavid du Colombier 
1009*9ef1f84bSDavid du Colombier 	if(c->state != 0)
1010*9ef1f84bSDavid du Colombier 		error(Econinuse);
1011*9ef1f84bSDavid du Colombier 	c->state = Announcing;
1012*9ef1f84bSDavid du Colombier 	c->cerr[0] = '\0';
1013*9ef1f84bSDavid du Colombier 	if(x->announce == nil)
1014*9ef1f84bSDavid du Colombier 		error("announce not supported");
1015*9ef1f84bSDavid du Colombier 	p = x->announce(c, cb->f, cb->nf);
1016*9ef1f84bSDavid du Colombier 	if(p != nil)
1017*9ef1f84bSDavid du Colombier 		error(p);
1018*9ef1f84bSDavid du Colombier 
1019*9ef1f84bSDavid du Colombier 	qunlock(c);
1020*9ef1f84bSDavid du Colombier 	if(waserror()){
1021*9ef1f84bSDavid du Colombier 		qlock(c);
1022*9ef1f84bSDavid du Colombier 		nexterror();
1023*9ef1f84bSDavid du Colombier 	}
1024*9ef1f84bSDavid du Colombier 	sleep(&c->cr, announced, c);
1025*9ef1f84bSDavid du Colombier 	qlock(c);
1026*9ef1f84bSDavid du Colombier 	poperror();
1027*9ef1f84bSDavid du Colombier 
1028*9ef1f84bSDavid du Colombier 	if(c->cerr[0] != '\0')
1029*9ef1f84bSDavid du Colombier 		error(c->cerr);
1030*9ef1f84bSDavid du Colombier }
1031*9ef1f84bSDavid du Colombier 
1032*9ef1f84bSDavid du Colombier /*
1033*9ef1f84bSDavid du Colombier  *  called by protocol bind routine to set addresses
1034*9ef1f84bSDavid du Colombier  */
1035*9ef1f84bSDavid du Colombier char*
Fsstdbind(Conv * c,char * argv[],int argc)1036*9ef1f84bSDavid du Colombier Fsstdbind(Conv* c, char* argv[], int argc)
1037*9ef1f84bSDavid du Colombier {
1038*9ef1f84bSDavid du Colombier 	switch(argc){
1039*9ef1f84bSDavid du Colombier 	default:
1040*9ef1f84bSDavid du Colombier 		break;
1041*9ef1f84bSDavid du Colombier 	case 2:
1042*9ef1f84bSDavid du Colombier 		return setladdrport(c, argv[1], 0);
1043*9ef1f84bSDavid du Colombier 	}
1044*9ef1f84bSDavid du Colombier 	return "bad args to bind";
1045*9ef1f84bSDavid du Colombier }
1046*9ef1f84bSDavid du Colombier 
1047*9ef1f84bSDavid du Colombier static void
bindctlmsg(Proto * x,Conv * c,Cmdbuf * cb)1048*9ef1f84bSDavid du Colombier bindctlmsg(Proto *x, Conv *c, Cmdbuf *cb)
1049*9ef1f84bSDavid du Colombier {
1050*9ef1f84bSDavid du Colombier 	char *p;
1051*9ef1f84bSDavid du Colombier 
1052*9ef1f84bSDavid du Colombier 	if(x->bind == nil)
1053*9ef1f84bSDavid du Colombier 		p = Fsstdbind(c, cb->f, cb->nf);
1054*9ef1f84bSDavid du Colombier 	else
1055*9ef1f84bSDavid du Colombier 		p = x->bind(c, cb->f, cb->nf);
1056*9ef1f84bSDavid du Colombier 	if(p != nil)
1057*9ef1f84bSDavid du Colombier 		error(p);
1058*9ef1f84bSDavid du Colombier }
1059*9ef1f84bSDavid du Colombier 
1060*9ef1f84bSDavid du Colombier static void
tosctlmsg(Conv * c,Cmdbuf * cb)1061*9ef1f84bSDavid du Colombier tosctlmsg(Conv *c, Cmdbuf *cb)
1062*9ef1f84bSDavid du Colombier {
1063*9ef1f84bSDavid du Colombier 	if(cb->nf < 2)
1064*9ef1f84bSDavid du Colombier 		c->tos = 0;
1065*9ef1f84bSDavid du Colombier 	else
1066*9ef1f84bSDavid du Colombier 		c->tos = atoi(cb->f[1]);
1067*9ef1f84bSDavid du Colombier }
1068*9ef1f84bSDavid du Colombier 
1069*9ef1f84bSDavid du Colombier static void
ttlctlmsg(Conv * c,Cmdbuf * cb)1070*9ef1f84bSDavid du Colombier ttlctlmsg(Conv *c, Cmdbuf *cb)
1071*9ef1f84bSDavid du Colombier {
1072*9ef1f84bSDavid du Colombier 	if(cb->nf < 2)
1073*9ef1f84bSDavid du Colombier 		c->ttl = MAXTTL;
1074*9ef1f84bSDavid du Colombier 	else
1075*9ef1f84bSDavid du Colombier 		c->ttl = atoi(cb->f[1]);
1076*9ef1f84bSDavid du Colombier }
1077*9ef1f84bSDavid du Colombier 
1078*9ef1f84bSDavid du Colombier static long
ipwrite(Chan * ch,void * v,long n,vlong off)1079*9ef1f84bSDavid du Colombier ipwrite(Chan* ch, void *v, long n, vlong off)
1080*9ef1f84bSDavid du Colombier {
1081*9ef1f84bSDavid du Colombier 	Conv *c;
1082*9ef1f84bSDavid du Colombier 	Proto *x;
1083*9ef1f84bSDavid du Colombier 	char *p;
1084*9ef1f84bSDavid du Colombier 	Cmdbuf *cb;
1085*9ef1f84bSDavid du Colombier 	uchar ia[IPaddrlen], ma[IPaddrlen];
1086*9ef1f84bSDavid du Colombier 	Fs *f;
1087*9ef1f84bSDavid du Colombier 	char *a;
1088*9ef1f84bSDavid du Colombier 	ulong offset = off;
1089*9ef1f84bSDavid du Colombier 
1090*9ef1f84bSDavid du Colombier 	a = v;
1091*9ef1f84bSDavid du Colombier 	f = ipfs[ch->devno];
1092*9ef1f84bSDavid du Colombier 
1093*9ef1f84bSDavid du Colombier 	switch(TYPE(ch->qid)){
1094*9ef1f84bSDavid du Colombier 	default:
1095*9ef1f84bSDavid du Colombier 		error(Eperm);
1096*9ef1f84bSDavid du Colombier 	case Qdata:
1097*9ef1f84bSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
1098*9ef1f84bSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
1099*9ef1f84bSDavid du Colombier 
1100*9ef1f84bSDavid du Colombier 		if(c->wq == nil)
1101*9ef1f84bSDavid du Colombier 			error(Eperm);
1102*9ef1f84bSDavid du Colombier 
1103*9ef1f84bSDavid du Colombier 		qwrite(c->wq, a, n);
1104*9ef1f84bSDavid du Colombier 		break;
1105*9ef1f84bSDavid du Colombier 	case Qarp:
1106*9ef1f84bSDavid du Colombier 		return arpwrite(f, a, n);
1107*9ef1f84bSDavid du Colombier 	case Qiproute:
1108*9ef1f84bSDavid du Colombier 		return routewrite(f, ch, a, n);
1109*9ef1f84bSDavid du Colombier 	case Qlog:
1110*9ef1f84bSDavid du Colombier 		netlogctl(f, a, n);
1111*9ef1f84bSDavid du Colombier 		return n;
1112*9ef1f84bSDavid du Colombier 	case Qndb:
1113*9ef1f84bSDavid du Colombier 		return ndbwrite(f, a, offset, n);
1114*9ef1f84bSDavid du Colombier 		break;
1115*9ef1f84bSDavid du Colombier 	case Qctl:
1116*9ef1f84bSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
1117*9ef1f84bSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
1118*9ef1f84bSDavid du Colombier 		cb = parsecmd(a, n);
1119*9ef1f84bSDavid du Colombier 
1120*9ef1f84bSDavid du Colombier 		qlock(c);
1121*9ef1f84bSDavid du Colombier 		if(waserror()) {
1122*9ef1f84bSDavid du Colombier 			qunlock(c);
1123*9ef1f84bSDavid du Colombier 			free(cb);
1124*9ef1f84bSDavid du Colombier 			nexterror();
1125*9ef1f84bSDavid du Colombier 		}
1126*9ef1f84bSDavid du Colombier 		if(cb->nf < 1)
1127*9ef1f84bSDavid du Colombier 			error("short control request");
1128*9ef1f84bSDavid du Colombier 		if(strcmp(cb->f[0], "connect") == 0)
1129*9ef1f84bSDavid du Colombier 			connectctlmsg(x, c, cb);
1130*9ef1f84bSDavid du Colombier 		else if(strcmp(cb->f[0], "announce") == 0)
1131*9ef1f84bSDavid du Colombier 			announcectlmsg(x, c, cb);
1132*9ef1f84bSDavid du Colombier 		else if(strcmp(cb->f[0], "bind") == 0)
1133*9ef1f84bSDavid du Colombier 			bindctlmsg(x, c, cb);
1134*9ef1f84bSDavid du Colombier 		else if(strcmp(cb->f[0], "ttl") == 0)
1135*9ef1f84bSDavid du Colombier 			ttlctlmsg(c, cb);
1136*9ef1f84bSDavid du Colombier 		else if(strcmp(cb->f[0], "tos") == 0)
1137*9ef1f84bSDavid du Colombier 			tosctlmsg(c, cb);
1138*9ef1f84bSDavid du Colombier 		else if(strcmp(cb->f[0], "ignoreadvice") == 0)
1139*9ef1f84bSDavid du Colombier 			c->ignoreadvice = 1;
1140*9ef1f84bSDavid du Colombier 		else if(strcmp(cb->f[0], "addmulti") == 0){
1141*9ef1f84bSDavid du Colombier 			if(cb->nf < 2)
1142*9ef1f84bSDavid du Colombier 				error("addmulti needs interface address");
1143*9ef1f84bSDavid du Colombier 			if(cb->nf == 2){
1144*9ef1f84bSDavid du Colombier 				if(!ipismulticast(c->raddr))
1145*9ef1f84bSDavid du Colombier 					error("addmulti for a non multicast address");
1146*9ef1f84bSDavid du Colombier 				if (parseip(ia, cb->f[1]) == -1)
1147*9ef1f84bSDavid du Colombier 					error(Ebadip);
1148*9ef1f84bSDavid du Colombier 				ipifcaddmulti(c, c->raddr, ia);
1149*9ef1f84bSDavid du Colombier 			} else {
1150*9ef1f84bSDavid du Colombier 				if (parseip(ia, cb->f[1]) == -1 ||
1151*9ef1f84bSDavid du Colombier 				    parseip(ma, cb->f[2]) == -1)
1152*9ef1f84bSDavid du Colombier 					error(Ebadip);
1153*9ef1f84bSDavid du Colombier 				if(!ipismulticast(ma))
1154*9ef1f84bSDavid du Colombier 					error("addmulti for a non multicast address");
1155*9ef1f84bSDavid du Colombier 				ipifcaddmulti(c, ma, ia);
1156*9ef1f84bSDavid du Colombier 			}
1157*9ef1f84bSDavid du Colombier 		} else if(strcmp(cb->f[0], "remmulti") == 0){
1158*9ef1f84bSDavid du Colombier 			if(cb->nf < 2)
1159*9ef1f84bSDavid du Colombier 				error("remmulti needs interface address");
1160*9ef1f84bSDavid du Colombier 			if(!ipismulticast(c->raddr))
1161*9ef1f84bSDavid du Colombier 				error("remmulti for a non multicast address");
1162*9ef1f84bSDavid du Colombier 			if (parseip(ia, cb->f[1]) == -1)
1163*9ef1f84bSDavid du Colombier 				error(Ebadip);
1164*9ef1f84bSDavid du Colombier 			ipifcremmulti(c, c->raddr, ia);
1165*9ef1f84bSDavid du Colombier 		} else if(strcmp(cb->f[0], "maxfragsize") == 0){
1166*9ef1f84bSDavid du Colombier 			if(cb->nf < 2)
1167*9ef1f84bSDavid du Colombier 				error("maxfragsize needs size");
1168*9ef1f84bSDavid du Colombier 
1169*9ef1f84bSDavid du Colombier 			c->maxfragsize = (int)strtol(cb->f[1], nil, 0);
1170*9ef1f84bSDavid du Colombier 
1171*9ef1f84bSDavid du Colombier 		} else if(x->ctl != nil) {
1172*9ef1f84bSDavid du Colombier 			p = x->ctl(c, cb->f, cb->nf);
1173*9ef1f84bSDavid du Colombier 			if(p != nil)
1174*9ef1f84bSDavid du Colombier 				error(p);
1175*9ef1f84bSDavid du Colombier 		} else
1176*9ef1f84bSDavid du Colombier 			error("unknown control request");
1177*9ef1f84bSDavid du Colombier 		qunlock(c);
1178*9ef1f84bSDavid du Colombier 		free(cb);
1179*9ef1f84bSDavid du Colombier 		poperror();
1180*9ef1f84bSDavid du Colombier 	}
1181*9ef1f84bSDavid du Colombier 	return n;
1182*9ef1f84bSDavid du Colombier }
1183*9ef1f84bSDavid du Colombier 
1184*9ef1f84bSDavid du Colombier static long
ipbwrite(Chan * ch,Block * bp,vlong offset)1185*9ef1f84bSDavid du Colombier ipbwrite(Chan* ch, Block* bp, vlong offset)
1186*9ef1f84bSDavid du Colombier {
1187*9ef1f84bSDavid du Colombier 	Conv *c;
1188*9ef1f84bSDavid du Colombier 	Proto *x;
1189*9ef1f84bSDavid du Colombier 	Fs *f;
1190*9ef1f84bSDavid du Colombier 	int n;
1191*9ef1f84bSDavid du Colombier 
1192*9ef1f84bSDavid du Colombier 	switch(TYPE(ch->qid)){
1193*9ef1f84bSDavid du Colombier 	case Qdata:
1194*9ef1f84bSDavid du Colombier 		f = ipfs[ch->devno];
1195*9ef1f84bSDavid du Colombier 		x = f->p[PROTO(ch->qid)];
1196*9ef1f84bSDavid du Colombier 		c = x->conv[CONV(ch->qid)];
1197*9ef1f84bSDavid du Colombier 
1198*9ef1f84bSDavid du Colombier 		if(c->wq == nil)
1199*9ef1f84bSDavid du Colombier 			error(Eperm);
1200*9ef1f84bSDavid du Colombier 
1201*9ef1f84bSDavid du Colombier 		if(bp->next)
1202*9ef1f84bSDavid du Colombier 			bp = concatblock(bp);
1203*9ef1f84bSDavid du Colombier 		n = BLEN(bp);
1204*9ef1f84bSDavid du Colombier 		qbwrite(c->wq, bp);
1205*9ef1f84bSDavid du Colombier 		return n;
1206*9ef1f84bSDavid du Colombier 	default:
1207*9ef1f84bSDavid du Colombier 		return devbwrite(ch, bp, offset);
1208*9ef1f84bSDavid du Colombier 	}
1209*9ef1f84bSDavid du Colombier }
1210*9ef1f84bSDavid du Colombier 
1211*9ef1f84bSDavid du Colombier Dev ipdevtab = {
1212*9ef1f84bSDavid du Colombier 	'I',
1213*9ef1f84bSDavid du Colombier 	"ip",
1214*9ef1f84bSDavid du Colombier 
1215*9ef1f84bSDavid du Colombier 	ipreset,
1216*9ef1f84bSDavid du Colombier 	devinit,
1217*9ef1f84bSDavid du Colombier 	devshutdown,
1218*9ef1f84bSDavid du Colombier 	ipattach,
1219*9ef1f84bSDavid du Colombier 	ipwalk,
1220*9ef1f84bSDavid du Colombier 	ipstat,
1221*9ef1f84bSDavid du Colombier 	ipopen,
1222*9ef1f84bSDavid du Colombier 	ipcreate,
1223*9ef1f84bSDavid du Colombier 	ipclose,
1224*9ef1f84bSDavid du Colombier 	ipread,
1225*9ef1f84bSDavid du Colombier 	ipbread,
1226*9ef1f84bSDavid du Colombier 	ipwrite,
1227*9ef1f84bSDavid du Colombier 	ipbwrite,
1228*9ef1f84bSDavid du Colombier 	ipremove,
1229*9ef1f84bSDavid du Colombier 	ipwstat,
1230*9ef1f84bSDavid du Colombier };
1231*9ef1f84bSDavid du Colombier 
1232*9ef1f84bSDavid du Colombier int
Fsproto(Fs * f,Proto * p)1233*9ef1f84bSDavid du Colombier Fsproto(Fs *f, Proto *p)
1234*9ef1f84bSDavid du Colombier {
1235*9ef1f84bSDavid du Colombier 	if(f->np >= Maxproto)
1236*9ef1f84bSDavid du Colombier 		return -1;
1237*9ef1f84bSDavid du Colombier 
1238*9ef1f84bSDavid du Colombier 	p->f = f;
1239*9ef1f84bSDavid du Colombier 
1240*9ef1f84bSDavid du Colombier 	if(p->ipproto > 0){
1241*9ef1f84bSDavid du Colombier 		if(f->t2p[p->ipproto] != nil)
1242*9ef1f84bSDavid du Colombier 			return -1;
1243*9ef1f84bSDavid du Colombier 		f->t2p[p->ipproto] = p;
1244*9ef1f84bSDavid du Colombier 	}
1245*9ef1f84bSDavid du Colombier 
1246*9ef1f84bSDavid du Colombier 	p->qid.type = QTDIR;
1247*9ef1f84bSDavid du Colombier 	p->qid.path = QID(f->np, 0, Qprotodir);
1248*9ef1f84bSDavid du Colombier 	p->conv = malloc(sizeof(Conv*)*(p->nc+1));
1249*9ef1f84bSDavid du Colombier 	if(p->conv == nil)
1250*9ef1f84bSDavid du Colombier 		panic("Fsproto");
1251*9ef1f84bSDavid du Colombier 
1252*9ef1f84bSDavid du Colombier 	p->x = f->np;
1253*9ef1f84bSDavid du Colombier 	p->nextrport = 600;
1254*9ef1f84bSDavid du Colombier 	f->p[f->np++] = p;
1255*9ef1f84bSDavid du Colombier 
1256*9ef1f84bSDavid du Colombier 	return 0;
1257*9ef1f84bSDavid du Colombier }
1258*9ef1f84bSDavid du Colombier 
1259*9ef1f84bSDavid du Colombier /*
1260*9ef1f84bSDavid du Colombier  *  return true if this protocol is
1261*9ef1f84bSDavid du Colombier  *  built in
1262*9ef1f84bSDavid du Colombier  */
1263*9ef1f84bSDavid du Colombier int
Fsbuiltinproto(Fs * f,uchar proto)1264*9ef1f84bSDavid du Colombier Fsbuiltinproto(Fs* f, uchar proto)
1265*9ef1f84bSDavid du Colombier {
1266*9ef1f84bSDavid du Colombier 	return f->t2p[proto] != nil;
1267*9ef1f84bSDavid du Colombier }
1268*9ef1f84bSDavid du Colombier 
1269*9ef1f84bSDavid du Colombier /*
1270*9ef1f84bSDavid du Colombier  *  called with protocol locked
1271*9ef1f84bSDavid du Colombier  */
1272*9ef1f84bSDavid du Colombier Conv*
Fsprotoclone(Proto * p,char * user)1273*9ef1f84bSDavid du Colombier Fsprotoclone(Proto *p, char *user)
1274*9ef1f84bSDavid du Colombier {
1275*9ef1f84bSDavid du Colombier 	Conv *c, **pp, **ep;
1276*9ef1f84bSDavid du Colombier 
1277*9ef1f84bSDavid du Colombier retry:
1278*9ef1f84bSDavid du Colombier 	c = nil;
1279*9ef1f84bSDavid du Colombier 	ep = &p->conv[p->nc];
1280*9ef1f84bSDavid du Colombier 	for(pp = p->conv; pp < ep; pp++) {
1281*9ef1f84bSDavid du Colombier 		c = *pp;
1282*9ef1f84bSDavid du Colombier 		if(c == nil){
1283*9ef1f84bSDavid du Colombier 			c = malloc(sizeof(Conv));
1284*9ef1f84bSDavid du Colombier 			if(c == nil)
1285*9ef1f84bSDavid du Colombier 				error(Enomem);
1286*9ef1f84bSDavid du Colombier 			qlock(c);
1287*9ef1f84bSDavid du Colombier 			c->p = p;
1288*9ef1f84bSDavid du Colombier 			c->x = pp - p->conv;
1289*9ef1f84bSDavid du Colombier 			if(p->ptclsize != 0){
1290*9ef1f84bSDavid du Colombier 				c->ptcl = malloc(p->ptclsize);
1291*9ef1f84bSDavid du Colombier 				if(c->ptcl == nil) {
1292*9ef1f84bSDavid du Colombier 					free(c);
1293*9ef1f84bSDavid du Colombier 					error(Enomem);
1294*9ef1f84bSDavid du Colombier 				}
1295*9ef1f84bSDavid du Colombier 			}
1296*9ef1f84bSDavid du Colombier 			*pp = c;
1297*9ef1f84bSDavid du Colombier 			p->ac++;
1298*9ef1f84bSDavid du Colombier 			c->eq = qopen(1024, Qmsg, 0, 0);
1299*9ef1f84bSDavid du Colombier 			(*p->create)(c);
1300*9ef1f84bSDavid du Colombier 			break;
1301*9ef1f84bSDavid du Colombier 		}
1302*9ef1f84bSDavid du Colombier 		if(canqlock(c)){
1303*9ef1f84bSDavid du Colombier 			/*
1304*9ef1f84bSDavid du Colombier 			 *  make sure both processes and protocol
1305*9ef1f84bSDavid du Colombier 			 *  are done with this Conv
1306*9ef1f84bSDavid du Colombier 			 */
1307*9ef1f84bSDavid du Colombier 			if(c->inuse == 0 && (p->inuse == nil || (*p->inuse)(c) == 0))
1308*9ef1f84bSDavid du Colombier 				break;
1309*9ef1f84bSDavid du Colombier 
1310*9ef1f84bSDavid du Colombier 			qunlock(c);
1311*9ef1f84bSDavid du Colombier 		}
1312*9ef1f84bSDavid du Colombier 	}
1313*9ef1f84bSDavid du Colombier 	if(pp >= ep) {
1314*9ef1f84bSDavid du Colombier 		if(p->gc)
1315*9ef1f84bSDavid du Colombier 			print("Fsprotoclone: garbage collecting Convs\n");
1316*9ef1f84bSDavid du Colombier 		if(p->gc != nil && (*p->gc)(p))
1317*9ef1f84bSDavid du Colombier 			goto retry;
1318*9ef1f84bSDavid du Colombier 		/* debugging: do we ever get here? */
1319*9ef1f84bSDavid du Colombier 		if (cpuserver)
1320*9ef1f84bSDavid du Colombier 			panic("Fsprotoclone: all conversations in use");
1321*9ef1f84bSDavid du Colombier 		return nil;
1322*9ef1f84bSDavid du Colombier 	}
1323*9ef1f84bSDavid du Colombier 
1324*9ef1f84bSDavid du Colombier 	c->inuse = 1;
1325*9ef1f84bSDavid du Colombier 	kstrdup(&c->owner, user);
1326*9ef1f84bSDavid du Colombier 	c->perm = 0660;
1327*9ef1f84bSDavid du Colombier 	c->state = Idle;
1328*9ef1f84bSDavid du Colombier 	ipmove(c->laddr, IPnoaddr);
1329*9ef1f84bSDavid du Colombier 	ipmove(c->raddr, IPnoaddr);
1330*9ef1f84bSDavid du Colombier 	c->r = nil;
1331*9ef1f84bSDavid du Colombier 	c->rgen = 0;
1332*9ef1f84bSDavid du Colombier 	c->lport = 0;
1333*9ef1f84bSDavid du Colombier 	c->rport = 0;
1334*9ef1f84bSDavid du Colombier 	c->restricted = 0;
1335*9ef1f84bSDavid du Colombier 	c->maxfragsize = 0;
1336*9ef1f84bSDavid du Colombier 	c->ttl = MAXTTL;
1337*9ef1f84bSDavid du Colombier 	qreopen(c->rq);
1338*9ef1f84bSDavid du Colombier 	qreopen(c->wq);
1339*9ef1f84bSDavid du Colombier 	qreopen(c->eq);
1340*9ef1f84bSDavid du Colombier 
1341*9ef1f84bSDavid du Colombier 	qunlock(c);
1342*9ef1f84bSDavid du Colombier 	return c;
1343*9ef1f84bSDavid du Colombier }
1344*9ef1f84bSDavid du Colombier 
1345*9ef1f84bSDavid du Colombier int
Fsconnected(Conv * c,char * msg)1346*9ef1f84bSDavid du Colombier Fsconnected(Conv* c, char* msg)
1347*9ef1f84bSDavid du Colombier {
1348*9ef1f84bSDavid du Colombier 	if(msg != nil && *msg != '\0')
1349*9ef1f84bSDavid du Colombier 		strncpy(c->cerr, msg, ERRMAX-1);
1350*9ef1f84bSDavid du Colombier 
1351*9ef1f84bSDavid du Colombier 	switch(c->state){
1352*9ef1f84bSDavid du Colombier 
1353*9ef1f84bSDavid du Colombier 	case Announcing:
1354*9ef1f84bSDavid du Colombier 		c->state = Announced;
1355*9ef1f84bSDavid du Colombier 		break;
1356*9ef1f84bSDavid du Colombier 
1357*9ef1f84bSDavid du Colombier 	case Connecting:
1358*9ef1f84bSDavid du Colombier 		c->state = Connected;
1359*9ef1f84bSDavid du Colombier 		break;
1360*9ef1f84bSDavid du Colombier 	}
1361*9ef1f84bSDavid du Colombier 
1362*9ef1f84bSDavid du Colombier 	wakeup(&c->cr);
1363*9ef1f84bSDavid du Colombier 	return 0;
1364*9ef1f84bSDavid du Colombier }
1365*9ef1f84bSDavid du Colombier 
1366*9ef1f84bSDavid du Colombier Proto*
Fsrcvpcol(Fs * f,uchar proto)1367*9ef1f84bSDavid du Colombier Fsrcvpcol(Fs* f, uchar proto)
1368*9ef1f84bSDavid du Colombier {
1369*9ef1f84bSDavid du Colombier 	if(f->ipmux)
1370*9ef1f84bSDavid du Colombier 		return f->ipmux;
1371*9ef1f84bSDavid du Colombier 	else
1372*9ef1f84bSDavid du Colombier 		return f->t2p[proto];
1373*9ef1f84bSDavid du Colombier }
1374*9ef1f84bSDavid du Colombier 
1375*9ef1f84bSDavid du Colombier Proto*
Fsrcvpcolx(Fs * f,uchar proto)1376*9ef1f84bSDavid du Colombier Fsrcvpcolx(Fs *f, uchar proto)
1377*9ef1f84bSDavid du Colombier {
1378*9ef1f84bSDavid du Colombier 	return f->t2p[proto];
1379*9ef1f84bSDavid du Colombier }
1380*9ef1f84bSDavid du Colombier 
1381*9ef1f84bSDavid du Colombier /*
1382*9ef1f84bSDavid du Colombier  *  called with protocol locked
1383*9ef1f84bSDavid du Colombier  */
1384*9ef1f84bSDavid du Colombier Conv*
Fsnewcall(Conv * c,uchar * raddr,ushort rport,uchar * laddr,ushort lport,uchar version)1385*9ef1f84bSDavid du Colombier Fsnewcall(Conv *c, uchar *raddr, ushort rport, uchar *laddr, ushort lport, uchar version)
1386*9ef1f84bSDavid du Colombier {
1387*9ef1f84bSDavid du Colombier 	Conv *nc;
1388*9ef1f84bSDavid du Colombier 	Conv **l;
1389*9ef1f84bSDavid du Colombier 	int i;
1390*9ef1f84bSDavid du Colombier 
1391*9ef1f84bSDavid du Colombier 	qlock(c);
1392*9ef1f84bSDavid du Colombier 	i = 0;
1393*9ef1f84bSDavid du Colombier 	for(l = &c->incall; *l; l = &(*l)->next)
1394*9ef1f84bSDavid du Colombier 		i++;
1395*9ef1f84bSDavid du Colombier 	if(i >= Maxincall) {
1396*9ef1f84bSDavid du Colombier 		static int beenhere;
1397*9ef1f84bSDavid du Colombier 
1398*9ef1f84bSDavid du Colombier 		qunlock(c);
1399*9ef1f84bSDavid du Colombier 		if (!beenhere) {
1400*9ef1f84bSDavid du Colombier 			beenhere = 1;
1401*9ef1f84bSDavid du Colombier 			print("Fsnewcall: incall queue full (%d) on port %d\n",
1402*9ef1f84bSDavid du Colombier 				i, c->lport);
1403*9ef1f84bSDavid du Colombier 		}
1404*9ef1f84bSDavid du Colombier 		return nil;
1405*9ef1f84bSDavid du Colombier 	}
1406*9ef1f84bSDavid du Colombier 
1407*9ef1f84bSDavid du Colombier 	/* find a free conversation */
1408*9ef1f84bSDavid du Colombier 	nc = Fsprotoclone(c->p, network);
1409*9ef1f84bSDavid du Colombier 	if(nc == nil) {
1410*9ef1f84bSDavid du Colombier 		qunlock(c);
1411*9ef1f84bSDavid du Colombier 		return nil;
1412*9ef1f84bSDavid du Colombier 	}
1413*9ef1f84bSDavid du Colombier 	ipmove(nc->raddr, raddr);
1414*9ef1f84bSDavid du Colombier 	nc->rport = rport;
1415*9ef1f84bSDavid du Colombier 	ipmove(nc->laddr, laddr);
1416*9ef1f84bSDavid du Colombier 	nc->lport = lport;
1417*9ef1f84bSDavid du Colombier 	nc->next = nil;
1418*9ef1f84bSDavid du Colombier 	*l = nc;
1419*9ef1f84bSDavid du Colombier 	nc->state = Connected;
1420*9ef1f84bSDavid du Colombier 	nc->ipversion = version;
1421*9ef1f84bSDavid du Colombier 
1422*9ef1f84bSDavid du Colombier 	qunlock(c);
1423*9ef1f84bSDavid du Colombier 
1424*9ef1f84bSDavid du Colombier 	wakeup(&c->listenr);
1425*9ef1f84bSDavid du Colombier 
1426*9ef1f84bSDavid du Colombier 	return nc;
1427*9ef1f84bSDavid du Colombier }
1428*9ef1f84bSDavid du Colombier 
1429*9ef1f84bSDavid du Colombier long
ndbwrite(Fs * f,char * a,ulong off,int n)1430*9ef1f84bSDavid du Colombier ndbwrite(Fs *f, char *a, ulong off, int n)
1431*9ef1f84bSDavid du Colombier {
1432*9ef1f84bSDavid du Colombier 	if(off > strlen(f->ndb))
1433*9ef1f84bSDavid du Colombier 		error(Eio);
1434*9ef1f84bSDavid du Colombier 	if(off+n >= sizeof(f->ndb))
1435*9ef1f84bSDavid du Colombier 		error(Eio);
1436*9ef1f84bSDavid du Colombier 	memmove(f->ndb+off, a, n);
1437*9ef1f84bSDavid du Colombier 	f->ndb[off+n] = 0;
1438*9ef1f84bSDavid du Colombier 	f->ndbvers++;
1439*9ef1f84bSDavid du Colombier 	f->ndbmtime = seconds();
1440*9ef1f84bSDavid du Colombier 	return n;
1441*9ef1f84bSDavid du Colombier }
1442*9ef1f84bSDavid du Colombier 
1443*9ef1f84bSDavid du Colombier ulong
scalednconv(void)1444*9ef1f84bSDavid du Colombier scalednconv(void)
1445*9ef1f84bSDavid du Colombier {
1446*9ef1f84bSDavid du Colombier 	if(cpuserver)
1447*9ef1f84bSDavid du Colombier 		return Nchans*4;
1448*9ef1f84bSDavid du Colombier 	return Nchans;
1449*9ef1f84bSDavid du Colombier }
1450