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