changelog shortlog tags branches changeset files revisions annotate raw help

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

changeset 7229: a0387db0dcba
parent: fe9f017a9d36
child: 3a5ccd543798
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 
8 #include "ip.h"
9 #include "ipv6.h"
10 
11 #define DPRINT if(0)print
12 
13 enum {
14  Maxmedia = 32,
15  Nself = Maxmedia*5,
16  NHASH = 1<<6,
17  NCACHE = 256,
18  QMAX = 192*1024-1,
19 };
20 
21 Medium *media[Maxmedia] = { 0 };
22 
23 /*
24  * cache of local addresses (addresses we answer to)
25  */
26 struct Ipself
27 {
28  uchar a[IPaddrlen];
29  Ipself *hnext; /* next address in the hash table */
30  Iplink *link; /* binding twixt Ipself and Ipifc */
31  ulong expire;
32  uchar type; /* type of address */
33  int ref;
34  Ipself *next; /* free list */
35 };
36 
37 struct Ipselftab
38 {
39  QLock;
40  int inited;
41  int acceptall; /* true if an interface has the null address */
42  Ipself *hash[NHASH]; /* hash chains */
43 };
44 
45 /*
46  * Multicast addresses are chained onto a Chan so that
47  * we can remove them when the Chan is closed.
48  */
49 typedef struct Ipmcast Ipmcast;
50 struct Ipmcast
51 {
52  Ipmcast *next;
53  uchar ma[IPaddrlen]; /* multicast address */
54  uchar ia[IPaddrlen]; /* interface address */
55 };
56 
57 /* quick hash for ip addresses */
58 #define hashipa(a) ( ( ((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1] )%NHASH )
59 
60 static char tifc[] = "ifc ";
61 
62 static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
63 static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
64 static void ipifcregisteraddr(Fs*, Ipifc*, Iplifc*, uchar*);
65 static void ipifcregisterproxy(Fs*, Ipifc*, uchar*, int);
66 static char* ipifcremlifc(Ipifc*, Iplifc**);
67 
68 enum {
69  unknownv6, /* UGH */
70  unspecifiedv6,
71  linklocalv6,
72  globalv6,
73 };
74 
75 static int
76 v6addrtype(uchar *addr)
77 {
78  if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0)
79  return unknownv6;
80  else if(islinklocal(addr) || ipcmp(addr, v6loopback) == 0 ||
81  isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop)
82  return linklocalv6;
83  else
84  return globalv6;
85 }
86 
87 static int
88 comprefixlen(uchar *a, uchar *b, int n)
89 {
90  int i, c;
91 
92  for(i = 0; i < n; i++){
93  if((c = a[i] ^ b[i]) == 0)
94  continue;
95  for(i <<= 3; (c & 0x80) == 0; i++)
96  c <<= 1;
97  return i;
98  }
99  return i << 3;
100 }
101 
102 /*
103  * link in a new medium
104  */
105 void
106 addipmedium(Medium *med)
107 {
108  int i;
109 
110  for(i = 0; i < nelem(media)-1; i++)
111  if(media[i] == nil){
112  media[i] = med;
113  break;
114  }
115 }
116 
117 /*
118  * find the medium with this name
119  */
120 Medium*
121 ipfindmedium(char *name)
122 {
123  Medium **mp;
124 
125  for(mp = media; *mp != nil; mp++)
126  if(strcmp((*mp)->name, name) == 0)
127  break;
128  return *mp;
129 }
130 
131 /*
132  * attach a device (or pkt driver) to the interface.
133  * called with c locked
134  */
135 static char*
136 ipifcbind(Conv *c, char **argv, int argc)
137 {
138  Ipifc *ifc;
139  Medium *m;
140 
141  if(argc < 2)
142  return Ebadarg;
143 
144  ifc = (Ipifc*)c->ptcl;
145 
146  /* bind the device to the interface */
147  m = ipfindmedium(argv[1]);
148  if(m == nil)
149  return "unknown interface type";
150 
151  wlock(ifc);
152  if(ifc->m != nil){
153  wunlock(ifc);
154  return "interface already bound";
155  }
156  if(waserror()){
157  wunlock(ifc);
158  nexterror();
159  }
160 
161  /* do medium specific binding */
162  (*m->bind)(ifc, argc, argv);
163 
164  /* set the bound device name */
165  if(argc > 2)
166  strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
167  else
168  snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
169  ifc->dev[sizeof(ifc->dev)-1] = 0;
170 
171  /* set up parameters */
172  ifc->m = m;
173  ifc->mintu = ifc->m->mintu;
174  ifc->maxtu = ifc->m->maxtu;
175  if(ifc->m->unbindonclose == 0)
176  ifc->conv->inuse++;
177 
178  /* default router paramters */
179  ifc->rp = c->p->f->v6p->rp;
180 
181  /* any ancillary structures (like routes) no longer pertain */
182  ifc->ifcid++;
183 
184  /* reopen all the queues closed by a previous unbind */
185  qreopen(c->rq);
186  qreopen(c->eq);
187  qreopen(c->sq);
188 
189  wunlock(ifc);
190  poperror();
191 
192  return nil;
193 }
194 
195 /*
196  * detach a device from an interface, close the interface
197  */
198 static char*
199 ipifcunbind(Ipifc *ifc)
200 {
201  wlock(ifc);
202  if(ifc->m == nil){
203  wunlock(ifc);
204  return "interface not bound";
205  }
206 
207  /* disassociate logical interfaces (before zeroing ifc->arg) */
208  while(ifc->lifc != nil)
209  ipifcremlifc(ifc, &ifc->lifc);
210 
211  /* disassociate device */
212  if(ifc->m->unbind != nil){
213  if(!waserror()){
214  (*ifc->m->unbind)(ifc);
215  poperror();
216  }
217  }
218 
219  memset(ifc->dev, 0, sizeof(ifc->dev));
220  ifc->arg = nil;
221 
222  ifc->reflect = 0;
223  ifc->reassemble = 0;
224 
225  /* close queues to stop queuing of packets */
226  qclose(ifc->conv->rq);
227  qclose(ifc->conv->wq);
228  qclose(ifc->conv->sq);
229 
230  /* dissociate routes */
231  ifc->ifcid++;
232  if(ifc->m->unbindonclose == 0)
233  ifc->conv->inuse--;
234  ifc->m = nil;
235  wunlock(ifc);
236 
237  return nil;
238 }
239 
240 char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag %d"
241 " maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt %d"
242 " pktin %lud pktout %lud errin %lud errout %lud speed %d delay %d\n";
243 
244 char slineformat[] = " %-40I %-10M %-40I %-12lud %-12lud\n";
245 
246 static int
247 ipifcstate(Conv *c, char *state, int n)
248 {
249  Ipifc *ifc;
250  Iplifc *lifc;
251  int m;
252 
253  ifc = (Ipifc*)c->ptcl;
254  m = snprint(state, n, sfixedformat,
255  ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
256  ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
257  ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
258  ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
259  ifc->in, ifc->out, ifc->inerr, ifc->outerr,
260  ifc->speed, ifc->delay);
261 
262  rlock(ifc);
263  for(lifc = ifc->lifc; lifc != nil && n > m; lifc = lifc->next)
264  m += snprint(state+m, n - m, slineformat, lifc->local,
265  lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
266  if(ifc->lifc == nil)
267  m += snprint(state+m, n - m, "\n");
268  runlock(ifc);
269  return m;
270 }
271 
272 static int
273 ipifclocal(Conv *c, char *state, int n)
274 {
275  Ipifc *ifc;
276  Iplifc *lifc;
277  Iplink *link;
278  int m;
279 
280  ifc = (Ipifc*)c->ptcl;
281  rlock(ifc);
282  m = 0;
283  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
284  m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
285  for(link = lifc->link; link != nil; link = link->lifclink)
286  m += snprint(state+m, n - m, " %-40.40I", link->self->a);
287  m += snprint(state+m, n - m, "\n");
288  }
289  runlock(ifc);
290  return m;
291 }
292 
293 static int
294 ipifcinuse(Conv *c)
295 {
296  Ipifc *ifc;
297 
298  ifc = (Ipifc*)c->ptcl;
299  return ifc->m != nil;
300 }
301 
302 static void
303 ipifcsetdelay(Ipifc *ifc, int delay)
304 {
305  if(delay < 0)
306  delay = 0;
307  else if(delay > 1000)
308  delay = 1000;
309  ifc->delay = delay;
310  ifc->burst = ((vlong)delay * ifc->speed) / 8000;
311  if(ifc->burst < ifc->maxtu)
312  ifc->burst = ifc->maxtu;
313 }
314 
315 static void
316 ipifcsetspeed(Ipifc *ifc, int speed)
317 {
318  if(speed < 0)
319  speed = 0;
320  ifc->speed = speed;
321  ifc->load = 0;
322  ipifcsetdelay(ifc, ifc->delay);
323 }
324 
325 void
326 ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip)
327 {
328  if(ifc->speed){
329  ulong now = MACHP(0)->ticks;
330  int dt = TK2MS(now - ifc->ticks);
331  ifc->ticks = now;
332  ifc->load -= ((vlong)dt * ifc->speed) / 8000;
333  if(ifc->load < 0 || dt < 0 || dt > 1000)
334  ifc->load = 0;
335  else if(ifc->load > ifc->burst){
336  freeblist(bp);
337  return;
338  }
339  }
340  bp = concatblock(bp);
341  ifc->load += BLEN(bp);
342  ifc->m->bwrite(ifc, bp, version, ip);
343 }
344 
345 
346 /*
347  * called when a process writes to an interface's 'data'
348  */
349 static void
350 ipifckick(void *x)
351 {
352  Conv *c = x;
353  Block *bp;
354  Ipifc *ifc;
355 
356  bp = qget(c->wq);
357  if(bp == nil)
358  return;
359 
360  ifc = (Ipifc*)c->ptcl;
361  if(!canrlock(ifc)){
362  freeb(bp);
363  return;
364  }
365  if(waserror()){
366  runlock(ifc);
367  nexterror();
368  }
369  if(ifc->m != nil && ifc->m->pktin != nil)
370  (*ifc->m->pktin)(c->p->f, ifc, bp);
371  else
372  freeb(bp);
373  runlock(ifc);
374  poperror();
375 }
376 
377 /*
378  * called when a new ipifc structure is created
379  */
380 static void
381 ipifccreate(Conv *c)
382 {
383  Ipifc *ifc;
384 
385  c->rq = qopen(QMAX, 0, 0, 0);
386  c->wq = qopen(QMAX, Qkick, ipifckick, c);
387  c->sq = qopen(QMAX, 0, 0, 0);
388  if(c->rq == nil || c->wq == nil || c->sq == nil)
389  error(Enomem);
390  ifc = (Ipifc*)c->ptcl;
391  ifc->conv = c;
392  ifc->m = nil;
393  ifc->reflect = 0;
394  ifc->reassemble = 0;
395  ipifcsetspeed(ifc, 0);
396  ipifcsetdelay(ifc, 40);
397 }
398 
399 /*
400  * called after last close of ipifc data or ctl
401  */
402 static void
403 ipifcclose(Conv *c)
404 {
405  Ipifc *ifc;
406  Medium *m;
407 
408  ifc = (Ipifc*)c->ptcl;
409  m = ifc->m;
410  if(m != nil && m->unbindonclose)
411  ipifcunbind(ifc);
412 }
413 
414 /*
415  * change an interface's mtu
416  */
417 char*
418 ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
419 {
420  int mtu;
421 
422  if(argc < 2 || ifc->m == nil)
423  return Ebadarg;
424  mtu = strtoul(argv[1], 0, 0);
425  if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
426  return Ebadarg;
427  ifc->maxtu = mtu;
428  return nil;
429 }
430 
431 /*
432  * add an address to an interface.
433  */
434 char*
435 ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
436 {
437  uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
438  uchar bcast[IPaddrlen], net[IPaddrlen];
439  Iplifc *lifc, **l;
440  int i, type, mtu;
441  Fs *f;
442 
443  mtu = 0;
444  type = Rifc;
445  memset(ip, 0, IPaddrlen);
446  memset(mask, 0, IPaddrlen);
447  memset(rem, 0, IPaddrlen);
448  switch(argc){
449  case 6:
450  if(strcmp(argv[5], "proxy") == 0)
451  type |= Rproxy;
452  /* fall through */
453  case 5:
454  mtu = strtoul(argv[4], 0, 0);
455  /* fall through */
456  case 4:
457  if (parseipandmask(ip, mask, argv[1], argv[2]) == -1 || parseip(rem, argv[3]) == -1)
458  return Ebadip;
459  maskip(rem, mask, net);
460  break;
461  case 3:
462  if (parseipandmask(ip, mask, argv[1], argv[2]) == -1)
463  return Ebadip;
464  maskip(ip, mask, rem);
465  maskip(rem, mask, net);
466  break;
467  case 2:
468  if (parseip(ip, argv[1]) == -1)
469  return Ebadip;
470  memmove(mask, defmask(ip), IPaddrlen);
471  maskip(ip, mask, rem);
472  maskip(rem, mask, net);
473  break;
474  default:
475  return Ebadarg;
476  }
477 
478  /* check for point-to-point interface */
479  if(ipcmp(ip, v6loopback) != 0) /* skip v6 loopback, it's a special address */
480  if(ipcmp(mask, IPallbits) == 0)
481  type |= Rptpt;
482 
483  if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0){
484  type |= Rv4;
485  tentative = 0;
486  }
487 
488  wlock(ifc);
489  if(ifc->m == nil){
490  wunlock(ifc);
491  return "interface not yet bound to device";
492  }
493  f = ifc->conv->p->f;
494  if(waserror()){
495  wunlock(ifc);
496  return up->errstr;
497  }
498 
499  if(mtu > 0 && mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
500  ifc->maxtu = mtu;
501 
502  /* ignore if this is already a local address for this ifc */
503  if((lifc = iplocalonifc(ifc, ip)) != nil){
504  if(lifcp != nil) {
505  if(!lifc->onlink && lifcp->onlink){
506  lifc->onlink = 1;
507  addroute(f, lifc->remote, lifc->mask, ip, IPallbits,
508  lifc->remote, lifc->type, ifc, tifc);
509  if(v6addrtype(ip) != linklocalv6)
510  addroute(f, lifc->remote, lifc->mask, ip, IPnoaddr,
511  lifc->remote, lifc->type, ifc, tifc);
512  }
513  lifc->autoflag = lifcp->autoflag;
514  lifc->validlt = lifcp->validlt;
515  lifc->preflt = lifcp->preflt;
516  lifc->origint = lifcp->origint;
517  }
518  if(lifc->tentative != tentative){
519  lifc->tentative = tentative;
520  goto done;
521  }
522  wunlock(ifc);
523  poperror();
524  return nil;
525  }
526 
527  /* add the address to the list of logical ifc's for this ifc */
528  lifc = smalloc(sizeof(Iplifc));
529  ipmove(lifc->local, ip);
530  ipmove(lifc->mask, mask);
531  ipmove(lifc->remote, rem);
532  ipmove(lifc->net, net);
533  lifc->type = type;
534  lifc->tentative = tentative;
535  if(lifcp != nil) {
536  lifc->onlink = lifcp->onlink;
537  lifc->autoflag = lifcp->autoflag;
538  lifc->validlt = lifcp->validlt;
539  lifc->preflt = lifcp->preflt;
540  lifc->origint = lifcp->origint;
541  } else { /* default values */
542  lifc->onlink = lifc->autoflag = 1;
543  lifc->validlt = lifc->preflt = ~0UL;
544  lifc->origint = NOW / 1000;
545  }
546  lifc->next = nil;
547 
548  for(l = &ifc->lifc; *l != nil; l = &(*l)->next)
549  ;
550  *l = lifc;
551 
552  /* add route for this logical interface */
553  if(lifc->onlink){
554  addroute(f, rem, mask, ip, IPallbits, rem, type, ifc, tifc);
555  if(v6addrtype(ip) != linklocalv6)
556  addroute(f, rem, mask, ip, IPnoaddr, rem, type, ifc, tifc);
557  }
558 
559  addselfcache(f, ifc, lifc, ip, Runi);
560 
561  /* register proxy */
562  if(type & Rptpt){
563  if(type & Rproxy)
564  ipifcregisterproxy(f, ifc, rem, 1);
565  goto done;
566  }
567 
568  if(type & Rv4) {
569  /* add subnet directed broadcast address to the self cache */
570  for(i = 0; i < IPaddrlen; i++)
571  bcast[i] = (ip[i] & mask[i]) | ~mask[i];
572  addselfcache(f, ifc, lifc, bcast, Rbcast);
573 
574  /* add subnet directed network address to the self cache */
575  for(i = 0; i < IPaddrlen; i++)
576  bcast[i] = (ip[i] & mask[i]) & mask[i];
577  addselfcache(f, ifc, lifc, bcast, Rbcast);
578 
579  /* add network directed broadcast address to the self cache */
580  memmove(mask, defmask(ip), IPaddrlen);
581  for(i = 0; i < IPaddrlen; i++)
582  bcast[i] = (ip[i] & mask[i]) | ~mask[i];
583  addselfcache(f, ifc, lifc, bcast, Rbcast);
584 
585  /* add network directed network address to the self cache */
586  memmove(mask, defmask(ip), IPaddrlen);
587  for(i = 0; i < IPaddrlen; i++)
588  bcast[i] = (ip[i] & mask[i]) & mask[i];
589  addselfcache(f, ifc, lifc, bcast, Rbcast);
590 
591  addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
592  } else {
593  if(ipcmp(ip, v6loopback) == 0) {
594  /* add node-local mcast address */
595  addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
596 
597  /* add route for all node multicast */
598  addroute(f, v6allnodesN, v6allnodesNmask,
599  ip, IPallbits,
600  v6allnodesN, Rmulti, ifc, tifc);
601  }
602 
603  /* add all nodes multicast address */
604  addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
605 
606  /* add route for all nodes multicast */
607  addroute(f, v6allnodesL, v6allnodesLmask,
608  ip, IPallbits,
609  v6allnodesL, Rmulti, ifc, tifc);
610 
611  /* add solicited-node multicast address */
612  ipv62smcast(bcast, ip);
613  addselfcache(f, ifc, lifc, bcast, Rmulti);
614  }
615 
616 done:
617  ipifcregisteraddr(f, ifc, lifc, ip);
618  wunlock(ifc);
619  poperror();
620 
621  return nil;
622 }
623 
624 /*
625  * remove a logical interface from an ifc
626  * called with ifc wlock'd
627  */
628 static char*
629 ipifcremlifc(Ipifc *ifc, Iplifc **l)
630 {
631  Iplifc *lifc = *l;
632  Fs *f = ifc->conv->p->f;
633 
634  if(lifc == nil)
635  return "address not on this interface";
636  *l = lifc->next;
637 
638  /* disassociate any addresses */
639  while(lifc->link != nil)
640  remselfcache(f, ifc, lifc, lifc->link->self->a);
641 
642  /* remove the route for this logical interface */
643  if(lifc->onlink){
644  remroute(f, lifc->remote, lifc->mask,
645  lifc->local, IPallbits,
646  lifc->remote, lifc->type, ifc, tifc);
647  if(v6addrtype(lifc->local) != linklocalv6)
648  remroute(f, lifc->remote, lifc->mask,
649  lifc->local, IPnoaddr,
650  lifc->remote, lifc->type, ifc, tifc);
651  }
652 
653  /* unregister proxy */
654  if(lifc->type & Rptpt){
655  if(lifc->type & Rproxy)
656  ipifcregisterproxy(f, ifc, lifc->remote, 0);
657  goto done;
658  }
659 
660  /* remove route for all nodes multicast */
661  if((lifc->type & Rv4) == 0){
662  if(ipcmp(lifc->local, v6loopback) == 0)
663  remroute(f, v6allnodesN, v6allnodesNmask,
664  lifc->local, IPallbits,
665  v6allnodesN, Rmulti, ifc, tifc);
666 
667  remroute(f, v6allnodesL, v6allnodesLmask,
668  lifc->local, IPallbits,
669  v6allnodesL, Rmulti, ifc, tifc);
670  }
671 
672 done:
673  free(lifc);
674  return nil;
675 }
676 
677 /*
678  * remove an address from an interface.
679  */
680 char*
681 ipifcrem(Ipifc *ifc, char **argv, int argc)
682 {
683  char *rv;
684  uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
685  Iplifc *lifc, **l;
686 
687  if(argc < 3)
688  return Ebadarg;
689  if(parseipandmask(ip, mask, argv[1], argv[2]) == -1)
690  return Ebadip;
691  if(argc < 4)
692  maskip(ip, mask, rem);
693  else if(parseip(rem, argv[3]) == -1)
694  return Ebadip;
695 
696  /*
697  * find address on this interface and remove from chain.
698  * for pt to pt we actually specify the remote address as the
699  * addresss to remove.
700  */
701  wlock(ifc);
702  l = &ifc->lifc;
703  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
704  if(ipcmp(ip, lifc->local) == 0
705  && ipcmp(mask, lifc->mask) == 0
706  && ipcmp(rem, lifc->remote) == 0)
707  break;
708  l = &lifc->next;
709  }
710  rv = ipifcremlifc(ifc, l);
711  wunlock(ifc);
712  return rv;
713 }
714 
715 /*
716  * associate an address with the interface. This wipes out any previous
717  * addresses. This is a macro that means, remove all the old interfaces
718  * and add a new one.
719  */
720 static char*
721 ipifcconnect(Conv* c, char **argv, int argc)
722 {
723  char *err;
724  Ipifc *ifc;
725 
726  ifc = (Ipifc*)c->ptcl;
727  wlock(ifc);
728  while(ifc->lifc != nil)
729  ipifcremlifc(ifc, &ifc->lifc);
730  wunlock(ifc);
731 
732  err = ipifcadd(ifc, argv, argc, 0, nil);
733  if(err != nil)
734  return err;
735 
736  Fsconnected(c, nil);
737  return nil;
738 }
739 
740 char*
741 ipifcra6(Ipifc *ifc, char **argv, int argc)
742 {
743  int i, argsleft;
744  uchar sendra, recvra;
745  Routerparams rp;
746 
747  i = 1;
748  argsleft = argc - 1;
749  if((argsleft % 2) != 0)
750  return Ebadarg;
751 
752  sendra = ifc->sendra6;
753  recvra = ifc->recvra6;
754  rp = ifc->rp;
755 
756  while (argsleft > 1) {
757  if(strcmp(argv[i], "recvra") == 0)
758  recvra = atoi(argv[i+1]) != 0;
759  else if(strcmp(argv[i], "sendra") == 0)
760  sendra = atoi(argv[i+1]) != 0;
761  else if(strcmp(argv[i], "mflag") == 0)
762  rp.mflag = atoi(argv[i+1]) != 0;
763  else if(strcmp(argv[i], "oflag") == 0)
764  rp.oflag = atoi(argv[i+1]) != 0;
765  else if(strcmp(argv[i], "maxraint") == 0)
766  rp.maxraint = atoi(argv[i+1]);
767  else if(strcmp(argv[i], "minraint") == 0)
768  rp.minraint = atoi(argv[i+1]);
769  else if(strcmp(argv[i], "linkmtu") == 0)
770  rp.linkmtu = atoi(argv[i+1]);
771  else if(strcmp(argv[i], "reachtime") == 0)
772  rp.reachtime = atoi(argv[i+1]);
773  else if(strcmp(argv[i], "rxmitra") == 0)
774  rp.rxmitra = atoi(argv[i+1]);
775  else if(strcmp(argv[i], "ttl") == 0)
776  rp.ttl = atoi(argv[i+1]);
777  else if(strcmp(argv[i], "routerlt") == 0)
778  rp.routerlt = atoi(argv[i+1]);
779  else
780  return Ebadarg;
781 
782  argsleft -= 2;
783  i += 2;
784  }
785 
786  /* consistency check */
787  if(rp.maxraint < rp.minraint)
788  return Ebadarg;
789 
790  ifc->rp = rp;
791  ifc->sendra6 = sendra;
792  ifc->recvra6 = recvra;
793 
794  return nil;
795 }
796 
797 /*
798  * non-standard control messages.
799  */
800 static char*
801 ipifcctl(Conv* c, char **argv, int argc)
802 {
803  Ipifc *ifc;
804 
805  ifc = (Ipifc*)c->ptcl;
806  if(strcmp(argv[0], "add") == 0)
807  return ipifcadd(ifc, argv, argc, 0, nil);
808  else if(strcmp(argv[0], "try") == 0)
809  return ipifcadd(ifc, argv, argc, 1, nil);
810  else if(strcmp(argv[0], "remove") == 0)
811  return ipifcrem(ifc, argv, argc);
812  else if(strcmp(argv[0], "unbind") == 0)
813  return ipifcunbind(ifc);
814  else if(strcmp(argv[0], "mtu") == 0)
815  return ipifcsetmtu(ifc, argv, argc);
816  else if(strcmp(argv[0], "speed") == 0){
817  ipifcsetspeed(ifc, argc>1? atoi(argv[1]): 0);
818  return nil;
819  }
820  else if(strcmp(argv[0], "delay") == 0){
821  ipifcsetdelay(ifc, argc>1? atoi(argv[1]): 0);
822  return nil;
823  }
824  else if(strcmp(argv[0], "iprouting") == 0){
825  iprouting(c->p->f, argc>1? atoi(argv[1]): 1);
826  return nil;
827  }
828  else if(strcmp(argv[0], "reflect") == 0){
829  ifc->reflect = argc>1? atoi(argv[1]): 1;
830  return nil;
831  }
832  else if(strcmp(argv[0], "reassemble") == 0){
833  ifc->reassemble = argc>1? atoi(argv[1]): 1;
834  return nil;
835  }
836  else if(strcmp(argv[0], "add6") == 0)
837  return ipifcadd6(ifc, argv, argc);
838  else if(strcmp(argv[0], "remove6") == 0)
839  return ipifcremove6(ifc, argv, argc);
840  else if(strcmp(argv[0], "ra6") == 0)
841  return ipifcra6(ifc, argv, argc);
842  return "unsupported ctl";
843 }
844 
845 int
846 ipifcstats(Proto *ipifc, char *buf, int len)
847 {
848  return ipstats(ipifc->f, buf, len);
849 }
850 
851 void
852 ipifcinit(Fs *f)
853 {
854  Proto *ipifc;
855 
856  ipifc = smalloc(sizeof(Proto));
857  ipifc->name = "ipifc";
858  ipifc->connect = ipifcconnect;
859  ipifc->announce = nil;
860  ipifc->bind = ipifcbind;
861  ipifc->state = ipifcstate;
862  ipifc->create = ipifccreate;
863  ipifc->close = ipifcclose;
864  ipifc->rcv = nil;
865  ipifc->ctl = ipifcctl;
866  ipifc->advise = nil;
867  ipifc->stats = ipifcstats;
868  ipifc->inuse = ipifcinuse;
869  ipifc->local = ipifclocal;
870  ipifc->ipproto = -1;
871  ipifc->nc = Maxmedia;
872  ipifc->ptclsize = sizeof(Ipifc);
873 
874  f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */
875  f->self = smalloc(sizeof(Ipselftab)); /* hack for ipforme */
876 
877  Fsproto(f, ipifc);
878 }
879 
880 /*
881  * add to self routing cache
882  */
883 static void
884 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
885 {
886  Iplink *lp;
887  Ipself *p;
888  int h;
889 
890  type |= (lifc->type & Rv4);
891  qlock(f->self);
892  if(waserror()){
893  qunlock(f->self);
894  nexterror();
895  }
896 
897  /* see if the address already exists */
898  h = hashipa(a);
899  for(p = f->self->hash[h]; p != nil; p = p->next)
900  if(ipcmp(a, p->a) == 0)
901  break;
902 
903  /* allocate a local address and add to hash chain */
904  if(p == nil){
905  p = smalloc(sizeof(*p));
906  ipmove(p->a, a);
907  p->type = type;
908  p->next = f->self->hash[h];
909  f->self->hash[h] = p;
910 
911  /* if the null address, accept all packets */
912  if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
913  f->self->acceptall = 1;
914  }
915 
916  /* look for a link for this lifc */
917  for(lp = p->link; lp != nil; lp = lp->selflink)
918  if(lp->lifc == lifc)
919  break;
920 
921  /* allocate a lifc-to-local link and link to both */
922  if(lp == nil){
923  lp = smalloc(sizeof(*lp));
924  lp->ref = 1;
925  lp->lifc = lifc;
926  lp->self = p;
927  lp->selflink = p->link;
928  p->link = lp;
929  lp->lifclink = lifc->link;
930  lifc->link = lp;
931 
932  /* add to routing table */
933  addroute(f, a, IPallbits,
934  lifc->local,
935  ((type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
936  IPallbits : IPnoaddr,
937  a, type, ifc, tifc);
938 
939  if((type & Rmulti) && ifc->m->addmulti != nil)
940  (*ifc->m->addmulti)(ifc, a, lifc->local);
941  } else
942  lp->ref++;
943 
944  qunlock(f->self);
945  poperror();
946 }
947 
948 /*
949  * These structures are unlinked from their chains while
950  * other threads may be using them. To avoid excessive locking,
951  * just put them aside for a while before freeing them.
952  * called with f->self locked
953  */
954 static Iplink *freeiplink;
955 static Ipself *freeipself;
956 
957 static void
958 iplinkfree(Iplink *p)
959 {
960  Iplink **l, *np;
961  ulong now = NOW;
962 
963  l = &freeiplink;
964  for(np = *l; np != nil; np = *l){
965  if((long)(now - np->expire) >= 0){
966  *l = np->next;
967  free(np);
968  continue;
969  }
970  l = &np->next;
971  }
972  p->expire = now + 5000; /* give other threads 5 secs to get out */
973  p->next = nil;
974  *l = p;
975 }
976 
977 static void
978 ipselffree(Ipself *p)
979 {
980  Ipself **l, *np;
981  ulong now = NOW;
982 
983  l = &freeipself;
984  for(np = *l; np != nil; np = *l){
985  if((long)(now - np->expire) >= 0){
986  *l = np->next;
987  free(np);
988  continue;
989  }
990  l = &np->next;
991  }
992  p->expire = now + 5000; /* give other threads 5 secs to get out */
993  p->next = nil;
994  *l = p;
995 }
996 
997 /*
998  * Decrement reference for this address on this link.
999  * Unlink from selftab if this is the last ref.
1000  */
1001 static void
1002 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
1003 {
1004  Ipself *p, **l;
1005  Iplink *link, **l_self, **l_lifc;
1006 
1007  qlock(f->self);
1008 
1009  /* find the unique selftab entry */
1010  l = &f->self->hash[hashipa(a)];
1011  for(p = *l; p != nil; p = *l){
1012  if(ipcmp(p->a, a) == 0)
1013  break;
1014  l = &p->next;
1015  }
1016 
1017  if(p == nil)
1018  goto out;
1019 
1020  /*
1021  * walk down links from an ifc looking for one
1022  * that matches the selftab entry
1023  */
1024  l_lifc = &lifc->link;
1025  for(link = *l_lifc; link != nil; link = *l_lifc){
1026  if(link->self == p)
1027  break;
1028  l_lifc = &link->lifclink;
1029  }
1030 
1031  if(link == nil)
1032  goto out;
1033 
1034  /*
1035  * walk down the links from the selftab looking for
1036  * the one we just found
1037  */
1038  l_self = &p->link;
1039  for(link = *l_self; link != nil; link = *l_self){
1040  if(link == *l_lifc)
1041  break;
1042  l_self = &link->selflink;
1043  }
1044 
1045  if(link == nil)
1046  panic("remselfcache");
1047 
1048  if(--(link->ref) != 0)
1049  goto out;
1050 
1051  /* remove from routing table */
1052  remroute(f, a, IPallbits,
1053  lifc->local,
1054  ((p->type & (Rbcast|Rmulti)) != 0 || v6addrtype(a) == linklocalv6) ?
1055  IPallbits : IPnoaddr,
1056  a, p->type, ifc, tifc);
1057 
1058  if((p->type & Rmulti) && ifc->m->remmulti != nil){
1059  if(!waserror()){
1060  (*ifc->m->remmulti)(ifc, a, lifc->local);
1061  poperror();
1062  }
1063  }
1064 
1065  /* ref == 0, remove from both chains and free the link */
1066  *l_lifc = link->lifclink;
1067  *l_self = link->selflink;
1068  iplinkfree(link);
1069 
1070  if(p->link != nil)
1071  goto out;
1072 
1073  /* if null address, forget */
1074  if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1075  f->self->acceptall = 0;
1076 
1077  /* no more links, remove from hash and free */
1078  *l = p->next;
1079  ipselffree(p);
1080 
1081 out:
1082  qunlock(f->self);
1083 }
1084 
1085 long
1086 ipselftabread(Fs *f, char *cp, ulong offset, int n)
1087 {
1088  int i, m, nifc, off;
1089  Ipself *p;
1090  Iplink *link;
1091  char state[8];
1092 
1093  m = 0;
1094  off = offset;
1095  qlock(f->self);
1096  for(i = 0; i < NHASH && m < n; i++){
1097  for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
1098  nifc = 0;
1099  for(link = p->link; link != nil; link = link->selflink)
1100  nifc++;
1101  routetype(p->type, state);
1102  m += snprint(cp + m, n - m, "%-44.44I %2.2d %4.4s\n",
1103  p->a, nifc, state);
1104  if(off > 0){
1105  off -= m;
1106  m = 0;
1107  }
1108  }
1109  }
1110  qunlock(f->self);
1111  return m;
1112 }
1113 
1114 /*
1115  * returns
1116  * 0 - no match
1117  * Runi
1118  * Rbcast
1119  * Rmulti
1120  */
1121 int
1122 ipforme(Fs *f, uchar *addr)
1123 {
1124  Ipself *p;
1125 
1126  for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next)
1127  if(ipcmp(addr, p->a) == 0)
1128  return p->type & (Runi|Rbcast|Rmulti);
1129 
1130  /* hack to say accept anything */
1131  if(f->self->acceptall)
1132  return Runi;
1133 
1134  return 0;
1135 }
1136 
1137 /*
1138  * find the ifc on same net as the remote system. If none,
1139  * return nil.
1140  */
1141 Ipifc*
1142 findipifc(Fs *f, uchar *local, uchar *remote, int type)
1143 {
1144  uchar gnet[IPaddrlen];
1145  int spec, xspec;
1146  Ipifc *ifc, *x;
1147  Iplifc *lifc;
1148  Conv **cp;
1149 
1150  x = nil;
1151  xspec = 0;
1152  for(cp = f->ipifc->conv; *cp != nil; cp++){
1153  ifc = (Ipifc*)(*cp)->ptcl;
1154  rlock(ifc);
1155  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1156  if(type & Runi){
1157  if(ipcmp(remote, lifc->local) == 0){
1158  Found:
1159  runlock(ifc);
1160  return ifc;
1161  }
1162  } else if(type & (Rbcast|Rmulti)) {
1163  if(ipcmp(local, lifc->local) == 0)
1164  goto Found;
1165  }
1166  maskip(remote, lifc->mask, gnet);
1167  if(ipcmp(gnet, lifc->net) == 0){
1168  spec = comprefixlen(remote, lifc->local, IPaddrlen);
1169  if(spec > xspec){
1170  x = ifc;
1171  xspec = spec;
1172  }
1173  }
1174  }
1175  runlock(ifc);
1176  }
1177  return x;
1178 }
1179 
1180 Ipifc*
1181 findipifcstr(Fs *f, char *s)
1182 {
1183  uchar ip[IPaddrlen];
1184  Conv *c;
1185  char *p;
1186  long x;
1187 
1188  x = strtol(s, &p, 10);
1189  if(p > s && *p == '\0'){
1190  if(x < 0)
1191  return nil;
1192  if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil && ipifcinuse(c))
1193  return (Ipifc*)c->ptcl;
1194  }
1195  if(parseip(ip, s) != -1)
1196  return findipifc(f, ip, ip, Runi);
1197  return nil;
1198 }
1199 
1200 /*
1201  * find "best" (global > link local > unspecified)
1202  * local address; address must be current.
1203  */
1204 static void
1205 findprimaryipv6(Fs *f, uchar *local)
1206 {
1207  ulong now = NOW/1000;
1208  int atype, atypel;
1209  Iplifc *lifc;
1210  Ipifc *ifc;
1211  Conv **cp;
1212 
1213  ipmove(local, v6Unspecified);
1214  atype = unspecifiedv6;
1215 
1216  for(cp = f->ipifc->conv; *cp != nil; cp++){
1217  ifc = (Ipifc*)(*cp)->ptcl;
1218  rlock(ifc);
1219  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1220  atypel = v6addrtype(lifc->local);
1221  if(atypel > atype)
1222  if(lifc->preflt == ~0UL || lifc->preflt >= now-lifc->origint) {
1223  ipmove(local, lifc->local);
1224  atype = atypel;
1225  if(atype == globalv6){
1226  runlock(ifc);
1227  return;
1228  }
1229  }
1230  }
1231  runlock(ifc);
1232  }
1233 }
1234 
1235 /*
1236  * returns first v4 address configured
1237  */
1238 static void
1239 findprimaryipv4(Fs *f, uchar *local)
1240 {
1241  Iplifc *lifc;
1242  Ipifc *ifc;
1243  Conv **cp;
1244 
1245  /* find first ifc local address */
1246  for(cp = f->ipifc->conv; *cp != nil; cp++){
1247  ifc = (Ipifc*)(*cp)->ptcl;
1248  rlock(ifc);
1249  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1250  if((lifc->type & Rv4) != 0){
1251  ipmove(local, lifc->local);
1252  runlock(ifc);
1253  return;
1254  }
1255  }
1256  runlock(ifc);
1257  }
1258  ipmove(local, IPnoaddr);
1259 }
1260 
1261 /*
1262  * return v4 address associated with an interface close to remote
1263  */
1264 int
1265 ipv4local(Ipifc *ifc, uchar *local, uchar *remote)
1266 {
1267  Iplifc *lifc;
1268  int a, b;
1269 
1270  b = -1;
1271  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1272  if((lifc->type & Rv4) == 0 || ipcmp(lifc->local, IPnoaddr) == 0)
1273  continue;
1274  a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
1275  if(a > b){
1276  b = a;
1277  memmove(local, lifc->local+IPv4off, IPv4addrlen);
1278  }
1279  }
1280  return b >= 0;
1281 }
1282 
1283 /*
1284  * return v6 address associated with an interface close to remote
1285  */
1286 int
1287 ipv6local(Ipifc *ifc, uchar *local, uchar *remote)
1288 {
1289  struct {
1290  int atype;
1291  int deprecated;
1292  int comprefixlen;
1293  } a, b;
1294  int atype;
1295  ulong now;
1296  Iplifc *lifc;
1297 
1298  if(isv4(remote)){
1299  ipmove(local, v4prefix);
1300  return ipv4local(ifc, local+IPv4off, remote+IPv4off);
1301  }
1302 
1303  atype = v6addrtype(remote);
1304  ipmove(local, v6Unspecified);
1305  b.atype = unknownv6;
1306  b.deprecated = 1;
1307  b.comprefixlen = 0;
1308 
1309  now = NOW/1000;
1310  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1311  if(lifc->tentative)
1312  continue;
1313 
1314  a.atype = v6addrtype(lifc->local);
1315  a.deprecated = lifc->preflt != ~0UL && lifc->preflt < now-lifc->origint;
1316  a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen);
1317 
1318  /* prefer appropriate scope */
1319  if(a.atype != b.atype){
1320  if(a.atype > b.atype && b.atype < atype ||
1321  a.atype < b.atype && b.atype > atype)
1322  goto Good;
1323  continue;
1324  }
1325  /* prefer non-deprecated addresses */
1326  if(a.deprecated != b.deprecated){
1327  if(b.deprecated)
1328  goto Good;
1329  continue;
1330  }
1331  /* prefer longer common prefix */
1332  if(a.comprefixlen != b.comprefixlen){
1333  if(a.comprefixlen > b.comprefixlen)
1334  goto Good;
1335  continue;
1336  }
1337  continue;
1338  Good:
1339  b = a;
1340  ipmove(local, lifc->local);
1341  }
1342 
1343  return b.atype >= atype;
1344 }
1345 
1346 void
1347 findlocalip(Fs *f, uchar *local, uchar *remote)
1348 {
1349  Route *r;
1350  Iplifc *lifc;
1351  Ipifc *ifc, *nifc;
1352  Conv **cp;
1353 
1354  for(cp = f->ipifc->conv; *cp != nil; cp++){
1355  ifc = (Ipifc*)(*cp)->ptcl;
1356  rlock(ifc);
1357  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1358  if(lifc->tentative)
1359  continue;
1360 
1361  r = v6lookup(f, remote, lifc->local, nil);
1362  if(r == nil || (nifc = r->ifc) == nil)
1363  continue;
1364  if(r->type & Runi){
1365  ipmove(local, remote);
1366  runlock(ifc);
1367  return;
1368  }
1369  if(nifc != ifc) rlock(nifc);
1370  if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
1371  ipmove(local, v4prefix);
1372  if(ipv4local(nifc, local+IPv4off, r->v4.gate)){
1373  if(nifc != ifc) runlock(nifc);
1374  runlock(ifc);
1375  return;
1376  }
1377  }
1378  if(ipv6local(nifc, local, remote)){
1379  if(nifc != ifc) runlock(nifc);
1380  runlock(ifc);
1381  return;
1382  }
1383  if(nifc != ifc) runlock(nifc);
1384  }
1385  runlock(ifc);
1386  }
1387  if(isv4(remote))
1388  findprimaryipv4(f, local);
1389  else
1390  findprimaryipv6(f, local);
1391 }
1392 
1393 
1394 /*
1395  * see if this address is bound to the interface
1396  */
1397 Iplifc*
1398 iplocalonifc(Ipifc *ifc, uchar *ip)
1399 {
1400  Iplifc *lifc;
1401 
1402  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
1403  if(ipcmp(ip, lifc->local) == 0)
1404  return lifc;
1405 
1406  return nil;
1407 }
1408 
1409 Iplifc*
1410 ipremoteonifc(Ipifc *ifc, uchar *ip)
1411 {
1412  uchar net[IPaddrlen];
1413  Iplifc *lifc;
1414 
1415  for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
1416  maskip(ip, lifc->mask, net);
1417  if(ipcmp(net, lifc->remote) == 0)
1418  return lifc;
1419  }
1420  return nil;
1421 }
1422 
1423 
1424 /*
1425  * See if we're proxying for this address on this interface
1426  */
1427 int
1428 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
1429 {
1430  Route *r;
1431 
1432  /* see if this is a direct connected pt to pt address */
1433  r = v6lookup(f, ip, ip, nil);
1434  if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
1435  return 0;
1436 
1437  return ipremoteonifc(ifc, ip) != nil;
1438 }
1439 
1440 /*
1441  * return multicast version if any
1442  */
1443 int
1444 ipismulticast(uchar *ip)
1445 {
1446  if(isv4(ip)){
1447  if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1448  return V4;
1449  }
1450  else if(ip[0] == 0xff)
1451  return V6;
1452  return 0;
1453 }
1454 
1455 /*
1456  * add a multicast address to an interface.
1457  */
1458 void
1459 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
1460 {
1461  Ipmulti *multi, **l;
1462  Iplifc *lifc;
1463  Ipifc *ifc;
1464  Fs *f;
1465 
1466  if(isv4(ma) != isv4(ia))
1467  error("incompatible multicast/interface ip address");
1468 
1469  for(l = &c->multi; *l != nil; l = &(*l)->next)
1470  if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1471  return; /* it's already there */
1472 
1473  f = c->p->f;
1474  if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1475  rlock(ifc);
1476  if(waserror()){
1477  runlock(ifc);
1478  nexterror();
1479  }
1480  if((lifc = iplocalonifc(ifc, ia)) != nil)
1481  addselfcache(f, ifc, lifc, ma, Rmulti);
1482  runlock(ifc);
1483  poperror();
1484  }
1485 
1486  multi = smalloc(sizeof(*multi));
1487  ipmove(multi->ma, ma);
1488  ipmove(multi->ia, ia);
1489  multi->next = nil;
1490  *l = multi;
1491 }
1492 
1493 
1494 /*
1495  * remove a multicast address from an interface.
1496  */
1497 void
1498 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
1499 {
1500  Ipmulti *multi, **l;
1501  Iplifc *lifc;
1502  Ipifc *ifc;
1503  Fs *f;
1504 
1505  for(l = &c->multi; *l != nil; l = &(*l)->next)
1506  if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
1507  break;
1508 
1509  multi = *l;
1510  if(multi == nil)
1511  return; /* we don't have it open */
1512 
1513  *l = multi->next;
1514  multi->next = nil;
1515 
1516  f = c->p->f;
1517  if((ifc = findipifc(f, ia, ma, Rmulti)) != nil){
1518  rlock(ifc);
1519  if(!waserror()){
1520  if((lifc = iplocalonifc(ifc, ia)) != nil)
1521  remselfcache(f, ifc, lifc, ma);
1522  poperror();
1523  }
1524  runlock(ifc);
1525  }
1526  free(multi);
1527 }
1528 
1529 /* register the address on this network for address resolution */
1530 static void
1531 ipifcregisteraddr(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip)
1532 {
1533  if(waserror()){
1534  print("ipifcregisteraddr %s %I %I: %s\n", ifc->dev, lifc->local, ip, up->errstr);
1535  return;
1536  }
1537  if(ifc->m != nil && ifc->m->areg != nil)
1538  (*ifc->m->areg)(f, ifc, lifc, ip);
1539  poperror();
1540 }
1541 
1542 static void
1543 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add)
1544 {
1545  uchar a[IPaddrlen];
1546  Iplifc *lifc;
1547  Ipifc *nifc;
1548  Conv **cp;
1549 
1550  /* register the address on any interface that will proxy for the ip */
1551  for(cp = f->ipifc->conv; *cp != nil; cp++){
1552  nifc = (Ipifc*)(*cp)->ptcl;
1553  if(nifc == ifc || !canrlock(nifc))
1554  continue;
1555 
1556  if(nifc->m == nil
1557  || (lifc = ipremoteonifc(nifc, ip)) == nil
1558  || (lifc->type & Rptpt) != 0
1559  || waserror()){
1560  runlock(nifc);
1561  continue;
1562  }
1563  if((lifc->type & Rv4) == 0){
1564  /* add solicited-node multicast addr */
1565  ipv62smcast(a, ip);
1566  if(add)
1567  addselfcache(f, nifc, lifc, a, Rmulti);
1568  else
1569  remselfcache(f, nifc, lifc, a);
1570  }
1571  if(add)
1572  ipifcregisteraddr(f, nifc, lifc, ip);
1573  runlock(nifc);
1574  poperror();
1575  }
1576 }
1577 
1578 char*
1579 ipifcadd6(Ipifc *ifc, char**argv, int argc)
1580 {
1581  int plen = 64;
1582  char addr[40], preflen[6];
1583  char *params[3];
1584  uchar prefix[IPaddrlen];
1585  Iplifc lifc;
1586 
1587  lifc.onlink = 1;
1588  lifc.autoflag = 1;
1589  lifc.validlt = lifc.preflt = ~0UL;
1590  lifc.origint = NOW / 1000;
1591 
1592  switch(argc) {
1593  case 7:
1594  lifc.preflt = strtoul(argv[6], 0, 10);
1595  /* fall through */
1596  case 6:
1597  lifc.validlt = strtoul(argv[5], 0, 10);
1598  /* fall through */
1599  case 5:
1600  lifc.autoflag = atoi(argv[4]) != 0;
1601  /* fall through */
1602  case 4:
1603  lifc.onlink = atoi(argv[3]) != 0;
1604  /* fall through */
1605  case 3:
1606  plen = atoi(argv[2]);
1607  /* fall through */
1608  case 2:
1609  break;
1610  default:
1611  return Ebadarg;
1612  }
1613 
1614  if (parseip(prefix, argv[1]) != 6 || lifc.validlt < lifc.preflt || plen < 0 ||
1615  plen > 64 || islinklocal(prefix))
1616  return Ebadarg;
1617 
1618  /* issue "add" ctl msg for v6 link-local addr and prefix len */
1619  if(ifc->m->pref2addr == nil)
1620  return Ebadarg;
1621  (*ifc->m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */
1622 
1623  sprint(addr, "%I", prefix);
1624  sprint(preflen, "/%d", plen);
1625  params[0] = "add";
1626  params[1] = addr;
1627  params[2] = preflen;
1628 
1629  return ipifcadd(ifc, params, 3, 0, &lifc);
1630 }
1631 
1632 char*
1633 ipifcremove6(Ipifc *ifc, char**, int argc)
1634 {
1635  Iplifc *lifc, **l;
1636  ulong now;
1637 
1638  if(argc != 1)
1639  return Ebadarg;
1640 
1641  wlock(ifc);
1642  now = NOW/1000;
1643  for(l = &ifc->lifc; (lifc = *l) != nil;) {
1644  if((lifc->type & Rv4) == 0)
1645  if(lifc->validlt != ~0UL && lifc->validlt < now-lifc->origint)
1646  if(ipifcremlifc(ifc, l) == nil)
1647  continue;
1648  l = &lifc->next;
1649  }
1650  wunlock(ifc);
1651 
1652  return nil;
1653 }