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