xref: /plan9/sys/src/cmd/cwfs/net.c (revision 01a344a29f2ff35133953eaef092a50fc8c3163b)
1*01a344a2SDavid du Colombier /* network i/o */
2*01a344a2SDavid du Colombier 
3*01a344a2SDavid du Colombier #include "all.h"
4*01a344a2SDavid du Colombier #include "io.h"
5*01a344a2SDavid du Colombier #include <fcall.h>		/* 9p2000 */
6*01a344a2SDavid du Colombier #include <thread.h>
7*01a344a2SDavid du Colombier 
8*01a344a2SDavid du Colombier enum {
9*01a344a2SDavid du Colombier 	Maxfdata	= 8192,
10*01a344a2SDavid du Colombier 	Nqueue		= 200,		/* queue size (tunable) */
11*01a344a2SDavid du Colombier 
12*01a344a2SDavid du Colombier 	Netclosed	= 0,		/* Connection state */
13*01a344a2SDavid du Colombier 	Netopen,
14*01a344a2SDavid du Colombier };
15*01a344a2SDavid du Colombier 
16*01a344a2SDavid du Colombier /*
17*01a344a2SDavid du Colombier  * the kernel file server read packets directly from
18*01a344a2SDavid du Colombier  * its ethernet(s) and did all the protocol processing.
19*01a344a2SDavid du Colombier  * if the incoming packets were 9p (over il/ip), they
20*01a344a2SDavid du Colombier  * were queued for the server processes to operate upon.
21*01a344a2SDavid du Colombier  *
22*01a344a2SDavid du Colombier  * in user mode, we have one process per incoming connection
23*01a344a2SDavid du Colombier  * instead, and those processes get just the data, minus
24*01a344a2SDavid du Colombier  * tcp and ip headers, so they just see a stream of 9p messages,
25*01a344a2SDavid du Colombier  * which they then queue for the server processes.
26*01a344a2SDavid du Colombier  *
27*01a344a2SDavid du Colombier  * there used to be more queueing (in the kernel), with separate
28*01a344a2SDavid du Colombier  * processes for ethernet input, il input, 9p processing, il output
29*01a344a2SDavid du Colombier  * and ethernet output, and queues connecting them.  we now let
30*01a344a2SDavid du Colombier  * the kernel's network queues, protocol stacks and processes do
31*01a344a2SDavid du Colombier  * much of this work.
32*01a344a2SDavid du Colombier  *
33*01a344a2SDavid du Colombier  * partly as a result of this, we can now process 9p messages
34*01a344a2SDavid du Colombier  * transported via tcp, exploit multiple x86 processors, and
35*01a344a2SDavid du Colombier  * were able to shed 70% of the file server's source, by line count.
36*01a344a2SDavid du Colombier  *
37*01a344a2SDavid du Colombier  * the upshot is that Ether (now Network) is no longer a perfect fit for
38*01a344a2SDavid du Colombier  * the way network i/o is done now.  the notion of `connection'
39*01a344a2SDavid du Colombier  * is being introduced to complement it.
40*01a344a2SDavid du Colombier  */
41*01a344a2SDavid du Colombier 
42*01a344a2SDavid du Colombier typedef struct Network Network;
43*01a344a2SDavid du Colombier typedef struct Netconn Netconn;
44*01a344a2SDavid du Colombier typedef struct Conn9p Conn9p;
45*01a344a2SDavid du Colombier 
46*01a344a2SDavid du Colombier /* a network, not necessarily an ethernet */
47*01a344a2SDavid du Colombier struct Network {
48*01a344a2SDavid du Colombier 	int	ctlrno;
49*01a344a2SDavid du Colombier 	char	iname[NAMELEN];
50*01a344a2SDavid du Colombier 	char	oname[NAMELEN];
51*01a344a2SDavid du Colombier 
52*01a344a2SDavid du Colombier 	char	*dialstr;
53*01a344a2SDavid du Colombier 	char	anndir[40];
54*01a344a2SDavid du Colombier 	char	lisdir[40];
55*01a344a2SDavid du Colombier 	int	annfd;			/* fd from announce */
56*01a344a2SDavid du Colombier };
57*01a344a2SDavid du Colombier 
58*01a344a2SDavid du Colombier /* an open tcp (or other transport) connection */
59*01a344a2SDavid du Colombier struct Netconn {
60*01a344a2SDavid du Colombier 	Queue*	reply;		/* network output */
61*01a344a2SDavid du Colombier 	char*	raddr;		/* remote caller's addr */
62*01a344a2SDavid du Colombier 	Chan*	chan;		/* list of tcp channels */
63*01a344a2SDavid du Colombier 
64*01a344a2SDavid du Colombier 	int	alloc;		/* flag: allocated */
65*01a344a2SDavid du Colombier 
66*01a344a2SDavid du Colombier 	int	state;
67*01a344a2SDavid du Colombier 	Conn9p*	conn9p;		/* not reference-counted */
68*01a344a2SDavid du Colombier 
69*01a344a2SDavid du Colombier 	Lock;
70*01a344a2SDavid du Colombier };
71*01a344a2SDavid du Colombier 
72*01a344a2SDavid du Colombier /*
73*01a344a2SDavid du Colombier  * incoming 9P network connection from a given machine.
74*01a344a2SDavid du Colombier  * typically will multiplex 9P sessions for multiple users.
75*01a344a2SDavid du Colombier  */
76*01a344a2SDavid du Colombier struct Conn9p {
77*01a344a2SDavid du Colombier 	QLock;
78*01a344a2SDavid du Colombier 	Ref;
79*01a344a2SDavid du Colombier 	int	fd;
80*01a344a2SDavid du Colombier 	char*	dir;
81*01a344a2SDavid du Colombier 	Netconn*netconn;		/* cross-connection */
82*01a344a2SDavid du Colombier 	char*	raddr;
83*01a344a2SDavid du Colombier };
84*01a344a2SDavid du Colombier 
85*01a344a2SDavid du Colombier static Network netif[Maxnets];
86*01a344a2SDavid du Colombier static struct {
87*01a344a2SDavid du Colombier 	Lock;
88*01a344a2SDavid du Colombier 	Chan*	chan;
89*01a344a2SDavid du Colombier } netchans;
90*01a344a2SDavid du Colombier static Queue *netoq;		/* only one network output queue is needed */
91*01a344a2SDavid du Colombier 
92*01a344a2SDavid du Colombier char *annstrs[Maxnets] = {
93*01a344a2SDavid du Colombier 	"tcp!*!9fs",
94*01a344a2SDavid du Colombier };
95*01a344a2SDavid du Colombier 
96*01a344a2SDavid du Colombier /* never returns nil */
97*01a344a2SDavid du Colombier static Chan*
getchan(Conn9p * conn9p)98*01a344a2SDavid du Colombier getchan(Conn9p *conn9p)
99*01a344a2SDavid du Colombier {
100*01a344a2SDavid du Colombier 	Netconn *netconn;
101*01a344a2SDavid du Colombier 	Chan *cp, *xcp;
102*01a344a2SDavid du Colombier 
103*01a344a2SDavid du Colombier 	lock(&netchans);
104*01a344a2SDavid du Colombier 
105*01a344a2SDavid du Colombier 	/* look for conn9p's Chan */
106*01a344a2SDavid du Colombier 	xcp = nil;
107*01a344a2SDavid du Colombier 	for(cp = netchans.chan; cp; cp = netconn->chan) {
108*01a344a2SDavid du Colombier 		netconn = cp->pdata;
109*01a344a2SDavid du Colombier 		if(!netconn->alloc)
110*01a344a2SDavid du Colombier 			xcp = cp;		/* remember free Chan */
111*01a344a2SDavid du Colombier 		else if(netconn->raddr != nil &&
112*01a344a2SDavid du Colombier 		    strcmp(conn9p->raddr, netconn->raddr) == 0) {
113*01a344a2SDavid du Colombier 			unlock(&netchans);
114*01a344a2SDavid du Colombier 			return cp;		/* found conn9p's Chan */
115*01a344a2SDavid du Colombier 		}
116*01a344a2SDavid du Colombier 	}
117*01a344a2SDavid du Colombier 
118*01a344a2SDavid du Colombier 	/* conn9p's Chan not found; if no free Chan, allocate & fill in one */
119*01a344a2SDavid du Colombier 	cp = xcp;
120*01a344a2SDavid du Colombier 	if(cp == nil) {
121*01a344a2SDavid du Colombier 		cp = fs_chaninit(Devnet, 1, sizeof(Netconn));
122*01a344a2SDavid du Colombier 		netconn = cp->pdata;
123*01a344a2SDavid du Colombier 		netconn->chan = netchans.chan;
124*01a344a2SDavid du Colombier 		netconn->state = Netopen;	/* a guess */
125*01a344a2SDavid du Colombier 		/* cross-connect netconn and conn9p */
126*01a344a2SDavid du Colombier 		netconn->conn9p = conn9p;	/* not reference-counted */
127*01a344a2SDavid du Colombier 		conn9p->netconn = netconn;
128*01a344a2SDavid du Colombier 		netchans.chan = cp;
129*01a344a2SDavid du Colombier 	}
130*01a344a2SDavid du Colombier 
131*01a344a2SDavid du Colombier 	/* fill in Chan's netconn */
132*01a344a2SDavid du Colombier 	netconn = cp->pdata;
133*01a344a2SDavid du Colombier 	netconn->raddr = strdup(conn9p->raddr);
134*01a344a2SDavid du Colombier 
135*01a344a2SDavid du Colombier 	/* fill in Chan */
136*01a344a2SDavid du Colombier 	cp->send = serveq;
137*01a344a2SDavid du Colombier 	if (cp->reply == nil)
138*01a344a2SDavid du Colombier 		cp->reply = netoq;
139*01a344a2SDavid du Colombier 	netconn->reply = netoq;
140*01a344a2SDavid du Colombier 	cp->protocol = nil;
141*01a344a2SDavid du Colombier 	cp->msize = 0;
142*01a344a2SDavid du Colombier 	cp->whotime = 0;
143*01a344a2SDavid du Colombier 	strncpy(cp->whochan, conn9p->raddr, sizeof cp->whochan);
144*01a344a2SDavid du Colombier //	cp->whoprint = tcpwhoprint;
145*01a344a2SDavid du Colombier 	netconn->alloc = 1;
146*01a344a2SDavid du Colombier 
147*01a344a2SDavid du Colombier 	unlock(&netchans);
148*01a344a2SDavid du Colombier 	return cp;
149*01a344a2SDavid du Colombier }
150*01a344a2SDavid du Colombier 
151*01a344a2SDavid du Colombier static char *
fd2name(int fd)152*01a344a2SDavid du Colombier fd2name(int fd)
153*01a344a2SDavid du Colombier {
154*01a344a2SDavid du Colombier 	char data[128];
155*01a344a2SDavid du Colombier 
156*01a344a2SDavid du Colombier 	if (fd2path(fd, data, sizeof data) < 0)
157*01a344a2SDavid du Colombier 		return strdup("/GOK");
158*01a344a2SDavid du Colombier 	return strdup(data);
159*01a344a2SDavid du Colombier }
160*01a344a2SDavid du Colombier 
161*01a344a2SDavid du Colombier static void
hangupdfd(int dfd)162*01a344a2SDavid du Colombier hangupdfd(int dfd)
163*01a344a2SDavid du Colombier {
164*01a344a2SDavid du Colombier 	int ctlfd;
165*01a344a2SDavid du Colombier 	char *end, *data;
166*01a344a2SDavid du Colombier 
167*01a344a2SDavid du Colombier 	data = fd2name(dfd);
168*01a344a2SDavid du Colombier 	close(dfd);
169*01a344a2SDavid du Colombier 
170*01a344a2SDavid du Colombier 	end = strstr(data, "/data");
171*01a344a2SDavid du Colombier 	if (end != nil)
172*01a344a2SDavid du Colombier 		strcpy(end, "/ctl");
173*01a344a2SDavid du Colombier 	ctlfd = open(data, OWRITE);
174*01a344a2SDavid du Colombier 	if (ctlfd >= 0) {
175*01a344a2SDavid du Colombier 		hangup(ctlfd);
176*01a344a2SDavid du Colombier 		close(ctlfd);
177*01a344a2SDavid du Colombier 	}
178*01a344a2SDavid du Colombier 	free(data);
179*01a344a2SDavid du Colombier }
180*01a344a2SDavid du Colombier 
181*01a344a2SDavid du Colombier void
closechan(int n)182*01a344a2SDavid du Colombier closechan(int n)
183*01a344a2SDavid du Colombier {
184*01a344a2SDavid du Colombier 	Chan *cp;
185*01a344a2SDavid du Colombier 
186*01a344a2SDavid du Colombier 	for(cp = chans; cp; cp = cp->next)
187*01a344a2SDavid du Colombier 		if(cp->whotime != 0 && cp->chan == n)
188*01a344a2SDavid du Colombier 			fileinit(cp);
189*01a344a2SDavid du Colombier }
190*01a344a2SDavid du Colombier 
191*01a344a2SDavid du Colombier void
nethangup(Chan * cp,char * msg,int dolock)192*01a344a2SDavid du Colombier nethangup(Chan *cp, char *msg, int dolock)
193*01a344a2SDavid du Colombier {
194*01a344a2SDavid du Colombier 	Netconn *netconn;
195*01a344a2SDavid du Colombier 
196*01a344a2SDavid du Colombier 	netconn = cp->pdata;
197*01a344a2SDavid du Colombier 	netconn->state = Netclosed;
198*01a344a2SDavid du Colombier 
199*01a344a2SDavid du Colombier 	if(msg != nil)
200*01a344a2SDavid du Colombier 		print("hangup! %s %s\n", msg, netconn->raddr);
201*01a344a2SDavid du Colombier 
202*01a344a2SDavid du Colombier 	fileinit(cp);
203*01a344a2SDavid du Colombier 	cp->whotime = 0;
204*01a344a2SDavid du Colombier 	strcpy(cp->whoname, "<none>");
205*01a344a2SDavid du Colombier 
206*01a344a2SDavid du Colombier 	if(dolock)
207*01a344a2SDavid du Colombier 		lock(&netchans);
208*01a344a2SDavid du Colombier 	netconn->alloc = 0;
209*01a344a2SDavid du Colombier 	free(netconn->raddr);
210*01a344a2SDavid du Colombier 	netconn->raddr = nil;
211*01a344a2SDavid du Colombier 	if(dolock)
212*01a344a2SDavid du Colombier 		unlock(&netchans);
213*01a344a2SDavid du Colombier }
214*01a344a2SDavid du Colombier 
215*01a344a2SDavid du Colombier void
chanhangup(Chan * cp,char * msg,int dolock)216*01a344a2SDavid du Colombier chanhangup(Chan *cp, char *msg, int dolock)
217*01a344a2SDavid du Colombier {
218*01a344a2SDavid du Colombier 	Netconn *netconn = cp->pdata;
219*01a344a2SDavid du Colombier 	Conn9p *conn9p = netconn->conn9p;
220*01a344a2SDavid du Colombier 
221*01a344a2SDavid du Colombier 	if (conn9p->fd > 0)
222*01a344a2SDavid du Colombier 		hangupdfd(conn9p->fd);	/* drop it */
223*01a344a2SDavid du Colombier 	nethangup(cp, msg, dolock);
224*01a344a2SDavid du Colombier }
225*01a344a2SDavid du Colombier 
226*01a344a2SDavid du Colombier /*
227*01a344a2SDavid du Colombier  * returns length of next 9p message (including the length) and
228*01a344a2SDavid du Colombier  * leaves it in the first few bytes of abuf.
229*01a344a2SDavid du Colombier  */
230*01a344a2SDavid du Colombier static long
size9pmsg(int fd,void * abuf,uint n)231*01a344a2SDavid du Colombier size9pmsg(int fd, void *abuf, uint n)
232*01a344a2SDavid du Colombier {
233*01a344a2SDavid du Colombier 	int m;
234*01a344a2SDavid du Colombier 	uchar *buf = abuf;
235*01a344a2SDavid du Colombier 
236*01a344a2SDavid du Colombier 	if (n < BIT32SZ)
237*01a344a2SDavid du Colombier 		return -1;	/* caller screwed up */
238*01a344a2SDavid du Colombier 
239*01a344a2SDavid du Colombier 	/* read count */
240*01a344a2SDavid du Colombier 	m = readn(fd, buf, BIT32SZ);
241*01a344a2SDavid du Colombier 	if(m != BIT32SZ){
242*01a344a2SDavid du Colombier 		if(m < 0)
243*01a344a2SDavid du Colombier 			return -1;
244*01a344a2SDavid du Colombier 		return 0;
245*01a344a2SDavid du Colombier 	}
246*01a344a2SDavid du Colombier 	return GBIT32(buf);
247*01a344a2SDavid du Colombier }
248*01a344a2SDavid du Colombier 
249*01a344a2SDavid du Colombier static int
readalloc9pmsg(int fd,Msgbuf ** mbp)250*01a344a2SDavid du Colombier readalloc9pmsg(int fd, Msgbuf **mbp)
251*01a344a2SDavid du Colombier {
252*01a344a2SDavid du Colombier 	int m, len;
253*01a344a2SDavid du Colombier 	uchar lenbuf[BIT32SZ];
254*01a344a2SDavid du Colombier 	Msgbuf *mb;
255*01a344a2SDavid du Colombier 
256*01a344a2SDavid du Colombier 	*mbp = nil;
257*01a344a2SDavid du Colombier 	len = size9pmsg(fd, lenbuf, BIT32SZ);
258*01a344a2SDavid du Colombier 	if (len <= 0)
259*01a344a2SDavid du Colombier 		return len;
260*01a344a2SDavid du Colombier 	if(len <= BIT32SZ || len > IOHDRSZ+Maxfdata){
261*01a344a2SDavid du Colombier 		werrstr("bad length in 9P2000 message header");
262*01a344a2SDavid du Colombier 		return -1;
263*01a344a2SDavid du Colombier 	}
264*01a344a2SDavid du Colombier 	if ((mb = mballoc(len, nil, Mbeth1)) == nil)
265*01a344a2SDavid du Colombier 		panic("readalloc9pmsg: mballoc failed");
266*01a344a2SDavid du Colombier 	*mbp = mb;
267*01a344a2SDavid du Colombier 	memmove(mb->data, lenbuf, BIT32SZ);
268*01a344a2SDavid du Colombier 	len -= BIT32SZ;
269*01a344a2SDavid du Colombier 	m = readn(fd, mb->data+BIT32SZ, len);
270*01a344a2SDavid du Colombier 	if(m < len)
271*01a344a2SDavid du Colombier 		return 0;
272*01a344a2SDavid du Colombier 	return BIT32SZ+m;
273*01a344a2SDavid du Colombier }
274*01a344a2SDavid du Colombier 
275*01a344a2SDavid du Colombier static void
connection(void * v)276*01a344a2SDavid du Colombier connection(void *v)
277*01a344a2SDavid du Colombier {
278*01a344a2SDavid du Colombier 	int n;
279*01a344a2SDavid du Colombier 	char buf[64];
280*01a344a2SDavid du Colombier 	Chan *chan9p;
281*01a344a2SDavid du Colombier 	Conn9p *conn9p = v;
282*01a344a2SDavid du Colombier 	Msgbuf *mb;
283*01a344a2SDavid du Colombier 	NetConnInfo *nci;
284*01a344a2SDavid du Colombier 
285*01a344a2SDavid du Colombier 	incref(conn9p);			/* count connections */
286*01a344a2SDavid du Colombier 	nci = getnetconninfo(conn9p->dir, conn9p->fd);
287*01a344a2SDavid du Colombier 	if (nci == nil)
288*01a344a2SDavid du Colombier 		panic("connection: getnetconninfo(%s, %d) failed",
289*01a344a2SDavid du Colombier 			conn9p->dir, conn9p->fd);
290*01a344a2SDavid du Colombier 	conn9p->raddr = nci->raddr;
291*01a344a2SDavid du Colombier 
292*01a344a2SDavid du Colombier 	chan9p = getchan(conn9p);
293*01a344a2SDavid du Colombier 	print("new connection on %s pid %d from %s\n",
294*01a344a2SDavid du Colombier 		conn9p->dir, getpid(), conn9p->raddr);
295*01a344a2SDavid du Colombier 
296*01a344a2SDavid du Colombier 	/*
297*01a344a2SDavid du Colombier 	 * reading from a pipe or a network device
298*01a344a2SDavid du Colombier 	 * will give an error after a few eof reads.
299*01a344a2SDavid du Colombier 	 * however, we cannot tell the difference
300*01a344a2SDavid du Colombier 	 * between a zero-length read and an interrupt
301*01a344a2SDavid du Colombier 	 * on the processes writing to us,
302*01a344a2SDavid du Colombier 	 * so we wait for the error.
303*01a344a2SDavid du Colombier 	 */
304*01a344a2SDavid du Colombier 	while (conn9p->fd > 0 && (n = readalloc9pmsg(conn9p->fd, &mb)) >= 0) {
305*01a344a2SDavid du Colombier 		if(n == 0)
306*01a344a2SDavid du Colombier 			continue;
307*01a344a2SDavid du Colombier 		mb->param = (uintptr)conn9p;	/* has fd for replies */
308*01a344a2SDavid du Colombier 		mb->chan = chan9p;
309*01a344a2SDavid du Colombier 
310*01a344a2SDavid du Colombier 		assert(mb->magic == Mbmagic);
311*01a344a2SDavid du Colombier 		incref(conn9p);			/* & count packets in flight */
312*01a344a2SDavid du Colombier 		fs_send(serveq, mb);		/* to 9P server processes */
313*01a344a2SDavid du Colombier 		/* mb will be freed by receiving process */
314*01a344a2SDavid du Colombier 	}
315*01a344a2SDavid du Colombier 
316*01a344a2SDavid du Colombier 	rerrstr(buf, sizeof buf);
317*01a344a2SDavid du Colombier 
318*01a344a2SDavid du Colombier 	qlock(conn9p);
319*01a344a2SDavid du Colombier 	print("connection hung up from %s\n", conn9p->dir);
320*01a344a2SDavid du Colombier 	if (conn9p->fd > 0)		/* not poisoned yet? */
321*01a344a2SDavid du Colombier 		hangupdfd(conn9p->fd);	/* poison the fd */
322*01a344a2SDavid du Colombier 
323*01a344a2SDavid du Colombier 	nethangup(chan9p, "remote hung up", 1);
324*01a344a2SDavid du Colombier 	closechan(chan9p->chan);
325*01a344a2SDavid du Colombier 
326*01a344a2SDavid du Colombier 	conn9p->fd = -1;		/* poison conn9p */
327*01a344a2SDavid du Colombier 	if (decref(conn9p) == 0) {	/* last conn.? turn the lights off */
328*01a344a2SDavid du Colombier 		free(conn9p->dir);
329*01a344a2SDavid du Colombier 		qunlock(conn9p);
330*01a344a2SDavid du Colombier 		free(conn9p);
331*01a344a2SDavid du Colombier 	} else
332*01a344a2SDavid du Colombier 		qunlock(conn9p);
333*01a344a2SDavid du Colombier 
334*01a344a2SDavid du Colombier 	freenetconninfo(nci);
335*01a344a2SDavid du Colombier 
336*01a344a2SDavid du Colombier 	if(buf[0] == '\0' || strstr(buf, "hungup") != nil)
337*01a344a2SDavid du Colombier 		exits("");
338*01a344a2SDavid du Colombier 	sysfatal("mount read, pid %d", getpid());
339*01a344a2SDavid du Colombier }
340*01a344a2SDavid du Colombier 
341*01a344a2SDavid du Colombier static void
neti(void * v)342*01a344a2SDavid du Colombier neti(void *v)
343*01a344a2SDavid du Colombier {
344*01a344a2SDavid du Colombier 	int lisfd, accfd;
345*01a344a2SDavid du Colombier 	Network *net;
346*01a344a2SDavid du Colombier 	Conn9p *conn9p;
347*01a344a2SDavid du Colombier 
348*01a344a2SDavid du Colombier 	net = v;
349*01a344a2SDavid du Colombier 	print("net%di\n", net->ctlrno);
350*01a344a2SDavid du Colombier 	for(;;) {
351*01a344a2SDavid du Colombier 		lisfd = listen(net->anndir, net->lisdir);
352*01a344a2SDavid du Colombier 		if (lisfd < 0) {
353*01a344a2SDavid du Colombier 			print("listen %s failed: %r\n", net->anndir);
354*01a344a2SDavid du Colombier 			continue;
355*01a344a2SDavid du Colombier 		}
356*01a344a2SDavid du Colombier 
357*01a344a2SDavid du Colombier 		/* got new call on lisfd */
358*01a344a2SDavid du Colombier 		accfd = accept(lisfd, net->lisdir);
359*01a344a2SDavid du Colombier 		if (accfd < 0) {
360*01a344a2SDavid du Colombier 			print("accept %d (from %s) failed: %r\n",
361*01a344a2SDavid du Colombier 				lisfd, net->lisdir);
362*01a344a2SDavid du Colombier 			continue;
363*01a344a2SDavid du Colombier 		}
364*01a344a2SDavid du Colombier 
365*01a344a2SDavid du Colombier 		/* accepted that call */
366*01a344a2SDavid du Colombier 		conn9p = malloc(sizeof *conn9p);
367*01a344a2SDavid du Colombier 		conn9p->dir = strdup(net->lisdir);
368*01a344a2SDavid du Colombier 		conn9p->fd = accfd;
369*01a344a2SDavid du Colombier 		newproc(connection, conn9p, smprint("9P read %s", conn9p->dir));
370*01a344a2SDavid du Colombier 		close(lisfd);
371*01a344a2SDavid du Colombier 	}
372*01a344a2SDavid du Colombier }
373*01a344a2SDavid du Colombier 
374*01a344a2SDavid du Colombier /* only need one of these for all network connections, thus all interfaces */
375*01a344a2SDavid du Colombier static void
neto(void *)376*01a344a2SDavid du Colombier neto(void *)
377*01a344a2SDavid du Colombier {
378*01a344a2SDavid du Colombier 	int len, datafd;
379*01a344a2SDavid du Colombier 	Msgbuf *mb;
380*01a344a2SDavid du Colombier 	Conn9p *conn9p;
381*01a344a2SDavid du Colombier 
382*01a344a2SDavid du Colombier 	print("neto\n");
383*01a344a2SDavid du Colombier 	for(;;) {
384*01a344a2SDavid du Colombier 		/* receive 9P answer from 9P server processes */
385*01a344a2SDavid du Colombier 		while((mb = fs_recv(netoq, 0)) == nil)
386*01a344a2SDavid du Colombier 			continue;
387*01a344a2SDavid du Colombier 
388*01a344a2SDavid du Colombier 		if(mb->data == nil) {
389*01a344a2SDavid du Colombier 			print("neto: pkt nil cat=%d free=%d\n",
390*01a344a2SDavid du Colombier 				mb->category, mb->flags&FREE);
391*01a344a2SDavid du Colombier 			if(!(mb->flags & FREE))
392*01a344a2SDavid du Colombier 				mbfree(mb);
393*01a344a2SDavid du Colombier 			continue;
394*01a344a2SDavid du Colombier 		}
395*01a344a2SDavid du Colombier 
396*01a344a2SDavid du Colombier 		/* send answer back over the network connection in the reply */
397*01a344a2SDavid du Colombier 		len = mb->count;
398*01a344a2SDavid du Colombier 		conn9p = (Conn9p *)mb->param;
399*01a344a2SDavid du Colombier 		assert(conn9p);
400*01a344a2SDavid du Colombier 
401*01a344a2SDavid du Colombier 		qlock(conn9p);
402*01a344a2SDavid du Colombier 		datafd = conn9p->fd;
403*01a344a2SDavid du Colombier 		assert(len >= 0);
404*01a344a2SDavid du Colombier 		/* datafd < 0 probably indicates poisoning by the read side */
405*01a344a2SDavid du Colombier 		if (datafd < 0 || write(datafd, mb->data, len) != len) {
406*01a344a2SDavid du Colombier 			print( "network write error (%r);");
407*01a344a2SDavid du Colombier 			print(" closing connection for %s\n", conn9p->dir);
408*01a344a2SDavid du Colombier 			nethangup(getchan(conn9p), "network write error", 1);
409*01a344a2SDavid du Colombier 			if (datafd > 0)
410*01a344a2SDavid du Colombier 				hangupdfd(datafd);	/* drop it */
411*01a344a2SDavid du Colombier 			conn9p->fd = -1;		/* poison conn9p */
412*01a344a2SDavid du Colombier 		}
413*01a344a2SDavid du Colombier 		mbfree(mb);
414*01a344a2SDavid du Colombier 		if (decref(conn9p) == 0)
415*01a344a2SDavid du Colombier 			panic("neto: zero ref count");
416*01a344a2SDavid du Colombier 		qunlock(conn9p);
417*01a344a2SDavid du Colombier 	}
418*01a344a2SDavid du Colombier }
419*01a344a2SDavid du Colombier 
420*01a344a2SDavid du Colombier void
netstart(void)421*01a344a2SDavid du Colombier netstart(void)
422*01a344a2SDavid du Colombier {
423*01a344a2SDavid du Colombier 	int netorun = 0;
424*01a344a2SDavid du Colombier 	Network *net;
425*01a344a2SDavid du Colombier 
426*01a344a2SDavid du Colombier 	if(netoq == nil)
427*01a344a2SDavid du Colombier 		netoq = newqueue(Nqueue, "network reply");
428*01a344a2SDavid du Colombier 	for(net = &netif[0]; net < &netif[Maxnets]; net++){
429*01a344a2SDavid du Colombier 		if(net->dialstr == nil)
430*01a344a2SDavid du Colombier 			continue;
431*01a344a2SDavid du Colombier 		sprint(net->oname, "neto");
432*01a344a2SDavid du Colombier 		if (netorun++ == 0)
433*01a344a2SDavid du Colombier 			newproc(neto, nil, net->oname);
434*01a344a2SDavid du Colombier 		sprint(net->iname, "net%di", net->ctlrno);
435*01a344a2SDavid du Colombier 		newproc(neti, net, net->iname);
436*01a344a2SDavid du Colombier 	}
437*01a344a2SDavid du Colombier }
438*01a344a2SDavid du Colombier 
439*01a344a2SDavid du Colombier void
netinit(void)440*01a344a2SDavid du Colombier netinit(void)
441*01a344a2SDavid du Colombier {
442*01a344a2SDavid du Colombier 	Network *net;
443*01a344a2SDavid du Colombier 
444*01a344a2SDavid du Colombier 	for (net = netif; net < netif + Maxnets; net++) {
445*01a344a2SDavid du Colombier 		net->dialstr = annstrs[net - netif];
446*01a344a2SDavid du Colombier 		if (net->dialstr == nil)
447*01a344a2SDavid du Colombier 			continue;
448*01a344a2SDavid du Colombier 		net->annfd = announce(net->dialstr, net->anndir);
449*01a344a2SDavid du Colombier 		/* /bin/service/tcp564 may already have grabbed the port */
450*01a344a2SDavid du Colombier 		if (net->annfd < 0)
451*01a344a2SDavid du Colombier 			sysfatal("can't announce %s: %r", net->dialstr);
452*01a344a2SDavid du Colombier 		print("netinit: announced on %s\n", net->dialstr);
453*01a344a2SDavid du Colombier 	}
454*01a344a2SDavid du Colombier }
455