The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/in6_ifattach.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: in6_ifattach.c,v 1.121 2022/11/15 18:42:46 claudio 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 void    in6_get_ifid(struct ifnet *, struct in6_addr *);
   62 int     in6_ifattach_loopback(struct ifnet *);
   63 
   64 #define EUI64_GBIT      0x01
   65 #define EUI64_UBIT      0x02
   66 #define EUI64_TO_IFID(in6)      do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
   67 #define EUI64_GROUP(in6)        ((in6)->s6_addr[8] & EUI64_GBIT)
   68 #define EUI64_INDIVIDUAL(in6)   (!EUI64_GROUP(in6))
   69 #define EUI64_LOCAL(in6)        ((in6)->s6_addr[8] & EUI64_UBIT)
   70 #define EUI64_UNIVERSAL(in6)    (!EUI64_LOCAL(in6))
   71 
   72 #define IFID_LOCAL(in6)         (!EUI64_LOCAL(in6))
   73 #define IFID_UNIVERSAL(in6)     (!EUI64_UNIVERSAL(in6))
   74 
   75 /*
   76  * Generate a random interface identifier.
   77  *
   78  * in6 - upper 64bits are preserved
   79  */
   80 void
   81 in6_get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6)
   82 {
   83         arc4random_buf(&in6->s6_addr32[2], 8);
   84 
   85         /* make sure to set "u" bit to local, and "g" bit to individual. */
   86         in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
   87         in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
   88 
   89         /* convert EUI64 into IPv6 interface identifier */
   90         EUI64_TO_IFID(in6);
   91 }
   92 
   93 /*
   94  * Get interface identifier for the specified interface.
   95  *
   96  * in6 - upper 64bits are preserved
   97  */
   98 int
   99 in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
  100 {
  101         struct sockaddr_dl *sdl;
  102         char *addr;
  103         size_t addrlen;
  104         static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  105         static u_int8_t allone[8] =
  106                 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  107 
  108         sdl = ifp->if_sadl;
  109         if (sdl == NULL || sdl->sdl_alen == 0)
  110                 return -1;
  111 
  112         addr = LLADDR(sdl);
  113         addrlen = sdl->sdl_alen;
  114 
  115         switch (ifp->if_type) {
  116         case IFT_IEEE1394:
  117         case IFT_IEEE80211:
  118                 /* IEEE1394 uses 16byte length address starting with EUI64 */
  119                 if (addrlen > 8)
  120                         addrlen = 8;
  121                 break;
  122         default:
  123                 break;
  124         }
  125 
  126         /* get EUI64 */
  127         switch (ifp->if_type) {
  128         /* IEEE802/EUI64 cases - what others? */
  129         case IFT_ETHER:
  130         case IFT_CARP:
  131         case IFT_IEEE1394:
  132         case IFT_IEEE80211:
  133                 /* look at IEEE802/EUI64 only */
  134                 if (addrlen != 8 && addrlen != 6)
  135                         return -1;
  136 
  137                 /*
  138                  * check for invalid MAC address - on bsdi, we see it a lot
  139                  * since wildboar configures all-zero MAC on pccard before
  140                  * card insertion.
  141                  */
  142                 if (bcmp(addr, allzero, addrlen) == 0)
  143                         return -1;
  144                 if (bcmp(addr, allone, addrlen) == 0)
  145                         return -1;
  146 
  147                 /* make EUI64 address */
  148                 if (addrlen == 8)
  149                         memcpy(&in6->s6_addr[8], addr, 8);
  150                 else if (addrlen == 6) {
  151                         in6->s6_addr[8] = addr[0];
  152                         in6->s6_addr[9] = addr[1];
  153                         in6->s6_addr[10] = addr[2];
  154                         in6->s6_addr[11] = 0xff;
  155                         in6->s6_addr[12] = 0xfe;
  156                         in6->s6_addr[13] = addr[3];
  157                         in6->s6_addr[14] = addr[4];
  158                         in6->s6_addr[15] = addr[5];
  159                 }
  160                 break;
  161 
  162         case IFT_GIF:
  163                 /*
  164                  * RFC2893 says: "SHOULD use IPv4 address as ifid source".
  165                  * however, IPv4 address is not very suitable as unique
  166                  * identifier source (can be renumbered).
  167                  * we don't do this.
  168                  */
  169                 return -1;
  170 
  171         default:
  172                 return -1;
  173         }
  174 
  175         /* sanity check: g bit must not indicate "group" */
  176         if (EUI64_GROUP(in6))
  177                 return -1;
  178 
  179         /* convert EUI64 into IPv6 interface identifier */
  180         EUI64_TO_IFID(in6);
  181 
  182         /*
  183          * sanity check: ifid must not be all zero, avoid conflict with
  184          * subnet router anycast
  185          */
  186         if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
  187             bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
  188                 return -1;
  189         }
  190 
  191         return 0;
  192 }
  193 
  194 /*
  195  * Get interface identifier for the specified interface.  If it is not
  196  * available on ifp0, borrow interface identifier from other information
  197  * sources.
  198  */
  199 void
  200 in6_get_ifid(struct ifnet *ifp0, struct in6_addr *in6)
  201 {
  202         struct ifnet *ifp;
  203 
  204         /* first, try to get it from the interface itself */
  205         if (in6_get_hw_ifid(ifp0, in6) == 0) {
  206                 nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
  207                     ifp0->if_xname));
  208                 goto success;
  209         }
  210 
  211         /* next, try to get it from some other hardware interface */
  212         TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
  213                 if (ifp == ifp0)
  214                         continue;
  215                 if (in6_get_hw_ifid(ifp, in6) == 0)
  216                         goto success;
  217         }
  218 
  219         /* last resort: get from random number source */
  220         in6_get_rand_ifid(ifp, in6);
  221         nd6log((LOG_DEBUG,
  222             "%s: interface identifier generated by random number\n",
  223             ifp0->if_xname));
  224 success:
  225         nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
  226             ifp0->if_xname, in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
  227             in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
  228             in6->s6_addr[14], in6->s6_addr[15]));
  229 }
  230 
  231 /*
  232  * ifid - used as EUI64 if not NULL, overrides other EUI64 sources
  233  */
  234 
  235 int
  236 in6_ifattach_linklocal(struct ifnet *ifp, struct in6_addr *ifid)
  237 {
  238         struct in6_aliasreq ifra;
  239         struct in6_ifaddr *ia6;
  240         int error, flags;
  241 
  242         NET_ASSERT_LOCKED();
  243 
  244         /*
  245          * configure link-local address.
  246          */
  247         bzero(&ifra, sizeof(ifra));
  248         strlcpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
  249         ifra.ifra_addr.sin6_family = AF_INET6;
  250         ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
  251         ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
  252         ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  253         ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
  254         if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
  255                 ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
  256                 ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
  257         } else if (ifid) {
  258                 ifra.ifra_addr.sin6_addr = *ifid;
  259                 ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
  260                 ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  261                 ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
  262                 ifra.ifra_addr.sin6_addr.s6_addr[8] &= ~EUI64_GBIT;
  263                 ifra.ifra_addr.sin6_addr.s6_addr[8] |= EUI64_UBIT;
  264         } else
  265                 in6_get_ifid(ifp, &ifra.ifra_addr.sin6_addr);
  266 
  267         ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
  268         ifra.ifra_prefixmask.sin6_family = AF_INET6;
  269         ifra.ifra_prefixmask.sin6_addr = in6mask64;
  270         /* link-local addresses should NEVER expire. */
  271         ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
  272         ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
  273 
  274         /*
  275          * XXX: Some P2P interfaces seem not to send packets just after
  276          * becoming up, so we skip p2p interfaces for safety.
  277          */
  278         if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) == 0))
  279                 ifra.ifra_flags |= IN6_IFF_TENTATIVE;
  280 
  281         error = in6_update_ifa(ifp, &ifra, in6ifa_ifpforlinklocal(ifp, 0));
  282         if (error != 0)
  283                 return (error);
  284 
  285         ia6 = in6ifa_ifpforlinklocal(ifp, 0);
  286 
  287         /* Perform DAD, if needed. */
  288         if (ia6->ia6_flags & IN6_IFF_TENTATIVE)
  289                 nd6_dad_start(&ia6->ia_ifa);
  290 
  291         if (ifp->if_flags & IFF_LOOPBACK) {
  292                 if_addrhooks_run(ifp);
  293                 return (0); /* No need to install a connected route. */
  294         }
  295 
  296         flags = RTF_CONNECTED | RTF_MPATH;
  297         if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
  298                 flags |= RTF_CLONING;
  299 
  300         error = rt_ifa_add(&ia6->ia_ifa, flags, ia6->ia_ifa.ifa_addr,
  301             ifp->if_rdomain);
  302         if (error) {
  303                 in6_purgeaddr(&ia6->ia_ifa);
  304                 return (error);
  305         }
  306         if_addrhooks_run(ifp);
  307 
  308         return (0);
  309 }
  310 
  311 int
  312 in6_ifattach_loopback(struct ifnet *ifp)
  313 {
  314         struct in6_addr in6 = in6addr_loopback;
  315         struct in6_aliasreq ifra;
  316 
  317         KASSERT(ifp->if_flags & IFF_LOOPBACK);
  318 
  319         if (in6ifa_ifpwithaddr(ifp, &in6) != NULL)
  320                 return (0);
  321 
  322         bzero(&ifra, sizeof(ifra));
  323         strlcpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
  324         ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
  325         ifra.ifra_prefixmask.sin6_family = AF_INET6;
  326         ifra.ifra_prefixmask.sin6_addr = in6mask128;
  327 
  328         /*
  329          * Always initialize ia_dstaddr (= broadcast address) to loopback
  330          * address.  Follows IPv4 practice - see in_ifinit().
  331          */
  332         ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
  333         ifra.ifra_dstaddr.sin6_family = AF_INET6;
  334         ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
  335 
  336         ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
  337         ifra.ifra_addr.sin6_family = AF_INET6;
  338         ifra.ifra_addr.sin6_addr = in6addr_loopback;
  339 
  340         /* the loopback  address should NEVER expire. */
  341         ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
  342         ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
  343 
  344         /*
  345          * We are sure that this is a newly assigned address, so we can set
  346          * NULL to the 3rd arg.
  347          */
  348         return (in6_update_ifa(ifp, &ifra, NULL));
  349 }
  350 
  351 /*
  352  * XXX multiple loopback interface needs more care.  for instance,
  353  * nodelocal address needs to be configured onto only one of them.
  354  * XXX multiple link-local address case
  355  */
  356 int
  357 in6_ifattach(struct ifnet *ifp)
  358 {
  359         /* some of the interfaces are inherently not IPv6 capable */
  360         switch (ifp->if_type) {
  361         case IFT_BRIDGE:
  362         case IFT_ENC:
  363         case IFT_PFLOG:
  364         case IFT_PFSYNC:
  365                 return (0);
  366         }
  367 
  368         /*
  369          * if link mtu is too small, don't try to configure IPv6.
  370          * remember there could be some link-layer that has special
  371          * fragmentation logic.
  372          */
  373         if (ifp->if_mtu < IPV6_MMTU)
  374                 return (EINVAL);
  375 
  376         if (nd6_need_cache(ifp) && (ifp->if_flags & IFF_MULTICAST) == 0)
  377                 return (EINVAL);
  378 
  379         /*
  380          * Assign loopback address if this lo(4) interface is the
  381          * default for its rdomain.
  382          */
  383         if ((ifp->if_flags & IFF_LOOPBACK) &&
  384             (ifp->if_index == rtable_loindex(ifp->if_rdomain))) {
  385                 int error;
  386 
  387                 error = in6_ifattach_loopback(ifp);
  388                 if (error)
  389                         return (error);
  390         }
  391 
  392         switch (ifp->if_type) {
  393         case IFT_WIREGUARD:
  394                 return (0);
  395         }
  396 
  397         /* Assign a link-local address, if there's none. */
  398         if (in6ifa_ifpforlinklocal(ifp, 0) == NULL) {
  399                 if (in6_ifattach_linklocal(ifp, NULL) != 0) {
  400                         /* failed to assign linklocal address. bark? */
  401                 }
  402         }
  403 
  404         return (0);
  405 }
  406 
  407 /*
  408  * NOTE: in6_ifdetach() does not support loopback if at this moment.
  409  */
  410 void
  411 in6_ifdetach(struct ifnet *ifp)
  412 {
  413         struct ifaddr *ifa, *next;
  414         struct rtentry *rt;
  415         struct sockaddr_in6 sin6;
  416 
  417 #ifdef MROUTING
  418         /* remove ip6_mrouter stuff */
  419         ip6_mrouter_detach(ifp);
  420 #endif
  421 
  422         /* nuke any of IPv6 addresses we have */
  423         TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
  424                 if (ifa->ifa_addr->sa_family != AF_INET6)
  425                         continue;
  426                 in6_purgeaddr(ifa);
  427                 if_addrhooks_run(ifp);
  428         }
  429 
  430         /*
  431          * Remove neighbor management table.  Must be called after
  432          * purging addresses.
  433          */
  434         nd6_purge(ifp);
  435 
  436         /* remove route to interface local allnodes multicast (ff01::1) */
  437         bzero(&sin6, sizeof(sin6));
  438         sin6.sin6_len = sizeof(struct sockaddr_in6);
  439         sin6.sin6_family = AF_INET6;
  440         sin6.sin6_addr = in6addr_intfacelocal_allnodes;
  441         sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  442         rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain);
  443         if (rt && rt->rt_ifidx == ifp->if_index) {
  444                 rtdeletemsg(rt, ifp, ifp->if_rdomain);
  445                 rtfree(rt);
  446         }
  447 
  448         /* remove route to link-local allnodes multicast (ff02::1) */
  449         bzero(&sin6, sizeof(sin6));
  450         sin6.sin6_len = sizeof(struct sockaddr_in6);
  451         sin6.sin6_family = AF_INET6;
  452         sin6.sin6_addr = in6addr_linklocal_allnodes;
  453         sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  454         rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain);
  455         if (rt && rt->rt_ifidx == ifp->if_index) {
  456                 rtdeletemsg(rt, ifp, ifp->if_rdomain);
  457                 rtfree(rt);
  458         }
  459 
  460         if (ifp->if_xflags & (IFXF_AUTOCONF6 | IFXF_AUTOCONF6TEMP))
  461                 ifp->if_xflags &= ~(IFXF_AUTOCONF6 | IFXF_AUTOCONF6TEMP);
  462 }

Cache object: ab9451b092ff8f1f2eb087264156369f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.