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