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