Have #ip's protocol ctl()s throw errors
[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 void ipifcctl(struct conv *c, char **argv, int argc)
806 {
807         struct Ipifc *ifc;
808         int i;
809
810         ifc = (struct Ipifc *)c->ptcl;
811         if (strcmp(argv[0], "add") == 0)
812                 ipifcadd(ifc, argv, argc, 0, NULL);
813         else if (strcmp(argv[0], "try") == 0)
814                 ipifcadd(ifc, argv, argc, 1, NULL);
815         else if (strcmp(argv[0], "remove") == 0)
816                 ipifcrem(ifc, argv, argc);
817         else if (strcmp(argv[0], "unbind") == 0)
818                 ipifcunbind(ifc);
819         else if (strcmp(argv[0], "joinmulti") == 0)
820                 ipifcjoinmulti(ifc, argv, argc);
821         else if (strcmp(argv[0], "leavemulti") == 0)
822                 ipifcleavemulti(ifc, argv, argc);
823         else if (strcmp(argv[0], "mtu") == 0)
824                 ipifcsetmtu(ifc, argv, argc);
825         else if (strcmp(argv[0], "reassemble") == 0)
826                 ifc->reassemble = 1;
827         else if (strcmp(argv[0], "iprouting") == 0)
828                 ipifc_iprouting(c->p->f, argv, argc);
829         else if (strcmp(argv[0], "addpref6") == 0)
830                 ipifcaddpref6(ifc, argv, argc);
831         else if (strcmp(argv[0], "setpar6") == 0)
832                 ipifcsetpar6(ifc, argv, argc);
833         else if (strcmp(argv[0], "sendra6") == 0)
834                 ipifcsendra6(ifc, argv, argc);
835         else if (strcmp(argv[0], "recvra6") == 0)
836                 ipifcrecvra6(ifc, argv, argc);
837         else
838                 error(EINVAL, "unknown command to %s", __func__);
839 }
840
841 int ipifcstats(struct Proto *ipifc, char *buf, int len)
842 {
843         return ipstats(ipifc->f, buf, len);
844 }
845
846 void ipifcinit(struct Fs *f)
847 {
848         struct Proto *ipifc;
849
850         ipifc = kzmalloc(sizeof(struct Proto), 0);
851         ipifc->name = "ipifc";
852         ipifc->connect = ipifcconnect;
853         ipifc->announce = NULL;
854         ipifc->bind = ipifcbind;
855         ipifc->state = ipifcstate;
856         ipifc->create = ipifccreate;
857         ipifc->close = ipifcclose;
858         ipifc->rcv = NULL;
859         ipifc->ctl = ipifcctl;
860         ipifc->advise = NULL;
861         ipifc->stats = ipifcstats;
862         ipifc->inuse = ipifcinuse;
863         ipifc->local = ipifclocal;
864         ipifc->ipproto = -1;
865         ipifc->nc = Maxmedia;
866         ipifc->ptclsize = sizeof(struct Ipifc);
867
868         f->ipifc = ipifc;       /* hack for ipifcremroute, findipifc, ... */
869         f->self = kzmalloc(sizeof(struct Ipselftab), 0);        /* hack for ipforme */
870         qlock_init(&f->self->qlock);
871
872         Fsproto(f, ipifc);
873 }
874
875 /*
876  *  add to self routing cache
877  *      called with c locked
878  */
879 static void
880 addselfcache(struct Fs *f, struct Ipifc *ifc,
881                          struct Iplifc *lifc, uint8_t * a, int type)
882 {
883         struct Ipself *p;
884         struct Iplink *lp;
885         int h;
886
887         qlock(&f->self->qlock);
888
889         /* see if the address already exists */
890         h = hashipa(a);
891         for (p = f->self->hash[h]; p; p = p->next)
892                 if (memcmp(a, p->a, IPaddrlen) == 0)
893                         break;
894
895         /* allocate a local address and add to hash chain */
896         if (p == NULL) {
897                 p = kzmalloc(sizeof(*p), 0);
898                 ipmove(p->a, a);
899                 p->type = type;
900                 p->next = f->self->hash[h];
901                 f->self->hash[h] = p;
902
903                 /* if the null address, accept all packets */
904                 if (ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
905                         f->self->acceptall = 1;
906         }
907
908         /* look for a link for this lifc */
909         for (lp = p->link; lp; lp = lp->selflink)
910                 if (lp->lifc == lifc)
911                         break;
912
913         /* allocate a lifc-to-local link and link to both */
914         if (lp == NULL) {
915                 lp = kzmalloc(sizeof(*lp), 0);
916                 kref_init(&lp->ref, fake_release, 1);
917                 lp->lifc = lifc;
918                 lp->self = p;
919                 lp->selflink = p->link;
920                 p->link = lp;
921                 lp->lifclink = lifc->link;
922                 lifc->link = lp;
923
924                 /* add to routing table */
925                 if (isv4(a))
926                         v4addroute(f, tifc, a + IPv4off, IPallbits + IPv4off, a + IPv4off,
927                                            type);
928                 else
929                         v6addroute(f, tifc, a, IPallbits, a, type);
930
931                 if ((type & Rmulti) && ifc->m->addmulti != NULL)
932                         (*ifc->m->addmulti) (ifc, a, lifc->local);
933         } else {
934                 kref_get(&lp->ref, 1);
935         }
936
937         qunlock(&f->self->qlock);
938 }
939
940 /*
941  *  These structures are unlinked from their chains while
942  *  other threads may be using them.  To avoid excessive locking,
943  *  just put them aside for a while before freeing them.
944  *      called with f->self locked
945  */
946 static struct Iplink *freeiplink;
947 static struct Ipself *freeipself;
948
949 static void iplinkfree(struct Iplink *p)
950 {
951         struct Iplink **l, *np;
952         uint64_t now = NOW;
953
954         l = &freeiplink;
955         for (np = *l; np; np = *l) {
956                 if (np->expire > now) {
957                         *l = np->next;
958                         kfree(np);
959                         continue;
960                 }
961                 l = &np->next;
962         }
963         p->expire = now + 5000; /* give other threads 5 secs to get out */
964         p->next = NULL;
965         *l = p;
966 }
967
968 static void ipselffree(struct Ipself *p)
969 {
970         struct Ipself **l, *np;
971         uint64_t now = NOW;
972
973         l = &freeipself;
974         for (np = *l; np; np = *l) {
975                 if (np->expire > now) {
976                         *l = np->next;
977                         kfree(np);
978                         continue;
979                 }
980                 l = &np->next;
981         }
982         p->expire = now + 5000; /* give other threads 5 secs to get out */
983         p->next = NULL;
984         *l = p;
985 }
986
987 /*
988  *  Decrement reference for this address on this link.
989  *  Unlink from selftab if this is the last ref.
990  *      called with c locked
991  */
992 static void
993 remselfcache(struct Fs *f, struct Ipifc *ifc, struct Iplifc *lifc, uint8_t * a)
994 {
995         struct Ipself *p, **l;
996         struct Iplink *link, **l_self, **l_lifc;
997
998         qlock(&f->self->qlock);
999
1000         /* find the unique selftab entry */
1001         l = &f->self->hash[hashipa(a)];
1002         for (p = *l; p; p = *l) {
1003                 if (ipcmp(p->a, a) == 0)
1004                         break;
1005                 l = &p->next;
1006         }
1007
1008         if (p == NULL)
1009                 goto out;
1010
1011         /*
1012          *  walk down links from an ifc looking for one
1013          *  that matches the selftab entry
1014          */
1015         l_lifc = &lifc->link;
1016         for (link = *l_lifc; link; link = *l_lifc) {
1017                 if (link->self == p)
1018                         break;
1019                 l_lifc = &link->lifclink;
1020         }
1021
1022         if (link == NULL)
1023                 goto out;
1024
1025         /*
1026          *  walk down the links from the selftab looking for
1027          *  the one we just found
1028          */
1029         l_self = &p->link;
1030         for (link = *l_self; link; link = *l_self) {
1031                 if (link == *(l_lifc))
1032                         break;
1033                 l_self = &link->selflink;
1034         }
1035
1036         if (link == NULL)
1037                 panic("remselfcache");
1038
1039         if (kref_refcnt(&link->ref) > 1)
1040                 goto out;
1041
1042         if ((p->type & Rmulti) && ifc->m->remmulti != NULL)
1043                 (*ifc->m->remmulti) (ifc, a, lifc->local);
1044
1045         /* ref == 0, remove from both chains and free the link */
1046         *l_lifc = link->lifclink;
1047         *l_self = link->selflink;
1048         iplinkfree(link);
1049
1050         if (p->link != NULL)
1051                 goto out;
1052
1053         /* remove from routing table */
1054         if (isv4(a))
1055                 v4delroute(f, a + IPv4off, IPallbits + IPv4off, 1);
1056         else
1057                 v6delroute(f, a, IPallbits, 1);
1058
1059         /* no more links, remove from hash and free */
1060         *l = p->next;
1061         ipselffree(p);
1062
1063         /* if IPnoaddr, forget */
1064         if (ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
1065                 f->self->acceptall = 0;
1066
1067 out:
1068         qunlock(&f->self->qlock);
1069 }
1070
1071 static char *stformat = "%-44.44I %2.2d %4.4s\n";
1072 enum {
1073         Nstformat = 41,
1074 };
1075
1076 long ipselftabread(struct Fs *f, char *cp, uint32_t offset, int n)
1077 {
1078         int i, m, nifc, off;
1079         struct Ipself *p;
1080         struct Iplink *link;
1081         char state[8];
1082
1083         m = 0;
1084         off = offset;
1085         qlock(&f->self->qlock);
1086         for (i = 0; i < NHASH && m < n; i++) {
1087                 for (p = f->self->hash[i]; p != NULL && m < n; p = p->next) {
1088                         nifc = 0;
1089                         for (link = p->link; link; link = link->selflink)
1090                                 nifc++;
1091                         routetype(p->type, state);
1092                         m += snprintf(cp + m, n - m, stformat, p->a, nifc, state);
1093                         if (off > 0) {
1094                                 off -= m;
1095                                 m = 0;
1096                         }
1097                 }
1098         }
1099         qunlock(&f->self->qlock);
1100         return m;
1101 }
1102
1103 int iptentative(struct Fs *f, uint8_t * addr)
1104 {
1105         struct Ipself *p;
1106
1107         p = f->self->hash[hashipa(addr)];
1108         for (; p; p = p->next) {
1109                 if (ipcmp(addr, p->a) == 0) {
1110                         return p->link->lifc->tentative;
1111                 }
1112         }
1113         return 0;
1114 }
1115
1116 /*
1117  *  returns
1118  *      0               - no match
1119  *      Runi
1120  *      Rbcast
1121  *      Rmcast
1122  */
1123 int ipforme(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->type;
1131         }
1132
1133         /* hack to say accept anything */
1134         if (f->self->acceptall)
1135                 return Runi;
1136
1137         return 0;
1138 }
1139
1140 /*
1141  *  find the ifc on same net as the remote system.  If none,
1142  *  return NULL.
1143  */
1144 struct Ipifc *findipifc(struct Fs *f, uint8_t * remote, int type)
1145 {
1146         struct Ipifc *ifc, *x;
1147         struct Iplifc *lifc;
1148         struct conv **cp, **e;
1149         uint8_t gnet[IPaddrlen];
1150         uint8_t xmask[IPaddrlen];
1151
1152         x = NULL;
1153         memset(xmask, 0, IPaddrlen);
1154
1155         /* find most specific match */
1156         e = &f->ipifc->conv[f->ipifc->nc];
1157         for (cp = f->ipifc->conv; cp < e; cp++) {
1158                 if (*cp == 0)
1159                         continue;
1160
1161                 ifc = (struct Ipifc *)(*cp)->ptcl;
1162
1163                 for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1164                         maskip(remote, lifc->mask, gnet);
1165                         if (ipcmp(gnet, lifc->net) == 0) {
1166                                 if (x == NULL || ipcmp(lifc->mask, xmask) > 0) {
1167                                         x = ifc;
1168                                         ipmove(xmask, lifc->mask);
1169                                 }
1170                         }
1171                 }
1172         }
1173         if (x != NULL)
1174                 return x;
1175
1176         /* for now for broadcast and multicast, just use first interface */
1177         if (type & (Rbcast | Rmulti)) {
1178                 for (cp = f->ipifc->conv; cp < e; cp++) {
1179                         if (*cp == 0)
1180                                 continue;
1181                         ifc = (struct Ipifc *)(*cp)->ptcl;
1182                         if (ifc->lifc != NULL)
1183                                 return ifc;
1184                 }
1185         }
1186
1187         return NULL;
1188 }
1189
1190 enum {
1191         unknownv6,
1192         multicastv6,
1193         unspecifiedv6,
1194         linklocalv6,
1195         sitelocalv6,
1196         globalv6,
1197 };
1198
1199 int v6addrtype(uint8_t * addr)
1200 {
1201         if (isv6global(addr))
1202                 return globalv6;
1203         if (islinklocal(addr))
1204                 return linklocalv6;
1205         if (isv6mcast(addr))
1206                 return multicastv6;
1207         if (issitelocal(addr))
1208                 return sitelocalv6;
1209         return unknownv6;
1210 }
1211
1212 #define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (NOW/10^3) ) || ( (lifc)->preflt == UINT64_MAX ))
1213
1214 static void findprimaryipv6(struct Fs *f, uint8_t * local)
1215 {
1216         struct conv **cp, **e;
1217         struct Ipifc *ifc;
1218         struct Iplifc *lifc;
1219         int atype, atypel;
1220
1221         ipmove(local, v6Unspecified);
1222         atype = unspecifiedv6;
1223
1224         /* find "best" (global > sitelocal > link local > unspecified)
1225          * local address; address must be current */
1226
1227         e = &f->ipifc->conv[f->ipifc->nc];
1228         for (cp = f->ipifc->conv; cp < e; cp++) {
1229                 if (*cp == 0)
1230                         continue;
1231                 ifc = (struct Ipifc *)(*cp)->ptcl;
1232                 for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1233                         atypel = v6addrtype(lifc->local);
1234                         if (atypel > atype)
1235                                 if (v6addrcurr(lifc)) {
1236                                         ipmove(local, lifc->local);
1237                                         atype = atypel;
1238                                         if (atype == globalv6)
1239                                                 return;
1240                                 }
1241                 }
1242         }
1243 }
1244
1245 /*
1246  *  returns first ip address configured
1247  */
1248 static void findprimaryipv4(struct Fs *f, uint8_t * local)
1249 {
1250         struct conv **cp, **e;
1251         struct Ipifc *ifc;
1252         struct Iplifc *lifc;
1253
1254         /* find first ifc local address */
1255         e = &f->ipifc->conv[f->ipifc->nc];
1256         for (cp = f->ipifc->conv; cp < e; cp++) {
1257                 if (*cp == 0)
1258                         continue;
1259                 ifc = (struct Ipifc *)(*cp)->ptcl;
1260                 if ((lifc = ifc->lifc) != NULL) {
1261                         ipmove(local, lifc->local);
1262                         return;
1263                 }
1264         }
1265 }
1266
1267 /*
1268  *  find the local address 'closest' to the remote system, copy it to
1269  *  local and return the ifc for that address
1270  */
1271 void findlocalip(struct Fs *f, uint8_t * local, uint8_t * remote)
1272 {
1273         struct Ipifc *ifc;
1274         struct Iplifc *lifc;
1275         struct route *r;
1276         uint8_t gate[IPaddrlen];
1277         uint8_t gnet[IPaddrlen];
1278         int version;
1279         int atype = unspecifiedv6, atypel = unknownv6;
1280
1281         qlock(&f->ipifc->qlock);
1282         r = v6lookup(f, remote, NULL);
1283         version = isv4(remote) ? V4 : V6;
1284
1285         if (r != NULL) {
1286                 ifc = r->rt.ifc;
1287                 if (r->rt.type & Rv4)
1288                         v4tov6(gate, r->v4.gate);
1289                 else {
1290                         ipmove(gate, r->v6.gate);
1291                         ipmove(local, v6Unspecified);
1292                 }
1293
1294                 /* find ifc address closest to the gateway to use */
1295                 switch (version) {
1296                         case V4:
1297                                 for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1298                                         maskip(gate, lifc->mask, gnet);
1299                                         if (ipcmp(gnet, lifc->net) == 0) {
1300                                                 ipmove(local, lifc->local);
1301                                                 goto out;
1302                                         }
1303                                 }
1304                                 break;
1305                         case V6:
1306                                 for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1307                                         atypel = v6addrtype(lifc->local);
1308                                         maskip(gate, lifc->mask, gnet);
1309                                         if (ipcmp(gnet, lifc->net) == 0)
1310                                                 if (atypel > atype)
1311                                                         if (v6addrcurr(lifc)) {
1312                                                                 ipmove(local, lifc->local);
1313                                                                 atype = atypel;
1314                                                                 if (atype == globalv6)
1315                                                                         break;
1316                                                         }
1317                                 }
1318                                 if (atype > unspecifiedv6)
1319                                         goto out;
1320                                 break;
1321                         default:
1322                                 panic("findlocalip: version %d", version);
1323                 }
1324         }
1325
1326         switch (version) {
1327                 case V4:
1328                         findprimaryipv4(f, local);
1329                         break;
1330                 case V6:
1331                         findprimaryipv6(f, local);
1332                         break;
1333                 default:
1334                         panic("findlocalip2: version %d", version);
1335         }
1336
1337 out:
1338         qunlock(&f->ipifc->qlock);
1339 }
1340
1341 /*
1342  *  return first v4 address associated with an interface
1343  */
1344 int ipv4local(struct Ipifc *ifc, uint8_t * addr)
1345 {
1346         struct Iplifc *lifc;
1347
1348         for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1349                 if (isv4(lifc->local)) {
1350                         memmove(addr, lifc->local + IPv4off, IPv4addrlen);
1351                         return 1;
1352                 }
1353         }
1354         return 0;
1355 }
1356
1357 /*
1358  *  return first v6 address associated with an interface
1359  */
1360 int ipv6local(struct Ipifc *ifc, uint8_t * addr)
1361 {
1362         struct Iplifc *lifc;
1363
1364         for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1365                 if (!isv4(lifc->local) && !(lifc->tentative)) {
1366                         ipmove(addr, lifc->local);
1367                         return 1;
1368                 }
1369         }
1370         return 0;
1371 }
1372
1373 int ipv6anylocal(struct Ipifc *ifc, uint8_t * addr)
1374 {
1375         struct Iplifc *lifc;
1376
1377         for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1378                 if (!isv4(lifc->local)) {
1379                         ipmove(addr, lifc->local);
1380                         return SRC_UNI;
1381                 }
1382         }
1383         return SRC_UNSPEC;
1384 }
1385
1386 /*
1387  *  see if this address is bound to the interface
1388  */
1389 struct Iplifc *iplocalonifc(struct Ipifc *ifc, uint8_t * ip)
1390 {
1391         struct Iplifc *lifc;
1392
1393         for (lifc = ifc->lifc; lifc; lifc = lifc->next)
1394                 if (ipcmp(ip, lifc->local) == 0)
1395                         return lifc;
1396         return NULL;
1397 }
1398
1399 /*
1400  *  See if we're proxying for this address on this interface
1401  */
1402 int ipproxyifc(struct Fs *f, struct Ipifc *ifc, uint8_t * ip)
1403 {
1404         struct route *r;
1405         uint8_t net[IPaddrlen];
1406         struct Iplifc *lifc;
1407
1408         /* see if this is a direct connected pt to pt address */
1409         r = v6lookup(f, ip, NULL);
1410         if (r == NULL)
1411                 return 0;
1412         if ((r->rt.type & (Rifc | Rproxy)) != (Rifc | Rproxy))
1413                 return 0;
1414
1415         /* see if this is on the right interface */
1416         for (lifc = ifc->lifc; lifc; lifc = lifc->next) {
1417                 maskip(ip, lifc->mask, net);
1418                 if (ipcmp(net, lifc->remote) == 0)
1419                         return 1;
1420         }
1421
1422         return 0;
1423 }
1424
1425 /*
1426  *  return multicast version if any
1427  */
1428 int ipismulticast(uint8_t * ip)
1429 {
1430         if (isv4(ip)) {
1431                 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1432                         return V4;
1433         } else {
1434                 if (ip[0] == 0xff)
1435                         return V6;
1436         }
1437         return 0;
1438 }
1439
1440 int ipisbm(uint8_t * ip)
1441 {
1442         if (isv4(ip)) {
1443                 if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
1444                         return V4;
1445                 if (ipcmp(ip, IPv4bcast) == 0)
1446                         return V4;
1447         } else {
1448                 if (ip[0] == 0xff)
1449                         return V6;
1450         }
1451         return 0;
1452 }
1453
1454 /*
1455  *  add a multicast address to an interface, called with c locked
1456  */
1457 void ipifcaddmulti(struct conv *c, uint8_t * ma, uint8_t * ia)
1458 {
1459         ERRSTACK(1);
1460         struct Ipifc *ifc;
1461         struct Iplifc *lifc;
1462         struct conv **p;
1463         struct Ipmulti *multi, **l;
1464         struct Fs *f;
1465
1466         f = c->p->f;
1467
1468         for (l = &c->multi; *l; l = &(*l)->next)
1469                 if (ipcmp(ma, (*l)->ma) == 0)
1470                         if (ipcmp(ia, (*l)->ia) == 0)
1471                                 return; /* it's already there */
1472
1473         multi = *l = kzmalloc(sizeof(*multi), 0);
1474         ipmove(multi->ma, ma);
1475         ipmove(multi->ia, ia);
1476         multi->next = NULL;
1477
1478         for (p = f->ipifc->conv; *p; p++) {
1479                 if ((*p)->inuse == 0)
1480                         continue;
1481                 ifc = (struct Ipifc *)(*p)->ptcl;
1482                 wlock(&ifc->rwlock);
1483                 if (waserror()) {
1484                         wunlock(&ifc->rwlock);
1485                         nexterror();
1486                 }
1487                 for (lifc = ifc->lifc; lifc; lifc = lifc->next)
1488                         if (ipcmp(ia, lifc->local) == 0)
1489                                 addselfcache(f, ifc, lifc, ma, Rmulti);
1490                 wunlock(&ifc->rwlock);
1491                 poperror();
1492         }
1493 }
1494
1495 /*
1496  *  remove a multicast address from an interface, called with c locked
1497  */
1498 void ipifcremmulti(struct conv *c, uint8_t * ma, uint8_t * ia)
1499 {
1500         ERRSTACK(1);
1501         struct Ipmulti *multi, **l;
1502         struct Iplifc *lifc;
1503         struct conv **p;
1504         struct Ipifc *ifc;
1505         struct Fs *f;
1506
1507         f = c->p->f;
1508
1509         for (l = &c->multi; *l; l = &(*l)->next)
1510                 if (ipcmp(ma, (*l)->ma) == 0)
1511                         if (ipcmp(ia, (*l)->ia) == 0)
1512                                 break;
1513
1514         multi = *l;
1515         if (multi == NULL)
1516                 return; /* we don't have it open */
1517
1518         *l = multi->next;
1519
1520         for (p = f->ipifc->conv; *p; p++) {
1521                 if ((*p)->inuse == 0)
1522                         continue;
1523
1524                 ifc = (struct Ipifc *)(*p)->ptcl;
1525                 wlock(&ifc->rwlock);
1526                 if (waserror()) {
1527                         wunlock(&ifc->rwlock);
1528                         nexterror();
1529                 }
1530                 for (lifc = ifc->lifc; lifc; lifc = lifc->next)
1531                         if (ipcmp(ia, lifc->local) == 0)
1532                                 remselfcache(f, ifc, lifc, ma);
1533                 wunlock(&ifc->rwlock);
1534                 poperror();
1535         }
1536
1537         kfree(multi);
1538 }
1539
1540 /*
1541  *  make lifc's join and leave multicast groups
1542  */
1543 static void ipifcjoinmulti(struct Ipifc *ifc, char **argv, int argc)
1544 {
1545         warn_once("Not implemented, should it be?");
1546 }
1547
1548 static void ipifcleavemulti(struct Ipifc *ifc, char **argv, int argc)
1549 {
1550         warn_once("Not implemented, should it be?");
1551 }
1552
1553 static void ipifcregisterproxy(struct Fs *f, struct Ipifc *ifc, uint8_t * ip)
1554 {
1555         struct conv **cp, **e;
1556         struct Ipifc *nifc;
1557         struct Iplifc *lifc;
1558         struct medium *m;
1559         uint8_t net[IPaddrlen];
1560
1561         /* register the address on any network that will proxy for us */
1562         e = &f->ipifc->conv[f->ipifc->nc];
1563
1564         if (!isv4(ip)) {        // V6
1565                 for (cp = f->ipifc->conv; cp < e; cp++) {
1566                         if (*cp == NULL)
1567                                 continue;
1568                         nifc = (struct Ipifc *)(*cp)->ptcl;
1569                         if (nifc == ifc)
1570                                 continue;
1571
1572                         rlock(&nifc->rwlock);
1573                         m = nifc->m;
1574                         if (m == NULL || m->addmulti == NULL) {
1575                                 runlock(&nifc->rwlock);
1576                                 continue;
1577                         }
1578                         for (lifc = nifc->lifc; lifc; lifc = lifc->next) {
1579                                 maskip(ip, lifc->mask, net);
1580                                 if (ipcmp(net, lifc->remote) == 0) {    /* add solicited-node multicast address */
1581                                         ipv62smcast(net, ip);
1582                                         addselfcache(f, nifc, lifc, net, Rmulti);
1583                                         arpenter(f, V6, ip, nifc->mac, 6, 0);
1584                                         //(*m->addmulti)(nifc, net, ip);
1585                                         break;
1586                                 }
1587                         }
1588                         runlock(&nifc->rwlock);
1589                 }
1590                 return;
1591         } else {        // V4
1592                 for (cp = f->ipifc->conv; cp < e; cp++) {
1593                         if (*cp == NULL)
1594                                 continue;
1595                         nifc = (struct Ipifc *)(*cp)->ptcl;
1596                         if (nifc == ifc)
1597                                 continue;
1598
1599                         rlock(&nifc->rwlock);
1600                         m = nifc->m;
1601                         if (m == NULL || m->areg == NULL) {
1602                                 runlock(&nifc->rwlock);
1603                                 continue;
1604                         }
1605                         for (lifc = nifc->lifc; lifc; lifc = lifc->next) {
1606                                 maskip(ip, lifc->mask, net);
1607                                 if (ipcmp(net, lifc->remote) == 0) {
1608                                         (*m->areg) (nifc, ip);
1609                                         break;
1610                                 }
1611                         }
1612                         runlock(&nifc->rwlock);
1613                 }
1614         }
1615 }
1616
1617 // added for new v6 mesg types
1618 static void adddefroute6(struct Fs *f, uint8_t * gate, int force)
1619 {
1620         struct route *r;
1621
1622         r = v6lookup(f, v6Unspecified, NULL);
1623         if (r != NULL)
1624                 if (!(force) && (strcmp(r->rt.tag, "ra") != 0)) // route entries generated
1625                         return; // by all other means take
1626         // precedence over router annc
1627
1628         v6delroute(f, v6Unspecified, v6Unspecified, 1);
1629         v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
1630 }
1631
1632 enum {
1633         Ngates = 3,
1634 };
1635
1636 static void ipifcaddpref6(struct Ipifc *ifc, char **argv, int argc)
1637 {
1638         uint8_t onlink = 1;
1639         uint8_t autoflag = 1;
1640         uint64_t validlt = UINT64_MAX;
1641         uint64_t preflt = UINT64_MAX;
1642         uint64_t origint = NOW / 10 ^ 3;
1643         uint8_t prefix[IPaddrlen];
1644         int plen = 64;
1645         struct Iplifc *lifc;
1646         char addr[40], preflen[6];
1647         char *params[3];
1648
1649         switch (argc) {
1650                 case 7:
1651                         preflt = atoi(argv[6]);
1652                         /* fall through */
1653                 case 6:
1654                         validlt = atoi(argv[5]);
1655                         /* fall through */
1656                 case 5:
1657                         autoflag = atoi(argv[4]);
1658                         /* fall through */
1659                 case 4:
1660                         onlink = atoi(argv[3]);
1661                         /* fall through */
1662                 case 3:
1663                         plen = atoi(argv[2]);
1664                 case 2:
1665                         break;
1666                 default:
1667                         error(EINVAL, "Bad arg num to %s", __func__);
1668         }
1669
1670         if ((parseip(prefix, argv[1]) != 6) ||
1671                 (validlt < preflt) || (plen < 0) || (plen > 64) || (islinklocal(prefix))
1672                 )
1673                 error(EFAIL, "IP parsing failed");
1674
1675         lifc = kzmalloc(sizeof(struct Iplifc), 0);
1676         lifc->onlink = (onlink != 0);
1677         lifc->autoflag = (autoflag != 0);
1678         lifc->validlt = validlt;
1679         lifc->preflt = preflt;
1680         lifc->origint = origint;
1681
1682         if (ifc->m->pref2addr != NULL)
1683                 ifc->m->pref2addr(prefix, ifc->mac);
1684         else
1685                 error(EFAIL, "Null IFC pref");
1686
1687         snprintf(addr, sizeof(addr), "%I", prefix);
1688         snprintf(preflen, sizeof(preflen), "/%d", plen);
1689         params[0] = "add";
1690         params[1] = addr;
1691         params[2] = preflen;
1692
1693         ipifcadd(ifc, params, 3, 0, lifc);
1694 }