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