changelog shortlog tags branches changeset files revisions annotate raw help

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

changeset 7231: 7c0cb11e474d
parent: 3a5ccd543798
child: 24d21d7c0868
author: cinap_lenrek@felloff.net
date: Sat, 11 May 2019 17:22:33 +0200
permissions: -rw-r--r--
description: devip: reset speed and delay on bind, adjust burst on mtu change, ifc->m nil check, consistent error strings

initialize the rate limits when the device gets
bound, not when it is created. so that the
rate limtis get reset to default when the ifc
is reused.

adjust the burst delay when the mtu is changed.
this is to make sure that we allow at least one
full sized packet burst.

make a local copy of ifc->m before doing nil
check as it can change under us when we do
not have the ifc locked.

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