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