xref: /plan9/sys/src/cmd/unix/drawterm/kern/devip.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include "u.h"
2*8ccd4a63SDavid du Colombier #include "lib.h"
3*8ccd4a63SDavid du Colombier #include "dat.h"
4*8ccd4a63SDavid du Colombier #include "fns.h"
5*8ccd4a63SDavid du Colombier #include "error.h"
6*8ccd4a63SDavid du Colombier 
7*8ccd4a63SDavid du Colombier #include "devip.h"
8*8ccd4a63SDavid du Colombier 
9*8ccd4a63SDavid du Colombier void		hnputl(void *p, unsigned long v);
10*8ccd4a63SDavid du Colombier void		hnputs(void *p, unsigned short v);
11*8ccd4a63SDavid du Colombier unsigned long	nhgetl(void *p);
12*8ccd4a63SDavid du Colombier unsigned short	nhgets(void *p);
13*8ccd4a63SDavid du Colombier unsigned long	parseip(char *to, char *from);
14*8ccd4a63SDavid du Colombier void	csclose(Chan*);
15*8ccd4a63SDavid du Colombier long	csread(Chan*, void*, long, vlong);
16*8ccd4a63SDavid du Colombier long	cswrite(Chan*, void*, long, vlong);
17*8ccd4a63SDavid du Colombier 
18*8ccd4a63SDavid du Colombier void osipinit(void);
19*8ccd4a63SDavid du Colombier 
20*8ccd4a63SDavid du Colombier enum
21*8ccd4a63SDavid du Colombier {
22*8ccd4a63SDavid du Colombier 	Qtopdir		= 1,	/* top level directory */
23*8ccd4a63SDavid du Colombier 	Qcs,
24*8ccd4a63SDavid du Colombier 	Qprotodir,		/* directory for a protocol */
25*8ccd4a63SDavid du Colombier 	Qclonus,
26*8ccd4a63SDavid du Colombier 	Qconvdir,		/* directory for a conversation */
27*8ccd4a63SDavid du Colombier 	Qdata,
28*8ccd4a63SDavid du Colombier 	Qctl,
29*8ccd4a63SDavid du Colombier 	Qstatus,
30*8ccd4a63SDavid du Colombier 	Qremote,
31*8ccd4a63SDavid du Colombier 	Qlocal,
32*8ccd4a63SDavid du Colombier 	Qlisten,
33*8ccd4a63SDavid du Colombier 
34*8ccd4a63SDavid du Colombier 	MAXPROTO	= 4
35*8ccd4a63SDavid du Colombier };
36*8ccd4a63SDavid du Colombier #define TYPE(x) 	((int)((x).path & 0xf))
37*8ccd4a63SDavid du Colombier #define CONV(x) 	((int)(((x).path >> 4)&0xfff))
38*8ccd4a63SDavid du Colombier #define PROTO(x) 	((int)(((x).path >> 16)&0xff))
39*8ccd4a63SDavid du Colombier #define QID(p, c, y) 	(((p)<<16) | ((c)<<4) | (y))
40*8ccd4a63SDavid du Colombier 
41*8ccd4a63SDavid du Colombier typedef struct Proto	Proto;
42*8ccd4a63SDavid du Colombier typedef struct Conv	Conv;
43*8ccd4a63SDavid du Colombier struct Conv
44*8ccd4a63SDavid du Colombier {
45*8ccd4a63SDavid du Colombier 	int	x;
46*8ccd4a63SDavid du Colombier 	Ref	r;
47*8ccd4a63SDavid du Colombier 	int	sfd;
48*8ccd4a63SDavid du Colombier 	int	perm;
49*8ccd4a63SDavid du Colombier 	char	owner[KNAMELEN];
50*8ccd4a63SDavid du Colombier 	char*	state;
51*8ccd4a63SDavid du Colombier 	ulong	laddr;
52*8ccd4a63SDavid du Colombier 	ushort	lport;
53*8ccd4a63SDavid du Colombier 	ulong	raddr;
54*8ccd4a63SDavid du Colombier 	ushort	rport;
55*8ccd4a63SDavid du Colombier 	int	restricted;
56*8ccd4a63SDavid du Colombier 	char	cerr[KNAMELEN];
57*8ccd4a63SDavid du Colombier 	Proto*	p;
58*8ccd4a63SDavid du Colombier };
59*8ccd4a63SDavid du Colombier 
60*8ccd4a63SDavid du Colombier struct Proto
61*8ccd4a63SDavid du Colombier {
62*8ccd4a63SDavid du Colombier 	Lock	l;
63*8ccd4a63SDavid du Colombier 	int	x;
64*8ccd4a63SDavid du Colombier 	int	stype;
65*8ccd4a63SDavid du Colombier 	char	name[KNAMELEN];
66*8ccd4a63SDavid du Colombier 	int	nc;
67*8ccd4a63SDavid du Colombier 	int	maxconv;
68*8ccd4a63SDavid du Colombier 	Conv**	conv;
69*8ccd4a63SDavid du Colombier 	Qid	qid;
70*8ccd4a63SDavid du Colombier };
71*8ccd4a63SDavid du Colombier 
72*8ccd4a63SDavid du Colombier static	int	np;
73*8ccd4a63SDavid du Colombier static	Proto	proto[MAXPROTO];
74*8ccd4a63SDavid du Colombier int	eipfmt(Fmt*);
75*8ccd4a63SDavid du Colombier 
76*8ccd4a63SDavid du Colombier static	Conv*	protoclone(Proto*, char*, int);
77*8ccd4a63SDavid du Colombier static	void	setladdr(Conv*);
78*8ccd4a63SDavid du Colombier 
79*8ccd4a63SDavid du Colombier int
80*8ccd4a63SDavid du Colombier ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp)
81*8ccd4a63SDavid du Colombier {
82*8ccd4a63SDavid du Colombier 	Qid q;
83*8ccd4a63SDavid du Colombier 	Conv *cv;
84*8ccd4a63SDavid du Colombier 	char *p;
85*8ccd4a63SDavid du Colombier 
86*8ccd4a63SDavid du Colombier 	USED(nname);
87*8ccd4a63SDavid du Colombier 	q.vers = 0;
88*8ccd4a63SDavid du Colombier 	q.type = 0;
89*8ccd4a63SDavid du Colombier 	switch(TYPE(c->qid)) {
90*8ccd4a63SDavid du Colombier 	case Qtopdir:
91*8ccd4a63SDavid du Colombier 		if(s >= 1+np)
92*8ccd4a63SDavid du Colombier 			return -1;
93*8ccd4a63SDavid du Colombier 
94*8ccd4a63SDavid du Colombier 		if(s == 0){
95*8ccd4a63SDavid du Colombier 			q.path = QID(s, 0, Qcs);
96*8ccd4a63SDavid du Colombier 			devdir(c, q, "cs", 0, "network", 0666, dp);
97*8ccd4a63SDavid du Colombier 		}else{
98*8ccd4a63SDavid du Colombier 			s--;
99*8ccd4a63SDavid du Colombier 			q.path = QID(s, 0, Qprotodir);
100*8ccd4a63SDavid du Colombier 			q.type = QTDIR;
101*8ccd4a63SDavid du Colombier 			devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp);
102*8ccd4a63SDavid du Colombier 		}
103*8ccd4a63SDavid du Colombier 		return 1;
104*8ccd4a63SDavid du Colombier 	case Qprotodir:
105*8ccd4a63SDavid du Colombier 		if(s < proto[PROTO(c->qid)].nc) {
106*8ccd4a63SDavid du Colombier 			cv = proto[PROTO(c->qid)].conv[s];
107*8ccd4a63SDavid du Colombier 			sprint(up->genbuf, "%d", s);
108*8ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), s, Qconvdir);
109*8ccd4a63SDavid du Colombier 			q.type = QTDIR;
110*8ccd4a63SDavid du Colombier 			devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp);
111*8ccd4a63SDavid du Colombier 			return 1;
112*8ccd4a63SDavid du Colombier 		}
113*8ccd4a63SDavid du Colombier 		s -= proto[PROTO(c->qid)].nc;
114*8ccd4a63SDavid du Colombier 		switch(s) {
115*8ccd4a63SDavid du Colombier 		default:
116*8ccd4a63SDavid du Colombier 			return -1;
117*8ccd4a63SDavid du Colombier 		case 0:
118*8ccd4a63SDavid du Colombier 			p = "clone";
119*8ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), 0, Qclonus);
120*8ccd4a63SDavid du Colombier 			break;
121*8ccd4a63SDavid du Colombier 		}
122*8ccd4a63SDavid du Colombier 		devdir(c, q, p, 0, "network", 0555, dp);
123*8ccd4a63SDavid du Colombier 		return 1;
124*8ccd4a63SDavid du Colombier 	case Qconvdir:
125*8ccd4a63SDavid du Colombier 		cv = proto[PROTO(c->qid)].conv[CONV(c->qid)];
126*8ccd4a63SDavid du Colombier 		switch(s) {
127*8ccd4a63SDavid du Colombier 		default:
128*8ccd4a63SDavid du Colombier 			return -1;
129*8ccd4a63SDavid du Colombier 		case 0:
130*8ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata);
131*8ccd4a63SDavid du Colombier 			devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
132*8ccd4a63SDavid du Colombier 			return 1;
133*8ccd4a63SDavid du Colombier 		case 1:
134*8ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl);
135*8ccd4a63SDavid du Colombier 			devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
136*8ccd4a63SDavid du Colombier 			return 1;
137*8ccd4a63SDavid du Colombier 		case 2:
138*8ccd4a63SDavid du Colombier 			p = "status";
139*8ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus);
140*8ccd4a63SDavid du Colombier 			break;
141*8ccd4a63SDavid du Colombier 		case 3:
142*8ccd4a63SDavid du Colombier 			p = "remote";
143*8ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote);
144*8ccd4a63SDavid du Colombier 			break;
145*8ccd4a63SDavid du Colombier 		case 4:
146*8ccd4a63SDavid du Colombier 			p = "local";
147*8ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal);
148*8ccd4a63SDavid du Colombier 			break;
149*8ccd4a63SDavid du Colombier 		case 5:
150*8ccd4a63SDavid du Colombier 			p = "listen";
151*8ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten);
152*8ccd4a63SDavid du Colombier 			break;
153*8ccd4a63SDavid du Colombier 		}
154*8ccd4a63SDavid du Colombier 		devdir(c, q, p, 0, cv->owner, 0444, dp);
155*8ccd4a63SDavid du Colombier 		return 1;
156*8ccd4a63SDavid du Colombier 	}
157*8ccd4a63SDavid du Colombier 	return -1;
158*8ccd4a63SDavid du Colombier }
159*8ccd4a63SDavid du Colombier 
160*8ccd4a63SDavid du Colombier static void
161*8ccd4a63SDavid du Colombier newproto(char *name, int type, int maxconv)
162*8ccd4a63SDavid du Colombier {
163*8ccd4a63SDavid du Colombier 	int l;
164*8ccd4a63SDavid du Colombier 	Proto *p;
165*8ccd4a63SDavid du Colombier 
166*8ccd4a63SDavid du Colombier 	if(np >= MAXPROTO) {
167*8ccd4a63SDavid du Colombier 		print("no %s: increase MAXPROTO", name);
168*8ccd4a63SDavid du Colombier 		return;
169*8ccd4a63SDavid du Colombier 	}
170*8ccd4a63SDavid du Colombier 
171*8ccd4a63SDavid du Colombier 	p = &proto[np];
172*8ccd4a63SDavid du Colombier 	strcpy(p->name, name);
173*8ccd4a63SDavid du Colombier 	p->stype = type;
174*8ccd4a63SDavid du Colombier 	p->qid.path = QID(np, 0, Qprotodir);
175*8ccd4a63SDavid du Colombier 	p->qid.type = QTDIR;
176*8ccd4a63SDavid du Colombier 	p->x = np++;
177*8ccd4a63SDavid du Colombier 	p->maxconv = maxconv;
178*8ccd4a63SDavid du Colombier 	l = sizeof(Conv*)*(p->maxconv+1);
179*8ccd4a63SDavid du Colombier 	p->conv = mallocz(l, 1);
180*8ccd4a63SDavid du Colombier 	if(p->conv == 0)
181*8ccd4a63SDavid du Colombier 		panic("no memory");
182*8ccd4a63SDavid du Colombier }
183*8ccd4a63SDavid du Colombier 
184*8ccd4a63SDavid du Colombier void
185*8ccd4a63SDavid du Colombier ipinit(void)
186*8ccd4a63SDavid du Colombier {
187*8ccd4a63SDavid du Colombier 	osipinit();
188*8ccd4a63SDavid du Colombier 
189*8ccd4a63SDavid du Colombier 	newproto("udp", S_UDP, 10);
190*8ccd4a63SDavid du Colombier 	newproto("tcp", S_TCP, 30);
191*8ccd4a63SDavid du Colombier 
192*8ccd4a63SDavid du Colombier 	fmtinstall('I', eipfmt);
193*8ccd4a63SDavid du Colombier 	fmtinstall('E', eipfmt);
194*8ccd4a63SDavid du Colombier 
195*8ccd4a63SDavid du Colombier }
196*8ccd4a63SDavid du Colombier 
197*8ccd4a63SDavid du Colombier Chan *
198*8ccd4a63SDavid du Colombier ipattach(char *spec)
199*8ccd4a63SDavid du Colombier {
200*8ccd4a63SDavid du Colombier 	Chan *c;
201*8ccd4a63SDavid du Colombier 
202*8ccd4a63SDavid du Colombier 	c = devattach('I', spec);
203*8ccd4a63SDavid du Colombier 	c->qid.path = QID(0, 0, Qtopdir);
204*8ccd4a63SDavid du Colombier 	c->qid.type = QTDIR;
205*8ccd4a63SDavid du Colombier 	c->qid.vers = 0;
206*8ccd4a63SDavid du Colombier 	return c;
207*8ccd4a63SDavid du Colombier }
208*8ccd4a63SDavid du Colombier 
209*8ccd4a63SDavid du Colombier static Walkqid*
210*8ccd4a63SDavid du Colombier ipwalk(Chan *c, Chan *nc, char **name, int nname)
211*8ccd4a63SDavid du Colombier {
212*8ccd4a63SDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, ipgen);
213*8ccd4a63SDavid du Colombier }
214*8ccd4a63SDavid du Colombier 
215*8ccd4a63SDavid du Colombier int
216*8ccd4a63SDavid du Colombier ipstat(Chan *c, uchar *dp, int n)
217*8ccd4a63SDavid du Colombier {
218*8ccd4a63SDavid du Colombier 	return devstat(c, dp, n, 0, 0, ipgen);
219*8ccd4a63SDavid du Colombier }
220*8ccd4a63SDavid du Colombier 
221*8ccd4a63SDavid du Colombier Chan *
222*8ccd4a63SDavid du Colombier ipopen(Chan *c, int omode)
223*8ccd4a63SDavid du Colombier {
224*8ccd4a63SDavid du Colombier 	Proto *p;
225*8ccd4a63SDavid du Colombier 	ulong raddr;
226*8ccd4a63SDavid du Colombier 	ushort rport;
227*8ccd4a63SDavid du Colombier 	int perm, sfd;
228*8ccd4a63SDavid du Colombier 	Conv *cv, *lcv;
229*8ccd4a63SDavid du Colombier 
230*8ccd4a63SDavid du Colombier 	omode &= 3;
231*8ccd4a63SDavid du Colombier 	perm = 0;
232*8ccd4a63SDavid du Colombier 	switch(omode) {
233*8ccd4a63SDavid du Colombier 	case OREAD:
234*8ccd4a63SDavid du Colombier 		perm = 4;
235*8ccd4a63SDavid du Colombier 		break;
236*8ccd4a63SDavid du Colombier 	case OWRITE:
237*8ccd4a63SDavid du Colombier 		perm = 2;
238*8ccd4a63SDavid du Colombier 		break;
239*8ccd4a63SDavid du Colombier 	case ORDWR:
240*8ccd4a63SDavid du Colombier 		perm = 6;
241*8ccd4a63SDavid du Colombier 		break;
242*8ccd4a63SDavid du Colombier 	}
243*8ccd4a63SDavid du Colombier 
244*8ccd4a63SDavid du Colombier 	switch(TYPE(c->qid)) {
245*8ccd4a63SDavid du Colombier 	default:
246*8ccd4a63SDavid du Colombier 		break;
247*8ccd4a63SDavid du Colombier 	case Qtopdir:
248*8ccd4a63SDavid du Colombier 	case Qprotodir:
249*8ccd4a63SDavid du Colombier 	case Qconvdir:
250*8ccd4a63SDavid du Colombier 	case Qstatus:
251*8ccd4a63SDavid du Colombier 	case Qremote:
252*8ccd4a63SDavid du Colombier 	case Qlocal:
253*8ccd4a63SDavid du Colombier 		if(omode != OREAD)
254*8ccd4a63SDavid du Colombier 			error(Eperm);
255*8ccd4a63SDavid du Colombier 		break;
256*8ccd4a63SDavid du Colombier 	case Qclonus:
257*8ccd4a63SDavid du Colombier 		p = &proto[PROTO(c->qid)];
258*8ccd4a63SDavid du Colombier 		cv = protoclone(p, up->user, -1);
259*8ccd4a63SDavid du Colombier 		if(cv == 0)
260*8ccd4a63SDavid du Colombier 			error(Enodev);
261*8ccd4a63SDavid du Colombier 		c->qid.path = QID(p->x, cv->x, Qctl);
262*8ccd4a63SDavid du Colombier 		c->qid.vers = 0;
263*8ccd4a63SDavid du Colombier 		break;
264*8ccd4a63SDavid du Colombier 	case Qdata:
265*8ccd4a63SDavid du Colombier 	case Qctl:
266*8ccd4a63SDavid du Colombier 		p = &proto[PROTO(c->qid)];
267*8ccd4a63SDavid du Colombier 		lock(&p->l);
268*8ccd4a63SDavid du Colombier 		cv = p->conv[CONV(c->qid)];
269*8ccd4a63SDavid du Colombier 		lock(&cv->r.lk);
270*8ccd4a63SDavid du Colombier 		if((perm & (cv->perm>>6)) != perm) {
271*8ccd4a63SDavid du Colombier 			if(strcmp(up->user, cv->owner) != 0 ||
272*8ccd4a63SDavid du Colombier 		 	  (perm & cv->perm) != perm) {
273*8ccd4a63SDavid du Colombier 				unlock(&cv->r.lk);
274*8ccd4a63SDavid du Colombier 				unlock(&p->l);
275*8ccd4a63SDavid du Colombier 				error(Eperm);
276*8ccd4a63SDavid du Colombier 			}
277*8ccd4a63SDavid du Colombier 		}
278*8ccd4a63SDavid du Colombier 		cv->r.ref++;
279*8ccd4a63SDavid du Colombier 		if(cv->r.ref == 1) {
280*8ccd4a63SDavid du Colombier 			memmove(cv->owner, up->user, KNAMELEN);
281*8ccd4a63SDavid du Colombier 			cv->perm = 0660;
282*8ccd4a63SDavid du Colombier 		}
283*8ccd4a63SDavid du Colombier 		unlock(&cv->r.lk);
284*8ccd4a63SDavid du Colombier 		unlock(&p->l);
285*8ccd4a63SDavid du Colombier 		break;
286*8ccd4a63SDavid du Colombier 	case Qlisten:
287*8ccd4a63SDavid du Colombier 		p = &proto[PROTO(c->qid)];
288*8ccd4a63SDavid du Colombier 		lcv = p->conv[CONV(c->qid)];
289*8ccd4a63SDavid du Colombier 		sfd = so_accept(lcv->sfd, &raddr, &rport);
290*8ccd4a63SDavid du Colombier 		cv = protoclone(p, up->user, sfd);
291*8ccd4a63SDavid du Colombier 		if(cv == 0) {
292*8ccd4a63SDavid du Colombier 			close(sfd);
293*8ccd4a63SDavid du Colombier 			error(Enodev);
294*8ccd4a63SDavid du Colombier 		}
295*8ccd4a63SDavid du Colombier 		cv->raddr = raddr;
296*8ccd4a63SDavid du Colombier 		cv->rport = rport;
297*8ccd4a63SDavid du Colombier 		setladdr(cv);
298*8ccd4a63SDavid du Colombier 		cv->state = "Established";
299*8ccd4a63SDavid du Colombier 		c->qid.path = QID(p->x, cv->x, Qctl);
300*8ccd4a63SDavid du Colombier 		break;
301*8ccd4a63SDavid du Colombier 	}
302*8ccd4a63SDavid du Colombier 	c->mode = openmode(omode);
303*8ccd4a63SDavid du Colombier 	c->flag |= COPEN;
304*8ccd4a63SDavid du Colombier 	c->offset = 0;
305*8ccd4a63SDavid du Colombier 	return c;
306*8ccd4a63SDavid du Colombier }
307*8ccd4a63SDavid du Colombier 
308*8ccd4a63SDavid du Colombier void
309*8ccd4a63SDavid du Colombier ipclose(Chan *c)
310*8ccd4a63SDavid du Colombier {
311*8ccd4a63SDavid du Colombier 	Conv *cc;
312*8ccd4a63SDavid du Colombier 
313*8ccd4a63SDavid du Colombier 	switch(TYPE(c->qid)) {
314*8ccd4a63SDavid du Colombier 	case Qcs:
315*8ccd4a63SDavid du Colombier 		csclose(c);
316*8ccd4a63SDavid du Colombier 		break;
317*8ccd4a63SDavid du Colombier 	case Qdata:
318*8ccd4a63SDavid du Colombier 	case Qctl:
319*8ccd4a63SDavid du Colombier 		if((c->flag & COPEN) == 0)
320*8ccd4a63SDavid du Colombier 			break;
321*8ccd4a63SDavid du Colombier 		cc = proto[PROTO(c->qid)].conv[CONV(c->qid)];
322*8ccd4a63SDavid du Colombier 		if(decref(&cc->r) != 0)
323*8ccd4a63SDavid du Colombier 			break;
324*8ccd4a63SDavid du Colombier 		strcpy(cc->owner, "network");
325*8ccd4a63SDavid du Colombier 		cc->perm = 0666;
326*8ccd4a63SDavid du Colombier 		cc->state = "Closed";
327*8ccd4a63SDavid du Colombier 		cc->laddr = 0;
328*8ccd4a63SDavid du Colombier 		cc->raddr = 0;
329*8ccd4a63SDavid du Colombier 		cc->lport = 0;
330*8ccd4a63SDavid du Colombier 		cc->rport = 0;
331*8ccd4a63SDavid du Colombier 		close(cc->sfd);
332*8ccd4a63SDavid du Colombier 		break;
333*8ccd4a63SDavid du Colombier 	}
334*8ccd4a63SDavid du Colombier }
335*8ccd4a63SDavid du Colombier 
336*8ccd4a63SDavid du Colombier long
337*8ccd4a63SDavid du Colombier ipread(Chan *ch, void *a, long n, vlong offset)
338*8ccd4a63SDavid du Colombier {
339*8ccd4a63SDavid du Colombier 	int r;
340*8ccd4a63SDavid du Colombier 	Conv *c;
341*8ccd4a63SDavid du Colombier 	Proto *x;
342*8ccd4a63SDavid du Colombier 	uchar ip[4];
343*8ccd4a63SDavid du Colombier 	char buf[128], *p;
344*8ccd4a63SDavid du Colombier 
345*8ccd4a63SDavid du Colombier /*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/
346*8ccd4a63SDavid du Colombier 	p = a;
347*8ccd4a63SDavid du Colombier 	switch(TYPE(ch->qid)) {
348*8ccd4a63SDavid du Colombier 	default:
349*8ccd4a63SDavid du Colombier 		error(Eperm);
350*8ccd4a63SDavid du Colombier 	case Qcs:
351*8ccd4a63SDavid du Colombier 		return csread(ch, a, n, offset);
352*8ccd4a63SDavid du Colombier 	case Qprotodir:
353*8ccd4a63SDavid du Colombier 	case Qtopdir:
354*8ccd4a63SDavid du Colombier 	case Qconvdir:
355*8ccd4a63SDavid du Colombier 		return devdirread(ch, a, n, 0, 0, ipgen);
356*8ccd4a63SDavid du Colombier 	case Qctl:
357*8ccd4a63SDavid du Colombier 		sprint(buf, "%d", CONV(ch->qid));
358*8ccd4a63SDavid du Colombier 		return readstr(offset, p, n, buf);
359*8ccd4a63SDavid du Colombier 	case Qremote:
360*8ccd4a63SDavid du Colombier 		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
361*8ccd4a63SDavid du Colombier 		hnputl(ip, c->raddr);
362*8ccd4a63SDavid du Colombier 		sprint(buf, "%I!%d\n", ip, c->rport);
363*8ccd4a63SDavid du Colombier 		return readstr(offset, p, n, buf);
364*8ccd4a63SDavid du Colombier 	case Qlocal:
365*8ccd4a63SDavid du Colombier 		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
366*8ccd4a63SDavid du Colombier 		hnputl(ip, c->laddr);
367*8ccd4a63SDavid du Colombier 		sprint(buf, "%I!%d\n", ip, c->lport);
368*8ccd4a63SDavid du Colombier 		return readstr(offset, p, n, buf);
369*8ccd4a63SDavid du Colombier 	case Qstatus:
370*8ccd4a63SDavid du Colombier 		x = &proto[PROTO(ch->qid)];
371*8ccd4a63SDavid du Colombier 		c = x->conv[CONV(ch->qid)];
372*8ccd4a63SDavid du Colombier 		sprint(buf, "%s/%d %d %s \n",
373*8ccd4a63SDavid du Colombier 			c->p->name, c->x, c->r.ref, c->state);
374*8ccd4a63SDavid du Colombier 		return readstr(offset, p, n, buf);
375*8ccd4a63SDavid du Colombier 	case Qdata:
376*8ccd4a63SDavid du Colombier 		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
377*8ccd4a63SDavid du Colombier 		r = so_recv(c->sfd, a, n, 0);
378*8ccd4a63SDavid du Colombier 		if(r < 0){
379*8ccd4a63SDavid du Colombier 			oserrstr();
380*8ccd4a63SDavid du Colombier 			nexterror();
381*8ccd4a63SDavid du Colombier 		}
382*8ccd4a63SDavid du Colombier 		return r;
383*8ccd4a63SDavid du Colombier 	}
384*8ccd4a63SDavid du Colombier }
385*8ccd4a63SDavid du Colombier 
386*8ccd4a63SDavid du Colombier static void
387*8ccd4a63SDavid du Colombier setladdr(Conv *c)
388*8ccd4a63SDavid du Colombier {
389*8ccd4a63SDavid du Colombier 	so_getsockname(c->sfd, &c->laddr, &c->lport);
390*8ccd4a63SDavid du Colombier }
391*8ccd4a63SDavid du Colombier 
392*8ccd4a63SDavid du Colombier static void
393*8ccd4a63SDavid du Colombier setlport(Conv *c)
394*8ccd4a63SDavid du Colombier {
395*8ccd4a63SDavid du Colombier 	if(c->restricted == 0 && c->lport == 0)
396*8ccd4a63SDavid du Colombier 		return;
397*8ccd4a63SDavid du Colombier 
398*8ccd4a63SDavid du Colombier 	so_bind(c->sfd, c->restricted, c->lport);
399*8ccd4a63SDavid du Colombier }
400*8ccd4a63SDavid du Colombier 
401*8ccd4a63SDavid du Colombier static void
402*8ccd4a63SDavid du Colombier setladdrport(Conv *c, char *str)
403*8ccd4a63SDavid du Colombier {
404*8ccd4a63SDavid du Colombier 	char *p, addr[4];
405*8ccd4a63SDavid du Colombier 
406*8ccd4a63SDavid du Colombier 	p = strchr(str, '!');
407*8ccd4a63SDavid du Colombier 	if(p == 0) {
408*8ccd4a63SDavid du Colombier 		p = str;
409*8ccd4a63SDavid du Colombier 		c->laddr = 0;
410*8ccd4a63SDavid du Colombier 	}
411*8ccd4a63SDavid du Colombier 	else {
412*8ccd4a63SDavid du Colombier 		*p++ = 0;
413*8ccd4a63SDavid du Colombier 		parseip(addr, str);
414*8ccd4a63SDavid du Colombier 		c->laddr = nhgetl((uchar*)addr);
415*8ccd4a63SDavid du Colombier 	}
416*8ccd4a63SDavid du Colombier 	if(*p == '*')
417*8ccd4a63SDavid du Colombier 		c->lport = 0;
418*8ccd4a63SDavid du Colombier 	else
419*8ccd4a63SDavid du Colombier 		c->lport = atoi(p);
420*8ccd4a63SDavid du Colombier 
421*8ccd4a63SDavid du Colombier 	setlport(c);
422*8ccd4a63SDavid du Colombier }
423*8ccd4a63SDavid du Colombier 
424*8ccd4a63SDavid du Colombier static char*
425*8ccd4a63SDavid du Colombier setraddrport(Conv *c, char *str)
426*8ccd4a63SDavid du Colombier {
427*8ccd4a63SDavid du Colombier 	char *p, addr[4];
428*8ccd4a63SDavid du Colombier 
429*8ccd4a63SDavid du Colombier 	p = strchr(str, '!');
430*8ccd4a63SDavid du Colombier 	if(p == 0)
431*8ccd4a63SDavid du Colombier 		return "malformed address";
432*8ccd4a63SDavid du Colombier 	*p++ = 0;
433*8ccd4a63SDavid du Colombier 	parseip(addr, str);
434*8ccd4a63SDavid du Colombier 	c->raddr = nhgetl((uchar*)addr);
435*8ccd4a63SDavid du Colombier 	c->rport = atoi(p);
436*8ccd4a63SDavid du Colombier 	p = strchr(p, '!');
437*8ccd4a63SDavid du Colombier 	if(p) {
438*8ccd4a63SDavid du Colombier 		if(strcmp(p, "!r") == 0)
439*8ccd4a63SDavid du Colombier 			c->restricted = 1;
440*8ccd4a63SDavid du Colombier 	}
441*8ccd4a63SDavid du Colombier 	return 0;
442*8ccd4a63SDavid du Colombier }
443*8ccd4a63SDavid du Colombier 
444*8ccd4a63SDavid du Colombier long
445*8ccd4a63SDavid du Colombier ipwrite(Chan *ch, void *a, long n, vlong offset)
446*8ccd4a63SDavid du Colombier {
447*8ccd4a63SDavid du Colombier 	Conv *c;
448*8ccd4a63SDavid du Colombier 	Proto *x;
449*8ccd4a63SDavid du Colombier 	int r, nf;
450*8ccd4a63SDavid du Colombier 	char *p, *fields[3], buf[128];
451*8ccd4a63SDavid du Colombier 
452*8ccd4a63SDavid du Colombier 	switch(TYPE(ch->qid)) {
453*8ccd4a63SDavid du Colombier 	default:
454*8ccd4a63SDavid du Colombier 		error(Eperm);
455*8ccd4a63SDavid du Colombier 	case Qcs:
456*8ccd4a63SDavid du Colombier 		return cswrite(ch, a, n, offset);
457*8ccd4a63SDavid du Colombier 	case Qctl:
458*8ccd4a63SDavid du Colombier 		x = &proto[PROTO(ch->qid)];
459*8ccd4a63SDavid du Colombier 		c = x->conv[CONV(ch->qid)];
460*8ccd4a63SDavid du Colombier 		if(n > sizeof(buf)-1)
461*8ccd4a63SDavid du Colombier 			n = sizeof(buf)-1;
462*8ccd4a63SDavid du Colombier 		memmove(buf, a, n);
463*8ccd4a63SDavid du Colombier 		buf[n] = '\0';
464*8ccd4a63SDavid du Colombier 
465*8ccd4a63SDavid du Colombier 		nf = tokenize(buf, fields, 3);
466*8ccd4a63SDavid du Colombier 		if(strcmp(fields[0], "connect") == 0){
467*8ccd4a63SDavid du Colombier 			switch(nf) {
468*8ccd4a63SDavid du Colombier 			default:
469*8ccd4a63SDavid du Colombier 				error("bad args to connect");
470*8ccd4a63SDavid du Colombier 			case 2:
471*8ccd4a63SDavid du Colombier 				p = setraddrport(c, fields[1]);
472*8ccd4a63SDavid du Colombier 				if(p != 0)
473*8ccd4a63SDavid du Colombier 					error(p);
474*8ccd4a63SDavid du Colombier 				break;
475*8ccd4a63SDavid du Colombier 			case 3:
476*8ccd4a63SDavid du Colombier 				p = setraddrport(c, fields[1]);
477*8ccd4a63SDavid du Colombier 				if(p != 0)
478*8ccd4a63SDavid du Colombier 					error(p);
479*8ccd4a63SDavid du Colombier 				c->lport = atoi(fields[2]);
480*8ccd4a63SDavid du Colombier 				setlport(c);
481*8ccd4a63SDavid du Colombier 				break;
482*8ccd4a63SDavid du Colombier 			}
483*8ccd4a63SDavid du Colombier 			so_connect(c->sfd, c->raddr, c->rport);
484*8ccd4a63SDavid du Colombier 			setladdr(c);
485*8ccd4a63SDavid du Colombier 			c->state = "Established";
486*8ccd4a63SDavid du Colombier 			return n;
487*8ccd4a63SDavid du Colombier 		}
488*8ccd4a63SDavid du Colombier 		if(strcmp(fields[0], "announce") == 0) {
489*8ccd4a63SDavid du Colombier 			switch(nf){
490*8ccd4a63SDavid du Colombier 			default:
491*8ccd4a63SDavid du Colombier 				error("bad args to announce");
492*8ccd4a63SDavid du Colombier 			case 2:
493*8ccd4a63SDavid du Colombier 				setladdrport(c, fields[1]);
494*8ccd4a63SDavid du Colombier 				break;
495*8ccd4a63SDavid du Colombier 			}
496*8ccd4a63SDavid du Colombier 			so_listen(c->sfd);
497*8ccd4a63SDavid du Colombier 			c->state = "Announced";
498*8ccd4a63SDavid du Colombier 			return n;
499*8ccd4a63SDavid du Colombier 		}
500*8ccd4a63SDavid du Colombier 		if(strcmp(fields[0], "bind") == 0){
501*8ccd4a63SDavid du Colombier 			switch(nf){
502*8ccd4a63SDavid du Colombier 			default:
503*8ccd4a63SDavid du Colombier 				error("bad args to bind");
504*8ccd4a63SDavid du Colombier 			case 2:
505*8ccd4a63SDavid du Colombier 				c->lport = atoi(fields[1]);
506*8ccd4a63SDavid du Colombier 				break;
507*8ccd4a63SDavid du Colombier 			}
508*8ccd4a63SDavid du Colombier 			setlport(c);
509*8ccd4a63SDavid du Colombier 			return n;
510*8ccd4a63SDavid du Colombier 		}
511*8ccd4a63SDavid du Colombier 		error("bad control message");
512*8ccd4a63SDavid du Colombier 	case Qdata:
513*8ccd4a63SDavid du Colombier 		x = &proto[PROTO(ch->qid)];
514*8ccd4a63SDavid du Colombier 		c = x->conv[CONV(ch->qid)];
515*8ccd4a63SDavid du Colombier 		r = so_send(c->sfd, a, n, 0);
516*8ccd4a63SDavid du Colombier 		if(r < 0){
517*8ccd4a63SDavid du Colombier 			oserrstr();
518*8ccd4a63SDavid du Colombier 			nexterror();
519*8ccd4a63SDavid du Colombier 		}
520*8ccd4a63SDavid du Colombier 		return r;
521*8ccd4a63SDavid du Colombier 	}
522*8ccd4a63SDavid du Colombier 	return n;
523*8ccd4a63SDavid du Colombier }
524*8ccd4a63SDavid du Colombier 
525*8ccd4a63SDavid du Colombier static Conv*
526*8ccd4a63SDavid du Colombier protoclone(Proto *p, char *user, int nfd)
527*8ccd4a63SDavid du Colombier {
528*8ccd4a63SDavid du Colombier 	Conv *c, **pp, **ep;
529*8ccd4a63SDavid du Colombier 
530*8ccd4a63SDavid du Colombier 	c = 0;
531*8ccd4a63SDavid du Colombier 	lock(&p->l);
532*8ccd4a63SDavid du Colombier 	if(waserror()) {
533*8ccd4a63SDavid du Colombier 		unlock(&p->l);
534*8ccd4a63SDavid du Colombier 		nexterror();
535*8ccd4a63SDavid du Colombier 	}
536*8ccd4a63SDavid du Colombier 	ep = &p->conv[p->maxconv];
537*8ccd4a63SDavid du Colombier 	for(pp = p->conv; pp < ep; pp++) {
538*8ccd4a63SDavid du Colombier 		c = *pp;
539*8ccd4a63SDavid du Colombier 		if(c == 0) {
540*8ccd4a63SDavid du Colombier 			c = mallocz(sizeof(Conv), 1);
541*8ccd4a63SDavid du Colombier 			if(c == 0)
542*8ccd4a63SDavid du Colombier 				error(Enomem);
543*8ccd4a63SDavid du Colombier 			lock(&c->r.lk);
544*8ccd4a63SDavid du Colombier 			c->r.ref = 1;
545*8ccd4a63SDavid du Colombier 			c->p = p;
546*8ccd4a63SDavid du Colombier 			c->x = pp - p->conv;
547*8ccd4a63SDavid du Colombier 			p->nc++;
548*8ccd4a63SDavid du Colombier 			*pp = c;
549*8ccd4a63SDavid du Colombier 			break;
550*8ccd4a63SDavid du Colombier 		}
551*8ccd4a63SDavid du Colombier 		lock(&c->r.lk);
552*8ccd4a63SDavid du Colombier 		if(c->r.ref == 0) {
553*8ccd4a63SDavid du Colombier 			c->r.ref++;
554*8ccd4a63SDavid du Colombier 			break;
555*8ccd4a63SDavid du Colombier 		}
556*8ccd4a63SDavid du Colombier 		unlock(&c->r.lk);
557*8ccd4a63SDavid du Colombier 	}
558*8ccd4a63SDavid du Colombier 	if(pp >= ep) {
559*8ccd4a63SDavid du Colombier 		unlock(&p->l);
560*8ccd4a63SDavid du Colombier 		poperror();
561*8ccd4a63SDavid du Colombier 		return 0;
562*8ccd4a63SDavid du Colombier 	}
563*8ccd4a63SDavid du Colombier 
564*8ccd4a63SDavid du Colombier 	strcpy(c->owner, user);
565*8ccd4a63SDavid du Colombier 	c->perm = 0660;
566*8ccd4a63SDavid du Colombier 	c->state = "Closed";
567*8ccd4a63SDavid du Colombier 	c->restricted = 0;
568*8ccd4a63SDavid du Colombier 	c->laddr = 0;
569*8ccd4a63SDavid du Colombier 	c->raddr = 0;
570*8ccd4a63SDavid du Colombier 	c->lport = 0;
571*8ccd4a63SDavid du Colombier 	c->rport = 0;
572*8ccd4a63SDavid du Colombier 	c->sfd = nfd;
573*8ccd4a63SDavid du Colombier 	if(nfd == -1)
574*8ccd4a63SDavid du Colombier 		c->sfd = so_socket(p->stype);
575*8ccd4a63SDavid du Colombier 
576*8ccd4a63SDavid du Colombier 	unlock(&c->r.lk);
577*8ccd4a63SDavid du Colombier 	unlock(&p->l);
578*8ccd4a63SDavid du Colombier 	poperror();
579*8ccd4a63SDavid du Colombier 	return c;
580*8ccd4a63SDavid du Colombier }
581*8ccd4a63SDavid du Colombier 
582*8ccd4a63SDavid du Colombier enum
583*8ccd4a63SDavid du Colombier {
584*8ccd4a63SDavid du Colombier 	Isprefix= 16,
585*8ccd4a63SDavid du Colombier };
586*8ccd4a63SDavid du Colombier 
587*8ccd4a63SDavid du Colombier uchar prefixvals[256] =
588*8ccd4a63SDavid du Colombier {
589*8ccd4a63SDavid du Colombier /*0x00*/ 0 | Isprefix,
590*8ccd4a63SDavid du Colombier 		   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
591*8ccd4a63SDavid du Colombier /*0x10*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
592*8ccd4a63SDavid du Colombier /*0x20*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
593*8ccd4a63SDavid du Colombier /*0x30*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
594*8ccd4a63SDavid du Colombier /*0x40*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
595*8ccd4a63SDavid du Colombier /*0x50*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
596*8ccd4a63SDavid du Colombier /*0x60*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
597*8ccd4a63SDavid du Colombier /*0x70*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
598*8ccd4a63SDavid du Colombier /*0x80*/ 1 | Isprefix,
599*8ccd4a63SDavid du Colombier 		   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
600*8ccd4a63SDavid du Colombier /*0x90*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
601*8ccd4a63SDavid du Colombier /*0xA0*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
602*8ccd4a63SDavid du Colombier /*0xB0*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
603*8ccd4a63SDavid du Colombier /*0xC0*/ 2 | Isprefix,
604*8ccd4a63SDavid du Colombier 		   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
605*8ccd4a63SDavid du Colombier /*0xD0*/	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
606*8ccd4a63SDavid du Colombier /*0xE0*/ 3 | Isprefix,
607*8ccd4a63SDavid du Colombier 		   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
608*8ccd4a63SDavid du Colombier /*0xF0*/ 4 | Isprefix,
609*8ccd4a63SDavid du Colombier 		   0, 0, 0, 0, 0, 0, 0,
610*8ccd4a63SDavid du Colombier /*0xF8*/ 5 | Isprefix,
611*8ccd4a63SDavid du Colombier 		   0, 0, 0,
612*8ccd4a63SDavid du Colombier /*0xFC*/ 6 | Isprefix,
613*8ccd4a63SDavid du Colombier 		   0,
614*8ccd4a63SDavid du Colombier /*0xFE*/ 7 | Isprefix,
615*8ccd4a63SDavid du Colombier /*0xFF*/ 8 | Isprefix,
616*8ccd4a63SDavid du Colombier };
617*8ccd4a63SDavid du Colombier 
618*8ccd4a63SDavid du Colombier int
619*8ccd4a63SDavid du Colombier eipfmt(Fmt *f)
620*8ccd4a63SDavid du Colombier {
621*8ccd4a63SDavid du Colombier 	char buf[5*8];
622*8ccd4a63SDavid du Colombier 	static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
623*8ccd4a63SDavid du Colombier 	static char *ifmt = "%d.%d.%d.%d";
624*8ccd4a63SDavid du Colombier 	uchar *p, ip[16];
625*8ccd4a63SDavid du Colombier 	ulong ul;
626*8ccd4a63SDavid du Colombier 
627*8ccd4a63SDavid du Colombier 	switch(f->r) {
628*8ccd4a63SDavid du Colombier 	case 'E':		/* Ethernet address */
629*8ccd4a63SDavid du Colombier 		p = va_arg(f->args, uchar*);
630*8ccd4a63SDavid du Colombier 		snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
631*8ccd4a63SDavid du Colombier 		return fmtstrcpy(f, buf);
632*8ccd4a63SDavid du Colombier 
633*8ccd4a63SDavid du Colombier 	case 'I':
634*8ccd4a63SDavid du Colombier 		ul = va_arg(f->args, ulong);
635*8ccd4a63SDavid du Colombier 		hnputl(ip, ul);
636*8ccd4a63SDavid du Colombier 		snprint(buf, sizeof buf, ifmt, ip[0], ip[1], ip[2], ip[3]);
637*8ccd4a63SDavid du Colombier 		return fmtstrcpy(f, buf);
638*8ccd4a63SDavid du Colombier 	}
639*8ccd4a63SDavid du Colombier 	return fmtstrcpy(f, "(eipfmt)");
640*8ccd4a63SDavid du Colombier }
641*8ccd4a63SDavid du Colombier 
642*8ccd4a63SDavid du Colombier void
643*8ccd4a63SDavid du Colombier hnputl(void *p, unsigned long v)
644*8ccd4a63SDavid du Colombier {
645*8ccd4a63SDavid du Colombier 	unsigned char *a;
646*8ccd4a63SDavid du Colombier 
647*8ccd4a63SDavid du Colombier 	a = p;
648*8ccd4a63SDavid du Colombier 	a[0] = v>>24;
649*8ccd4a63SDavid du Colombier 	a[1] = v>>16;
650*8ccd4a63SDavid du Colombier 	a[2] = v>>8;
651*8ccd4a63SDavid du Colombier 	a[3] = v;
652*8ccd4a63SDavid du Colombier }
653*8ccd4a63SDavid du Colombier 
654*8ccd4a63SDavid du Colombier void
655*8ccd4a63SDavid du Colombier hnputs(void *p, unsigned short v)
656*8ccd4a63SDavid du Colombier {
657*8ccd4a63SDavid du Colombier 	unsigned char *a;
658*8ccd4a63SDavid du Colombier 
659*8ccd4a63SDavid du Colombier 	a = p;
660*8ccd4a63SDavid du Colombier 	a[0] = v>>8;
661*8ccd4a63SDavid du Colombier 	a[1] = v;
662*8ccd4a63SDavid du Colombier }
663*8ccd4a63SDavid du Colombier 
664*8ccd4a63SDavid du Colombier unsigned long
665*8ccd4a63SDavid du Colombier nhgetl(void *p)
666*8ccd4a63SDavid du Colombier {
667*8ccd4a63SDavid du Colombier 	unsigned char *a;
668*8ccd4a63SDavid du Colombier 	a = p;
669*8ccd4a63SDavid du Colombier 	return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
670*8ccd4a63SDavid du Colombier }
671*8ccd4a63SDavid du Colombier 
672*8ccd4a63SDavid du Colombier unsigned short
673*8ccd4a63SDavid du Colombier nhgets(void *p)
674*8ccd4a63SDavid du Colombier {
675*8ccd4a63SDavid du Colombier 	unsigned char *a;
676*8ccd4a63SDavid du Colombier 	a = p;
677*8ccd4a63SDavid du Colombier 	return (a[0]<<8)|(a[1]<<0);
678*8ccd4a63SDavid du Colombier }
679*8ccd4a63SDavid du Colombier 
680*8ccd4a63SDavid du Colombier #define CLASS(p) ((*(unsigned char*)(p))>>6)
681*8ccd4a63SDavid du Colombier 
682*8ccd4a63SDavid du Colombier unsigned long
683*8ccd4a63SDavid du Colombier parseip(char *to, char *from)
684*8ccd4a63SDavid du Colombier {
685*8ccd4a63SDavid du Colombier 	int i;
686*8ccd4a63SDavid du Colombier 	char *p;
687*8ccd4a63SDavid du Colombier 
688*8ccd4a63SDavid du Colombier 	p = from;
689*8ccd4a63SDavid du Colombier 	memset(to, 0, 4);
690*8ccd4a63SDavid du Colombier 	for(i = 0; i < 4 && *p; i++){
691*8ccd4a63SDavid du Colombier 		to[i] = strtoul(p, &p, 0);
692*8ccd4a63SDavid du Colombier 		if(*p == '.')
693*8ccd4a63SDavid du Colombier 			p++;
694*8ccd4a63SDavid du Colombier 	}
695*8ccd4a63SDavid du Colombier 	switch(CLASS(to)){
696*8ccd4a63SDavid du Colombier 	case 0:	/* class A - 1 byte net */
697*8ccd4a63SDavid du Colombier 	case 1:
698*8ccd4a63SDavid du Colombier 		if(i == 3){
699*8ccd4a63SDavid du Colombier 			to[3] = to[2];
700*8ccd4a63SDavid du Colombier 			to[2] = to[1];
701*8ccd4a63SDavid du Colombier 			to[1] = 0;
702*8ccd4a63SDavid du Colombier 		} else if (i == 2){
703*8ccd4a63SDavid du Colombier 			to[3] = to[1];
704*8ccd4a63SDavid du Colombier 			to[1] = 0;
705*8ccd4a63SDavid du Colombier 		}
706*8ccd4a63SDavid du Colombier 		break;
707*8ccd4a63SDavid du Colombier 	case 2:	/* class B - 2 byte net */
708*8ccd4a63SDavid du Colombier 		if(i == 3){
709*8ccd4a63SDavid du Colombier 			to[3] = to[2];
710*8ccd4a63SDavid du Colombier 			to[2] = 0;
711*8ccd4a63SDavid du Colombier 		}
712*8ccd4a63SDavid du Colombier 		break;
713*8ccd4a63SDavid du Colombier 	}
714*8ccd4a63SDavid du Colombier 	return nhgetl(to);
715*8ccd4a63SDavid du Colombier }
716*8ccd4a63SDavid du Colombier 
717*8ccd4a63SDavid du Colombier void
718*8ccd4a63SDavid du Colombier csclose(Chan *c)
719*8ccd4a63SDavid du Colombier {
720*8ccd4a63SDavid du Colombier 	free(c->aux);
721*8ccd4a63SDavid du Colombier }
722*8ccd4a63SDavid du Colombier 
723*8ccd4a63SDavid du Colombier long
724*8ccd4a63SDavid du Colombier csread(Chan *c, void *a, long n, vlong offset)
725*8ccd4a63SDavid du Colombier {
726*8ccd4a63SDavid du Colombier 	if(c->aux == nil)
727*8ccd4a63SDavid du Colombier 		return 0;
728*8ccd4a63SDavid du Colombier 	return readstr(offset, a, n, c->aux);
729*8ccd4a63SDavid du Colombier }
730*8ccd4a63SDavid du Colombier 
731*8ccd4a63SDavid du Colombier static struct
732*8ccd4a63SDavid du Colombier {
733*8ccd4a63SDavid du Colombier 	char *name;
734*8ccd4a63SDavid du Colombier 	uint num;
735*8ccd4a63SDavid du Colombier } tab[] = {
736*8ccd4a63SDavid du Colombier 	"cs", 1,
737*8ccd4a63SDavid du Colombier 	"echo", 7,
738*8ccd4a63SDavid du Colombier 	"discard", 9,
739*8ccd4a63SDavid du Colombier 	"systat", 11,
740*8ccd4a63SDavid du Colombier 	"daytime", 13,
741*8ccd4a63SDavid du Colombier 	"netstat", 15,
742*8ccd4a63SDavid du Colombier 	"chargen", 19,
743*8ccd4a63SDavid du Colombier 	"ftp-data", 20,
744*8ccd4a63SDavid du Colombier 	"ftp", 21,
745*8ccd4a63SDavid du Colombier 	"ssh", 22,
746*8ccd4a63SDavid du Colombier 	"telnet", 23,
747*8ccd4a63SDavid du Colombier 	"smtp", 25,
748*8ccd4a63SDavid du Colombier 	"time", 37,
749*8ccd4a63SDavid du Colombier 	"whois", 43,
750*8ccd4a63SDavid du Colombier 	"dns", 53,
751*8ccd4a63SDavid du Colombier 	"domain", 53,
752*8ccd4a63SDavid du Colombier 	"uucp", 64,
753*8ccd4a63SDavid du Colombier 	"gopher", 70,
754*8ccd4a63SDavid du Colombier 	"rje", 77,
755*8ccd4a63SDavid du Colombier 	"finger", 79,
756*8ccd4a63SDavid du Colombier 	"http", 80,
757*8ccd4a63SDavid du Colombier 	"link", 87,
758*8ccd4a63SDavid du Colombier 	"supdup", 95,
759*8ccd4a63SDavid du Colombier 	"hostnames", 101,
760*8ccd4a63SDavid du Colombier 	"iso-tsap", 102,
761*8ccd4a63SDavid du Colombier 	"x400", 103,
762*8ccd4a63SDavid du Colombier 	"x400-snd", 104,
763*8ccd4a63SDavid du Colombier 	"csnet-ns", 105,
764*8ccd4a63SDavid du Colombier 	"pop-2", 109,
765*8ccd4a63SDavid du Colombier 	"pop3", 110,
766*8ccd4a63SDavid du Colombier 	"portmap", 111,
767*8ccd4a63SDavid du Colombier 	"uucp-path", 117,
768*8ccd4a63SDavid du Colombier 	"nntp", 119,
769*8ccd4a63SDavid du Colombier 	"netbios", 139,
770*8ccd4a63SDavid du Colombier 	"imap4", 143,
771*8ccd4a63SDavid du Colombier 	"NeWS", 144,
772*8ccd4a63SDavid du Colombier 	"print-srv", 170,
773*8ccd4a63SDavid du Colombier 	"z39.50", 210,
774*8ccd4a63SDavid du Colombier 	"fsb", 400,
775*8ccd4a63SDavid du Colombier 	"sysmon", 401,
776*8ccd4a63SDavid du Colombier 	"proxy", 402,
777*8ccd4a63SDavid du Colombier 	"proxyd", 404,
778*8ccd4a63SDavid du Colombier 	"https", 443,
779*8ccd4a63SDavid du Colombier 	"cifs", 445,
780*8ccd4a63SDavid du Colombier 	"ssmtp", 465,
781*8ccd4a63SDavid du Colombier 	"rexec", 512,
782*8ccd4a63SDavid du Colombier 	"login", 513,
783*8ccd4a63SDavid du Colombier 	"shell", 514,
784*8ccd4a63SDavid du Colombier 	"printer", 515,
785*8ccd4a63SDavid du Colombier 	"courier", 530,
786*8ccd4a63SDavid du Colombier 	"cscan", 531,
787*8ccd4a63SDavid du Colombier 	"uucp", 540,
788*8ccd4a63SDavid du Colombier 	"snntp", 563,
789*8ccd4a63SDavid du Colombier 	"9fs", 564,
790*8ccd4a63SDavid du Colombier 	"whoami", 565,
791*8ccd4a63SDavid du Colombier 	"guard", 566,
792*8ccd4a63SDavid du Colombier 	"ticket", 567,
793*8ccd4a63SDavid du Colombier 	"dlsftp", 666,
794*8ccd4a63SDavid du Colombier 	"fmclient", 729,
795*8ccd4a63SDavid du Colombier 	"imaps", 993,
796*8ccd4a63SDavid du Colombier 	"pop3s", 995,
797*8ccd4a63SDavid du Colombier 	"ingreslock", 1524,
798*8ccd4a63SDavid du Colombier 	"pptp", 1723,
799*8ccd4a63SDavid du Colombier 	"nfs", 2049,
800*8ccd4a63SDavid du Colombier 	"webster", 2627,
801*8ccd4a63SDavid du Colombier 	"weather", 3000,
802*8ccd4a63SDavid du Colombier 	"secstore", 5356,
803*8ccd4a63SDavid du Colombier 	"Xdisplay", 6000,
804*8ccd4a63SDavid du Colombier 	"styx", 6666,
805*8ccd4a63SDavid du Colombier 	"mpeg", 6667,
806*8ccd4a63SDavid du Colombier 	"rstyx", 6668,
807*8ccd4a63SDavid du Colombier 	"infdb", 6669,
808*8ccd4a63SDavid du Colombier 	"infsigner", 6671,
809*8ccd4a63SDavid du Colombier 	"infcsigner", 6672,
810*8ccd4a63SDavid du Colombier 	"inflogin", 6673,
811*8ccd4a63SDavid du Colombier 	"bandt", 7330,
812*8ccd4a63SDavid du Colombier 	"face", 32000,
813*8ccd4a63SDavid du Colombier 	"dhashgate", 11978,
814*8ccd4a63SDavid du Colombier 	"exportfs", 17007,
815*8ccd4a63SDavid du Colombier 	"rexexec", 17009,
816*8ccd4a63SDavid du Colombier 	"ncpu", 17010,
817*8ccd4a63SDavid du Colombier 	"cpu", 17013,
818*8ccd4a63SDavid du Colombier 	"glenglenda1", 17020,
819*8ccd4a63SDavid du Colombier 	"glenglenda2", 17021,
820*8ccd4a63SDavid du Colombier 	"glenglenda3", 17022,
821*8ccd4a63SDavid du Colombier 	"glenglenda4", 17023,
822*8ccd4a63SDavid du Colombier 	"glenglenda5", 17024,
823*8ccd4a63SDavid du Colombier 	"glenglenda6", 17025,
824*8ccd4a63SDavid du Colombier 	"glenglenda7", 17026,
825*8ccd4a63SDavid du Colombier 	"glenglenda8", 17027,
826*8ccd4a63SDavid du Colombier 	"glenglenda9", 17028,
827*8ccd4a63SDavid du Colombier 	"glenglenda10", 17029,
828*8ccd4a63SDavid du Colombier 	"flyboy", 17032,
829*8ccd4a63SDavid du Colombier 	"dlsftp", 17033,
830*8ccd4a63SDavid du Colombier 	"venti", 17034,
831*8ccd4a63SDavid du Colombier 	"wiki", 17035,
832*8ccd4a63SDavid du Colombier 	"vica", 17036,
833*8ccd4a63SDavid du Colombier 	0
834*8ccd4a63SDavid du Colombier };
835*8ccd4a63SDavid du Colombier 
836*8ccd4a63SDavid du Colombier static int
837*8ccd4a63SDavid du Colombier lookupport(char *s)
838*8ccd4a63SDavid du Colombier {
839*8ccd4a63SDavid du Colombier 	int i;
840*8ccd4a63SDavid du Colombier 	char buf[10], *p;
841*8ccd4a63SDavid du Colombier 
842*8ccd4a63SDavid du Colombier 	i = strtol(s, &p, 0);
843*8ccd4a63SDavid du Colombier 	if(*s && *p == 0)
844*8ccd4a63SDavid du Colombier 		return i;
845*8ccd4a63SDavid du Colombier 
846*8ccd4a63SDavid du Colombier 	i = so_getservbyname(s, "tcp", buf);
847*8ccd4a63SDavid du Colombier 	if(i != -1)
848*8ccd4a63SDavid du Colombier 		return atoi(buf);
849*8ccd4a63SDavid du Colombier 	for(i=0; tab[i].name; i++)
850*8ccd4a63SDavid du Colombier 		if(strcmp(s, tab[i].name) == 0)
851*8ccd4a63SDavid du Colombier 			return tab[i].num;
852*8ccd4a63SDavid du Colombier 	return 0;
853*8ccd4a63SDavid du Colombier }
854*8ccd4a63SDavid du Colombier 
855*8ccd4a63SDavid du Colombier static ulong
856*8ccd4a63SDavid du Colombier lookuphost(char *s)
857*8ccd4a63SDavid du Colombier {
858*8ccd4a63SDavid du Colombier 	char to[4];
859*8ccd4a63SDavid du Colombier 	ulong ip;
860*8ccd4a63SDavid du Colombier 
861*8ccd4a63SDavid du Colombier 	memset(to, 0, sizeof to);
862*8ccd4a63SDavid du Colombier 	parseip(to, s);
863*8ccd4a63SDavid du Colombier 	ip = nhgetl(to);
864*8ccd4a63SDavid du Colombier 	if(ip != 0)
865*8ccd4a63SDavid du Colombier 		return ip;
866*8ccd4a63SDavid du Colombier 	if((s = hostlookup(s)) == nil)
867*8ccd4a63SDavid du Colombier 		return 0;
868*8ccd4a63SDavid du Colombier 	parseip(to, s);
869*8ccd4a63SDavid du Colombier 	ip = nhgetl(to);
870*8ccd4a63SDavid du Colombier 	free(s);
871*8ccd4a63SDavid du Colombier 	return ip;
872*8ccd4a63SDavid du Colombier }
873*8ccd4a63SDavid du Colombier 
874*8ccd4a63SDavid du Colombier long
875*8ccd4a63SDavid du Colombier cswrite(Chan *c, void *a, long n, vlong offset)
876*8ccd4a63SDavid du Colombier {
877*8ccd4a63SDavid du Colombier 	char *f[4];
878*8ccd4a63SDavid du Colombier 	char *s, *ns;
879*8ccd4a63SDavid du Colombier 	ulong ip;
880*8ccd4a63SDavid du Colombier 	int nf, port;
881*8ccd4a63SDavid du Colombier 
882*8ccd4a63SDavid du Colombier 	s = malloc(n+1);
883*8ccd4a63SDavid du Colombier 	if(s == nil)
884*8ccd4a63SDavid du Colombier 		error(Enomem);
885*8ccd4a63SDavid du Colombier 	if(waserror()){
886*8ccd4a63SDavid du Colombier 		free(s);
887*8ccd4a63SDavid du Colombier 		nexterror();
888*8ccd4a63SDavid du Colombier 	}
889*8ccd4a63SDavid du Colombier 	memmove(s, a, n);
890*8ccd4a63SDavid du Colombier 	s[n] = 0;
891*8ccd4a63SDavid du Colombier 	nf = getfields(s, f, nelem(f), 0, "!");
892*8ccd4a63SDavid du Colombier 	if(nf != 3)
893*8ccd4a63SDavid du Colombier 		error("can't translate");
894*8ccd4a63SDavid du Colombier 
895*8ccd4a63SDavid du Colombier 	port = lookupport(f[2]);
896*8ccd4a63SDavid du Colombier 	if(port <= 0)
897*8ccd4a63SDavid du Colombier 		error("no translation for port found");
898*8ccd4a63SDavid du Colombier 
899*8ccd4a63SDavid du Colombier 	ip = lookuphost(f[1]);
900*8ccd4a63SDavid du Colombier 	if(ip == 0)
901*8ccd4a63SDavid du Colombier 		error("no translation for host found");
902*8ccd4a63SDavid du Colombier 
903*8ccd4a63SDavid du Colombier 	ns = smprint("/net/%s/clone %I!%d", f[0], ip, port);
904*8ccd4a63SDavid du Colombier 	if(ns == nil)
905*8ccd4a63SDavid du Colombier 		error(Enomem);
906*8ccd4a63SDavid du Colombier 	free(c->aux);
907*8ccd4a63SDavid du Colombier 	c->aux = ns;
908*8ccd4a63SDavid du Colombier 	poperror();
909*8ccd4a63SDavid du Colombier 	free(s);
910*8ccd4a63SDavid du Colombier 	return n;
911*8ccd4a63SDavid du Colombier }
912*8ccd4a63SDavid du Colombier 
913*8ccd4a63SDavid du Colombier Dev ipdevtab =
914*8ccd4a63SDavid du Colombier {
915*8ccd4a63SDavid du Colombier 	'I',
916*8ccd4a63SDavid du Colombier 	"ip",
917*8ccd4a63SDavid du Colombier 
918*8ccd4a63SDavid du Colombier 	devreset,
919*8ccd4a63SDavid du Colombier 	ipinit,
920*8ccd4a63SDavid du Colombier 	devshutdown,
921*8ccd4a63SDavid du Colombier 	ipattach,
922*8ccd4a63SDavid du Colombier 	ipwalk,
923*8ccd4a63SDavid du Colombier 	ipstat,
924*8ccd4a63SDavid du Colombier 	ipopen,
925*8ccd4a63SDavid du Colombier 	devcreate,
926*8ccd4a63SDavid du Colombier 	ipclose,
927*8ccd4a63SDavid du Colombier 	ipread,
928*8ccd4a63SDavid du Colombier 	devbread,
929*8ccd4a63SDavid du Colombier 	ipwrite,
930*8ccd4a63SDavid du Colombier 	devbwrite,
931*8ccd4a63SDavid du Colombier 	devremove,
932*8ccd4a63SDavid du Colombier 	devwstat,
933*8ccd4a63SDavid du Colombier };
934*8ccd4a63SDavid du Colombier 
935