LCOV - code coverage report
Current view: top level - netinet6 - in6_ifattach.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 240 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: in6_ifattach.c,v 1.110 2018/08/26 22:30:00 mpi Exp $  */
       2             : /*      $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei 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/socket.h>
      36             : #include <sys/sockio.h>
      37             : #include <sys/kernel.h>
      38             : #include <sys/syslog.h>
      39             : 
      40             : #include <crypto/sha2.h>
      41             : 
      42             : #include <net/if.h>
      43             : #include <net/if_var.h>
      44             : #include <net/if_dl.h>
      45             : #include <net/if_types.h>
      46             : #include <net/route.h>
      47             : 
      48             : #include <netinet/in.h>
      49             : 
      50             : #include <netinet6/in6_var.h>
      51             : #include <netinet/ip6.h>
      52             : #include <netinet6/ip6_var.h>
      53             : #include <netinet6/in6_ifattach.h>
      54             : #include <netinet6/nd6.h>
      55             : #ifdef MROUTING
      56             : #include <netinet6/ip6_mroute.h>
      57             : #endif
      58             : 
      59             : void    in6_get_rand_ifid(struct ifnet *, struct in6_addr *);
      60             : int     in6_get_hw_ifid(struct ifnet *, struct in6_addr *);
      61             : int     in6_get_soii_ifid(struct ifnet *, struct in6_addr *);
      62             : void    in6_get_ifid(struct ifnet *, struct in6_addr *);
      63             : int     in6_ifattach_loopback(struct ifnet *);
      64             : 
      65             : #define EUI64_GBIT      0x01
      66             : #define EUI64_UBIT      0x02
      67             : #define EUI64_TO_IFID(in6)      do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
      68             : #define EUI64_GROUP(in6)        ((in6)->s6_addr[8] & EUI64_GBIT)
      69             : #define EUI64_INDIVIDUAL(in6)   (!EUI64_GROUP(in6))
      70             : #define EUI64_LOCAL(in6)        ((in6)->s6_addr[8] & EUI64_UBIT)
      71             : #define EUI64_UNIVERSAL(in6)    (!EUI64_LOCAL(in6))
      72             : 
      73             : #define IFID_LOCAL(in6)         (!EUI64_LOCAL(in6))
      74             : #define IFID_UNIVERSAL(in6)     (!EUI64_UNIVERSAL(in6))
      75             : 
      76             : void
      77           0 : in6_soiiupdate(struct ifnet *ifp)
      78             : {
      79             :         struct ifaddr *ifa;
      80             : 
      81           0 :         NET_ASSERT_LOCKED();
      82             : 
      83             :         /*
      84             :          * Update the link-local address.
      85             :          */
      86           0 :         ifa = &in6ifa_ifpforlinklocal(ifp, 0)->ia_ifa;
      87           0 :         if (ifa) {
      88           0 :                 in6_purgeaddr(ifa);
      89           0 :                 dohooks(ifp->if_addrhooks, 0);
      90           0 :                 in6_ifattach(ifp);
      91           0 :         }
      92           0 : }
      93             : 
      94             : /*
      95             :  * Generate a random interface identifier.
      96             :  *
      97             :  * in6 - upper 64bits are preserved
      98             :  */
      99             : void
     100           0 : in6_get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6)
     101             : {
     102           0 :         arc4random_buf(&in6->s6_addr32[2], 8);
     103             : 
     104             :         /* make sure to set "u" bit to local, and "g" bit to individual. */
     105           0 :         in6->s6_addr[8] &= ~EUI64_GBIT;  /* g bit to "individual" */
     106           0 :         in6->s6_addr[8] |= EUI64_UBIT;       /* u bit to "local" */
     107             : 
     108             :         /* convert EUI64 into IPv6 interface identifier */
     109           0 :         EUI64_TO_IFID(in6);
     110           0 : }
     111             : 
     112             : /*
     113             :  * Get interface identifier for the specified interface.
     114             :  *
     115             :  * in6 - upper 64bits are preserved
     116             :  */
     117             : int
     118           0 : in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
     119             : {
     120             :         struct sockaddr_dl *sdl;
     121             :         char *addr;
     122             :         size_t addrlen;
     123             :         static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
     124             :         static u_int8_t allone[8] =
     125             :                 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
     126             : 
     127           0 :         sdl = ifp->if_sadl;
     128           0 :         if (sdl == NULL || sdl->sdl_alen == 0)
     129           0 :                 return -1;
     130             : 
     131           0 :         addr = LLADDR(sdl);
     132           0 :         addrlen = sdl->sdl_alen;
     133             : 
     134           0 :         switch (ifp->if_type) {
     135             :         case IFT_IEEE1394:
     136             :         case IFT_IEEE80211:
     137             :                 /* IEEE1394 uses 16byte length address starting with EUI64 */
     138           0 :                 if (addrlen > 8)
     139           0 :                         addrlen = 8;
     140             :                 break;
     141             :         default:
     142             :                 break;
     143             :         }
     144             : 
     145             :         /* get EUI64 */
     146           0 :         switch (ifp->if_type) {
     147             :         /* IEEE802/EUI64 cases - what others? */
     148             :         case IFT_ETHER:
     149             :         case IFT_CARP:
     150             :         case IFT_IEEE1394:
     151             :         case IFT_IEEE80211:
     152             :                 /* look at IEEE802/EUI64 only */
     153           0 :                 if (addrlen != 8 && addrlen != 6)
     154           0 :                         return -1;
     155             : 
     156             :                 /*
     157             :                  * check for invalid MAC address - on bsdi, we see it a lot
     158             :                  * since wildboar configures all-zero MAC on pccard before
     159             :                  * card insertion.
     160             :                  */
     161           0 :                 if (bcmp(addr, allzero, addrlen) == 0)
     162           0 :                         return -1;
     163           0 :                 if (bcmp(addr, allone, addrlen) == 0)
     164           0 :                         return -1;
     165             : 
     166             :                 /* make EUI64 address */
     167           0 :                 if (addrlen == 8)
     168           0 :                         memcpy(&in6->s6_addr[8], addr, 8);
     169           0 :                 else if (addrlen == 6) {
     170           0 :                         in6->s6_addr[8] = addr[0];
     171           0 :                         in6->s6_addr[9] = addr[1];
     172           0 :                         in6->s6_addr[10] = addr[2];
     173           0 :                         in6->s6_addr[11] = 0xff;
     174           0 :                         in6->s6_addr[12] = 0xfe;
     175           0 :                         in6->s6_addr[13] = addr[3];
     176           0 :                         in6->s6_addr[14] = addr[4];
     177           0 :                         in6->s6_addr[15] = addr[5];
     178           0 :                 }
     179             :                 break;
     180             : 
     181             :         case IFT_GIF:
     182             :                 /*
     183             :                  * RFC2893 says: "SHOULD use IPv4 address as ifid source".
     184             :                  * however, IPv4 address is not very suitable as unique
     185             :                  * identifier source (can be renumbered).
     186             :                  * we don't do this.
     187             :                  */
     188           0 :                 return -1;
     189             : 
     190             :         default:
     191           0 :                 return -1;
     192             :         }
     193             : 
     194             :         /* sanity check: g bit must not indicate "group" */
     195           0 :         if (EUI64_GROUP(in6))
     196           0 :                 return -1;
     197             : 
     198             :         /* convert EUI64 into IPv6 interface identifier */
     199           0 :         EUI64_TO_IFID(in6);
     200             : 
     201             :         /*
     202             :          * sanity check: ifid must not be all zero, avoid conflict with
     203             :          * subnet router anycast
     204             :          */
     205           0 :         if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
     206           0 :             bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
     207           0 :                 return -1;
     208             :         }
     209             : 
     210           0 :         return 0;
     211           0 : }
     212             : 
     213             : /*
     214             :  * Generate a Semantically Opaque Interface Identifier according to RFC 7217
     215             :  *
     216             :  * in6 - upper 64bits are preserved
     217             :  */
     218             : int
     219           0 : in6_get_soii_ifid(struct ifnet *ifp0, struct in6_addr *in6)
     220             : {
     221             :         struct ifnet *ifp;
     222           0 :         SHA2_CTX ctx;
     223           0 :         u_int8_t digest[SHA512_DIGEST_LENGTH];
     224           0 :         struct in6_addr prefix;
     225             :         struct sockaddr_dl *sdl;
     226           0 :         int dad_counter = 0; /* XXX not used */
     227             :         char *addr;
     228             : 
     229           0 :         if (ifp0->if_xflags & IFXF_INET6_NOSOII)
     230           0 :                 return -1;
     231             : 
     232           0 :         sdl = ifp0->if_sadl;
     233             : 
     234           0 :         if (sdl == NULL || sdl->sdl_alen == 0) {
     235             :                 /*
     236             :                  * try to get it from some other hardware interface like
     237             :                  * in in6_get_ifid()
     238             :                  */
     239           0 :                 TAILQ_FOREACH(ifp, &ifnet, if_list) {
     240           0 :                         if (ifp == ifp0)
     241             :                                 continue;
     242           0 :                         sdl = ifp->if_sadl;
     243           0 :                         if (sdl != NULL && sdl->sdl_alen != 0)
     244             :                                 break;
     245             :                 }
     246             :         }
     247             : 
     248           0 :         if (sdl == NULL || sdl->sdl_alen == 0)
     249           0 :                 return -1;
     250             : 
     251           0 :         memset(&prefix, 0, sizeof(prefix));
     252           0 :         prefix.s6_addr16[0] = htons(0xfe80);
     253           0 :         addr = LLADDR(sdl);
     254             : 
     255           0 :         SHA512Init(&ctx);
     256             : 
     257           0 :         SHA512Update(&ctx, &prefix, sizeof(prefix));
     258           0 :         SHA512Update(&ctx, addr, sdl->sdl_alen);
     259           0 :         SHA512Update(&ctx, &dad_counter, sizeof(dad_counter));
     260           0 :         SHA512Update(&ctx, ip6_soiikey, sizeof(ip6_soiikey));
     261           0 :         SHA512Final(digest, &ctx);
     262             : 
     263           0 :         memcpy(&in6->s6_addr[8], digest + (sizeof(digest) - 8), 8);
     264             : 
     265           0 :         return 0;
     266           0 : }
     267             : 
     268             : /*
     269             :  * Get interface identifier for the specified interface.  If it is not
     270             :  * available on ifp0, borrow interface identifier from other information
     271             :  * sources.
     272             :  */
     273             : void
     274           0 : in6_get_ifid(struct ifnet *ifp0, struct in6_addr *in6)
     275             : {
     276             :         struct ifnet *ifp;
     277             : 
     278             :         /* first, try to generate a Semantically Opaque Interface Identifier */
     279           0 :         if (in6_get_soii_ifid(ifp0, in6) == 0) {
     280           0 :                 nd6log((LOG_DEBUG, "%s: got Semantically Opaque Interface "
     281             :                     "Identifier\n", ifp0->if_xname));
     282             :                 goto success;
     283             :         }
     284             : 
     285             :         /* next, try to get it from the interface itself */
     286           0 :         if (in6_get_hw_ifid(ifp0, in6) == 0) {
     287           0 :                 nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
     288             :                     ifp0->if_xname));
     289             :                 goto success;
     290             :         }
     291             : 
     292             :         /* next, try to get it from some other hardware interface */
     293           0 :         TAILQ_FOREACH(ifp, &ifnet, if_list) {
     294           0 :                 if (ifp == ifp0)
     295             :                         continue;
     296           0 :                 if (in6_get_hw_ifid(ifp, in6) == 0)
     297             :                         goto success;
     298             :         }
     299             : 
     300             :         /* last resort: get from random number source */
     301           0 :         in6_get_rand_ifid(ifp, in6);
     302           0 :         nd6log((LOG_DEBUG,
     303             :             "%s: interface identifier generated by random number\n",
     304             :             ifp0->if_xname));
     305             : success:
     306           0 :         nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
     307             :             ifp0->if_xname, in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
     308             :             in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
     309             :             in6->s6_addr[14], in6->s6_addr[15]));
     310           0 : }
     311             : 
     312             : /*
     313             :  * ifid - used as EUI64 if not NULL, overrides other EUI64 sources
     314             :  */
     315             : 
     316             : int
     317           0 : in6_ifattach_linklocal(struct ifnet *ifp, struct in6_addr *ifid)
     318             : {
     319           0 :         struct in6_aliasreq ifra;
     320             :         struct in6_ifaddr *ia6;
     321             :         int error, flags;
     322             : 
     323           0 :         NET_ASSERT_LOCKED();
     324             : 
     325             :         /*
     326             :          * configure link-local address.
     327             :          */
     328           0 :         bzero(&ifra, sizeof(ifra));
     329           0 :         strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
     330           0 :         ifra.ifra_addr.sin6_family = AF_INET6;
     331           0 :         ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
     332           0 :         ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
     333           0 :         ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
     334           0 :         ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
     335           0 :         if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
     336           0 :                 ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
     337           0 :                 ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
     338           0 :         } else if (ifid) {
     339           0 :                 ifra.ifra_addr.sin6_addr = *ifid;
     340           0 :                 ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
     341           0 :                 ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
     342           0 :                 ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
     343           0 :                 ifra.ifra_addr.sin6_addr.s6_addr[8] &= ~EUI64_GBIT;
     344           0 :                 ifra.ifra_addr.sin6_addr.s6_addr[8] |= EUI64_UBIT;
     345           0 :         } else
     346           0 :                 in6_get_ifid(ifp, &ifra.ifra_addr.sin6_addr);
     347             : 
     348           0 :         ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
     349           0 :         ifra.ifra_prefixmask.sin6_family = AF_INET6;
     350           0 :         ifra.ifra_prefixmask.sin6_addr = in6mask64;
     351             :         /* link-local addresses should NEVER expire. */
     352           0 :         ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
     353           0 :         ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
     354             : 
     355             :         /*
     356             :          * XXX: Some P2P interfaces seem not to send packets just after
     357             :          * becoming up, so we skip p2p interfaces for safety.
     358             :          */
     359           0 :         if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) == 0))
     360           0 :                 ifra.ifra_flags |= IN6_IFF_TENTATIVE;
     361             : 
     362           0 :         error = in6_update_ifa(ifp, &ifra, in6ifa_ifpforlinklocal(ifp, 0));
     363           0 :         if (error != 0)
     364           0 :                 return (error);
     365             : 
     366           0 :         ia6 = in6ifa_ifpforlinklocal(ifp, 0);
     367             : 
     368             :         /* Perform DAD, if needed. */
     369           0 :         if (ia6->ia6_flags & IN6_IFF_TENTATIVE)
     370           0 :                 nd6_dad_start(&ia6->ia_ifa);
     371             : 
     372           0 :         if (ifp->if_flags & IFF_LOOPBACK) {
     373           0 :                 dohooks(ifp->if_addrhooks, 0);
     374           0 :                 return (0); /* No need to install a connected route. */
     375             :         }
     376             : 
     377             :         flags = RTF_CONNECTED;
     378           0 :         if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
     379           0 :                 flags |= RTF_CLONING;
     380             : 
     381           0 :         error = rt_ifa_add(&ia6->ia_ifa, flags, ia6->ia_ifa.ifa_addr);
     382           0 :         if (error) {
     383           0 :                 in6_purgeaddr(&ia6->ia_ifa);
     384           0 :                 return (error);
     385             :         }
     386           0 :         dohooks(ifp->if_addrhooks, 0);
     387             : 
     388           0 :         return (0);
     389           0 : }
     390             : 
     391             : int
     392           0 : in6_ifattach_loopback(struct ifnet *ifp)
     393             : {
     394           0 :         struct in6_addr in6 = in6addr_loopback;
     395           0 :         struct in6_aliasreq ifra;
     396             : 
     397           0 :         KASSERT(ifp->if_flags & IFF_LOOPBACK);
     398             : 
     399           0 :         if (in6ifa_ifpwithaddr(ifp, &in6) != NULL)
     400           0 :                 return (0);
     401             : 
     402           0 :         bzero(&ifra, sizeof(ifra));
     403           0 :         strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
     404           0 :         ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
     405           0 :         ifra.ifra_prefixmask.sin6_family = AF_INET6;
     406           0 :         ifra.ifra_prefixmask.sin6_addr = in6mask128;
     407             : 
     408             :         /*
     409             :          * Always initialize ia_dstaddr (= broadcast address) to loopback
     410             :          * address.  Follows IPv4 practice - see in_ifinit().
     411             :          */
     412           0 :         ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
     413           0 :         ifra.ifra_dstaddr.sin6_family = AF_INET6;
     414           0 :         ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
     415             : 
     416           0 :         ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
     417           0 :         ifra.ifra_addr.sin6_family = AF_INET6;
     418           0 :         ifra.ifra_addr.sin6_addr = in6addr_loopback;
     419             : 
     420             :         /* the loopback  address should NEVER expire. */
     421           0 :         ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
     422           0 :         ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
     423             : 
     424             :         /*
     425             :          * We are sure that this is a newly assigned address, so we can set
     426             :          * NULL to the 3rd arg.
     427             :          */
     428           0 :         return (in6_update_ifa(ifp, &ifra, NULL));
     429           0 : }
     430             : 
     431             : /*
     432             :  * compute NI group address, based on the current hostname setting.
     433             :  * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
     434             :  *
     435             :  * when ifp == NULL, the caller is responsible for filling scopeid.
     436             :  */
     437             : int
     438           0 : in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
     439             :     struct sockaddr_in6 *sa6)
     440             : {
     441             :         const char *p;
     442             :         u_int8_t *q;
     443           0 :         SHA2_CTX ctx;
     444           0 :         u_int8_t digest[SHA512_DIGEST_LENGTH];
     445           0 :         u_int8_t l;
     446           0 :         u_int8_t n[64]; /* a single label must not exceed 63 chars */
     447             : 
     448           0 :         if (!namelen || !name)
     449           0 :                 return -1;
     450             : 
     451             :         p = name;
     452           0 :         while (p && *p && *p != '.' && p - name < namelen)
     453           0 :                 p++;
     454           0 :         if (p - name > sizeof(n) - 1)
     455           0 :                 return -1;      /* label too long */
     456           0 :         l = p - name;
     457           0 :         strncpy((char *)n, name, l);
     458           0 :         n[(int)l] = '\0';
     459           0 :         for (q = n; *q; q++) {
     460           0 :                 if ('A' <= *q && *q <= 'Z')
     461           0 :                         *q = *q - 'A' + 'a';
     462             :         }
     463             : 
     464             :         /* generate 8 bytes of pseudo-random value. */
     465           0 :         SHA512Init(&ctx);
     466           0 :         SHA512Update(&ctx, &l, sizeof(l));
     467           0 :         SHA512Update(&ctx, n, l);
     468           0 :         SHA512Final(digest, &ctx);
     469             : 
     470           0 :         bzero(sa6, sizeof(*sa6));
     471           0 :         sa6->sin6_family = AF_INET6;
     472           0 :         sa6->sin6_len = sizeof(*sa6);
     473           0 :         sa6->sin6_addr.s6_addr16[0] = htons(0xff02);
     474           0 :         sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
     475           0 :         sa6->sin6_addr.s6_addr8[11] = 2;
     476           0 :         memcpy(&sa6->sin6_addr.s6_addr32[3], digest,
     477             :             sizeof(sa6->sin6_addr.s6_addr32[3]));
     478             : 
     479           0 :         return 0;
     480           0 : }
     481             : 
     482             : /*
     483             :  * XXX multiple loopback interface needs more care.  for instance,
     484             :  * nodelocal address needs to be configured onto only one of them.
     485             :  * XXX multiple link-local address case
     486             :  */
     487             : int
     488           0 : in6_ifattach(struct ifnet *ifp)
     489             : {
     490             :         /* some of the interfaces are inherently not IPv6 capable */
     491           0 :         switch (ifp->if_type) {
     492             :         case IFT_BRIDGE:
     493             :         case IFT_ENC:
     494             :         case IFT_PFLOG:
     495             :         case IFT_PFSYNC:
     496           0 :                 return (0);
     497             :         }
     498             : 
     499             :         /*
     500             :          * if link mtu is too small, don't try to configure IPv6.
     501             :          * remember there could be some link-layer that has special
     502             :          * fragmentation logic.
     503             :          */
     504           0 :         if (ifp->if_mtu < IPV6_MMTU)
     505           0 :                 return (EINVAL);
     506             : 
     507           0 :         if ((ifp->if_flags & IFF_MULTICAST) == 0)
     508           0 :                 return (EINVAL);
     509             : 
     510             :         /*
     511             :          * Assign loopback address if this lo(4) interface is the
     512             :          * default for its rdomain.
     513             :          */
     514           0 :         if ((ifp->if_flags & IFF_LOOPBACK) &&
     515           0 :             (ifp->if_index == rtable_loindex(ifp->if_rdomain))) {
     516             :                 int error;
     517             : 
     518           0 :                 error = in6_ifattach_loopback(ifp);
     519           0 :                 if (error)
     520           0 :                         return (error);
     521           0 :         }
     522             : 
     523             :         /* Assign a link-local address, if there's none. */
     524           0 :         if (in6ifa_ifpforlinklocal(ifp, 0) == NULL) {
     525           0 :                 if (in6_ifattach_linklocal(ifp, NULL) != 0) {
     526             :                         /* failed to assign linklocal address. bark? */
     527             :                 }
     528           0 :         }
     529             : 
     530           0 :         return (0);
     531           0 : }
     532             : 
     533             : /*
     534             :  * NOTE: in6_ifdetach() does not support loopback if at this moment.
     535             :  */
     536             : void
     537           0 : in6_ifdetach(struct ifnet *ifp)
     538             : {
     539             :         struct ifaddr *ifa, *next;
     540             :         struct rtentry *rt;
     541           0 :         struct sockaddr_in6 sin6;
     542             : 
     543             : #ifdef MROUTING
     544             :         /* remove ip6_mrouter stuff */
     545           0 :         ip6_mrouter_detach(ifp);
     546             : #endif
     547             : 
     548             :         /* nuke any of IPv6 addresses we have */
     549           0 :         TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
     550           0 :                 if (ifa->ifa_addr->sa_family != AF_INET6)
     551             :                         continue;
     552           0 :                 in6_purgeaddr(ifa);
     553           0 :                 dohooks(ifp->if_addrhooks, 0);
     554           0 :         }
     555             : 
     556             :         /*
     557             :          * Remove neighbor management table.  Must be called after
     558             :          * purging addresses.
     559             :          */
     560           0 :         nd6_purge(ifp);
     561             : 
     562             :         /* remove route to interface local allnodes multicast (ff01::1) */
     563           0 :         bzero(&sin6, sizeof(sin6));
     564           0 :         sin6.sin6_len = sizeof(struct sockaddr_in6);
     565           0 :         sin6.sin6_family = AF_INET6;
     566           0 :         sin6.sin6_addr = in6addr_intfacelocal_allnodes;
     567           0 :         sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
     568           0 :         rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain);
     569           0 :         if (rt && rt->rt_ifidx == ifp->if_index) {
     570           0 :                 rtdeletemsg(rt, ifp, ifp->if_rdomain);
     571           0 :                 rtfree(rt);
     572           0 :         }
     573             : 
     574             :         /* remove route to link-local allnodes multicast (ff02::1) */
     575           0 :         bzero(&sin6, sizeof(sin6));
     576           0 :         sin6.sin6_len = sizeof(struct sockaddr_in6);
     577           0 :         sin6.sin6_family = AF_INET6;
     578           0 :         sin6.sin6_addr = in6addr_linklocal_allnodes;
     579           0 :         sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
     580           0 :         rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain);
     581           0 :         if (rt && rt->rt_ifidx == ifp->if_index) {
     582           0 :                 rtdeletemsg(rt, ifp, ifp->if_rdomain);
     583           0 :                 rtfree(rt);
     584           0 :         }
     585             : 
     586           0 :         if (ifp->if_xflags & IFXF_AUTOCONF6)
     587           0 :                 ifp->if_xflags &= ~IFXF_AUTOCONF6;
     588           0 : }

Generated by: LCOV version 1.13