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