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