changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/ip/devip.c

changeset 7229: a0387db0dcba
parent: fbb7d37047fc
child: 4b1fae89dd27
author: cinap_lenrek@felloff.net
date: Sat, 11 May 2019 14:01:26 +0200
permissions: -rw-r--r--
description: devip: remove unused c->car qlock, avoid potential deadlock in ipifcregisterproxy()

remove references to the unused Conv.car qlock.

ipifcregisterproxy() is called with the proxy
ifc wlock'd, which means we cannot acquire the
rwlock of the interfaces that will proxy for us
because it is allowed to rlock() multiple ifc's
in any order. to get arround this, we use canrlock()
and skip the interface when we cannot acquire the
lock.

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