Lindent pass
[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 incoming(void *arg)
355 {
356         struct conv *conv;
357
358         conv = arg;
359         return conv->incall != NULL;
360 }
361
362 static int m2p[] = {
363         [OREAD] 4,
364         [OWRITE] 2,
365         [ORDWR] 6
366 };
367
368 static struct chan *ipopen(struct chan *c, int omode)
369 {
370         ERRSTACK(2);
371         struct conv *cv, *nc;
372         struct Proto *p;
373         int perm;
374         struct Fs *f;
375
376         perm = m2p[omode & 3];
377
378         f = ipfs[c->dev];
379
380         switch (TYPE(c->qid)) {
381                 default:
382                         break;
383                 case Qndb:
384                         if (omode & (OWRITE | OTRUNC) && !iseve())
385                                 error(Eperm);
386                         if ((omode & (OWRITE | OTRUNC)) == (OWRITE | OTRUNC))
387                                 f->ndb[0] = 0;
388                         break;
389                 case Qlog:
390                         netlogopen(f);
391                         break;
392                 case Qiprouter:
393                         iprouteropen(f);
394                         break;
395                 case Qiproute:
396                         break;
397                 case Qtopdir:
398                 case Qprotodir:
399                 case Qconvdir:
400                 case Qstatus:
401                 case Qremote:
402                 case Qlocal:
403                 case Qstats:
404                 case Qbootp:
405                 case Qipselftab:
406                         if (!IS_RDONLY(omode))
407                                 error(Eperm);
408                         break;
409                 case Qsnoop:
410                         if (!IS_RDONLY(omode))
411                                 error(Eperm);
412                         p = f->p[PROTO(c->qid)];
413                         cv = p->conv[CONV(c->qid)];
414                         if (strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())
415                                 error(Eperm);
416                         atomic_inc(&cv->snoopers);
417                         break;
418                 case Qclone:
419                         p = f->p[PROTO(c->qid)];
420                         qlock(&p->qlock);
421                         if (waserror()) {
422                                 qunlock(&p->qlock);
423                                 nexterror();
424                         }
425                         cv = Fsprotoclone(p, ATTACHER(c));
426                         qunlock(&p->qlock);
427                         poperror();
428                         if (cv == NULL) {
429                                 error(Enodev);
430                                 break;
431                         }
432                         mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
433                         break;
434                 case Qdata:
435                 case Qctl:
436                 case Qerr:
437                         p = f->p[PROTO(c->qid)];
438                         qlock(&p->qlock);
439                         cv = p->conv[CONV(c->qid)];
440                         qlock(&cv->qlock);
441                         if (waserror()) {
442                                 qunlock(&cv->qlock);
443                                 qunlock(&p->qlock);
444                                 nexterror();
445                         }
446                         if ((perm & (cv->perm >> 6)) != perm) {
447                                 if (strcmp(ATTACHER(c), cv->owner) != 0)
448                                         error(Eperm);
449                                 if ((perm & cv->perm) != perm)
450                                         error(Eperm);
451
452                         }
453                         cv->inuse++;
454                         if (cv->inuse == 1) {
455                                 kstrdup(&cv->owner, ATTACHER(c));
456                                 cv->perm = 0660;
457                         }
458                         qunlock(&cv->qlock);
459                         qunlock(&p->qlock);
460                         poperror();
461                         break;
462                 case Qlisten:
463                         cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
464                         if ((perm & (cv->perm >> 6)) != perm) {
465                                 if (strcmp(ATTACHER(c), cv->owner) != 0)
466                                         error(Eperm);
467                                 if ((perm & cv->perm) != perm)
468                                         error(Eperm);
469
470                         }
471
472                         if (cv->state != Announced)
473                                 error("not announced");
474
475                         if (waserror()) {
476                                 closeconv(cv);
477                                 nexterror();
478                         }
479                         qlock(&cv->qlock);
480                         cv->inuse++;
481                         qunlock(&cv->qlock);
482
483                         nc = NULL;
484                         while (nc == NULL) {
485                                 /* give up if we got a hangup */
486                                 if (qisclosed(cv->rq))
487                                         error("listen hungup");
488
489                                 qlock(&cv->listenq);
490                                 if (waserror()) {
491                                         qunlock(&cv->listenq);
492                                         nexterror();
493                                 }
494
495                                 /* wait for a connect */
496                                 rendez_sleep(&cv->listenr, incoming, cv);
497
498                                 qlock(&cv->qlock);
499                                 nc = cv->incall;
500                                 if (nc != NULL) {
501                                         cv->incall = nc->next;
502                                         mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
503                                         kstrdup(&cv->owner, ATTACHER(c));
504                                 }
505                                 qunlock(&cv->qlock);
506
507                                 qunlock(&cv->listenq);
508                                 poperror();
509                         }
510                         closeconv(cv);
511                         poperror();
512                         break;
513         }
514         c->mode = openmode(omode);
515         c->flag |= COPEN;
516         c->offset = 0;
517         return c;
518 }
519
520 static int ipwstat(struct chan *c, uint8_t * dp, int n)
521 {
522         ERRSTACK(2);
523         struct dir *d;
524         struct conv *cv;
525         struct Fs *f;
526         struct Proto *p;
527
528         f = ipfs[c->dev];
529         switch (TYPE(c->qid)) {
530                 default:
531                         error(Eperm);
532                         break;
533                 case Qctl:
534                 case Qdata:
535                         break;
536         }
537
538         d = kzmalloc(sizeof(*d) + n, 0);
539         if (waserror()) {
540                 kfree(d);
541                 nexterror();
542         }
543         n = convM2D(dp, n, d, (char *)&d[1]);
544         if (n == 0)
545                 error(Eshortstat);
546         p = f->p[PROTO(c->qid)];
547         cv = p->conv[CONV(c->qid)];
548         if (!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
549                 error(Eperm);
550         if (!emptystr(d->uid))
551                 kstrdup(&cv->owner, d->uid);
552         if (d->mode != ~0UL)
553                 cv->perm = d->mode & 0777;
554         poperror();
555         kfree(d);
556         return n;
557 }
558
559 /* Should be able to handle any file type chan. Feel free to extend it. */
560 static char *ipchaninfo(struct chan *ch, char *ret, size_t ret_l)
561 {
562         struct conv *conv;
563         struct Proto *proto;
564         char *p;
565         struct Fs *f;
566
567         f = ipfs[ch->dev];
568
569         switch (TYPE(ch->qid)) {
570                 default:
571                         ret = "Unknown type";
572                         break;
573                 case Qdata:
574                         proto = f->p[PROTO(ch->qid)];
575                         conv = proto->conv[CONV(ch->qid)];
576                         snprintf(ret, ret_l, "Qdata, proto %s, conv idx %d", proto->name,
577                                          conv->x);
578                         break;
579                 case Qarp:
580                         ret = "Qarp";
581                         break;
582                 case Qiproute:
583                         ret = "Qiproute";
584                         break;
585                 case Qlog:
586                         ret = "Qlog";
587                         break;
588                 case Qndb:
589                         ret = "Qndb";
590                         break;
591                 case Qctl:
592                         proto = f->p[PROTO(ch->qid)];
593                         conv = proto->conv[CONV(ch->qid)];
594                         snprintf(ret, ret_l, "Qctl, proto %s, conv idx %d", proto->name,
595                                          conv->x);
596                         break;
597         }
598         return ret;
599 }
600
601 static void closeconv(struct conv *cv)
602 {
603         struct conv *nc;
604         struct Ipmulti *mp;
605
606         qlock(&cv->qlock);
607
608         if (--cv->inuse > 0) {
609                 qunlock(&cv->qlock);
610                 return;
611         }
612
613         /* close all incoming calls since no listen will ever happen */
614         for (nc = cv->incall; nc; nc = cv->incall) {
615                 cv->incall = nc->next;
616                 closeconv(nc);
617         }
618         cv->incall = NULL;
619
620         kstrdup(&cv->owner, network);
621         cv->perm = 0660;
622
623         while ((mp = cv->multi) != NULL)
624                 ipifcremmulti(cv, mp->ma, mp->ia);
625
626         cv->r = NULL;
627         cv->rgen = 0;
628         cv->p->close(cv);
629         cv->state = Idle;
630         qunlock(&cv->qlock);
631 }
632
633 static void ipclose(struct chan *c)
634 {
635         struct Fs *f;
636
637         f = ipfs[c->dev];
638         switch (TYPE(c->qid)) {
639                 default:
640                         break;
641                 case Qlog:
642                         if (c->flag & COPEN)
643                                 netlogclose(f);
644                         break;
645                 case Qiprouter:
646                         if (c->flag & COPEN)
647                                 iprouterclose(f);
648                         break;
649                 case Qdata:
650                 case Qctl:
651                 case Qerr:
652                         if (c->flag & COPEN)
653                                 closeconv(f->p[PROTO(c->qid)]->conv[CONV(c->qid)]);
654                         break;
655                 case Qsnoop:
656                         if (c->flag & COPEN)
657                                 atomic_dec(&f->p[PROTO(c->qid)]->conv[CONV(c->qid)]->snoopers);
658                         break;
659         }
660         kfree(((struct IPaux *)c->aux)->owner);
661         kfree(c->aux);
662 }
663
664 enum {
665         Statelen = 32 * 1024,
666 };
667
668 static long ipread(struct chan *ch, void *a, long n, int64_t off)
669 {
670         struct conv *c;
671         struct Proto *x;
672         char *buf, *p;
673         long rv;
674         struct Fs *f;
675         uint32_t offset = off;
676
677         f = ipfs[ch->dev];
678
679         p = a;
680         switch (TYPE(ch->qid)) {
681                 default:
682                         error(Eperm);
683                 case Qtopdir:
684                 case Qprotodir:
685                 case Qconvdir:
686                         return devdirread(ch, a, n, 0, 0, ipgen);
687                 case Qarp:
688                         return arpread(f->arp, a, offset, n);
689                 case Qbootp:
690                         return bootpread(a, offset, n);
691                 case Qndb:
692                         return readstr(offset, a, n, f->ndb);
693                 case Qiproute:
694                         return routeread(f, a, offset, n);
695                 case Qiprouter:
696                         return iprouterread(f, a, n);
697                 case Qipselftab:
698                         return ipselftabread(f, a, offset, n);
699                 case Qlog:
700                         return netlogread(f, a, offset, n);
701                 case Qctl:
702                         snprintf(get_cur_genbuf(), GENBUF_SZ, "%lu", CONV(ch->qid));
703                         return readstr(offset, p, n, get_cur_genbuf());
704                 case Qremote:
705                         buf = kzmalloc(Statelen, 0);
706                         x = f->p[PROTO(ch->qid)];
707                         c = x->conv[CONV(ch->qid)];
708                         if (x->remote == NULL) {
709                                 snprintf(buf, Statelen, "%I!%d\n", c->raddr, c->rport);
710                         } else {
711                                 (*x->remote) (c, buf, Statelen - 2);
712                         }
713                         rv = readstr(offset, p, n, buf);
714                         kfree(buf);
715                         return rv;
716                 case Qlocal:
717                         buf = kzmalloc(Statelen, 0);
718                         x = f->p[PROTO(ch->qid)];
719                         c = x->conv[CONV(ch->qid)];
720                         if (x->local == NULL) {
721                                 snprintf(buf, Statelen, "%I!%d\n", c->laddr, c->lport);
722                         } else {
723                                 (*x->local) (c, buf, Statelen - 2);
724                         }
725                         rv = readstr(offset, p, n, buf);
726                         kfree(buf);
727                         return rv;
728                 case Qstatus:
729                         buf = kzmalloc(Statelen, 0);
730                         x = f->p[PROTO(ch->qid)];
731                         c = x->conv[CONV(ch->qid)];
732                         (*x->state) (c, buf, Statelen - 2);
733                         rv = readstr(offset, p, n, buf);
734                         kfree(buf);
735                         return rv;
736                 case Qdata:
737                         c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
738                         return qread(c->rq, a, n);
739                 case Qerr:
740                         c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
741                         return qread(c->eq, a, n);
742                 case Qsnoop:
743                         c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
744                         return qread(c->sq, a, n);
745                 case Qstats:
746                         x = f->p[PROTO(ch->qid)];
747                         if (x->stats == NULL)
748                                 error("stats not implemented");
749                         buf = kzmalloc(Statelen, 0);
750                         (*x->stats) (x, buf, Statelen);
751                         rv = readstr(offset, p, n, buf);
752                         kfree(buf);
753                         return rv;
754         }
755 }
756
757 static struct block *ipbread(struct chan *ch, long n, uint32_t offset)
758 {
759         struct conv *c;
760         struct Proto *x;
761         struct Fs *f;
762
763         switch (TYPE(ch->qid)) {
764                 case Qdata:
765                         f = ipfs[ch->dev];
766                         x = f->p[PROTO(ch->qid)];
767                         c = x->conv[CONV(ch->qid)];
768                         return qbread(c->rq, n);
769                 default:
770                         return devbread(ch, n, offset);
771         }
772 }
773
774 /*
775  *  set local address to be that of the ifc closest to remote address
776  */
777 static void setladdr(struct conv *c)
778 {
779         findlocalip(c->p->f, c->laddr, c->raddr);
780 }
781
782 /*
783  *  set a local port making sure the quad of raddr,rport,laddr,lport is unique
784  */
785 static char *setluniqueport(struct conv *c, int lport)
786 {
787         struct Proto *p;
788         struct conv *xp;
789         int x;
790
791         p = c->p;
792
793         qlock(&p->qlock);
794         for (x = 0; x < p->nc; x++) {
795                 xp = p->conv[x];
796                 if (xp == NULL)
797                         break;
798                 if (xp == c)
799                         continue;
800                 if ((xp->state == Connected || xp->state == Announced)
801                         && xp->lport == lport
802                         && xp->rport == c->rport
803                         && ipcmp(xp->raddr, c->raddr) == 0
804                         && ipcmp(xp->laddr, c->laddr) == 0) {
805                         qunlock(&p->qlock);
806                         return "address in use";
807                 }
808         }
809         c->lport = lport;
810         qunlock(&p->qlock);
811         return NULL;
812 }
813
814 /*
815  *  pick a local port and set it
816  */
817 static void setlport(struct conv *c)
818 {
819         struct Proto *p;
820         uint16_t *pp;
821         int x, found;
822
823         p = c->p;
824         if (c->restricted)
825                 pp = &p->nextrport;
826         else
827                 pp = &p->nextport;
828         qlock(&p->qlock);
829         for (;; (*pp)++) {
830                 /*
831                  * Fsproto initialises p->nextport to 0 and the restricted
832                  * ports (p->nextrport) to 600.
833                  * Restricted ports must lie between 600 and 1024.
834                  * For the initial condition or if the unrestricted port number
835                  * has wrapped round, select a random port between 5000 and 1<<15
836                  * to start at.
837                  */
838                 if (c->restricted) {
839                         if (*pp >= 1024)
840                                 *pp = 600;
841                 } else
842                         while (*pp < 5000)
843                                 *pp = nrand(1 << 15);
844
845                 found = 0;
846                 for (x = 0; x < p->nc; x++) {
847                         if (p->conv[x] == NULL)
848                                 break;
849                         if (p->conv[x]->lport == *pp) {
850                                 found = 1;
851                                 break;
852                         }
853                 }
854                 if (!found)
855                         break;
856         }
857         c->lport = (*pp)++;
858         qunlock(&p->qlock);
859 }
860
861 /*
862  *  set a local address and port from a string of the form
863  *      [address!]port[!r]
864  */
865 static char *setladdrport(struct conv *c, char *str, int announcing)
866 {
867         char *p;
868         char *rv;
869         uint16_t lport;
870         uint8_t addr[IPaddrlen];
871
872         rv = NULL;
873
874         /*
875          *  ignore restricted part if it exists.  it's
876          *  meaningless on local ports.
877          */
878         p = strchr(str, '!');
879         if (p != NULL) {
880                 *p++ = 0;
881                 if (strcmp(p, "r") == 0)
882                         p = NULL;
883         }
884
885         c->lport = 0;
886         if (p == NULL) {
887                 if (announcing)
888                         ipmove(c->laddr, IPnoaddr);
889                 else
890                         setladdr(c);
891                 p = str;
892         } else {
893                 if (strcmp(str, "*") == 0)
894                         ipmove(c->laddr, IPnoaddr);
895                 else {
896                         parseip(addr, str);
897                         if (ipforme(c->p->f, addr))
898                                 ipmove(c->laddr, addr);
899                         else
900                                 return "not a local IP address";
901                 }
902         }
903
904         /* one process can get all connections */
905         if (announcing && strcmp(p, "*") == 0) {
906                 if (!iseve())
907                         error(Eperm);
908                 return setluniqueport(c, 0);
909         }
910
911         lport = atoi(p);
912         if (lport <= 0)
913                 setlport(c);
914         else
915                 rv = setluniqueport(c, lport);
916         return rv;
917 }
918
919 static char *setraddrport(struct conv *c, char *str)
920 {
921         char *p;
922
923         p = strchr(str, '!');
924         if (p == NULL)
925                 return "malformed address";
926         *p++ = 0;
927         parseip(c->raddr, str);
928         c->rport = atoi(p);
929         p = strchr(p, '!');
930         if (p) {
931                 if (strstr(p, "!r") != NULL)
932                         c->restricted = 1;
933         }
934         return NULL;
935 }
936
937 /*
938  *  called by protocol connect routine to set addresses
939  */
940 char *Fsstdconnect(struct conv *c, char *argv[], int argc)
941 {
942         char *p;
943
944         switch (argc) {
945                 default:
946                         return "bad args to connect";
947                 case 2:
948                         p = setraddrport(c, argv[1]);
949                         if (p != NULL)
950                                 return p;
951                         setladdr(c);
952                         setlport(c);
953                         break;
954                 case 3:
955                         p = setraddrport(c, argv[1]);
956                         if (p != NULL)
957                                 return p;
958                         p = setladdrport(c, argv[2], 0);
959                         if (p != NULL)
960                                 return p;
961         }
962
963         if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
964                  memcmp(c->laddr, v4prefix, IPv4off) == 0)
965                 || ipcmp(c->raddr, IPnoaddr) == 0)
966                 c->ipversion = V4;
967         else
968                 c->ipversion = V6;
969
970         return NULL;
971 }
972
973 /*
974  *  initiate connection and sleep till its set up
975  */
976 static int connected(void *a)
977 {
978         return ((struct conv *)a)->state == Connected;
979 }
980
981 static void connectctlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
982 {
983         ERRSTACK(1);
984         char *p;
985
986         if (c->state != 0)
987                 error(Econinuse);
988         c->state = Connecting;
989         c->cerr[0] = '\0';
990         if (x->connect == NULL)
991                 error("connect not supported");
992         p = x->connect(c, cb->f, cb->nf);
993         if (p != NULL)
994                 error(p);
995
996         qunlock(&c->qlock);
997         if (waserror()) {
998                 qlock(&c->qlock);
999                 nexterror();
1000         }
1001         rendez_sleep(&c->cr, connected, c);
1002         qlock(&c->qlock);
1003         poperror();
1004
1005         if (c->cerr[0] != '\0')
1006                 error(c->cerr);
1007 }
1008
1009 /*
1010  *  called by protocol announce routine to set addresses
1011  */
1012 char *Fsstdannounce(struct conv *c, char *argv[], int argc)
1013 {
1014         memset(c->raddr, 0, sizeof(c->raddr));
1015         c->rport = 0;
1016         switch (argc) {
1017                 default:
1018                         return "bad args to announce";
1019                 case 2:
1020                         return setladdrport(c, argv[1], 1);
1021         }
1022 }
1023
1024 /*
1025  *  initiate announcement and sleep till its set up
1026  */
1027 static int announced(void *a)
1028 {
1029         return ((struct conv *)a)->state == Announced;
1030 }
1031
1032 static void announcectlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
1033 {
1034         ERRSTACK(1);
1035         char *p;
1036
1037         if (c->state != 0)
1038                 error(Econinuse);
1039         c->state = Announcing;
1040         c->cerr[0] = '\0';
1041         if (x->announce == NULL)
1042                 error("announce not supported");
1043         p = x->announce(c, cb->f, cb->nf);
1044         if (p != NULL)
1045                 error(p);
1046
1047         qunlock(&c->qlock);
1048         if (waserror()) {
1049                 qlock(&c->qlock);
1050                 nexterror();
1051         }
1052         rendez_sleep(&c->cr, announced, c);
1053         qlock(&c->qlock);
1054         poperror();
1055
1056         if (c->cerr[0] != '\0')
1057                 error(c->cerr);
1058 }
1059
1060 /*
1061  *  called by protocol bind routine to set addresses
1062  */
1063 char *Fsstdbind(struct conv *c, char *argv[], int argc)
1064 {
1065         switch (argc) {
1066                 default:
1067                         return "bad args to bind";
1068                 case 2:
1069                         return setladdrport(c, argv[1], 0);
1070         }
1071 }
1072
1073 static void bindctlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
1074 {
1075         char *p;
1076
1077         if (x->bind == NULL)
1078                 p = Fsstdbind(c, cb->f, cb->nf);
1079         else
1080                 p = x->bind(c, cb->f, cb->nf);
1081         if (p != NULL)
1082                 error(p);
1083 }
1084
1085 static void tosctlmsg(struct conv *c, struct cmdbuf *cb)
1086 {
1087         if (cb->nf < 2)
1088                 c->tos = 0;
1089         else
1090                 c->tos = atoi(cb->f[1]);
1091 }
1092
1093 static void ttlctlmsg(struct conv *c, struct cmdbuf *cb)
1094 {
1095         if (cb->nf < 2)
1096                 c->ttl = MAXTTL;
1097         else
1098                 c->ttl = atoi(cb->f[1]);
1099 }
1100
1101 static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
1102 {
1103         ERRSTACK(1);
1104         struct conv *c;
1105         struct Proto *x;
1106         char *p;
1107         struct cmdbuf *cb;
1108         uint8_t ia[IPaddrlen], ma[IPaddrlen];
1109         struct Fs *f;
1110         char *a;
1111
1112         a = v;
1113         f = ipfs[ch->dev];
1114
1115         switch (TYPE(ch->qid)) {
1116                 default:
1117                         error(Eperm);
1118                 case Qdata:
1119                         x = f->p[PROTO(ch->qid)];
1120                         c = x->conv[CONV(ch->qid)];
1121
1122                         if (c->wq == NULL)
1123                                 error(Eperm);
1124
1125                         qwrite(c->wq, a, n);
1126                         break;
1127                 case Qarp:
1128                         return arpwrite(f, a, n);
1129                 case Qiproute:
1130                         return routewrite(f, ch, a, n);
1131                 case Qlog:
1132                         netlogctl(f, a, n);
1133                         return n;
1134                 case Qndb:
1135                         return ndbwrite(f, a, off, n);
1136                 case Qctl:
1137                         x = f->p[PROTO(ch->qid)];
1138                         c = x->conv[CONV(ch->qid)];
1139                         cb = parsecmd(a, n);
1140
1141                         qlock(&c->qlock);
1142                         if (waserror()) {
1143                                 qunlock(&c->qlock);
1144                                 kfree(cb);
1145                                 nexterror();
1146                         }
1147                         if (cb->nf < 1)
1148                                 error("short control request");
1149                         if (strcmp(cb->f[0], "connect") == 0)
1150                                 connectctlmsg(x, c, cb);
1151                         else if (strcmp(cb->f[0], "announce") == 0)
1152                                 announcectlmsg(x, c, cb);
1153                         else if (strcmp(cb->f[0], "bind") == 0)
1154                                 bindctlmsg(x, c, cb);
1155                         else if (strcmp(cb->f[0], "ttl") == 0)
1156                                 ttlctlmsg(c, cb);
1157                         else if (strcmp(cb->f[0], "tos") == 0)
1158                                 tosctlmsg(c, cb);
1159                         else if (strcmp(cb->f[0], "ignoreadvice") == 0)
1160                                 c->ignoreadvice = 1;
1161                         else if (strcmp(cb->f[0], "addmulti") == 0) {
1162                                 if (cb->nf < 2)
1163                                         error("addmulti needs interface address");
1164                                 if (cb->nf == 2) {
1165                                         if (!ipismulticast(c->raddr))
1166                                                 error("addmulti for a non multicast address");
1167                                         parseip(ia, cb->f[1]);
1168                                         ipifcaddmulti(c, c->raddr, ia);
1169                                 } else {
1170                                         parseip(ma, cb->f[2]);
1171                                         if (!ipismulticast(ma))
1172                                                 error("addmulti for a non multicast address");
1173                                         parseip(ia, cb->f[1]);
1174                                         ipifcaddmulti(c, ma, ia);
1175                                 }
1176                         } else if (strcmp(cb->f[0], "remmulti") == 0) {
1177                                 if (cb->nf < 2)
1178                                         error("remmulti needs interface address");
1179                                 if (!ipismulticast(c->raddr))
1180                                         error("remmulti for a non multicast address");
1181                                 parseip(ia, cb->f[1]);
1182                                 ipifcremmulti(c, c->raddr, ia);
1183                         } else if (x->ctl != NULL) {
1184                                 p = x->ctl(c, cb->f, cb->nf);
1185                                 if (p != NULL)
1186                                         error(p);
1187                         } else
1188                                 error("unknown control request");
1189                         qunlock(&c->qlock);
1190                         kfree(cb);
1191                         poperror();
1192         }
1193         return n;
1194 }
1195
1196 static long ipbwrite(struct chan *ch, struct block *bp, uint32_t offset)
1197 {
1198         struct conv *c;
1199         struct Proto *x;
1200         struct Fs *f;
1201         int n;
1202
1203         switch (TYPE(ch->qid)) {
1204                 case Qdata:
1205                         f = ipfs[ch->dev];
1206                         x = f->p[PROTO(ch->qid)];
1207                         c = x->conv[CONV(ch->qid)];
1208
1209                         if (c->wq == NULL)
1210                                 error(Eperm);
1211
1212                         if (bp->next)
1213                                 bp = concatblock(bp);
1214                         n = BLEN(bp);
1215                         qbwrite(c->wq, bp);
1216                         return n;
1217                 default:
1218                         return devbwrite(ch, bp, offset);
1219         }
1220 }
1221
1222 struct dev ipdevtab __devtab = {
1223         'I',
1224         "ip",
1225
1226         ipreset,
1227         ipinit,
1228         devshutdown,
1229         ipattach,
1230         ipwalk,
1231         ipstat,
1232         ipopen,
1233         devcreate,
1234         ipclose,
1235         ipread,
1236         ipbread,
1237         ipwrite,
1238         ipbwrite,
1239         devremove,
1240         ipwstat,
1241         devpower,
1242         ipchaninfo,
1243 };
1244
1245 int Fsproto(struct Fs *f, struct Proto *p)
1246 {
1247         if (f->np >= Maxproto)
1248                 return -1;
1249
1250         qlock_init(&p->qlock);
1251         p->f = f;
1252
1253         if (p->ipproto > 0) {
1254                 if (f->t2p[p->ipproto] != NULL)
1255                         return -1;
1256                 f->t2p[p->ipproto] = p;
1257         }
1258
1259         p->qid.type = QTDIR;
1260         p->qid.path = QID(f->np, 0, Qprotodir);
1261         p->conv = kzmalloc(sizeof(struct conv *) * (p->nc + 1), 0);
1262         if (p->conv == NULL)
1263                 panic("Fsproto");
1264
1265         p->x = f->np;
1266         p->nextport = 0;
1267         p->nextrport = 600;
1268         f->p[f->np++] = p;
1269
1270         return 0;
1271 }
1272
1273 /*
1274  *  return true if this protocol is
1275  *  built in
1276  */
1277 int Fsbuiltinproto(struct Fs *f, uint8_t proto)
1278 {
1279         return f->t2p[proto] != NULL;
1280 }
1281
1282 /*
1283  *  called with protocol locked
1284  */
1285 struct conv *Fsprotoclone(struct Proto *p, char *user)
1286 {
1287         struct conv *c, **pp, **ep;
1288
1289 retry:
1290         c = NULL;
1291         ep = &p->conv[p->nc];
1292         for (pp = p->conv; pp < ep; pp++) {
1293                 c = *pp;
1294                 if (c == NULL) {
1295                         c = kzmalloc(sizeof(struct conv), 0);
1296                         if (c == NULL)
1297                                 error(Enomem);
1298                         qlock_init(&c->qlock);
1299                         qlock_init(&c->listenq);
1300                         rendez_init(&c->cr);
1301                         rendez_init(&c->listenr);
1302                         qlock(&c->qlock);
1303                         c->p = p;
1304                         c->x = pp - p->conv;
1305                         if (p->ptclsize != 0) {
1306                                 c->ptcl = kzmalloc(p->ptclsize, 0);
1307                                 if (c->ptcl == NULL) {
1308                                         kfree(c);
1309                                         error(Enomem);
1310                                 }
1311                         }
1312                         *pp = c;
1313                         p->ac++;
1314                         c->eq = qopen(1024, Qmsg, 0, 0);
1315                         (*p->create) (c);
1316                         break;
1317                 }
1318                 if (canqlock(&c->qlock)) {
1319                         /*
1320                          *  make sure both processes and protocol
1321                          *  are done with this Conv
1322                          */
1323                         if (c->inuse == 0 && (p->inuse == NULL || (*p->inuse) (c) == 0))
1324                                 break;
1325
1326                         qunlock(&c->qlock);
1327                 }
1328         }
1329         if (pp >= ep) {
1330                 if (p->gc != NULL && (*p->gc) (p))
1331                         goto retry;
1332                 return NULL;
1333         }
1334
1335         c->inuse = 1;
1336         kstrdup(&c->owner, user);
1337         c->perm = 0660;
1338         c->state = Idle;
1339         ipmove(c->laddr, IPnoaddr);
1340         ipmove(c->raddr, IPnoaddr);
1341         c->r = NULL;
1342         c->rgen = 0;
1343         c->lport = 0;
1344         c->rport = 0;
1345         c->restricted = 0;
1346         c->ttl = MAXTTL;
1347         c->tos = DFLTTOS;
1348         qreopen(c->rq);
1349         qreopen(c->wq);
1350         qreopen(c->eq);
1351
1352         qunlock(&c->qlock);
1353         return c;
1354 }
1355
1356 int Fsconnected(struct conv *c, char *msg)
1357 {
1358         if (msg != NULL && *msg != '\0')
1359                 strncpy(c->cerr, msg, sizeof(c->cerr));
1360
1361         switch (c->state) {
1362
1363                 case Announcing:
1364                         c->state = Announced;
1365                         break;
1366
1367                 case Connecting:
1368                         c->state = Connected;
1369                         break;
1370         }
1371
1372         rendez_wakeup(&c->cr);
1373         return 0;
1374 }
1375
1376 struct Proto *Fsrcvpcol(struct Fs *f, uint8_t proto)
1377 {
1378         if (f->ipmux)
1379                 return f->ipmux;
1380         else
1381                 return f->t2p[proto];
1382 }
1383
1384 struct Proto *Fsrcvpcolx(struct Fs *f, uint8_t proto)
1385 {
1386         return f->t2p[proto];
1387 }
1388
1389 /*
1390  *  called with protocol locked
1391  */
1392 struct conv *Fsnewcall(struct conv *c, uint8_t * raddr, uint16_t rport,
1393                                            uint8_t * laddr, uint16_t lport, uint8_t version)
1394 {
1395         struct conv *nc;
1396         struct conv **l;
1397         int i;
1398
1399         qlock(&c->qlock);
1400         i = 0;
1401         for (l = &c->incall; *l; l = &(*l)->next)
1402                 i++;
1403         if (i >= Maxincall) {
1404                 qunlock(&c->qlock);
1405                 return NULL;
1406         }
1407
1408         /* find a free conversation */
1409         nc = Fsprotoclone(c->p, network);
1410         if (nc == NULL) {
1411                 qunlock(&c->qlock);
1412                 return NULL;
1413         }
1414         ipmove(nc->raddr, raddr);
1415         nc->rport = rport;
1416         ipmove(nc->laddr, laddr);
1417         nc->lport = lport;
1418         nc->next = NULL;
1419         *l = nc;
1420         nc->state = Connected;
1421         nc->ipversion = version;
1422
1423         qunlock(&c->qlock);
1424
1425         rendez_wakeup(&c->listenr);
1426
1427         return nc;
1428 }
1429
1430 static long ndbwrite(struct Fs *f, char *a, uint32_t off, int n)
1431 {
1432         if (off > strlen(f->ndb))
1433                 error(Eio);
1434         if (off + n >= sizeof(f->ndb) - 1)
1435                 error(Eio);
1436         memmove(f->ndb + off, a, n);
1437         f->ndb[off + n] = 0;
1438         f->ndbvers++;
1439         f->ndbmtime = seconds();
1440         return n;
1441 }
1442
1443 uint32_t scalednconv(void)
1444 {
1445         //if(conf.npage*BY2PG >= 128*MB)
1446         return Nchans * 4;
1447         //  return Nchans;
1448 }