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