changelog shortlog tags branches changeset files revisions annotate raw help

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

changeset 7233: 24d21d7c0868
parent: 7c0cb11e474d
child: 88a2f67638e2
author: cinap_lenrek@felloff.net
date: Sun, 12 May 2019 01:20:21 +0200
permissions: -rw-r--r--
description: devip: do not lock selftab in ipselftabread(), remove unused fields from Ipself

the Ipselftab is designed to not require locking on read
operation. locking the selftab in ipselftabread() risks
deadlock when accessing the user buffer creates a fault.

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