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