xref: /plan9/sys/src/cmd/unix/drawterm/kern/devip.c (revision 58da3067adcdccaaa043d0bfde28ba83b7ced07d)
18ccd4a63SDavid du Colombier #include "u.h"
28ccd4a63SDavid du Colombier #include "lib.h"
38ccd4a63SDavid du Colombier #include "dat.h"
48ccd4a63SDavid du Colombier #include "fns.h"
58ccd4a63SDavid du Colombier #include "error.h"
6*58da3067SDavid du Colombier #include "ip.h"
78ccd4a63SDavid du Colombier 
88ccd4a63SDavid du Colombier #include "devip.h"
98ccd4a63SDavid du Colombier 
108ccd4a63SDavid du Colombier void	csclose(Chan*);
118ccd4a63SDavid du Colombier long	csread(Chan*, void*, long, vlong);
128ccd4a63SDavid du Colombier long	cswrite(Chan*, void*, long, vlong);
138ccd4a63SDavid du Colombier 
148ccd4a63SDavid du Colombier void osipinit(void);
158ccd4a63SDavid du Colombier 
168ccd4a63SDavid du Colombier enum
178ccd4a63SDavid du Colombier {
188ccd4a63SDavid du Colombier 	Qtopdir		= 1,	/* top level directory */
198ccd4a63SDavid du Colombier 	Qcs,
208ccd4a63SDavid du Colombier 	Qprotodir,		/* directory for a protocol */
218ccd4a63SDavid du Colombier 	Qclonus,
228ccd4a63SDavid du Colombier 	Qconvdir,		/* directory for a conversation */
238ccd4a63SDavid du Colombier 	Qdata,
248ccd4a63SDavid du Colombier 	Qctl,
258ccd4a63SDavid du Colombier 	Qstatus,
268ccd4a63SDavid du Colombier 	Qremote,
278ccd4a63SDavid du Colombier 	Qlocal,
288ccd4a63SDavid du Colombier 	Qlisten,
298ccd4a63SDavid du Colombier 
308ccd4a63SDavid du Colombier 	MAXPROTO	= 4
318ccd4a63SDavid du Colombier };
328ccd4a63SDavid du Colombier #define TYPE(x) 	((int)((x).path & 0xf))
338ccd4a63SDavid du Colombier #define CONV(x) 	((int)(((x).path >> 4)&0xfff))
348ccd4a63SDavid du Colombier #define PROTO(x) 	((int)(((x).path >> 16)&0xff))
358ccd4a63SDavid du Colombier #define QID(p, c, y) 	(((p)<<16) | ((c)<<4) | (y))
36*58da3067SDavid du Colombier #define ipzero(x)	memset(x, 0, IPaddrlen)
378ccd4a63SDavid du Colombier 
388ccd4a63SDavid du Colombier typedef struct Proto	Proto;
398ccd4a63SDavid du Colombier typedef struct Conv	Conv;
408ccd4a63SDavid du Colombier struct Conv
418ccd4a63SDavid du Colombier {
428ccd4a63SDavid du Colombier 	int	x;
438ccd4a63SDavid du Colombier 	Ref	r;
448ccd4a63SDavid du Colombier 	int	sfd;
458ccd4a63SDavid du Colombier 	int	perm;
468ccd4a63SDavid du Colombier 	char	owner[KNAMELEN];
478ccd4a63SDavid du Colombier 	char*	state;
48*58da3067SDavid du Colombier 	uchar	laddr[IPaddrlen];
498ccd4a63SDavid du Colombier 	ushort	lport;
50*58da3067SDavid du Colombier 	uchar	raddr[IPaddrlen];
518ccd4a63SDavid du Colombier 	ushort	rport;
528ccd4a63SDavid du Colombier 	int	restricted;
538ccd4a63SDavid du Colombier 	char	cerr[KNAMELEN];
548ccd4a63SDavid du Colombier 	Proto*	p;
558ccd4a63SDavid du Colombier };
568ccd4a63SDavid du Colombier 
578ccd4a63SDavid du Colombier struct Proto
588ccd4a63SDavid du Colombier {
598ccd4a63SDavid du Colombier 	Lock	l;
608ccd4a63SDavid du Colombier 	int	x;
618ccd4a63SDavid du Colombier 	int	stype;
628ccd4a63SDavid du Colombier 	char	name[KNAMELEN];
638ccd4a63SDavid du Colombier 	int	nc;
648ccd4a63SDavid du Colombier 	int	maxconv;
658ccd4a63SDavid du Colombier 	Conv**	conv;
668ccd4a63SDavid du Colombier 	Qid	qid;
678ccd4a63SDavid du Colombier };
688ccd4a63SDavid du Colombier 
698ccd4a63SDavid du Colombier static	int	np;
708ccd4a63SDavid du Colombier static	Proto	proto[MAXPROTO];
718ccd4a63SDavid du Colombier 
728ccd4a63SDavid du Colombier static	Conv*	protoclone(Proto*, char*, int);
738ccd4a63SDavid du Colombier static	void	setladdr(Conv*);
748ccd4a63SDavid du Colombier 
758ccd4a63SDavid du Colombier int
ipgen(Chan * c,char * nname,Dirtab * d,int nd,int s,Dir * dp)768ccd4a63SDavid du Colombier ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp)
778ccd4a63SDavid du Colombier {
788ccd4a63SDavid du Colombier 	Qid q;
798ccd4a63SDavid du Colombier 	Conv *cv;
808ccd4a63SDavid du Colombier 	char *p;
818ccd4a63SDavid du Colombier 
828ccd4a63SDavid du Colombier 	USED(nname);
838ccd4a63SDavid du Colombier 	q.vers = 0;
848ccd4a63SDavid du Colombier 	q.type = 0;
858ccd4a63SDavid du Colombier 	switch(TYPE(c->qid)) {
868ccd4a63SDavid du Colombier 	case Qtopdir:
878ccd4a63SDavid du Colombier 		if(s >= 1+np)
888ccd4a63SDavid du Colombier 			return -1;
898ccd4a63SDavid du Colombier 
908ccd4a63SDavid du Colombier 		if(s == 0){
918ccd4a63SDavid du Colombier 			q.path = QID(s, 0, Qcs);
928ccd4a63SDavid du Colombier 			devdir(c, q, "cs", 0, "network", 0666, dp);
938ccd4a63SDavid du Colombier 		}else{
948ccd4a63SDavid du Colombier 			s--;
958ccd4a63SDavid du Colombier 			q.path = QID(s, 0, Qprotodir);
968ccd4a63SDavid du Colombier 			q.type = QTDIR;
978ccd4a63SDavid du Colombier 			devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp);
988ccd4a63SDavid du Colombier 		}
998ccd4a63SDavid du Colombier 		return 1;
1008ccd4a63SDavid du Colombier 	case Qprotodir:
1018ccd4a63SDavid du Colombier 		if(s < proto[PROTO(c->qid)].nc) {
1028ccd4a63SDavid du Colombier 			cv = proto[PROTO(c->qid)].conv[s];
1038ccd4a63SDavid du Colombier 			sprint(up->genbuf, "%d", s);
1048ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), s, Qconvdir);
1058ccd4a63SDavid du Colombier 			q.type = QTDIR;
1068ccd4a63SDavid du Colombier 			devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp);
1078ccd4a63SDavid du Colombier 			return 1;
1088ccd4a63SDavid du Colombier 		}
1098ccd4a63SDavid du Colombier 		s -= proto[PROTO(c->qid)].nc;
1108ccd4a63SDavid du Colombier 		switch(s) {
1118ccd4a63SDavid du Colombier 		default:
1128ccd4a63SDavid du Colombier 			return -1;
1138ccd4a63SDavid du Colombier 		case 0:
1148ccd4a63SDavid du Colombier 			p = "clone";
1158ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), 0, Qclonus);
1168ccd4a63SDavid du Colombier 			break;
1178ccd4a63SDavid du Colombier 		}
1188ccd4a63SDavid du Colombier 		devdir(c, q, p, 0, "network", 0555, dp);
1198ccd4a63SDavid du Colombier 		return 1;
1208ccd4a63SDavid du Colombier 	case Qconvdir:
1218ccd4a63SDavid du Colombier 		cv = proto[PROTO(c->qid)].conv[CONV(c->qid)];
1228ccd4a63SDavid du Colombier 		switch(s) {
1238ccd4a63SDavid du Colombier 		default:
1248ccd4a63SDavid du Colombier 			return -1;
1258ccd4a63SDavid du Colombier 		case 0:
1268ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata);
1278ccd4a63SDavid du Colombier 			devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
1288ccd4a63SDavid du Colombier 			return 1;
1298ccd4a63SDavid du Colombier 		case 1:
1308ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl);
1318ccd4a63SDavid du Colombier 			devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
1328ccd4a63SDavid du Colombier 			return 1;
1338ccd4a63SDavid du Colombier 		case 2:
1348ccd4a63SDavid du Colombier 			p = "status";
1358ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus);
1368ccd4a63SDavid du Colombier 			break;
1378ccd4a63SDavid du Colombier 		case 3:
1388ccd4a63SDavid du Colombier 			p = "remote";
1398ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote);
1408ccd4a63SDavid du Colombier 			break;
1418ccd4a63SDavid du Colombier 		case 4:
1428ccd4a63SDavid du Colombier 			p = "local";
1438ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal);
1448ccd4a63SDavid du Colombier 			break;
1458ccd4a63SDavid du Colombier 		case 5:
1468ccd4a63SDavid du Colombier 			p = "listen";
1478ccd4a63SDavid du Colombier 			q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten);
1488ccd4a63SDavid du Colombier 			break;
1498ccd4a63SDavid du Colombier 		}
1508ccd4a63SDavid du Colombier 		devdir(c, q, p, 0, cv->owner, 0444, dp);
1518ccd4a63SDavid du Colombier 		return 1;
1528ccd4a63SDavid du Colombier 	}
1538ccd4a63SDavid du Colombier 	return -1;
1548ccd4a63SDavid du Colombier }
1558ccd4a63SDavid du Colombier 
1568ccd4a63SDavid du Colombier static void
newproto(char * name,int type,int maxconv)1578ccd4a63SDavid du Colombier newproto(char *name, int type, int maxconv)
1588ccd4a63SDavid du Colombier {
1598ccd4a63SDavid du Colombier 	int l;
1608ccd4a63SDavid du Colombier 	Proto *p;
1618ccd4a63SDavid du Colombier 
1628ccd4a63SDavid du Colombier 	if(np >= MAXPROTO) {
1638ccd4a63SDavid du Colombier 		print("no %s: increase MAXPROTO", name);
1648ccd4a63SDavid du Colombier 		return;
1658ccd4a63SDavid du Colombier 	}
1668ccd4a63SDavid du Colombier 
1678ccd4a63SDavid du Colombier 	p = &proto[np];
1688ccd4a63SDavid du Colombier 	strcpy(p->name, name);
1698ccd4a63SDavid du Colombier 	p->stype = type;
1708ccd4a63SDavid du Colombier 	p->qid.path = QID(np, 0, Qprotodir);
1718ccd4a63SDavid du Colombier 	p->qid.type = QTDIR;
1728ccd4a63SDavid du Colombier 	p->x = np++;
1738ccd4a63SDavid du Colombier 	p->maxconv = maxconv;
1748ccd4a63SDavid du Colombier 	l = sizeof(Conv*)*(p->maxconv+1);
1758ccd4a63SDavid du Colombier 	p->conv = mallocz(l, 1);
1768ccd4a63SDavid du Colombier 	if(p->conv == 0)
1778ccd4a63SDavid du Colombier 		panic("no memory");
1788ccd4a63SDavid du Colombier }
1798ccd4a63SDavid du Colombier 
1808ccd4a63SDavid du Colombier void
ipinit(void)1818ccd4a63SDavid du Colombier ipinit(void)
1828ccd4a63SDavid du Colombier {
1838ccd4a63SDavid du Colombier 	osipinit();
1848ccd4a63SDavid du Colombier 
1858ccd4a63SDavid du Colombier 	newproto("udp", S_UDP, 10);
1868ccd4a63SDavid du Colombier 	newproto("tcp", S_TCP, 30);
1878ccd4a63SDavid du Colombier 
1888ccd4a63SDavid du Colombier 	fmtinstall('I', eipfmt);
1898ccd4a63SDavid du Colombier 	fmtinstall('E', eipfmt);
1908ccd4a63SDavid du Colombier 
1918ccd4a63SDavid du Colombier }
1928ccd4a63SDavid du Colombier 
1938ccd4a63SDavid du Colombier Chan *
ipattach(char * spec)1948ccd4a63SDavid du Colombier ipattach(char *spec)
1958ccd4a63SDavid du Colombier {
1968ccd4a63SDavid du Colombier 	Chan *c;
1978ccd4a63SDavid du Colombier 
1988ccd4a63SDavid du Colombier 	c = devattach('I', spec);
1998ccd4a63SDavid du Colombier 	c->qid.path = QID(0, 0, Qtopdir);
2008ccd4a63SDavid du Colombier 	c->qid.type = QTDIR;
2018ccd4a63SDavid du Colombier 	c->qid.vers = 0;
2028ccd4a63SDavid du Colombier 	return c;
2038ccd4a63SDavid du Colombier }
2048ccd4a63SDavid du Colombier 
2058ccd4a63SDavid du Colombier static Walkqid*
ipwalk(Chan * c,Chan * nc,char ** name,int nname)2068ccd4a63SDavid du Colombier ipwalk(Chan *c, Chan *nc, char **name, int nname)
2078ccd4a63SDavid du Colombier {
2088ccd4a63SDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, ipgen);
2098ccd4a63SDavid du Colombier }
2108ccd4a63SDavid du Colombier 
2118ccd4a63SDavid du Colombier int
ipstat(Chan * c,uchar * dp,int n)2128ccd4a63SDavid du Colombier ipstat(Chan *c, uchar *dp, int n)
2138ccd4a63SDavid du Colombier {
2148ccd4a63SDavid du Colombier 	return devstat(c, dp, n, 0, 0, ipgen);
2158ccd4a63SDavid du Colombier }
2168ccd4a63SDavid du Colombier 
2178ccd4a63SDavid du Colombier Chan *
ipopen(Chan * c,int omode)2188ccd4a63SDavid du Colombier ipopen(Chan *c, int omode)
2198ccd4a63SDavid du Colombier {
2208ccd4a63SDavid du Colombier 	Proto *p;
221*58da3067SDavid du Colombier 	uchar raddr[IPaddrlen];
2228ccd4a63SDavid du Colombier 	ushort rport;
2238ccd4a63SDavid du Colombier 	int perm, sfd;
2248ccd4a63SDavid du Colombier 	Conv *cv, *lcv;
2258ccd4a63SDavid du Colombier 
2268ccd4a63SDavid du Colombier 	omode &= 3;
2278ccd4a63SDavid du Colombier 	perm = 0;
2288ccd4a63SDavid du Colombier 	switch(omode) {
2298ccd4a63SDavid du Colombier 	case OREAD:
2308ccd4a63SDavid du Colombier 		perm = 4;
2318ccd4a63SDavid du Colombier 		break;
2328ccd4a63SDavid du Colombier 	case OWRITE:
2338ccd4a63SDavid du Colombier 		perm = 2;
2348ccd4a63SDavid du Colombier 		break;
2358ccd4a63SDavid du Colombier 	case ORDWR:
2368ccd4a63SDavid du Colombier 		perm = 6;
2378ccd4a63SDavid du Colombier 		break;
2388ccd4a63SDavid du Colombier 	}
2398ccd4a63SDavid du Colombier 
2408ccd4a63SDavid du Colombier 	switch(TYPE(c->qid)) {
2418ccd4a63SDavid du Colombier 	default:
2428ccd4a63SDavid du Colombier 		break;
2438ccd4a63SDavid du Colombier 	case Qtopdir:
2448ccd4a63SDavid du Colombier 	case Qprotodir:
2458ccd4a63SDavid du Colombier 	case Qconvdir:
2468ccd4a63SDavid du Colombier 	case Qstatus:
2478ccd4a63SDavid du Colombier 	case Qremote:
2488ccd4a63SDavid du Colombier 	case Qlocal:
2498ccd4a63SDavid du Colombier 		if(omode != OREAD)
2508ccd4a63SDavid du Colombier 			error(Eperm);
2518ccd4a63SDavid du Colombier 		break;
2528ccd4a63SDavid du Colombier 	case Qclonus:
2538ccd4a63SDavid du Colombier 		p = &proto[PROTO(c->qid)];
2548ccd4a63SDavid du Colombier 		cv = protoclone(p, up->user, -1);
2558ccd4a63SDavid du Colombier 		if(cv == 0)
2568ccd4a63SDavid du Colombier 			error(Enodev);
2578ccd4a63SDavid du Colombier 		c->qid.path = QID(p->x, cv->x, Qctl);
2588ccd4a63SDavid du Colombier 		c->qid.vers = 0;
2598ccd4a63SDavid du Colombier 		break;
2608ccd4a63SDavid du Colombier 	case Qdata:
2618ccd4a63SDavid du Colombier 	case Qctl:
2628ccd4a63SDavid du Colombier 		p = &proto[PROTO(c->qid)];
2638ccd4a63SDavid du Colombier 		lock(&p->l);
2648ccd4a63SDavid du Colombier 		cv = p->conv[CONV(c->qid)];
2658ccd4a63SDavid du Colombier 		lock(&cv->r.lk);
2668ccd4a63SDavid du Colombier 		if((perm & (cv->perm>>6)) != perm) {
2678ccd4a63SDavid du Colombier 			if(strcmp(up->user, cv->owner) != 0 ||
2688ccd4a63SDavid du Colombier 		 	  (perm & cv->perm) != perm) {
2698ccd4a63SDavid du Colombier 				unlock(&cv->r.lk);
2708ccd4a63SDavid du Colombier 				unlock(&p->l);
2718ccd4a63SDavid du Colombier 				error(Eperm);
2728ccd4a63SDavid du Colombier 			}
2738ccd4a63SDavid du Colombier 		}
2748ccd4a63SDavid du Colombier 		cv->r.ref++;
2758ccd4a63SDavid du Colombier 		if(cv->r.ref == 1) {
2768ccd4a63SDavid du Colombier 			memmove(cv->owner, up->user, KNAMELEN);
2778ccd4a63SDavid du Colombier 			cv->perm = 0660;
2788ccd4a63SDavid du Colombier 		}
2798ccd4a63SDavid du Colombier 		unlock(&cv->r.lk);
2808ccd4a63SDavid du Colombier 		unlock(&p->l);
2818ccd4a63SDavid du Colombier 		break;
2828ccd4a63SDavid du Colombier 	case Qlisten:
2838ccd4a63SDavid du Colombier 		p = &proto[PROTO(c->qid)];
2848ccd4a63SDavid du Colombier 		lcv = p->conv[CONV(c->qid)];
285*58da3067SDavid du Colombier 		sfd = so_accept(lcv->sfd, raddr, &rport);
2868ccd4a63SDavid du Colombier 		cv = protoclone(p, up->user, sfd);
2878ccd4a63SDavid du Colombier 		if(cv == 0) {
2888ccd4a63SDavid du Colombier 			close(sfd);
2898ccd4a63SDavid du Colombier 			error(Enodev);
2908ccd4a63SDavid du Colombier 		}
291*58da3067SDavid du Colombier 		ipmove(cv->raddr, raddr);
2928ccd4a63SDavid du Colombier 		cv->rport = rport;
2938ccd4a63SDavid du Colombier 		setladdr(cv);
2948ccd4a63SDavid du Colombier 		cv->state = "Established";
2958ccd4a63SDavid du Colombier 		c->qid.path = QID(p->x, cv->x, Qctl);
2968ccd4a63SDavid du Colombier 		break;
2978ccd4a63SDavid du Colombier 	}
2988ccd4a63SDavid du Colombier 	c->mode = openmode(omode);
2998ccd4a63SDavid du Colombier 	c->flag |= COPEN;
3008ccd4a63SDavid du Colombier 	c->offset = 0;
3018ccd4a63SDavid du Colombier 	return c;
3028ccd4a63SDavid du Colombier }
3038ccd4a63SDavid du Colombier 
3048ccd4a63SDavid du Colombier void
ipclose(Chan * c)3058ccd4a63SDavid du Colombier ipclose(Chan *c)
3068ccd4a63SDavid du Colombier {
3078ccd4a63SDavid du Colombier 	Conv *cc;
3088ccd4a63SDavid du Colombier 
3098ccd4a63SDavid du Colombier 	switch(TYPE(c->qid)) {
3108ccd4a63SDavid du Colombier 	case Qcs:
3118ccd4a63SDavid du Colombier 		csclose(c);
3128ccd4a63SDavid du Colombier 		break;
3138ccd4a63SDavid du Colombier 	case Qdata:
3148ccd4a63SDavid du Colombier 	case Qctl:
3158ccd4a63SDavid du Colombier 		if((c->flag & COPEN) == 0)
3168ccd4a63SDavid du Colombier 			break;
3178ccd4a63SDavid du Colombier 		cc = proto[PROTO(c->qid)].conv[CONV(c->qid)];
3188ccd4a63SDavid du Colombier 		if(decref(&cc->r) != 0)
3198ccd4a63SDavid du Colombier 			break;
3208ccd4a63SDavid du Colombier 		strcpy(cc->owner, "network");
3218ccd4a63SDavid du Colombier 		cc->perm = 0666;
3228ccd4a63SDavid du Colombier 		cc->state = "Closed";
323*58da3067SDavid du Colombier 		ipzero(cc->laddr);
324*58da3067SDavid du Colombier 		ipzero(cc->raddr);
3258ccd4a63SDavid du Colombier 		cc->lport = 0;
3268ccd4a63SDavid du Colombier 		cc->rport = 0;
3278ccd4a63SDavid du Colombier 		close(cc->sfd);
3288ccd4a63SDavid du Colombier 		break;
3298ccd4a63SDavid du Colombier 	}
3308ccd4a63SDavid du Colombier }
3318ccd4a63SDavid du Colombier 
3328ccd4a63SDavid du Colombier long
ipread(Chan * ch,void * a,long n,vlong offset)3338ccd4a63SDavid du Colombier ipread(Chan *ch, void *a, long n, vlong offset)
3348ccd4a63SDavid du Colombier {
3358ccd4a63SDavid du Colombier 	int r;
3368ccd4a63SDavid du Colombier 	Conv *c;
3378ccd4a63SDavid du Colombier 	Proto *x;
338*58da3067SDavid du Colombier 	uchar ip[IPaddrlen];
3398ccd4a63SDavid du Colombier 	char buf[128], *p;
3408ccd4a63SDavid du Colombier 
3418ccd4a63SDavid du Colombier /*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/
3428ccd4a63SDavid du Colombier 	p = a;
3438ccd4a63SDavid du Colombier 	switch(TYPE(ch->qid)) {
3448ccd4a63SDavid du Colombier 	default:
3458ccd4a63SDavid du Colombier 		error(Eperm);
3468ccd4a63SDavid du Colombier 	case Qcs:
3478ccd4a63SDavid du Colombier 		return csread(ch, a, n, offset);
3488ccd4a63SDavid du Colombier 	case Qprotodir:
3498ccd4a63SDavid du Colombier 	case Qtopdir:
3508ccd4a63SDavid du Colombier 	case Qconvdir:
3518ccd4a63SDavid du Colombier 		return devdirread(ch, a, n, 0, 0, ipgen);
3528ccd4a63SDavid du Colombier 	case Qctl:
3538ccd4a63SDavid du Colombier 		sprint(buf, "%d", CONV(ch->qid));
3548ccd4a63SDavid du Colombier 		return readstr(offset, p, n, buf);
3558ccd4a63SDavid du Colombier 	case Qremote:
3568ccd4a63SDavid du Colombier 		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
357*58da3067SDavid du Colombier 		ipmove(ip, c->raddr);
3588ccd4a63SDavid du Colombier 		sprint(buf, "%I!%d\n", ip, c->rport);
3598ccd4a63SDavid du Colombier 		return readstr(offset, p, n, buf);
3608ccd4a63SDavid du Colombier 	case Qlocal:
3618ccd4a63SDavid du Colombier 		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
362*58da3067SDavid du Colombier 		ipmove(ip, c->laddr);
3638ccd4a63SDavid du Colombier 		sprint(buf, "%I!%d\n", ip, c->lport);
3648ccd4a63SDavid du Colombier 		return readstr(offset, p, n, buf);
3658ccd4a63SDavid du Colombier 	case Qstatus:
3668ccd4a63SDavid du Colombier 		x = &proto[PROTO(ch->qid)];
3678ccd4a63SDavid du Colombier 		c = x->conv[CONV(ch->qid)];
3688ccd4a63SDavid du Colombier 		sprint(buf, "%s/%d %d %s \n",
3698ccd4a63SDavid du Colombier 			c->p->name, c->x, c->r.ref, c->state);
3708ccd4a63SDavid du Colombier 		return readstr(offset, p, n, buf);
3718ccd4a63SDavid du Colombier 	case Qdata:
3728ccd4a63SDavid du Colombier 		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
3738ccd4a63SDavid du Colombier 		r = so_recv(c->sfd, a, n, 0);
3748ccd4a63SDavid du Colombier 		if(r < 0){
3758ccd4a63SDavid du Colombier 			oserrstr();
3768ccd4a63SDavid du Colombier 			nexterror();
3778ccd4a63SDavid du Colombier 		}
3788ccd4a63SDavid du Colombier 		return r;
3798ccd4a63SDavid du Colombier 	}
3808ccd4a63SDavid du Colombier }
3818ccd4a63SDavid du Colombier 
3828ccd4a63SDavid du Colombier static void
setladdr(Conv * c)3838ccd4a63SDavid du Colombier setladdr(Conv *c)
3848ccd4a63SDavid du Colombier {
385*58da3067SDavid du Colombier 	so_getsockname(c->sfd, c->laddr, &c->lport);
3868ccd4a63SDavid du Colombier }
3878ccd4a63SDavid du Colombier 
3888ccd4a63SDavid du Colombier static void
setlport(Conv * c)3898ccd4a63SDavid du Colombier setlport(Conv *c)
3908ccd4a63SDavid du Colombier {
3918ccd4a63SDavid du Colombier 	if(c->restricted == 0 && c->lport == 0)
3928ccd4a63SDavid du Colombier 		return;
3938ccd4a63SDavid du Colombier 
394*58da3067SDavid du Colombier 	if(c->sfd == -1)
395*58da3067SDavid du Colombier 		c->sfd = so_socket(c->p->stype, c->laddr);
396*58da3067SDavid du Colombier 
397*58da3067SDavid du Colombier 	so_bind(c->sfd, c->restricted, c->lport, c->laddr);
3988ccd4a63SDavid du Colombier }
3998ccd4a63SDavid du Colombier 
4008ccd4a63SDavid du Colombier static void
setladdrport(Conv * c,char * str)4018ccd4a63SDavid du Colombier setladdrport(Conv *c, char *str)
4028ccd4a63SDavid du Colombier {
403*58da3067SDavid du Colombier 	char *p;
404*58da3067SDavid du Colombier 	uchar addr[IPaddrlen];
4058ccd4a63SDavid du Colombier 
4068ccd4a63SDavid du Colombier 	p = strchr(str, '!');
4078ccd4a63SDavid du Colombier 	if(p == 0) {
4088ccd4a63SDavid du Colombier 		p = str;
409*58da3067SDavid du Colombier 		ipzero(c->laddr);
4108ccd4a63SDavid du Colombier 	}
4118ccd4a63SDavid du Colombier 	else {
4128ccd4a63SDavid du Colombier 		*p++ = 0;
4138ccd4a63SDavid du Colombier 		parseip(addr, str);
414*58da3067SDavid du Colombier 		ipmove(c->laddr, addr);
4158ccd4a63SDavid du Colombier 	}
4168ccd4a63SDavid du Colombier 	if(*p == '*')
4178ccd4a63SDavid du Colombier 		c->lport = 0;
4188ccd4a63SDavid du Colombier 	else
4198ccd4a63SDavid du Colombier 		c->lport = atoi(p);
4208ccd4a63SDavid du Colombier 
4218ccd4a63SDavid du Colombier 	setlport(c);
4228ccd4a63SDavid du Colombier }
4238ccd4a63SDavid du Colombier 
4248ccd4a63SDavid du Colombier static char*
setraddrport(Conv * c,char * str)4258ccd4a63SDavid du Colombier setraddrport(Conv *c, char *str)
4268ccd4a63SDavid du Colombier {
427*58da3067SDavid du Colombier 	char *p;
428*58da3067SDavid du Colombier 	uchar addr[IPaddrlen];
4298ccd4a63SDavid du Colombier 
4308ccd4a63SDavid du Colombier 	p = strchr(str, '!');
4318ccd4a63SDavid du Colombier 	if(p == 0)
4328ccd4a63SDavid du Colombier 		return "malformed address";
4338ccd4a63SDavid du Colombier 	*p++ = 0;
4348ccd4a63SDavid du Colombier 	parseip(addr, str);
435*58da3067SDavid du Colombier 	ipmove(c->raddr, addr);
4368ccd4a63SDavid du Colombier 	c->rport = atoi(p);
4378ccd4a63SDavid du Colombier 	p = strchr(p, '!');
4388ccd4a63SDavid du Colombier 	if(p) {
4398ccd4a63SDavid du Colombier 		if(strcmp(p, "!r") == 0)
4408ccd4a63SDavid du Colombier 			c->restricted = 1;
4418ccd4a63SDavid du Colombier 	}
4428ccd4a63SDavid du Colombier 	return 0;
4438ccd4a63SDavid du Colombier }
4448ccd4a63SDavid du Colombier 
4458ccd4a63SDavid du Colombier long
ipwrite(Chan * ch,void * a,long n,vlong offset)4468ccd4a63SDavid du Colombier ipwrite(Chan *ch, void *a, long n, vlong offset)
4478ccd4a63SDavid du Colombier {
4488ccd4a63SDavid du Colombier 	Conv *c;
4498ccd4a63SDavid du Colombier 	Proto *x;
4508ccd4a63SDavid du Colombier 	int r, nf;
4518ccd4a63SDavid du Colombier 	char *p, *fields[3], buf[128];
4528ccd4a63SDavid du Colombier 
4538ccd4a63SDavid du Colombier 	switch(TYPE(ch->qid)) {
4548ccd4a63SDavid du Colombier 	default:
4558ccd4a63SDavid du Colombier 		error(Eperm);
4568ccd4a63SDavid du Colombier 	case Qcs:
4578ccd4a63SDavid du Colombier 		return cswrite(ch, a, n, offset);
4588ccd4a63SDavid du Colombier 	case Qctl:
4598ccd4a63SDavid du Colombier 		x = &proto[PROTO(ch->qid)];
4608ccd4a63SDavid du Colombier 		c = x->conv[CONV(ch->qid)];
4618ccd4a63SDavid du Colombier 		if(n > sizeof(buf)-1)
4628ccd4a63SDavid du Colombier 			n = sizeof(buf)-1;
4638ccd4a63SDavid du Colombier 		memmove(buf, a, n);
4648ccd4a63SDavid du Colombier 		buf[n] = '\0';
4658ccd4a63SDavid du Colombier 
4668ccd4a63SDavid du Colombier 		nf = tokenize(buf, fields, 3);
4678ccd4a63SDavid du Colombier 		if(strcmp(fields[0], "connect") == 0){
4688ccd4a63SDavid du Colombier 			switch(nf) {
4698ccd4a63SDavid du Colombier 			default:
4708ccd4a63SDavid du Colombier 				error("bad args to connect");
4718ccd4a63SDavid du Colombier 			case 2:
4728ccd4a63SDavid du Colombier 				p = setraddrport(c, fields[1]);
4738ccd4a63SDavid du Colombier 				if(p != 0)
4748ccd4a63SDavid du Colombier 					error(p);
4758ccd4a63SDavid du Colombier 				break;
4768ccd4a63SDavid du Colombier 			case 3:
4778ccd4a63SDavid du Colombier 				p = setraddrport(c, fields[1]);
4788ccd4a63SDavid du Colombier 				if(p != 0)
4798ccd4a63SDavid du Colombier 					error(p);
4808ccd4a63SDavid du Colombier 				c->lport = atoi(fields[2]);
4818ccd4a63SDavid du Colombier 				setlport(c);
4828ccd4a63SDavid du Colombier 				break;
4838ccd4a63SDavid du Colombier 			}
484*58da3067SDavid du Colombier 			if(c->sfd == -1)
485*58da3067SDavid du Colombier 				c->sfd = so_socket(c->p->stype, c->raddr);
4868ccd4a63SDavid du Colombier 			so_connect(c->sfd, c->raddr, c->rport);
4878ccd4a63SDavid du Colombier 			setladdr(c);
4888ccd4a63SDavid du Colombier 			c->state = "Established";
4898ccd4a63SDavid du Colombier 			return n;
4908ccd4a63SDavid du Colombier 		}
4918ccd4a63SDavid du Colombier 		if(strcmp(fields[0], "announce") == 0) {
4928ccd4a63SDavid du Colombier 			switch(nf){
4938ccd4a63SDavid du Colombier 			default:
4948ccd4a63SDavid du Colombier 				error("bad args to announce");
4958ccd4a63SDavid du Colombier 			case 2:
4968ccd4a63SDavid du Colombier 				setladdrport(c, fields[1]);
4978ccd4a63SDavid du Colombier 				break;
4988ccd4a63SDavid du Colombier 			}
4998ccd4a63SDavid du Colombier 			so_listen(c->sfd);
5008ccd4a63SDavid du Colombier 			c->state = "Announced";
5018ccd4a63SDavid du Colombier 			return n;
5028ccd4a63SDavid du Colombier 		}
5038ccd4a63SDavid du Colombier 		if(strcmp(fields[0], "bind") == 0){
5048ccd4a63SDavid du Colombier 			switch(nf){
5058ccd4a63SDavid du Colombier 			default:
5068ccd4a63SDavid du Colombier 				error("bad args to bind");
5078ccd4a63SDavid du Colombier 			case 2:
5088ccd4a63SDavid du Colombier 				c->lport = atoi(fields[1]);
5098ccd4a63SDavid du Colombier 				break;
5108ccd4a63SDavid du Colombier 			}
5118ccd4a63SDavid du Colombier 			setlport(c);
5128ccd4a63SDavid du Colombier 			return n;
5138ccd4a63SDavid du Colombier 		}
5148ccd4a63SDavid du Colombier 		error("bad control message");
5158ccd4a63SDavid du Colombier 	case Qdata:
5168ccd4a63SDavid du Colombier 		x = &proto[PROTO(ch->qid)];
5178ccd4a63SDavid du Colombier 		c = x->conv[CONV(ch->qid)];
5188ccd4a63SDavid du Colombier 		r = so_send(c->sfd, a, n, 0);
5198ccd4a63SDavid du Colombier 		if(r < 0){
5208ccd4a63SDavid du Colombier 			oserrstr();
5218ccd4a63SDavid du Colombier 			nexterror();
5228ccd4a63SDavid du Colombier 		}
5238ccd4a63SDavid du Colombier 		return r;
5248ccd4a63SDavid du Colombier 	}
5258ccd4a63SDavid du Colombier 	return n;
5268ccd4a63SDavid du Colombier }
5278ccd4a63SDavid du Colombier 
5288ccd4a63SDavid du Colombier static Conv*
protoclone(Proto * p,char * user,int nfd)5298ccd4a63SDavid du Colombier protoclone(Proto *p, char *user, int nfd)
5308ccd4a63SDavid du Colombier {
5318ccd4a63SDavid du Colombier 	Conv *c, **pp, **ep;
5328ccd4a63SDavid du Colombier 
5338ccd4a63SDavid du Colombier 	c = 0;
5348ccd4a63SDavid du Colombier 	lock(&p->l);
5358ccd4a63SDavid du Colombier 	if(waserror()) {
5368ccd4a63SDavid du Colombier 		unlock(&p->l);
5378ccd4a63SDavid du Colombier 		nexterror();
5388ccd4a63SDavid du Colombier 	}
5398ccd4a63SDavid du Colombier 	ep = &p->conv[p->maxconv];
5408ccd4a63SDavid du Colombier 	for(pp = p->conv; pp < ep; pp++) {
5418ccd4a63SDavid du Colombier 		c = *pp;
5428ccd4a63SDavid du Colombier 		if(c == 0) {
5438ccd4a63SDavid du Colombier 			c = mallocz(sizeof(Conv), 1);
5448ccd4a63SDavid du Colombier 			if(c == 0)
5458ccd4a63SDavid du Colombier 				error(Enomem);
5468ccd4a63SDavid du Colombier 			lock(&c->r.lk);
5478ccd4a63SDavid du Colombier 			c->r.ref = 1;
5488ccd4a63SDavid du Colombier 			c->p = p;
5498ccd4a63SDavid du Colombier 			c->x = pp - p->conv;
5508ccd4a63SDavid du Colombier 			p->nc++;
5518ccd4a63SDavid du Colombier 			*pp = c;
5528ccd4a63SDavid du Colombier 			break;
5538ccd4a63SDavid du Colombier 		}
5548ccd4a63SDavid du Colombier 		lock(&c->r.lk);
5558ccd4a63SDavid du Colombier 		if(c->r.ref == 0) {
5568ccd4a63SDavid du Colombier 			c->r.ref++;
5578ccd4a63SDavid du Colombier 			break;
5588ccd4a63SDavid du Colombier 		}
5598ccd4a63SDavid du Colombier 		unlock(&c->r.lk);
5608ccd4a63SDavid du Colombier 	}
5618ccd4a63SDavid du Colombier 	if(pp >= ep) {
5628ccd4a63SDavid du Colombier 		unlock(&p->l);
5638ccd4a63SDavid du Colombier 		poperror();
5648ccd4a63SDavid du Colombier 		return 0;
5658ccd4a63SDavid du Colombier 	}
5668ccd4a63SDavid du Colombier 
5678ccd4a63SDavid du Colombier 	strcpy(c->owner, user);
5688ccd4a63SDavid du Colombier 	c->perm = 0660;
5698ccd4a63SDavid du Colombier 	c->state = "Closed";
5708ccd4a63SDavid du Colombier 	c->restricted = 0;
571*58da3067SDavid du Colombier 	ipzero(c->laddr);
572*58da3067SDavid du Colombier 	ipzero(c->raddr);
5738ccd4a63SDavid du Colombier 	c->lport = 0;
5748ccd4a63SDavid du Colombier 	c->rport = 0;
5758ccd4a63SDavid du Colombier 	c->sfd = nfd;
5768ccd4a63SDavid du Colombier 
5778ccd4a63SDavid du Colombier 	unlock(&c->r.lk);
5788ccd4a63SDavid du Colombier 	unlock(&p->l);
5798ccd4a63SDavid du Colombier 	poperror();
5808ccd4a63SDavid du Colombier 	return c;
5818ccd4a63SDavid du Colombier }
5828ccd4a63SDavid du Colombier 
5838ccd4a63SDavid du Colombier void
csclose(Chan * c)5848ccd4a63SDavid du Colombier csclose(Chan *c)
5858ccd4a63SDavid du Colombier {
5868ccd4a63SDavid du Colombier 	free(c->aux);
5878ccd4a63SDavid du Colombier }
5888ccd4a63SDavid du Colombier 
5898ccd4a63SDavid du Colombier long
csread(Chan * c,void * a,long n,vlong offset)5908ccd4a63SDavid du Colombier csread(Chan *c, void *a, long n, vlong offset)
5918ccd4a63SDavid du Colombier {
5928ccd4a63SDavid du Colombier 	if(c->aux == nil)
5938ccd4a63SDavid du Colombier 		return 0;
5948ccd4a63SDavid du Colombier 	return readstr(offset, a, n, c->aux);
5958ccd4a63SDavid du Colombier }
5968ccd4a63SDavid du Colombier 
5978ccd4a63SDavid du Colombier static struct
5988ccd4a63SDavid du Colombier {
5998ccd4a63SDavid du Colombier 	char *name;
6008ccd4a63SDavid du Colombier 	uint num;
6018ccd4a63SDavid du Colombier } tab[] = {
6028ccd4a63SDavid du Colombier 	"cs", 1,
6038ccd4a63SDavid du Colombier 	"echo", 7,
6048ccd4a63SDavid du Colombier 	"discard", 9,
6058ccd4a63SDavid du Colombier 	"systat", 11,
6068ccd4a63SDavid du Colombier 	"daytime", 13,
6078ccd4a63SDavid du Colombier 	"netstat", 15,
6088ccd4a63SDavid du Colombier 	"chargen", 19,
6098ccd4a63SDavid du Colombier 	"ftp-data", 20,
6108ccd4a63SDavid du Colombier 	"ftp", 21,
6118ccd4a63SDavid du Colombier 	"ssh", 22,
6128ccd4a63SDavid du Colombier 	"telnet", 23,
6138ccd4a63SDavid du Colombier 	"smtp", 25,
6148ccd4a63SDavid du Colombier 	"time", 37,
6158ccd4a63SDavid du Colombier 	"whois", 43,
6168ccd4a63SDavid du Colombier 	"dns", 53,
6178ccd4a63SDavid du Colombier 	"domain", 53,
6188ccd4a63SDavid du Colombier 	"uucp", 64,
6198ccd4a63SDavid du Colombier 	"gopher", 70,
6208ccd4a63SDavid du Colombier 	"rje", 77,
6218ccd4a63SDavid du Colombier 	"finger", 79,
6228ccd4a63SDavid du Colombier 	"http", 80,
6238ccd4a63SDavid du Colombier 	"link", 87,
6248ccd4a63SDavid du Colombier 	"supdup", 95,
6258ccd4a63SDavid du Colombier 	"hostnames", 101,
6268ccd4a63SDavid du Colombier 	"iso-tsap", 102,
6278ccd4a63SDavid du Colombier 	"x400", 103,
6288ccd4a63SDavid du Colombier 	"x400-snd", 104,
6298ccd4a63SDavid du Colombier 	"csnet-ns", 105,
6308ccd4a63SDavid du Colombier 	"pop-2", 109,
6318ccd4a63SDavid du Colombier 	"pop3", 110,
6328ccd4a63SDavid du Colombier 	"portmap", 111,
6338ccd4a63SDavid du Colombier 	"uucp-path", 117,
6348ccd4a63SDavid du Colombier 	"nntp", 119,
6358ccd4a63SDavid du Colombier 	"netbios", 139,
6368ccd4a63SDavid du Colombier 	"imap4", 143,
6378ccd4a63SDavid du Colombier 	"NeWS", 144,
6388ccd4a63SDavid du Colombier 	"print-srv", 170,
6398ccd4a63SDavid du Colombier 	"z39.50", 210,
6408ccd4a63SDavid du Colombier 	"fsb", 400,
6418ccd4a63SDavid du Colombier 	"sysmon", 401,
6428ccd4a63SDavid du Colombier 	"proxy", 402,
6438ccd4a63SDavid du Colombier 	"proxyd", 404,
6448ccd4a63SDavid du Colombier 	"https", 443,
6458ccd4a63SDavid du Colombier 	"cifs", 445,
6468ccd4a63SDavid du Colombier 	"ssmtp", 465,
6478ccd4a63SDavid du Colombier 	"rexec", 512,
6488ccd4a63SDavid du Colombier 	"login", 513,
6498ccd4a63SDavid du Colombier 	"shell", 514,
6508ccd4a63SDavid du Colombier 	"printer", 515,
6518ccd4a63SDavid du Colombier 	"courier", 530,
6528ccd4a63SDavid du Colombier 	"cscan", 531,
6538ccd4a63SDavid du Colombier 	"uucp", 540,
6548ccd4a63SDavid du Colombier 	"snntp", 563,
6558ccd4a63SDavid du Colombier 	"9fs", 564,
6568ccd4a63SDavid du Colombier 	"whoami", 565,
6578ccd4a63SDavid du Colombier 	"guard", 566,
6588ccd4a63SDavid du Colombier 	"ticket", 567,
6598ccd4a63SDavid du Colombier 	"dlsftp", 666,
6608ccd4a63SDavid du Colombier 	"fmclient", 729,
6618ccd4a63SDavid du Colombier 	"imaps", 993,
6628ccd4a63SDavid du Colombier 	"pop3s", 995,
6638ccd4a63SDavid du Colombier 	"ingreslock", 1524,
6648ccd4a63SDavid du Colombier 	"pptp", 1723,
6658ccd4a63SDavid du Colombier 	"nfs", 2049,
6668ccd4a63SDavid du Colombier 	"webster", 2627,
6678ccd4a63SDavid du Colombier 	"weather", 3000,
6688ccd4a63SDavid du Colombier 	"secstore", 5356,
6698ccd4a63SDavid du Colombier 	"Xdisplay", 6000,
6708ccd4a63SDavid du Colombier 	"styx", 6666,
6718ccd4a63SDavid du Colombier 	"mpeg", 6667,
6728ccd4a63SDavid du Colombier 	"rstyx", 6668,
6738ccd4a63SDavid du Colombier 	"infdb", 6669,
6748ccd4a63SDavid du Colombier 	"infsigner", 6671,
6758ccd4a63SDavid du Colombier 	"infcsigner", 6672,
6768ccd4a63SDavid du Colombier 	"inflogin", 6673,
6778ccd4a63SDavid du Colombier 	"bandt", 7330,
6788ccd4a63SDavid du Colombier 	"face", 32000,
6798ccd4a63SDavid du Colombier 	"dhashgate", 11978,
6808ccd4a63SDavid du Colombier 	"exportfs", 17007,
6818ccd4a63SDavid du Colombier 	"rexexec", 17009,
6828ccd4a63SDavid du Colombier 	"ncpu", 17010,
6838ccd4a63SDavid du Colombier 	"cpu", 17013,
6848ccd4a63SDavid du Colombier 	"glenglenda1", 17020,
6858ccd4a63SDavid du Colombier 	"glenglenda2", 17021,
6868ccd4a63SDavid du Colombier 	"glenglenda3", 17022,
6878ccd4a63SDavid du Colombier 	"glenglenda4", 17023,
6888ccd4a63SDavid du Colombier 	"glenglenda5", 17024,
6898ccd4a63SDavid du Colombier 	"glenglenda6", 17025,
6908ccd4a63SDavid du Colombier 	"glenglenda7", 17026,
6918ccd4a63SDavid du Colombier 	"glenglenda8", 17027,
6928ccd4a63SDavid du Colombier 	"glenglenda9", 17028,
6938ccd4a63SDavid du Colombier 	"glenglenda10", 17029,
6948ccd4a63SDavid du Colombier 	"flyboy", 17032,
6958ccd4a63SDavid du Colombier 	"dlsftp", 17033,
6968ccd4a63SDavid du Colombier 	"venti", 17034,
6978ccd4a63SDavid du Colombier 	"wiki", 17035,
6988ccd4a63SDavid du Colombier 	"vica", 17036,
6998ccd4a63SDavid du Colombier 	0
7008ccd4a63SDavid du Colombier };
7018ccd4a63SDavid du Colombier 
7028ccd4a63SDavid du Colombier static int
lookupport(char * s)7038ccd4a63SDavid du Colombier lookupport(char *s)
7048ccd4a63SDavid du Colombier {
7058ccd4a63SDavid du Colombier 	int i;
7068ccd4a63SDavid du Colombier 	char buf[10], *p;
7078ccd4a63SDavid du Colombier 
7088ccd4a63SDavid du Colombier 	i = strtol(s, &p, 0);
7098ccd4a63SDavid du Colombier 	if(*s && *p == 0)
7108ccd4a63SDavid du Colombier 		return i;
7118ccd4a63SDavid du Colombier 
7128ccd4a63SDavid du Colombier 	i = so_getservbyname(s, "tcp", buf);
7138ccd4a63SDavid du Colombier 	if(i != -1)
7148ccd4a63SDavid du Colombier 		return atoi(buf);
7158ccd4a63SDavid du Colombier 	for(i=0; tab[i].name; i++)
7168ccd4a63SDavid du Colombier 		if(strcmp(s, tab[i].name) == 0)
7178ccd4a63SDavid du Colombier 			return tab[i].num;
7188ccd4a63SDavid du Colombier 	return 0;
7198ccd4a63SDavid du Colombier }
7208ccd4a63SDavid du Colombier 
721*58da3067SDavid du Colombier static int
lookuphost(char * s,uchar * to)722*58da3067SDavid du Colombier lookuphost(char *s, uchar *to)
7238ccd4a63SDavid du Colombier {
724*58da3067SDavid du Colombier 	ipzero(to);
725*58da3067SDavid du Colombier 	if(parseip(to, s) != -1)
7268ccd4a63SDavid du Colombier 		return 0;
727*58da3067SDavid du Colombier 	if((s = hostlookup(s)) == nil)
728*58da3067SDavid du Colombier 		return -1;
7298ccd4a63SDavid du Colombier 	parseip(to, s);
7308ccd4a63SDavid du Colombier 	free(s);
731*58da3067SDavid du Colombier 	return 0;
7328ccd4a63SDavid du Colombier }
7338ccd4a63SDavid du Colombier 
7348ccd4a63SDavid du Colombier long
cswrite(Chan * c,void * a,long n,vlong offset)7358ccd4a63SDavid du Colombier cswrite(Chan *c, void *a, long n, vlong offset)
7368ccd4a63SDavid du Colombier {
7378ccd4a63SDavid du Colombier 	char *f[4];
7388ccd4a63SDavid du Colombier 	char *s, *ns;
739*58da3067SDavid du Colombier 	uchar ip[IPaddrlen];
7408ccd4a63SDavid du Colombier 	int nf, port;
7418ccd4a63SDavid du Colombier 
7428ccd4a63SDavid du Colombier 	s = malloc(n+1);
7438ccd4a63SDavid du Colombier 	if(s == nil)
7448ccd4a63SDavid du Colombier 		error(Enomem);
7458ccd4a63SDavid du Colombier 	if(waserror()){
7468ccd4a63SDavid du Colombier 		free(s);
7478ccd4a63SDavid du Colombier 		nexterror();
7488ccd4a63SDavid du Colombier 	}
7498ccd4a63SDavid du Colombier 	memmove(s, a, n);
7508ccd4a63SDavid du Colombier 	s[n] = 0;
7518ccd4a63SDavid du Colombier 	nf = getfields(s, f, nelem(f), 0, "!");
7528ccd4a63SDavid du Colombier 	if(nf != 3)
7538ccd4a63SDavid du Colombier 		error("can't translate");
7548ccd4a63SDavid du Colombier 
7558ccd4a63SDavid du Colombier 	port = lookupport(f[2]);
7568ccd4a63SDavid du Colombier 	if(port <= 0)
7578ccd4a63SDavid du Colombier 		error("no translation for port found");
7588ccd4a63SDavid du Colombier 
759*58da3067SDavid du Colombier 	if(lookuphost(f[1], ip) < 0)
7608ccd4a63SDavid du Colombier 		error("no translation for host found");
7618ccd4a63SDavid du Colombier 
7628ccd4a63SDavid du Colombier 	ns = smprint("/net/%s/clone %I!%d", f[0], ip, port);
7638ccd4a63SDavid du Colombier 	if(ns == nil)
7648ccd4a63SDavid du Colombier 		error(Enomem);
7658ccd4a63SDavid du Colombier 	free(c->aux);
7668ccd4a63SDavid du Colombier 	c->aux = ns;
7678ccd4a63SDavid du Colombier 	poperror();
7688ccd4a63SDavid du Colombier 	free(s);
7698ccd4a63SDavid du Colombier 	return n;
7708ccd4a63SDavid du Colombier }
7718ccd4a63SDavid du Colombier 
7728ccd4a63SDavid du Colombier Dev ipdevtab =
7738ccd4a63SDavid du Colombier {
7748ccd4a63SDavid du Colombier 	'I',
7758ccd4a63SDavid du Colombier 	"ip",
7768ccd4a63SDavid du Colombier 
7778ccd4a63SDavid du Colombier 	devreset,
7788ccd4a63SDavid du Colombier 	ipinit,
7798ccd4a63SDavid du Colombier 	devshutdown,
7808ccd4a63SDavid du Colombier 	ipattach,
7818ccd4a63SDavid du Colombier 	ipwalk,
7828ccd4a63SDavid du Colombier 	ipstat,
7838ccd4a63SDavid du Colombier 	ipopen,
7848ccd4a63SDavid du Colombier 	devcreate,
7858ccd4a63SDavid du Colombier 	ipclose,
7868ccd4a63SDavid du Colombier 	ipread,
7878ccd4a63SDavid du Colombier 	devbread,
7888ccd4a63SDavid du Colombier 	ipwrite,
7898ccd4a63SDavid du Colombier 	devbwrite,
7908ccd4a63SDavid du Colombier 	devremove,
7918ccd4a63SDavid du Colombier 	devwstat,
7928ccd4a63SDavid du Colombier };
7938ccd4a63SDavid du Colombier 
794