darwin-xnu/bsd/netinet6/in6_ifattach.c
<<
>>
Prefs
   1/*      $FreeBSD: src/sys/netinet6/in6_ifattach.c,v 1.8 2002/04/19 04:46:22 suz Exp $   */
   2/*      $KAME: in6_ifattach.c,v 1.118 2001/05/24 07:44:00 itojun Exp $  */
   3
   4/*
   5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
   6 * All rights reserved.
   7 *
   8 * Redistribution and use in source and binary forms, with or without
   9 * modification, are permitted provided that the following conditions
  10 * are met:
  11 * 1. Redistributions of source code must retain the above copyright
  12 *    notice, this list of conditions and the following disclaimer.
  13 * 2. Redistributions in binary form must reproduce the above copyright
  14 *    notice, this list of conditions and the following disclaimer in the
  15 *    documentation and/or other materials provided with the distribution.
  16 * 3. Neither the name of the project nor the names of its contributors
  17 *    may be used to endorse or promote products derived from this software
  18 *    without specific prior written permission.
  19 *
  20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30 * SUCH DAMAGE.
  31 */
  32
  33#include <sys/param.h>
  34#include <sys/systm.h>
  35#include <sys/malloc.h>
  36#include <sys/socket.h>
  37#include <sys/socketvar.h>
  38#include <sys/sockio.h>
  39#include <sys/kernel.h>
  40#include <sys/syslog.h>
  41#include <sys/md5.h>
  42#include <kern/lock.h>
  43
  44#include <net/if.h>
  45#include <net/if_dl.h>
  46#include <net/if_types.h>
  47#include <net/route.h>
  48
  49#include <netinet/in.h>
  50#include <netinet/in_var.h>
  51#include <netinet/if_ether.h>
  52#include <netinet/in_pcb.h>
  53
  54#include <netinet/ip6.h>
  55#include <netinet6/ip6_var.h>
  56#include <netinet6/in6_var.h>
  57#include <netinet6/in6_pcb.h>
  58#include <netinet6/in6_ifattach.h>
  59#include <netinet6/ip6_var.h>
  60#include <netinet6/nd6.h>
  61#include <netinet6/scope6_var.h>
  62
  63#include <net/net_osdep.h>
  64
  65struct in6_ifstat **in6_ifstat = NULL;
  66struct icmp6_ifstat **icmp6_ifstat = NULL;
  67size_t in6_ifstatmax = 0;
  68size_t icmp6_ifstatmax = 0;
  69unsigned long in6_maxmtu = 0;
  70extern lck_mtx_t *nd6_mutex;
  71
  72#if IP6_AUTO_LINKLOCAL
  73int ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;
  74#else
  75int ip6_auto_linklocal = 1;     /* enable by default */
  76#endif
  77
  78
  79extern struct inpcbinfo udbinfo;
  80extern struct inpcbinfo ripcbinfo;
  81extern lck_mtx_t *rt_mtx;
  82
  83static int get_rand_ifid(struct ifnet *, struct in6_addr *);
  84static int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *);
  85static int get_hw_ifid(struct ifnet *, struct in6_addr *);
  86static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
  87static int in6_ifattach_linklocal(struct ifnet *, struct ifnet *, struct in6_aliasreq *);
  88static int in6_ifattach_loopback(struct ifnet *);
  89
  90#define EUI64_GBIT      0x01
  91#define EUI64_UBIT      0x02
  92#define EUI64_TO_IFID(in6)      do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
  93#define EUI64_GROUP(in6)        ((in6)->s6_addr[8] & EUI64_GBIT)
  94#define EUI64_INDIVIDUAL(in6)   (!EUI64_GROUP(in6))
  95#define EUI64_LOCAL(in6)        ((in6)->s6_addr[8] & EUI64_UBIT)
  96#define EUI64_UNIVERSAL(in6)    (!EUI64_LOCAL(in6))
  97
  98#define IFID_LOCAL(in6)         (!EUI64_LOCAL(in6))
  99#define IFID_UNIVERSAL(in6)     (!EUI64_UNIVERSAL(in6))
 100
 101/*
 102 * Generate a last-resort interface identifier, when the machine has no
 103 * IEEE802/EUI64 address sources.
 104 * The goal here is to get an interface identifier that is
 105 * (1) random enough and (2) does not change across reboot.
 106 * We currently use MD5(hostname) for it.
 107 */
 108static int
 109get_rand_ifid(
 110        struct ifnet *ifp,
 111        struct in6_addr *in6)   /* upper 64bits are preserved */
 112{
 113        MD5_CTX ctxt;
 114        u_int8_t digest[16];
 115        int hostnamelen = strlen(hostname);
 116
 117#if 0
 118        /* we need at least several letters as seed for ifid */
 119        if (hostnamelen < 3)
 120                return -1;
 121#endif
 122
 123        /* generate 8 bytes of pseudo-random value. */
 124        bzero(&ctxt, sizeof(ctxt));
 125        MD5Init(&ctxt);
 126        MD5Update(&ctxt, hostname, hostnamelen);
 127        MD5Final(digest, &ctxt);
 128
 129        /* assumes sizeof(digest) > sizeof(ifid) */
 130        bcopy(digest, &in6->s6_addr[8], 8);
 131
 132        /* make sure to set "u" bit to local, and "g" bit to individual. */
 133        in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
 134        in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
 135
 136        /* convert EUI64 into IPv6 interface identifier */
 137        EUI64_TO_IFID(in6);
 138
 139        return 0;
 140}
 141
 142static int
 143generate_tmp_ifid(
 144        u_int8_t *seed0,
 145        const u_int8_t *seed1,
 146        u_int8_t *ret)
 147{
 148        MD5_CTX ctxt;
 149        u_int8_t seed[16], digest[16], nullbuf[8];
 150        u_int32_t val32;
 151        struct timeval tv;
 152
 153        /* If there's no hisotry, start with a random seed. */
 154        bzero(nullbuf, sizeof(nullbuf));
 155        if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
 156                int i;
 157
 158                for (i = 0; i < 2; i++) {
 159                        microtime(&tv);
 160                        val32 = random() ^ tv.tv_usec;
 161                        bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
 162                }
 163        } else {
 164                bcopy(seed0, seed, 8);
 165        }
 166
 167        /* copy the right-most 64-bits of the given address */
 168        /* XXX assumption on the size of IFID */
 169        bcopy(seed1, &seed[8], 8);
 170
 171        if (0) {                /* for debugging purposes only */
 172                int i;
 173
 174                printf("generate_tmp_ifid: new randomized ID from: ");
 175                for (i = 0; i < 16; i++)
 176                        printf("%02x", seed[i]);
 177                printf(" ");
 178        }
 179
 180        /* generate 16 bytes of pseudo-random value. */
 181        bzero(&ctxt, sizeof(ctxt));
 182        MD5Init(&ctxt);
 183        MD5Update(&ctxt, seed, sizeof(seed));
 184        MD5Final(digest, &ctxt);
 185
 186        /*
 187         * RFC 3041 3.2.1. (3)
 188         * Take the left-most 64-bits of the MD5 digest and set bit 6 (the
 189         * left-most bit is numbered 0) to zero.
 190         */
 191        bcopy(digest, ret, 8);
 192        ret[0] &= ~EUI64_UBIT;
 193
 194        /*
 195         * XXX: we'd like to ensure that the generated value is not zero
 196         * for simplicity.  If the caclculated digest happens to be zero,
 197         * use a random non-zero value as the last resort.
 198         */
 199        if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) {
 200                log(LOG_INFO,
 201                    "generate_tmp_ifid: computed MD5 value is zero.\n");
 202
 203                microtime(&tv);
 204                val32 = random() ^ tv.tv_usec;
 205                val32 = 1 + (val32 % (0xffffffff - 1));
 206        }
 207
 208        /*
 209         * RFC 3041 3.2.1. (4)
 210         * Take the rightmost 64-bits of the MD5 digest and save them in
 211         * stable storage as the history value to be used in the next
 212         * iteration of the algorithm. 
 213         */
 214        bcopy(&digest[8], seed0, 8);
 215
 216        if (0) {                /* for debugging purposes only */
 217                int i;
 218
 219                printf("to: ");
 220                for (i = 0; i < 16; i++)
 221                        printf("%02x", digest[i]);
 222                printf("\n");
 223        }
 224
 225        return 0;
 226}
 227
 228/*
 229 * Get interface identifier for the specified interface.
 230 * XXX assumes single sockaddr_dl (AF_LINK address) per an interface
 231 */
 232static int
 233get_hw_ifid(
 234        struct ifnet *ifp,
 235        struct in6_addr *in6)   /* upper 64bits are preserved */
 236{
 237        struct ifaddr *ifa;
 238        struct sockaddr_dl *sdl;
 239        u_int8_t *addr;
 240        size_t addrlen;
 241        static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 242        static u_int8_t allone[8] =
 243                { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 244
 245        /* Why doesn't this code use ifnet_addrs? */
 246        ifnet_lock_shared(ifp);
 247        for (ifa = ifp->if_addrlist.tqh_first;
 248             ifa;
 249             ifa = ifa->ifa_list.tqe_next)
 250        {
 251                if (ifa->ifa_addr->sa_family != AF_LINK)
 252                        continue;
 253                sdl = (struct sockaddr_dl *)ifa->ifa_addr;
 254                if (sdl == NULL)
 255                        continue;
 256                if (sdl->sdl_alen == 0)
 257                        continue;
 258
 259                goto found;
 260        }
 261        ifnet_lock_done(ifp);
 262
 263        return -1;
 264
 265found:
 266        ifnet_lock_done(ifp);
 267        addr = LLADDR(sdl);
 268        addrlen = sdl->sdl_alen;
 269
 270        /* get EUI64 */
 271        switch (ifp->if_type) {
 272        case IFT_ETHER:
 273        case IFT_FDDI:
 274        case IFT_ATM:
 275        case IFT_IEEE1394:
 276        case IFT_L2VLAN:
 277        case IFT_IEEE8023ADLAG:
 278#if IFT_IEEE80211
 279        case IFT_IEEE80211:
 280#endif
 281                /* IEEE802/EUI64 cases - what others? */
 282                /* IEEE1394 uses 16byte length address starting with EUI64 */
 283                if (addrlen > 8)
 284                        addrlen = 8;
 285
 286                /* look at IEEE802/EUI64 only */
 287                if (addrlen != 8 && addrlen != 6)
 288                        return -1;
 289
 290                /*
 291                 * check for invalid MAC address - on bsdi, we see it a lot
 292                 * since wildboar configures all-zero MAC on pccard before
 293                 * card insertion.
 294                 */
 295                if (bcmp(addr, allzero, addrlen) == 0)
 296                        return -1;
 297                if (bcmp(addr, allone, addrlen) == 0)
 298                        return -1;
 299
 300                /* make EUI64 address */
 301                if (addrlen == 8)
 302                        bcopy(addr, &in6->s6_addr[8], 8);
 303                else if (addrlen == 6) {
 304                        in6->s6_addr[8] = addr[0];
 305                        in6->s6_addr[9] = addr[1];
 306                        in6->s6_addr[10] = addr[2];
 307                        in6->s6_addr[11] = 0xff;
 308                        in6->s6_addr[12] = 0xfe;
 309                        in6->s6_addr[13] = addr[3];
 310                        in6->s6_addr[14] = addr[4];
 311                        in6->s6_addr[15] = addr[5];
 312                }
 313                break;
 314
 315        case IFT_ARCNET:
 316                if (addrlen != 1)
 317                        return -1;
 318                if (!addr[0])
 319                        return -1;
 320
 321                bzero(&in6->s6_addr[8], 8);
 322                in6->s6_addr[15] = addr[0];
 323
 324                /*
 325                 * due to insufficient bitwidth, we mark it local.
 326                 */
 327                in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
 328                in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
 329                break;
 330
 331        case IFT_GIF:
 332#if IFT_STF
 333        case IFT_STF:
 334#endif
 335                /*
 336                 * RFC2893 says: "SHOULD use IPv4 address as ifid source".
 337                 * however, IPv4 address is not very suitable as unique
 338                 * identifier source (can be renumbered).
 339                 * we don't do this.
 340                 */
 341                return -1;
 342
 343        default:
 344                return -1;
 345        }
 346
 347        /* sanity check: g bit must not indicate "group" */
 348        if (EUI64_GROUP(in6))
 349                return -1;
 350
 351        /* convert EUI64 into IPv6 interface identifier */
 352        EUI64_TO_IFID(in6);
 353
 354        /*
 355         * sanity check: ifid must not be all zero, avoid conflict with
 356         * subnet router anycast
 357         */
 358        if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
 359            bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
 360                return -1;
 361        }
 362
 363        return 0;
 364}
 365
 366/*
 367 * Get interface identifier for the specified interface.  If it is not
 368 * available on ifp0, borrow interface identifier from other information
 369 * sources.
 370 */
 371static int
 372get_ifid(
 373        struct ifnet *ifp0,
 374        struct ifnet *altifp,   /* secondary EUI64 source */
 375        struct in6_addr *in6)
 376{
 377        struct ifnet *ifp;
 378
 379        /* first, try to get it from the interface itself */
 380        if (get_hw_ifid(ifp0, in6) == 0) {
 381                nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
 382                    if_name(ifp0)));
 383                goto success;
 384        }
 385
 386        /* try secondary EUI64 source. this basically is for ATM PVC */
 387        if (altifp && get_hw_ifid(altifp, in6) == 0) {
 388                nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
 389                    if_name(ifp0), if_name(altifp)));
 390                goto success;
 391        }
 392
 393        /* next, try to get it from some other hardware interface */
 394        ifnet_head_lock_shared();
 395        TAILQ_FOREACH(ifp, &ifnet_head, if_list) {
 396                if (ifp == ifp0)
 397                        continue;
 398                if (get_hw_ifid(ifp, in6) != 0)
 399                        continue;
 400
 401                /*
 402                 * to borrow ifid from other interface, ifid needs to be
 403                 * globally unique
 404                 */
 405                if (IFID_UNIVERSAL(in6)) {
 406                        nd6log((LOG_DEBUG,
 407                            "%s: borrow interface identifier from %s\n",
 408                            if_name(ifp0), if_name(ifp)));
 409                        ifnet_head_done();
 410                        goto success;
 411                }
 412        }
 413        ifnet_head_done();
 414
 415        /* last resort: get from random number source */
 416        if (get_rand_ifid(ifp, in6) == 0) {
 417                nd6log((LOG_DEBUG,
 418                    "%s: interface identifier generated by random number\n",
 419                    if_name(ifp0)));
 420                goto success;
 421        }
 422
 423        printf("%s: failed to get interface identifier\n", if_name(ifp0));
 424        return -1;
 425
 426success:
 427        nd6log((LOG_INFO, "%s: ifid: "
 428                "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
 429                if_name(ifp0),
 430                in6->s6_addr[8], in6->s6_addr[9],
 431                in6->s6_addr[10], in6->s6_addr[11],
 432                in6->s6_addr[12], in6->s6_addr[13],
 433                in6->s6_addr[14], in6->s6_addr[15]));
 434        return 0;
 435}
 436
 437static int
 438in6_ifattach_linklocal(
 439        struct ifnet *ifp,
 440        struct ifnet *altifp,   /* secondary EUI64 source */
 441        struct in6_aliasreq *ifra_passed)
 442{
 443        struct in6_ifaddr *ia;
 444        struct in6_aliasreq ifra;
 445        struct nd_prefix pr0;
 446        int i, error;
 447
 448        /*
 449         * configure link-local address.
 450         */
 451        bzero(&ifra, sizeof(ifra));
 452
 453        dlil_plumb_protocol(PF_INET6, ifp);
 454
 455        /*
 456         * in6_update_ifa() does not use ifra_name, but we accurately set it
 457         * for safety.
 458         */
 459        strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
 460
 461        if (ifp->if_type == IFT_PPP && ifra_passed != NULL)  /* PPP provided both addresses for us */
 462                bcopy(&ifra_passed->ifra_addr, &(ifra.ifra_addr), sizeof(struct sockaddr_in6));
 463        else {
 464                ifra.ifra_addr.sin6_family = AF_INET6;
 465                ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
 466                ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
 467#if SCOPEDROUTING
 468                ifra.ifra_addr.sin6_addr.s6_addr16[1] = 0
 469#else
 470                ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); /* XXX */
 471#endif
 472                ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
 473                if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
 474                        ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
 475                        ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
 476                } else {
 477                        if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
 478                                nd6log((LOG_ERR,
 479                            "   %s: no ifid available\n", if_name(ifp)));
 480                                return -1;
 481                        }
 482                }
 483#if SCOPEDROUTING
 484                ifra.ifra_addr.sin6_scope_id =
 485                        in6_addr2scopeid(ifp,  &ifra.ifra_addr.sin6_addr);
 486#endif
 487        }
 488        ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
 489        ifra.ifra_prefixmask.sin6_family = AF_INET6;
 490        ifra.ifra_prefixmask.sin6_addr = in6mask64;
 491#if SCOPEDROUTING
 492        /* take into accound the sin6_scope_id field for routing */
 493        ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff;
 494#endif
 495        /* link-local addresses should NEVER expire. */
 496        ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
 497        ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
 498
 499        /*
 500         * Do not let in6_update_ifa() do DAD, since we need a random delay
 501         * before sending an NS at the first time the interface becomes up.
 502         * Instead, in6_if_up() will start DAD with a proper random delay.
 503         */
 504        ifra.ifra_flags |= IN6_IFF_NODAD;
 505
 506        /*
 507         * Now call in6_update_ifa() to do a bunch of procedures to configure
 508         * a link-local address. We can set NULL to the 3rd argument, because
 509         * we know there's no other link-local address on the interface
 510         * and therefore we are adding one (instead of updating one).
 511         */
 512        if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
 513                /*
 514                 * XXX: When the interface does not support IPv6, this call
 515                 * would fail in the SIOCSIFADDR ioctl.  I believe the
 516                 * notification is rather confusing in this case, so just
 517                 * supress it.  (jinmei@kame.net 20010130)
 518                 */
 519                if (error != EAFNOSUPPORT)
 520                        log(LOG_NOTICE, "in6_ifattach_linklocal: failed to "
 521                            "configure a link-local address on %s "
 522                            "(errno=%d)\n",
 523                            if_name(ifp), error);
 524                return(-1);
 525        }
 526
 527        /*
 528         * Adjust ia6_flags so that in6_if_up will perform DAD.
 529         * XXX: Some P2P interfaces seem not to send packets just after
 530         * becoming up, so we skip p2p interfaces for safety.
 531         */
 532        ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
 533#if DIAGNOSTIC
 534        if (!ia) {
 535                panic("ia == NULL in in6_ifattach_linklocal");
 536                /*NOTREACHED*/
 537        }
 538#endif
 539        if (in6if_do_dad(ifp) && (ifp->if_flags & IFF_POINTOPOINT) == 0) {
 540                ia->ia6_flags &= ~IN6_IFF_NODAD;
 541                ia->ia6_flags |= IN6_IFF_TENTATIVE;
 542        }
 543
 544        /*
 545         * Make the link-local prefix (fe80::/64%link) as on-link.
 546         * Since we'd like to manage prefixes separately from addresses,
 547         * we make an ND6 prefix structure for the link-local prefix,
 548         * and add it to the prefix list as a never-expire prefix.
 549         * XXX: this change might affect some existing code base...
 550         */
 551        bzero(&pr0, sizeof(pr0));
 552        pr0.ndpr_ifp = ifp;
 553        /* this should be 64 at this moment. */
 554        pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
 555        pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr;
 556        pr0.ndpr_prefix = ifra.ifra_addr;
 557        /* apply the mask for safety. (nd6_prelist_add will apply it again) */
 558        for (i = 0; i < 4; i++) {
 559                pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
 560                        in6mask64.s6_addr32[i];
 561        }
 562        /*
 563         * Initialize parameters.  The link-local prefix must always be
 564         * on-link, and its lifetimes never expire.
 565         */
 566        pr0.ndpr_raf_onlink = 1;
 567        pr0.ndpr_raf_auto = 1;  /* probably meaningless */
 568        pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
 569        pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
 570        /*
 571         * Since there is no other link-local addresses, nd6_prefix_lookup()
 572         * probably returns NULL.  However, we cannot always expect the result.
 573         * For example, if we first remove the (only) existing link-local
 574         * address, and then reconfigure another one, the prefix is still
 575         * valid with referring to the old link-local address.
 576         */
 577        if (nd6_prefix_lookup(&pr0) == NULL) {
 578                if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
 579                        return(error);
 580        }
 581
 582        in6_post_msg(ifp, KEV_INET6_NEW_LL_ADDR, ia);
 583        return 0;
 584}
 585
 586static int
 587in6_ifattach_loopback(
 588        struct ifnet *ifp)      /* must be IFT_LOOP */
 589{
 590        struct in6_aliasreq ifra;
 591        int error;
 592
 593        bzero(&ifra, sizeof(ifra));
 594
 595        /*
 596         * in6_update_ifa() does not use ifra_name, but we accurately set it
 597         * for safety.
 598         */
 599        strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
 600
 601        ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
 602        ifra.ifra_prefixmask.sin6_family = AF_INET6;
 603        ifra.ifra_prefixmask.sin6_addr = in6mask128;
 604
 605        /*
 606         * Always initialize ia_dstaddr (= broadcast address) to loopback
 607         * address.  Follows IPv4 practice - see in_ifinit().
 608         */
 609        ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
 610        ifra.ifra_dstaddr.sin6_family = AF_INET6;
 611        ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
 612
 613        ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
 614        ifra.ifra_addr.sin6_family = AF_INET6;
 615        ifra.ifra_addr.sin6_addr = in6addr_loopback;
 616
 617        /* the loopback  address should NEVER expire. */
 618        ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
 619        ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
 620
 621        /* we don't need to perform DAD on loopback interfaces. */
 622        ifra.ifra_flags |= IN6_IFF_NODAD;
 623
 624        /* skip registration to the prefix list. XXX should be temporary. */
 625        ifra.ifra_flags |= IN6_IFF_NOPFX;
 626
 627        /*
 628         * We are sure that this is a newly assigned address, so we can set
 629         * NULL to the 3rd arg.
 630         */
 631        if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
 632                log(LOG_ERR, "in6_ifattach_loopback: failed to configure "
 633                    "the loopback address on %s (errno=%d)\n",
 634                    if_name(ifp), error);
 635                return(-1);
 636        }
 637
 638        return 0;
 639}
 640
 641/*
 642 * compute NI group address, based on the current hostname setting.
 643 * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
 644 *
 645 * when ifp == NULL, the caller is responsible for filling scopeid.
 646 */
 647int
 648in6_nigroup(
 649        struct ifnet *ifp,
 650        const char *name,
 651        int namelen,
 652        struct in6_addr *in6)
 653{
 654        const char *p;
 655        u_char *q;
 656        MD5_CTX ctxt;
 657        u_int8_t digest[16];
 658        char l;
 659        char n[64];     /* a single label must not exceed 63 chars */
 660
 661        if (!namelen || !name)
 662                return -1;
 663
 664        p = name;
 665        while (p && *p && *p != '.' && p - name < namelen)
 666                p++;
 667        if (p - name > sizeof(n) - 1)
 668                return -1;      /* label too long */
 669        l = p - name;
 670        strncpy(n, name, l);
 671        n[(int)l] = '\0';
 672        for (q = n; *q; q++) {
 673                if ('A' <= *q && *q <= 'Z')
 674                        *q = *q - 'A' + 'a';
 675        }
 676
 677        /* generate 8 bytes of pseudo-random value. */
 678        bzero(&ctxt, sizeof(ctxt));
 679        MD5Init(&ctxt);
 680        MD5Update(&ctxt, &l, sizeof(l));
 681        MD5Update(&ctxt, n, l);
 682        MD5Final(digest, &ctxt);
 683
 684        bzero(in6, sizeof(*in6));
 685        in6->s6_addr16[0] = htons(0xff02);
 686        if (ifp)
 687                in6->s6_addr16[1] = htons(ifp->if_index);
 688        in6->s6_addr8[11] = 2;
 689        bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
 690
 691        return 0;
 692}
 693
 694void
 695in6_nigroup_attach(
 696        const char *name,
 697        int namelen)
 698{
 699        struct ifnet *ifp;
 700        struct sockaddr_in6 mltaddr;
 701        struct in6_multi *in6m;
 702        int error;
 703
 704        bzero(&mltaddr, sizeof(mltaddr));
 705        mltaddr.sin6_family = AF_INET6;
 706        mltaddr.sin6_len = sizeof(struct sockaddr_in6);
 707        if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
 708                return;
 709
 710        ifnet_head_lock_shared();
 711        TAILQ_FOREACH(ifp, &ifnet_head, if_list) {
 712                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
 713                ifnet_lock_shared(ifp);
 714                IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
 715                ifnet_lock_done(ifp);
 716                if (!in6m) {
 717                        if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error, 0)) {
 718                                nd6log((LOG_ERR, "%s: failed to join %s "
 719                                    "(errno=%d)\n", if_name(ifp),
 720                                    ip6_sprintf(&mltaddr.sin6_addr), 
 721                                    error));
 722                        }
 723                }
 724        }
 725        ifnet_head_done();
 726}
 727
 728void
 729in6_nigroup_detach(
 730        const char *name,
 731        int namelen)
 732{
 733        struct ifnet *ifp;
 734        struct sockaddr_in6 mltaddr;
 735        struct in6_multi *in6m;
 736
 737        bzero(&mltaddr, sizeof(mltaddr));
 738        mltaddr.sin6_family = AF_INET6;
 739        mltaddr.sin6_len = sizeof(struct sockaddr_in6);
 740        if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
 741                return;
 742
 743        ifnet_head_lock_shared();
 744        TAILQ_FOREACH(ifp, &ifnet_head, if_list) {
 745                mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
 746                ifnet_lock_shared(ifp);
 747                IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
 748                ifnet_lock_done(ifp);
 749                if (in6m)
 750                        in6_delmulti(in6m, 0);
 751        }
 752        ifnet_head_done();
 753}
 754
 755/*
 756 * XXX multiple loopback interface needs more care.  for instance,
 757 * nodelocal address needs to be configured onto only one of them.
 758 * XXX multiple link-local address case
 759 */
 760void
 761in6_ifattach(
 762        struct ifnet *ifp,
 763        struct ifnet *altifp,   /* secondary EUI64 source */
 764        struct  in6_aliasreq *ifra)
 765{
 766        static size_t if_indexlim = 8;
 767        struct in6_ifaddr *ia;
 768        struct in6_addr in6;
 769
 770        /*
 771         * We have some arrays that should be indexed by if_index.
 772         * since if_index will grow dynamically, they should grow too.
 773         *      struct in6_ifstat **in6_ifstat
 774         *      struct icmp6_ifstat **icmp6_ifstat
 775         */
 776        if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
 777            if_index >= if_indexlim) {
 778                size_t n;
 779                caddr_t q;
 780                size_t olim;
 781
 782                olim = if_indexlim;
 783                while (if_index >= if_indexlim)
 784                        if_indexlim <<= 1;
 785
 786                /* grow in6_ifstat */
 787                n = if_indexlim * sizeof(struct in6_ifstat *);
 788                q = (caddr_t)_MALLOC(n, M_IFADDR, M_WAITOK);
 789                bzero(q, n);
 790                if (in6_ifstat) {
 791                        bcopy((caddr_t)in6_ifstat, q,
 792                                olim * sizeof(struct in6_ifstat *));
 793                        FREE((caddr_t)in6_ifstat, M_IFADDR);
 794                }
 795                in6_ifstat = (struct in6_ifstat **)q;
 796                in6_ifstatmax = if_indexlim;
 797
 798                /* grow icmp6_ifstat */
 799                n = if_indexlim * sizeof(struct icmp6_ifstat *);
 800                q = (caddr_t)_MALLOC(n, M_IFADDR, M_WAITOK);
 801                bzero(q, n);
 802                if (icmp6_ifstat) {
 803                        bcopy((caddr_t)icmp6_ifstat, q,
 804                                olim * sizeof(struct icmp6_ifstat *));
 805                        FREE((caddr_t)icmp6_ifstat, M_IFADDR);
 806                }
 807                icmp6_ifstat = (struct icmp6_ifstat **)q;
 808                icmp6_ifstatmax = if_indexlim;
 809        }
 810
 811        /* initialize NDP variables */
 812        nd6_ifattach(ifp);
 813
 814        /* initialize scope identifiers */
 815        scope6_ifattach(ifp);
 816
 817        /*
 818         * quirks based on interface type
 819         */
 820        switch (ifp->if_type) {
 821#if IFT_STF
 822        case IFT_STF:
 823                /*
 824                 * 6to4 interface is a very special kind of beast.
 825                 * no multicast, no linklocal.  RFC2529 specifies how to make
 826                 * linklocals for 6to4 interface, but there's no use and
 827                 * it is rather harmful to have one.
 828                 */
 829                goto statinit;
 830#endif
 831        default:
 832                break;
 833        }
 834
 835        /*
 836         * usually, we require multicast capability to the interface
 837         */
 838        if ((ifp->if_flags & IFF_MULTICAST) == 0) {
 839                log(LOG_INFO, "in6_ifattach: "
 840                    "%s is not multicast capable, IPv6 not enabled\n",
 841                    if_name(ifp));
 842                return;
 843        }
 844
 845        /*
 846         * assign loopback address for loopback interface.
 847         * XXX multiple loopback interface case.
 848         */
 849        if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
 850                struct in6_ifaddr *ia6 = NULL;
 851                in6 = in6addr_loopback;
 852                if ((ia6 = in6ifa_ifpwithaddr(ifp, &in6)) == NULL) {
 853                        if (in6_ifattach_loopback(ifp) != 0)
 854                                return;
 855                }
 856                else {
 857                        ifafree(&ia6->ia_ifa);
 858                }
 859        }
 860
 861        /*
 862         * assign a link-local address, if there's none. 
 863         */
 864        if (ip6_auto_linklocal) {
 865                ia = in6ifa_ifpforlinklocal(ifp, 0);
 866                if (ia == NULL) {
 867                        if (in6_ifattach_linklocal(ifp, altifp, ifra) == 0) {
 868                                /* linklocal address assigned */
 869                        } else {
 870                                log(LOG_INFO, "in6_ifattach: "
 871                                        "%s failed to attach a linklocal address.\n",
 872                                        if_name(ifp));
 873                                /* failed to assign linklocal address. bark? */
 874                        }
 875                }
 876        }
 877
 878#if IFT_STF                     /* XXX */
 879statinit:       
 880#endif
 881
 882        /* update dynamically. */
 883        if (in6_maxmtu < ifp->if_mtu)
 884                in6_maxmtu = ifp->if_mtu;
 885
 886        if (in6_ifstat[ifp->if_index] == NULL) {
 887                in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
 888                        _MALLOC(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
 889                bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
 890        }
 891        if (icmp6_ifstat[ifp->if_index] == NULL) {
 892                icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
 893                        _MALLOC(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
 894                bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
 895        }
 896}
 897
 898/*
 899 * NOTE: in6_ifdetach() does not support loopback if at this moment.
 900 * We don't need this function in bsdi, because interfaces are never removed
 901 * from the ifnet list in bsdi.
 902 */
 903void
 904in6_ifdetach(
 905        struct ifnet *ifp)
 906{
 907        struct in6_ifaddr *ia, *oia, *nia;
 908        struct ifaddr *ifa, *next;
 909        struct rtentry *rt;
 910        short rtflags;
 911        struct sockaddr_in6 sin6;
 912        struct in6_multi *in6m;
 913        struct in6_multi *in6m_next;
 914
 915        /* nuke prefix list.  this may try to remove some of ifaddrs as well */
 916        in6_purgeprefix(ifp);
 917
 918        /* remove neighbor management table */
 919        nd6_purge(ifp);
 920
 921        /* nuke any of IPv6 addresses we have */
 922        
 923        lck_mtx_lock(nd6_mutex);
 924        for (ia = in6_ifaddrs; ia != NULL; ia = nia) {
 925                nia = ia->ia_next;
 926                if (ia->ia_ifa.ifa_ifp != ifp)
 927                        continue;
 928                in6_purgeaddr(&ia->ia_ifa, 1);
 929        }
 930        lck_mtx_unlock(nd6_mutex);
 931
 932        ifnet_lock_exclusive(ifp);
 933
 934        /* undo everything done by in6_ifattach(), just in case */
 935        for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
 936        {
 937                next = ifa->ifa_list.tqe_next;
 938
 939
 940                if (ifa->ifa_addr->sa_family != AF_INET6
 941                 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
 942                        continue;
 943                }
 944
 945                ia = (struct in6_ifaddr *)ifa;
 946
 947                /* remove from the routing table */
 948                lck_mtx_lock(rt_mtx);
 949                if ((ia->ia_flags & IFA_ROUTE)
 950                 && (rt = rtalloc1_locked((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
 951                        rtflags = rt->rt_flags;
 952                        rtfree_locked(rt);
 953                        rtrequest_locked(RTM_DELETE,
 954                                (struct sockaddr *)&ia->ia_addr,
 955                                (struct sockaddr *)&ia->ia_addr,
 956                                (struct sockaddr *)&ia->ia_prefixmask,
 957                                rtflags, (struct rtentry **)0);
 958                }
 959                lck_mtx_unlock(rt_mtx);
 960
 961                /* remove from the linked list */
 962                if_detach_ifa(ifp, &ia->ia_ifa);
 963                ifafree(&ia->ia_ifa);
 964
 965                /* also remove from the IPv6 address chain(itojun&jinmei) */
 966                oia = ia;
 967                lck_mtx_lock(nd6_mutex);
 968                if (oia == (ia = in6_ifaddrs))
 969                        in6_ifaddrs = ia->ia_next;
 970                else {
 971                        while (ia->ia_next && (ia->ia_next != oia))
 972                                ia = ia->ia_next;
 973                        if (ia->ia_next)
 974                                ia->ia_next = oia->ia_next;
 975                        else {
 976                                nd6log((LOG_ERR, 
 977                                    "%s: didn't unlink in6ifaddr from "
 978                                    "list\n", if_name(ifp)));
 979                        }
 980                }
 981                lck_mtx_unlock(nd6_mutex);
 982
 983                ifafree(&oia->ia_ifa);
 984        }
 985        ifnet_lock_done(ifp);
 986
 987        /*
 988         * remove neighbor management table.  we call it twice just to make
 989         * sure we nuke everything.  maybe we need just one call.
 990         * XXX: since the first call did not release addresses, some prefixes
 991         * might remain.  We should call nd6_purge() again to release the
 992         * prefixes after removing all addresses above.
 993         * (Or can we just delay calling nd6_purge until at this point?)
 994         */
 995        nd6_purge(ifp);
 996
 997        /* remove route to link-local allnodes multicast (ff02::1) */
 998        bzero(&sin6, sizeof(sin6));
 999        sin6.sin6_len = sizeof(struct sockaddr_in6);
1000        sin6.sin6_family = AF_INET6;
1001        sin6.sin6_addr = in6addr_linklocal_allnodes;
1002        sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1003        lck_mtx_lock(rt_mtx);
1004        rt = rtalloc1_locked((struct sockaddr *)&sin6, 0, 0UL);
1005        if (rt && rt->rt_ifp == ifp) {
1006                rtrequest_locked(RTM_DELETE, (struct sockaddr *)rt_key(rt),
1007                        rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
1008                rtfree_locked(rt);
1009        }
1010        lck_mtx_unlock(rt_mtx);
1011}
1012
1013void
1014in6_get_tmpifid(
1015        struct ifnet *ifp,
1016        u_int8_t *retbuf,
1017        const u_int8_t *baseid,
1018        int generate)
1019{
1020        u_int8_t nullbuf[8];
1021        struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
1022
1023        bzero(nullbuf, sizeof(nullbuf));
1024        if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
1025                /* we've never created a random ID.  Create a new one. */
1026                generate = 1;
1027        }
1028
1029        if (generate) {
1030                bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
1031
1032                /* generate_tmp_ifid will update seedn and buf */
1033                (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
1034                                        ndi->randomid);
1035        }
1036        bcopy(ndi->randomid, retbuf, 8);
1037}
1038
1039extern size_t nd_ifinfo_indexlim;
1040extern int ip6_use_tempaddr;
1041void
1042in6_tmpaddrtimer(
1043        void *ignored_arg)
1044{
1045        int i;
1046        struct nd_ifinfo *ndi;
1047        u_int8_t nullbuf[8];
1048        int s = splnet();
1049
1050        timeout(in6_tmpaddrtimer, (caddr_t)0,
1051                      (ip6_temp_preferred_lifetime - ip6_desync_factor -
1052                       ip6_temp_regen_advance) * hz);
1053
1054        if (ip6_use_tempaddr) {
1055                
1056                bzero(nullbuf, sizeof(nullbuf));
1057                for (i = 1; i < nd_ifinfo_indexlim + 1; i++) {
1058                        ndi = &nd_ifinfo[i];
1059                        if (ndi->flags != ND6_IFF_PERFORMNUD)
1060                                continue;
1061                        if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
1062                                /*
1063                                 * We've been generating a random ID on this interface.
1064                                 * Create a new one.
1065                                 */
1066                                (void)generate_tmp_ifid(ndi->randomseed0,
1067                                                        ndi->randomseed1,
1068                                                        ndi->randomid);
1069                        }
1070                }
1071        }
1072
1073        splx(s);
1074}
1075
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.