Added explicit errno reporting from error() API.
[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 Ebadarg;
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 Ebadarg;
351         if (ifc->m == NULL)
352                 return Ebadarg;
353         mtu = strtoul(argv[1], 0, 0);
354         if (mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
355                 return Ebadarg;
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 Ebadarg;
412                         break;
413         }
414         if (isv4(ip))
415                 tentative = 0;
416         wlock(&ifc->rwlock);
417
418         /* ignore if this is already a local address for this ifc */
419         for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
420                 if (ipcmp(lifc->local, ip) == 0) {
421                         if (lifc->tentative != tentative)
422                                 lifc->tentative = tentative;
423                         if (lifcp != NULL) {
424                                 lifc->onlink = lifcp->onlink;
425                                 lifc->autoflag = lifcp->autoflag;
426                                 lifc->validlt = lifcp->validlt;
427                                 lifc->preflt = lifcp->preflt;
428                                 lifc->origint = lifcp->origint;
429                         }
430                         goto out;
431                 }
432         }
433
434         /* add the address to the list of logical ifc's for this ifc */
435         lifc = kzmalloc(sizeof(struct Iplifc), 0);
436         ipmove(lifc->local, ip);
437         ipmove(lifc->mask, mask);
438         ipmove(lifc->remote, rem);
439         ipmove(lifc->net, net);
440         lifc->tentative = tentative;
441         if (lifcp != NULL) {
442                 lifc->onlink = lifcp->onlink;
443                 lifc->autoflag = lifcp->autoflag;
444                 lifc->validlt = lifcp->validlt;
445                 lifc->preflt = lifcp->preflt;
446                 lifc->origint = lifcp->origint;
447         } else {        // default values
448                 lifc->onlink = 1;
449                 lifc->autoflag = 1;
450                 lifc->validlt = UINT64_MAX;
451                 lifc->preflt = UINT64_MAX;
452                 lifc->origint = NOW / 10 ^ 3;
453         }
454         lifc->next = NULL;
455
456         for (l = &ifc->lifc; *l; l = &(*l)->next) ;
457         *l = lifc;
458
459         /* check for point-to-point interface */
460         if (ipcmp(ip, v6loopback))      /* skip v6 loopback, it's a special address */
461                 if (ipcmp(mask, IPallbits) == 0)
462                         type |= Rptpt;
463
464         /* add local routes */
465         if (isv4(ip))
466                 v4addroute(f, tifc, rem + IPv4off, mask + IPv4off, rem + IPv4off, type);
467         else
468                 v6addroute(f, tifc, rem, mask, rem, type);
469
470         addselfcache(f, ifc, lifc, ip, Runi);
471
472         if ((type & (Rproxy | Rptpt)) == (Rproxy | Rptpt)) {
473                 ipifcregisterproxy(f, ifc, rem);
474                 goto out;
475         }
476
477         if (isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
478                 /* add subnet directed broadcast address to the self cache */
479                 for (i = 0; i < IPaddrlen; i++)
480                         bcast[i] = (ip[i] & mask[i]) | ~mask[i];
481                 addselfcache(f, ifc, lifc, bcast, Rbcast);
482
483                 /* add subnet directed network address to the self cache */
484                 for (i = 0; i < IPaddrlen; i++)
485                         bcast[i] = (ip[i] & mask[i]) & mask[i];
486                 addselfcache(f, ifc, lifc, bcast, Rbcast);
487
488                 /* add network directed broadcast address to the self cache */
489                 memmove(mask, defmask(ip), IPaddrlen);
490                 for (i = 0; i < IPaddrlen; i++)
491                         bcast[i] = (ip[i] & mask[i]) | ~mask[i];
492                 addselfcache(f, ifc, lifc, bcast, Rbcast);
493
494                 /* add network directed network address to the self cache */
495                 memmove(mask, defmask(ip), IPaddrlen);
496                 for (i = 0; i < IPaddrlen; i++)
497                         bcast[i] = (ip[i] & mask[i]) & mask[i];
498                 addselfcache(f, ifc, lifc, bcast, Rbcast);
499
500                 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
501         } else {
502                 if (ipcmp(ip, v6loopback) == 0) {
503                         /* add node-local mcast address */
504                         addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
505
506                         /* add route for all node multicast */
507                         v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, v6allnodesN,
508                                            Rmulti);
509                 }
510
511                 /* add all nodes multicast address */
512                 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
513
514                 /* add route for all nodes multicast */
515                 v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, Rmulti);
516
517                 /* add solicited-node multicast address */
518                 ipv62smcast(bcast, ip);
519                 addselfcache(f, ifc, lifc, bcast, Rmulti);
520
521                 sendnbrdisc = 1;
522         }
523
524         /* register the address on this network for address resolution */
525         if (isv4(ip) && ifc->m->areg != NULL)
526                 (*ifc->m->areg) (ifc, ip);
527
528 out:
529         wunlock(&ifc->rwlock);
530         if (tentative && sendnbrdisc)
531                 icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
532         return NULL;
533 }
534
535 /*
536  *  remove a logical interface from an ifc
537  *  always called with ifc wlock'd
538  */
539 static char *ipifcremlifc(struct Ipifc *ifc, struct Iplifc *lifc)
540 {
541         struct Iplifc **l;
542         struct Fs *f;
543
544         f = ifc->conv->p->f;
545
546         /*
547          *  find address on this interface and remove from chain.
548          *  for pt to pt we actually specify the remote address as the
549          *  addresss to remove.
550          */
551         for (l = &ifc->lifc; *l != NULL && *l != lifc; l = &(*l)->next) ;
552         if (*l == NULL)
553                 return "address not on this interface";
554         *l = lifc->next;
555
556         /* disassociate any addresses */
557         while (lifc->link)
558                 remselfcache(f, ifc, lifc, lifc->link->self->a);
559
560         /* remove the route for this logical interface */
561         if (isv4(lifc->local))
562                 v4delroute(f, lifc->remote + IPv4off, lifc->mask + IPv4off, 1);
563         else {
564                 v6delroute(f, lifc->remote, lifc->mask, 1);
565                 if (ipcmp(lifc->local, v6loopback) == 0)
566                         /* remove route for all node multicast */
567                         v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
568                 else if (memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
569                         /* remove route for all link multicast */
570                         v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
571         }
572
573         kfree(lifc);
574         return NULL;
575
576 }
577
578 /*
579  *  remove an address from an interface.
580  *  called with c locked
581  */
582 char *ipifcrem(struct Ipifc *ifc, char **argv, int argc)
583 {
584         uint8_t ip[IPaddrlen];
585         uint8_t mask[IPaddrlen];
586         uint8_t rem[IPaddrlen];
587         struct Iplifc *lifc;
588         char *rv;
589
590         if (argc < 3)
591                 return Ebadarg;
592
593         parseip(ip, argv[1]);
594         parseipmask(mask, argv[2]);
595         if (argc < 4)
596                 maskip(ip, mask, rem);
597         else
598                 parseip(rem, argv[3]);
599
600         wlock(&ifc->rwlock);
601
602         /*
603          *  find address on this interface and remove from chain.
604          *  for pt to pt we actually specify the remote address as the
605          *  addresss to remove.
606          */
607         for (lifc = ifc->lifc; lifc != NULL; lifc = lifc->next) {
608                 if (memcmp(ip, lifc->local, IPaddrlen) == 0
609                         && memcmp(mask, lifc->mask, IPaddrlen) == 0
610                         && memcmp(rem, lifc->remote, IPaddrlen) == 0)
611                         break;
612         }
613
614         rv = ipifcremlifc(ifc, lifc);
615         wunlock(&ifc->rwlock);
616         return rv;
617 }
618
619 /*
620  * distribute routes to active interfaces like the
621  * TRIP linecards
622  */
623 void
624 ipifcaddroute(struct Fs *f, int vers, uint8_t * addr, uint8_t * mask,
625                           uint8_t * gate, int type)
626 {
627         struct medium *m;
628         struct conv **cp, **e;
629         struct Ipifc *ifc;
630
631         e = &f->ipifc->conv[f->ipifc->nc];
632         for (cp = f->ipifc->conv; cp < e; cp++) {
633                 if (*cp != NULL) {
634                         ifc = (struct Ipifc *)(*cp)->ptcl;
635                         m = ifc->m;
636                         if (m == NULL)
637                                 continue;
638                         if (m->addroute != NULL)
639                                 m->addroute(ifc, vers, addr, mask, gate, type);
640                 }
641         }
642 }
643
644 void ipifcremroute(struct Fs *f, int vers, uint8_t * addr, uint8_t * mask)
645 {
646         struct medium *m;
647         struct conv **cp, **e;
648         struct Ipifc *ifc;
649
650         e = &f->ipifc->conv[f->ipifc->nc];
651         for (cp = f->ipifc->conv; cp < e; cp++) {
652                 if (*cp != NULL) {
653                         ifc = (struct Ipifc *)(*cp)->ptcl;
654                         m = ifc->m;
655                         if (m == NULL)
656                                 continue;
657                         if (m->remroute != NULL)
658                                 m->remroute(ifc, vers, addr, mask);
659                 }
660         }
661 }
662
663 /*
664  *  associate an address with the interface.  This wipes out any previous
665  *  addresses.  This is a macro that means, remove all the old interfaces
666  *  and add a new one.
667  */
668 static char *ipifcconnect(struct conv *c, char **argv, int argc)
669 {
670         ERRSTACK(1);
671         char *err;
672         struct Ipifc *ifc;
673
674         ifc = (struct Ipifc *)c->ptcl;
675
676         if (ifc->m == NULL)
677                 return "ipifc not yet bound to device";
678
679         if (waserror()) {
680                 wunlock(&ifc->rwlock);
681                 nexterror();
682         }
683         wlock(&ifc->rwlock);
684         while (ifc->lifc) {
685                 err = ipifcremlifc(ifc, ifc->lifc);
686                 if (err)
687                         error(EFAIL, err);
688         }
689         wunlock(&ifc->rwlock);
690         poperror();
691
692         err = ipifcadd(ifc, argv, argc, 0, NULL);
693         if (err)
694                 return err;
695
696         Fsconnected(c, NULL);
697
698         return NULL;
699 }
700
701 char *ipifcsetpar6(struct Ipifc *ifc, char **argv, int argc)
702 {
703         int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
704
705         argsleft = argc - 1;
706         i = 1;
707
708         if (argsleft % 2 != 0)
709                 return Ebadarg;
710
711         while (argsleft > 1) {
712                 if (strcmp(argv[i], "recvra") == 0)
713                         ifc->recvra6 = (atoi(argv[i + 1]) != 0);
714                 else if (strcmp(argv[i], "sendra") == 0)
715                         ifc->sendra6 = (atoi(argv[i + 1]) != 0);
716                 else if (strcmp(argv[i], "mflag") == 0)
717                         ifc->rp.mflag = (atoi(argv[i + 1]) != 0);
718                 else if (strcmp(argv[i], "oflag") == 0)
719                         ifc->rp.oflag = (atoi(argv[i + 1]) != 0);
720                 else if (strcmp(argv[i], "maxraint") == 0)
721                         ifc->rp.maxraint = atoi(argv[i + 1]);
722                 else if (strcmp(argv[i], "minraint") == 0)
723                         ifc->rp.minraint = atoi(argv[i + 1]);
724                 else if (strcmp(argv[i], "linkmtu") == 0)
725                         ifc->rp.linkmtu = atoi(argv[i + 1]);
726                 else if (strcmp(argv[i], "reachtime") == 0)
727                         ifc->rp.reachtime = atoi(argv[i + 1]);
728                 else if (strcmp(argv[i], "rxmitra") == 0)
729                         ifc->rp.rxmitra = atoi(argv[i + 1]);
730                 else if (strcmp(argv[i], "ttl") == 0)
731                         ifc->rp.ttl = atoi(argv[i + 1]);
732                 else if (strcmp(argv[i], "routerlt") == 0)
733                         ifc->rp.routerlt = atoi(argv[i + 1]);
734                 else
735                         return Ebadarg;
736
737                 argsleft -= 2;
738                 i += 2;
739         }
740
741         // consistency check
742         if (ifc->rp.maxraint < ifc->rp.minraint) {
743                 ifc->rp.maxraint = vmax;
744                 ifc->rp.minraint = vmin;
745                 return Ebadarg;
746         }
747
748         return NULL;
749 }
750
751 char *ipifcsendra6(struct Ipifc *ifc, char **argv, int argc)
752 {
753         int i;
754
755         i = 0;
756         if (argc > 1)
757                 i = atoi(argv[1]);
758         ifc->sendra6 = (i != 0);
759         return NULL;
760 }
761
762 char *ipifcrecvra6(struct Ipifc *ifc, char **argv, int argc)
763 {
764         int i;
765
766         i = 0;
767         if (argc > 1)
768                 i = atoi(argv[1]);
769         ifc->recvra6 = (i != 0);
770         return NULL;
771 }
772
773 /*
774  *  non-standard control messages.
775  *  called with c locked.
776  */
777 static char *ipifcctl(struct conv *c, char **argv, int argc)
778 {
779         struct Ipifc *ifc;
780         int i;
781
782         ifc = (struct Ipifc *)c->ptcl;
783         if (strcmp(argv[0], "add") == 0)
784                 return ipifcadd(ifc, argv, argc, 0, NULL);
785         else if (strcmp(argv[0], "bootp") == 0)
786                 return bootp(ifc);
787         else if (strcmp(argv[0], "try") == 0)
788                 return ipifcadd(ifc, argv, argc, 1, NULL);
789         else if (strcmp(argv[0], "remove") == 0)
790                 return ipifcrem(ifc, argv, argc);
791         else if (strcmp(argv[0], "unbind") == 0)
792                 return ipifcunbind(ifc);
793         else if (strcmp(argv[0], "joinmulti") == 0)
794                 return ipifcjoinmulti(ifc, argv, argc);
795         else if (strcmp(argv[0], "leavemulti") == 0)
796                 return ipifcleavemulti(ifc, argv, argc);
797         else if (strcmp(argv[0], "mtu") == 0)
798                 return ipifcsetmtu(ifc, argv, argc);
799         else if (strcmp(argv[0], "reassemble") == 0) {
800                 ifc->reassemble = 1;
801                 return NULL;
802         } else if (strcmp(argv[0], "iprouting") == 0) {
803                 i = 1;
804                 if (argc > 1)
805                         i = atoi(argv[1]);
806                 iprouting(c->p->f, i);
807                 return NULL;
808         } else if (strcmp(argv[0], "addpref6") == 0)
809                 return ipifcaddpref6(ifc, argv, argc);
810         else if (strcmp(argv[0], "setpar6") == 0)
811                 return ipifcsetpar6(ifc, argv, argc);
812         else if (strcmp(argv[0], "sendra6") == 0)
813                 return ipifcsendra6(ifc, argv, argc);
814         else if (strcmp(argv[0], "recvra6") == 0)
815                 return ipifcrecvra6(ifc, argv, argc);
816         return "unsupported ctl";
817 }
818
819 int ipifcstats(struct Proto *ipifc, char *buf, int len)
820 {
821         return ipstats(ipifc->f, buf, len);
822 }
823
824 void ipifcinit(struct Fs *f)
825 {
826         struct Proto *ipifc;
827
828         ipifc = kzmalloc(sizeof(struct Proto), 0);
829         ipifc->name = "ipifc";
830         ipifc->connect = ipifcconnect;
831         ipifc->announce = NULL;
832         ipifc->bind = ipifcbind;
833         ipifc->state = ipifcstate;
834         ipifc->create = ipifccreate;
835         ipifc->close = ipifcclose;
836         ipifc->rcv = NULL;
837         ipifc->ctl = ipifcctl;
838         ipifc->advise = NULL;
839         ipifc->stats = ipifcstats;
840         ipifc->inuse = ipifcinuse;
841         ipifc->local = ipifclocal;
842         ipifc->ipproto = -1;
843         ipifc->nc = Maxmedia;
844         ipifc->ptclsize = sizeof(struct Ipifc);
845
846         f->ipifc = ipifc;       /* hack for ipifcremroute, findipifc, ... */
847         f->self = kzmalloc(sizeof(struct Ipselftab), 0);        /* hack for ipforme */
848         qlock_init(&f->self->qlock);
849
850         Fsproto(f, ipifc);
851 }
852
853 /*
854  *  add to self routing cache
855  *      called with c locked
856  */
857 static void
858 addselfcache(struct Fs *f, struct Ipifc *ifc,
859                          struct Iplifc *lifc, uint8_t * a, int type)
860 {
861         struct Ipself *p;
862         struct Iplink *lp;
863         int h;
864
865         qlock(&f->self->qlock);
866
867         /* see if the address already exists */
868         h = hashipa(a);
869         for (p = f->self->hash[h]; p; p = p->next)
870                 if (memcmp(a, p->a, IPaddrlen) == 0)
871                         break;
872
873         /* allocate a local address and add to hash chain */
874         if (p == NULL) {
875                 p = kzmalloc(sizeof(*p), 0);
876                 ipmove(p->a, a);
877                 p->type = type;
878                 p->next = f->self->hash[h];
879                 f->self->hash[h] = p;
880
881                 /* if the null address, accept all packets */
882                 if (ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
883                         f->self->acceptall = 1;
884         }
885
886         /* look for a link for this lifc */
887         for (lp = p->link; lp; lp = lp->selflink)
888                 if (lp->lifc == lifc)
889                         break;
890
891         /* allocate a lifc-to-local link and link to both */
892         if (lp == NULL) {
893                 lp = kzmalloc(sizeof(*lp), 0);
894                 kref_init(&lp->ref, fake_release, 1);
895                 lp->lifc = lifc;
896                 lp->self = p;
897                 lp->selflink = p->link;
898                 p->link = lp;
899                 lp->lifclink = lifc->link;
900                 lifc->link = lp;
901
902                 /* add to routing table */
903                 if (isv4(a))
904                         v4addroute(f, tifc, a + IPv4off, IPallbits + IPv4off, a + IPv4off,
905                                            type);
906                 else
907                         v6addroute(f, tifc, a, IPallbits, a, type);
908
909                 if ((type & Rmulti) && ifc->m->addmulti != NULL)
910                         (*ifc->m->addmulti) (ifc, a, lifc->local);
911         } else {
912                 kref_get(&lp->ref, 1);
913         }
914
915         qunlock(&f->self->qlock);
916 }
917
918 /*
919  *  These structures are unlinked from their chains while
920  *  other threads may be using them.  To avoid excessive locking,
921  *  just put them aside for a while before freeing them.
922  *      called with f->self locked
923  */
924 static struct Iplink *freeiplink;
925 static struct Ipself *freeipself;
926
927 static void iplinkfree(struct Iplink *p)
928 {
929         struct Iplink **l, *np;
930         uint64_t now = NOW;
931
932         l = &freeiplink;
933         for (np = *l; np; np = *l) {
934                 if (np->expire > now) {
935                         *l = np->next;
936                         kfree(np);
937                         continue;
938                 }
939                 l = &np->next;
940         }
941         p->expire = now + 5000; /* give other threads 5 secs to get out */
942         p->next = NULL;
943         *l = p;
944 }
945
946 static void ipselffree(struct Ipself *p)
947 {
948         struct Ipself **l, *np;
949         uint64_t now = NOW;
950
951         l = &freeipself;
952         for (np = *l; np; np = *l) {
953                 if (np->expire > now) {
954                         *l = np->next;
955                         kfree(np);
956                         continue;
957                 }
958                 l = &np->next;
959         }
960         p->expire = now + 5000; /* give other threads 5 secs to get out */
961         p->next = NULL;
962         *l = p;
963 }
964
965 /*
966  *  Decrement reference for this address on this link.
967  *  Unlink from selftab if this is the last ref.
968  *      called with c locked
969  */
970 static void
971 remselfcache(struct Fs *f, struct Ipifc *ifc, struct Iplifc *lifc, uint8_t * a)
972 {
973         struct Ipself *p, **l;
974         struct Iplink *link, **l_self, **l_lifc;
975
976         qlock(&f->self->qlock);
977
978         /* find the unique selftab entry */
979         l = &f->self->hash[hashipa(a)];
980         for (p = *l; p; p = *l) {
981                 if (ipcmp(p->a, a) == 0)
982                         break;
983                 l = &p->next;
984         }
985
986         if (p == NULL)
987                 goto out;
988
989         /*
990          *  walk down links from an ifc looking for one
991          *  that matches the selftab entry
992          */
993         l_lifc = &lifc->link;
994         for (link = *l_lifc; link; link = *l_lifc) {
995                 if (link->self == p)
996                         break;
997                 l_lifc = &link->lifclink;
998         }
999
1000         if (link == NULL)
1001                 goto out;
1002
1003         /*
1004          *  walk down the links from the selftab looking for
1005          *  the one we just found
1006          */
1007         l_self = &p->link;
1008         for (link = *l_self; link; link = *l_self) {
1009                 if (link == *(l_lifc))
1010                         break;
1011                 l_self = &link->selflink;
1012         }
1013
1014         if (link == NULL)
1015                 panic("remselfcache");
1016
1017         if (kref_refcnt(&link->ref) > 1)
1018                 goto out;
1019
1020         if ((p->type & Rmulti) && ifc->m->remmulti != NULL)
1021                 (*ifc->m->remmulti) (ifc, a, lifc->local);
1022
1023         /* ref == 0, remove from both chains and free the link */
1024         *l_lifc = link->lifclink;
1025         *l_self = link->selflink;
1026         iplinkfree(link);
1027
1028         if (p->link != NULL)
1029                 goto out;
1030
1031         /* remove from routing table */
1032         if (isv4(a))
1033                 v4delroute(f, a + IPv4off, IPallbits + IPv4off, 1);
1034         else
1035                 v6delroute(f, a, IPallbits, 1);
1036
1037         /* no more links, remove from hash and free */
1038         *l = p->next;
1039         ipselffree(p);
1040
1041         /* if IPnoaddr, forget */
1042         if (ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1043                 f->self->acceptall = 0;
1044
1045 out:
1046         qunlock(&f->self->qlock);
1047 }
1048
1049 static char *stformat = "%-44.44I %2.2d %4.4s\n";
1050 enum {
1051         Nstformat = 41,
1052 };
1053
1054 long ipselftabread(struct Fs *f, char *cp, uint32_t offset, int n)
1055 {
1056         int i, m, nifc, off;
1057         struct Ipself *p;
1058         struct Iplink *link;
1059         char state[8];
1060
1061         m = 0;
1062         off = offset;
1063         qlock(&f->self->qlock);
1064         for (i = 0; i < NHASH && m < n; i++) {
1065                 for (p = f->self->hash[i]; p != NULL && m < n; p = p->next) {
1066                         nifc = 0;
1067                         for (link = p->link; link; link = link->selflink)
1068                                 nifc++;
1069                         routetype(p->type, state);
1070                         m += snprintf(cp + m, n - m, stformat, p->a, nifc, state);
1071                         if (off > 0) {
1072                                 off -= m;
1073                                 m = 0;
1074                         }
1075                 }
1076         }
1077         qunlock(&f->self->qlock);
1078         return m;
1079 }
1080
1081 int iptentative(struct Fs *f, uint8_t * addr)
1082 {
1083         struct Ipself *p;
1084
1085         p = f->self->hash[hashipa(addr)];
1086         for (; p; p = p->next) {
1087                 if (ipcmp(addr, p->a) == 0) {
1088                         return p->link->lifc->tentative;
1089                 }
1090         }
1091         return 0;
1092 }
1093
1094 /*
1095  *  returns
1096  *      0               - no match
1097  *      Runi
1098  *      Rbcast
1099  *      Rmcast
1100  */
1101 int ipforme(struct Fs *f, uint8_t * addr)
1102 {
1103         struct Ipself *p;
1104
1105         p = f->self->hash[hashipa(addr)];
1106         for (; p; p = p->next) {
1107                 if (ipcmp(addr, p->a) == 0)
1108                         return p->type;
1109         }
1110
1111         /* hack to say accept anything */
1112         if (f->self->acceptall)
1113                 return Runi;
1114
1115         return 0;
1116 }
1117
1118 /*
1119  *  find the ifc on same net as the remote system.  If none,
1120  *  return NULL.
1121  */
1122 struct Ipifc *findipifc(struct Fs *f, uint8_t * remote, int type)
1123 {
1124         struct Ipifc *ifc, *x;
1125         struct Iplifc *lifc;
1126         struct conv **cp, **e;
1127         uint8_t gnet[IPaddrlen];
1128         uint8_t xmask[IPaddrlen];
1129
1130         x = NULL;
1131         memset(xmask, 0, IPaddrlen);
1132
1133         /* find most specific match */
1134         e = &f->ipifc->conv[f->ipifc->nc];
1135         for (cp = f->ipifc->conv; cp < e; cp++) {
1136                 if (*cp == 0)
1137                         continue;
1138
1139                 ifc = (struct Ipifc *)(*cp)->ptcl;
1140
1141                 for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1142                         maskip(remote, lifc->mask, gnet);
1143                         if (ipcmp(gnet, lifc->net) == 0) {
1144                                 if (x == NULL || ipcmp(lifc->mask, xmask) > 0) {
1145                                         x = ifc;
1146                                         ipmove(xmask, lifc->mask);
1147                                 }
1148                         }
1149                 }
1150         }
1151         if (x != NULL)
1152                 return x;
1153
1154         /* for now for broadcast and multicast, just use first interface */
1155         if (type & (Rbcast | Rmulti)) {
1156                 for (cp = f->ipifc->conv; cp < e; cp++) {
1157                         if (*cp == 0)
1158                                 continue;
1159                         ifc = (struct Ipifc *)(*cp)->ptcl;
1160                         if (ifc->lifc != NULL)
1161                                 return ifc;
1162                 }
1163         }
1164
1165         return NULL;
1166 }
1167
1168 enum {
1169         unknownv6,
1170         multicastv6,
1171         unspecifiedv6,
1172         linklocalv6,
1173         sitelocalv6,
1174         globalv6,
1175 };
1176
1177 int v6addrtype(uint8_t * addr)
1178 {
1179         if (isv6global(addr))
1180                 return globalv6;
1181         if (islinklocal(addr))
1182                 return linklocalv6;
1183         if (isv6mcast(addr))
1184                 return multicastv6;
1185         if (issitelocal(addr))
1186                 return sitelocalv6;
1187         return unknownv6;
1188 }
1189
1190 #define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (NOW/10^3) ) || ( (lifc)->preflt == UINT64_MAX ))
1191
1192 static void findprimaryipv6(struct Fs *f, uint8_t * local)
1193 {
1194         struct conv **cp, **e;
1195         struct Ipifc *ifc;
1196         struct Iplifc *lifc;
1197         int atype, atypel;
1198
1199         ipmove(local, v6Unspecified);
1200         atype = unspecifiedv6;
1201
1202         /* find "best" (global > sitelocal > link local > unspecified)
1203          * local address; address must be current */
1204
1205         e = &f->ipifc->conv[f->ipifc->nc];
1206         for (cp = f->ipifc->conv; cp < e; cp++) {
1207                 if (*cp == 0)
1208                         continue;
1209                 ifc = (struct Ipifc *)(*cp)->ptcl;
1210                 for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1211                         atypel = v6addrtype(lifc->local);
1212                         if (atypel > atype)
1213                                 if (v6addrcurr(lifc)) {
1214                                         ipmove(local, lifc->local);
1215                                         atype = atypel;
1216                                         if (atype == globalv6)
1217                                                 return;
1218                                 }
1219                 }
1220         }
1221 }
1222
1223 /*
1224  *  returns first ip address configured
1225  */
1226 static void findprimaryipv4(struct Fs *f, uint8_t * local)
1227 {
1228         struct conv **cp, **e;
1229         struct Ipifc *ifc;
1230         struct Iplifc *lifc;
1231
1232         /* find first ifc local address */
1233         e = &f->ipifc->conv[f->ipifc->nc];
1234         for (cp = f->ipifc->conv; cp < e; cp++) {
1235                 if (*cp == 0)
1236                         continue;
1237                 ifc = (struct Ipifc *)(*cp)->ptcl;
1238                 if ((lifc = ifc->lifc) != NULL) {
1239                         ipmove(local, lifc->local);
1240                         return;
1241                 }
1242         }
1243 }
1244
1245 /*
1246  *  find the local address 'closest' to the remote system, copy it to
1247  *  local and return the ifc for that address
1248  */
1249 void findlocalip(struct Fs *f, uint8_t * local, uint8_t * remote)
1250 {
1251         struct Ipifc *ifc;
1252         struct Iplifc *lifc;
1253         struct route *r;
1254         uint8_t gate[IPaddrlen];
1255         uint8_t gnet[IPaddrlen];
1256         int version;
1257         int atype = unspecifiedv6, atypel = unknownv6;
1258
1259         qlock(&f->ipifc->qlock);
1260         r = v6lookup(f, remote, NULL);
1261         version = isv4(remote) ? V4 : V6;
1262
1263         if (r != NULL) {
1264                 ifc = r->rt.ifc;
1265                 if (r->rt.type & Rv4)
1266                         v4tov6(gate, r->v4.gate);
1267                 else {
1268                         ipmove(gate, r->v6.gate);
1269                         ipmove(local, v6Unspecified);
1270                 }
1271
1272                 /* find ifc address closest to the gateway to use */
1273                 switch (version) {
1274                         case V4:
1275                                 for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1276                                         maskip(gate, lifc->mask, gnet);
1277                                         if (ipcmp(gnet, lifc->net) == 0) {
1278                                                 ipmove(local, lifc->local);
1279                                                 goto out;
1280                                         }
1281                                 }
1282                                 break;
1283                         case V6:
1284                                 for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1285                                         atypel = v6addrtype(lifc->local);
1286                                         maskip(gate, lifc->mask, gnet);
1287                                         if (ipcmp(gnet, lifc->net) == 0)
1288                                                 if (atypel > atype)
1289                                                         if (v6addrcurr(lifc)) {
1290                                                                 ipmove(local, lifc->local);
1291                                                                 atype = atypel;
1292                                                                 if (atype == globalv6)
1293                                                                         break;
1294                                                         }
1295                                 }
1296                                 if (atype > unspecifiedv6)
1297                                         goto out;
1298                                 break;
1299                         default:
1300                                 panic("findlocalip: version %d", version);
1301                 }
1302         }
1303
1304         switch (version) {
1305                 case V4:
1306                         findprimaryipv4(f, local);
1307                         break;
1308                 case V6:
1309                         findprimaryipv6(f, local);
1310                         break;
1311                 default:
1312                         panic("findlocalip2: version %d", version);
1313         }
1314
1315 out:
1316         qunlock(&f->ipifc->qlock);
1317 }
1318
1319 /*
1320  *  return first v4 address associated with an interface
1321  */
1322 int ipv4local(struct Ipifc *ifc, uint8_t * addr)
1323 {
1324         struct Iplifc *lifc;
1325
1326         for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1327                 if (isv4(lifc->local)) {
1328                         memmove(addr, lifc->local + IPv4off, IPv4addrlen);
1329                         return 1;
1330                 }
1331         }
1332         return 0;
1333 }
1334
1335 /*
1336  *  return first v6 address associated with an interface
1337  */
1338 int ipv6local(struct Ipifc *ifc, uint8_t * addr)
1339 {
1340         struct Iplifc *lifc;
1341
1342         for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1343                 if (!isv4(lifc->local) && !(lifc->tentative)) {
1344                         ipmove(addr, lifc->local);
1345                         return 1;
1346                 }
1347         }
1348         return 0;
1349 }
1350
1351 int ipv6anylocal(struct Ipifc *ifc, uint8_t * addr)
1352 {
1353         struct Iplifc *lifc;
1354
1355         for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1356                 if (!isv4(lifc->local)) {
1357                         ipmove(addr, lifc->local);
1358                         return SRC_UNI;
1359                 }
1360         }
1361         return SRC_UNSPEC;
1362 }
1363
1364 /*
1365  *  see if this address is bound to the interface
1366  */
1367 struct Iplifc *iplocalonifc(struct Ipifc *ifc, uint8_t * ip)
1368 {
1369         struct Iplifc *lifc;
1370
1371         for (lifc = ifc->lifc; lifc; lifc = lifc->next)
1372                 if (ipcmp(ip, lifc->local) == 0)
1373                         return lifc;
1374         return NULL;
1375 }
1376
1377 /*
1378  *  See if we're proxying for this address on this interface
1379  */
1380 int ipproxyifc(struct Fs *f, struct Ipifc *ifc, uint8_t * ip)
1381 {
1382         struct route *r;
1383         uint8_t net[IPaddrlen];
1384         struct Iplifc *lifc;
1385
1386         /* see if this is a direct connected pt to pt address */
1387         r = v6lookup(f, ip, NULL);
1388         if (r == NULL)
1389                 return 0;
1390         if ((r->rt.type & (Rifc | Rproxy)) != (Rifc | Rproxy))
1391                 return 0;
1392
1393         /* see if this is on the right interface */
1394         for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1395                 maskip(ip, lifc->mask, net);
1396                 if (ipcmp(net, lifc->remote) == 0)
1397                         return 1;
1398         }
1399
1400         return 0;
1401 }
1402
1403 /*
1404  *  return multicast version if any
1405  */
1406 int ipismulticast(uint8_t * ip)
1407 {
1408         if (isv4(ip)) {
1409                 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1410                         return V4;
1411         } else {
1412                 if (ip[0] == 0xff)
1413                         return V6;
1414         }
1415         return 0;
1416 }
1417
1418 int ipisbm(uint8_t * ip)
1419 {
1420         if (isv4(ip)) {
1421                 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1422                         return V4;
1423                 if (ipcmp(ip, IPv4bcast) == 0)
1424                         return V4;
1425         } else {
1426                 if (ip[0] == 0xff)
1427                         return V6;
1428         }
1429         return 0;
1430 }
1431
1432 /*
1433  *  add a multicast address to an interface, called with c locked
1434  */
1435 void ipifcaddmulti(struct conv *c, uint8_t * ma, uint8_t * ia)
1436 {
1437         ERRSTACK(1);
1438         struct Ipifc *ifc;
1439         struct Iplifc *lifc;
1440         struct conv **p;
1441         struct Ipmulti *multi, **l;
1442         struct Fs *f;
1443
1444         f = c->p->f;
1445
1446         for (l = &c->multi; *l; l = &(*l)->next)
1447                 if (ipcmp(ma, (*l)->ma) == 0)
1448                         if (ipcmp(ia, (*l)->ia) == 0)
1449                                 return; /* it's already there */
1450
1451         multi = *l = kzmalloc(sizeof(*multi), 0);
1452         ipmove(multi->ma, ma);
1453         ipmove(multi->ia, ia);
1454         multi->next = NULL;
1455
1456         for (p = f->ipifc->conv; *p; p++) {
1457                 if ((*p)->inuse == 0)
1458                         continue;
1459                 ifc = (struct Ipifc *)(*p)->ptcl;
1460                 if (waserror()) {
1461                         wunlock(&ifc->rwlock);
1462                         nexterror();
1463                 }
1464                 wlock(&ifc->rwlock);
1465                 for (lifc = ifc->lifc; lifc; lifc = lifc->next)
1466                         if (ipcmp(ia, lifc->local) == 0)
1467                                 addselfcache(f, ifc, lifc, ma, Rmulti);
1468                 wunlock(&ifc->rwlock);
1469                 poperror();
1470         }
1471 }
1472
1473 /*
1474  *  remove a multicast address from an interface, called with c locked
1475  */
1476 void ipifcremmulti(struct conv *c, uint8_t * ma, uint8_t * ia)
1477 {
1478         ERRSTACK(1);
1479         struct Ipmulti *multi, **l;
1480         struct Iplifc *lifc;
1481         struct conv **p;
1482         struct Ipifc *ifc;
1483         struct Fs *f;
1484
1485         f = c->p->f;
1486
1487         for (l = &c->multi; *l; l = &(*l)->next)
1488                 if (ipcmp(ma, (*l)->ma) == 0)
1489                         if (ipcmp(ia, (*l)->ia) == 0)
1490                                 break;
1491
1492         multi = *l;
1493         if (multi == NULL)
1494                 return; /* we don't have it open */
1495
1496         *l = multi->next;
1497
1498         for (p = f->ipifc->conv; *p; p++) {
1499                 if ((*p)->inuse == 0)
1500                         continue;
1501
1502                 ifc = (struct Ipifc *)(*p)->ptcl;
1503                 if (waserror()) {
1504                         wunlock(&ifc->rwlock);
1505                         nexterror();
1506                 }
1507                 wlock(&ifc->rwlock);
1508                 for (lifc = ifc->lifc; lifc; lifc = lifc->next)
1509                         if (ipcmp(ia, lifc->local) == 0)
1510                                 remselfcache(f, ifc, lifc, ma);
1511                 wunlock(&ifc->rwlock);
1512                 poperror();
1513         }
1514
1515         kfree(multi);
1516 }
1517
1518 /*
1519  *  make lifc's join and leave multicast groups
1520  */
1521 static char *ipifcjoinmulti(struct Ipifc *ifc, char **argv, int argc)
1522 {
1523         return NULL;
1524 }
1525
1526 static char *ipifcleavemulti(struct Ipifc *ifc, char **argv, int argc)
1527 {
1528         return NULL;
1529 }
1530
1531 static void ipifcregisterproxy(struct Fs *f, struct Ipifc *ifc, uint8_t * ip)
1532 {
1533         struct conv **cp, **e;
1534         struct Ipifc *nifc;
1535         struct Iplifc *lifc;
1536         struct medium *m;
1537         uint8_t net[IPaddrlen];
1538
1539         /* register the address on any network that will proxy for us */
1540         e = &f->ipifc->conv[f->ipifc->nc];
1541
1542         if (!isv4(ip)) {        // V6
1543                 for (cp = f->ipifc->conv; cp < e; cp++) {
1544                         if (*cp == NULL)
1545                                 continue;
1546                         nifc = (struct Ipifc *)(*cp)->ptcl;
1547                         if (nifc == ifc)
1548                                 continue;
1549
1550                         rlock(&nifc->rwlock);
1551                         m = nifc->m;
1552                         if (m == NULL || m->addmulti == NULL) {
1553                                 runlock(&nifc->rwlock);
1554                                 continue;
1555                         }
1556                         for (lifc = nifc->lifc; lifc; lifc = lifc->next) {
1557                                 maskip(ip, lifc->mask, net);
1558                                 if (ipcmp(net, lifc->remote) == 0) {    /* add solicited-node multicast address */
1559                                         ipv62smcast(net, ip);
1560                                         addselfcache(f, nifc, lifc, net, Rmulti);
1561                                         arpenter(f, V6, ip, nifc->mac, 6, 0);
1562                                         //(*m->addmulti)(nifc, net, ip);
1563                                         break;
1564                                 }
1565                         }
1566                         runlock(&nifc->rwlock);
1567                 }
1568                 return;
1569         } else {        // V4
1570                 for (cp = f->ipifc->conv; cp < e; cp++) {
1571                         if (*cp == NULL)
1572                                 continue;
1573                         nifc = (struct Ipifc *)(*cp)->ptcl;
1574                         if (nifc == ifc)
1575                                 continue;
1576
1577                         rlock(&nifc->rwlock);
1578                         m = nifc->m;
1579                         if (m == NULL || m->areg == NULL) {
1580                                 runlock(&nifc->rwlock);
1581                                 continue;
1582                         }
1583                         for (lifc = nifc->lifc; lifc; lifc = lifc->next) {
1584                                 maskip(ip, lifc->mask, net);
1585                                 if (ipcmp(net, lifc->remote) == 0) {
1586                                         (*m->areg) (nifc, ip);
1587                                         break;
1588                                 }
1589                         }
1590                         runlock(&nifc->rwlock);
1591                 }
1592         }
1593 }
1594
1595 // added for new v6 mesg types
1596 static void adddefroute6(struct Fs *f, uint8_t * gate, int force)
1597 {
1598         struct route *r;
1599
1600         r = v6lookup(f, v6Unspecified, NULL);
1601         if (r != NULL)
1602                 if (!(force) && (strcmp(r->rt.tag, "ra") != 0)) // route entries generated
1603                         return; // by all other means take
1604         // precedence over router annc
1605
1606         v6delroute(f, v6Unspecified, v6Unspecified, 1);
1607         v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
1608 }
1609
1610 enum {
1611         Ngates = 3,
1612 };
1613
1614 char *ipifcaddpref6(struct Ipifc *ifc, char **argv, int argc)
1615 {
1616         uint8_t onlink = 1;
1617         uint8_t autoflag = 1;
1618         uint64_t validlt = UINT64_MAX;
1619         uint64_t preflt = UINT64_MAX;
1620         uint64_t origint = NOW / 10 ^ 3;
1621         uint8_t prefix[IPaddrlen];
1622         int plen = 64;
1623         struct Iplifc *lifc;
1624         char addr[40], preflen[6];
1625         char *params[3];
1626
1627         switch (argc) {
1628                 case 7:
1629                         preflt = atoi(argv[6]);
1630                         /* fall through */
1631                 case 6:
1632                         validlt = atoi(argv[5]);
1633                         /* fall through */
1634                 case 5:
1635                         autoflag = atoi(argv[4]);
1636                         /* fall through */
1637                 case 4:
1638                         onlink = atoi(argv[3]);
1639                         /* fall through */
1640                 case 3:
1641                         plen = atoi(argv[2]);
1642                 case 2:
1643                         break;
1644                 default:
1645                         return Ebadarg;
1646         }
1647
1648         if ((parseip(prefix, argv[1]) != 6) ||
1649                 (validlt < preflt) || (plen < 0) || (plen > 64) || (islinklocal(prefix))
1650                 )
1651                 return Ebadarg;
1652
1653         lifc = kzmalloc(sizeof(struct Iplifc), 0);
1654         lifc->onlink = (onlink != 0);
1655         lifc->autoflag = (autoflag != 0);
1656         lifc->validlt = validlt;
1657         lifc->preflt = preflt;
1658         lifc->origint = origint;
1659
1660         if (ifc->m->pref2addr != NULL)
1661                 ifc->m->pref2addr(prefix, ifc->mac);
1662         else
1663                 return Ebadarg;
1664
1665         snprintf(addr, sizeof(addr), "%I", prefix);
1666         snprintf(preflen, sizeof(preflen), "/%d", plen);
1667         params[0] = "add";
1668         params[1] = addr;
1669         params[2] = preflen;
1670
1671         return ipifcadd(ifc, params, 3, 0, lifc);
1672 }