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