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