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