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_src.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_src.c,v 1.86 2022/02/22 01:15:02 guenther Exp $   */
    2 /*      $KAME: in6_src.c,v 1.36 2001/02/06 04:08:17 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 /*
   34  * Copyright (c) 1982, 1986, 1991, 1993
   35  *      The Regents of the University of California.  All rights reserved.
   36  *
   37  * Redistribution and use in source and binary forms, with or without
   38  * modification, are permitted provided that the following conditions
   39  * are met:
   40  * 1. Redistributions of source code must retain the above copyright
   41  *    notice, this list of conditions and the following disclaimer.
   42  * 2. Redistributions in binary form must reproduce the above copyright
   43  *    notice, this list of conditions and the following disclaimer in the
   44  *    documentation and/or other materials provided with the distribution.
   45  * 3. Neither the name of the University nor the names of its contributors
   46  *    may be used to endorse or promote products derived from this software
   47  *    without specific prior written permission.
   48  *
   49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   59  * SUCH DAMAGE.
   60  *
   61  *      @(#)in_pcb.c    8.2 (Berkeley) 1/4/94
   62  */
   63 
   64 #include <sys/param.h>
   65 #include <sys/systm.h>
   66 #include <sys/mbuf.h>
   67 #include <sys/socket.h>
   68 #include <sys/socketvar.h>
   69 #include <sys/ioctl.h>
   70 #include <sys/errno.h>
   71 #include <sys/time.h>
   72 
   73 #include <net/if.h>
   74 #include <net/if_var.h>
   75 #include <net/route.h>
   76 
   77 #include <netinet/in.h>
   78 #include <netinet/ip.h>
   79 #include <netinet/in_pcb.h>
   80 #include <netinet6/in6_var.h>
   81 #include <netinet/ip6.h>
   82 #include <netinet6/ip6_var.h>
   83 #include <netinet6/nd6.h>
   84 
   85 int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
   86     struct ip6_moptions *, struct route_in6 *, struct ifnet **, u_int);
   87 
   88 /*
   89  * Return an IPv6 address, which is the most appropriate for a given
   90  * destination and pcb. We need the additional opt parameter because
   91  * the values set at pcb level can be overridden via cmsg.
   92  */
   93 int
   94 in6_pcbselsrc(struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
   95     struct inpcb *inp, struct ip6_pktopts *opts)
   96 {
   97         struct ip6_moptions *mopts = inp->inp_moptions6;
   98         struct route_in6 *ro = &inp->inp_route6;
   99         struct in6_addr *laddr = &inp->inp_laddr6;
  100         u_int rtableid = inp->inp_rtableid;
  101         struct ifnet *ifp = NULL;
  102         struct sockaddr *ip6_source = NULL;
  103         struct in6_addr *dst;
  104         struct in6_ifaddr *ia6 = NULL;
  105         struct in6_pktinfo *pi = NULL;
  106         int     error;
  107 
  108         dst = &dstsock->sin6_addr;
  109 
  110         /*
  111          * If the source address is explicitly specified by the caller,
  112          * check if the requested source address is indeed a unicast address
  113          * assigned to the node, and can be used as the packet's source
  114          * address.  If everything is okay, use the address as source.
  115          */
  116         if (opts && (pi = opts->ip6po_pktinfo) &&
  117             !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
  118                 struct sockaddr_in6 sa6;
  119 
  120                 /* get the outgoing interface */
  121                 error = in6_selectif(dstsock, opts, mopts, ro, &ifp, rtableid);
  122                 if (error)
  123                         return (error);
  124 
  125                 bzero(&sa6, sizeof(sa6));
  126                 sa6.sin6_family = AF_INET6;
  127                 sa6.sin6_len = sizeof(sa6);
  128                 sa6.sin6_addr = pi->ipi6_addr;
  129 
  130                 if (ifp && IN6_IS_SCOPE_EMBED(&sa6.sin6_addr))
  131                         sa6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  132                 if_put(ifp); /* put reference from in6_selectif */
  133 
  134                 ia6 = ifatoia6(ifa_ifwithaddr(sin6tosa(&sa6), rtableid));
  135                 if (ia6 == NULL || (ia6->ia6_flags &
  136                      (IN6_IFF_ANYCAST|IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)))
  137                         return (EADDRNOTAVAIL);
  138 
  139                 pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */
  140 
  141                 *in6src = &pi->ipi6_addr;
  142                 return (0);
  143         }
  144 
  145         /*
  146          * If the source address is not specified but the socket(if any)
  147          * is already bound, use the bound address.
  148          */
  149         if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
  150                 *in6src = laddr;
  151                 return (0);
  152         }
  153 
  154         /*
  155          * If the caller doesn't specify the source address but
  156          * the outgoing interface, use an address associated with
  157          * the interface.
  158          */
  159         if (pi && pi->ipi6_ifindex) {
  160                 ifp = if_get(pi->ipi6_ifindex);
  161                 if (ifp == NULL)
  162                         return (ENXIO); /* XXX: better error? */
  163 
  164                 ia6 = in6_ifawithscope(ifp, dst, rtableid);
  165                 if_put(ifp);
  166 
  167                 if (ia6 == NULL)
  168                         return (EADDRNOTAVAIL);
  169 
  170                 *in6src = &ia6->ia_addr.sin6_addr;
  171                 return (0);
  172         }
  173 
  174         error = in6_selectsrc(in6src, dstsock, mopts, rtableid);
  175         if (error != EADDRNOTAVAIL)
  176                 return (error);
  177 
  178         /*
  179          * If route is known or can be allocated now,
  180          * our src addr is taken from the i/f, else punt.
  181          */
  182         if (!rtisvalid(ro->ro_rt) || (ro->ro_tableid != rtableid) ||
  183             !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, dst)) {
  184                 rtfree(ro->ro_rt);
  185                 ro->ro_rt = NULL;
  186         }
  187         if (ro->ro_rt == NULL) {
  188                 struct sockaddr_in6 *sa6;
  189 
  190                 /* No route yet, so try to acquire one */
  191                 bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
  192                 ro->ro_tableid = rtableid;
  193                 sa6 = &ro->ro_dst;
  194                 sa6->sin6_family = AF_INET6;
  195                 sa6->sin6_len = sizeof(struct sockaddr_in6);
  196                 sa6->sin6_addr = *dst;
  197                 sa6->sin6_scope_id = dstsock->sin6_scope_id;
  198                 ro->ro_rt = rtalloc(sin6tosa(&ro->ro_dst),
  199                     RT_RESOLVE, ro->ro_tableid);
  200         }
  201 
  202         /*
  203          * in_pcbconnect() checks out IFF_LOOPBACK to skip using
  204          * the address. But we don't know why it does so.
  205          * It is necessary to ensure the scope even for lo0
  206          * so doesn't check out IFF_LOOPBACK.
  207          */
  208 
  209         if (ro->ro_rt) {
  210                 ifp = if_get(ro->ro_rt->rt_ifidx);
  211                 if (ifp != NULL) {
  212                         ia6 = in6_ifawithscope(ifp, dst, rtableid);
  213                         if_put(ifp);
  214                 }
  215                 if (ia6 == NULL) /* xxx scope error ?*/
  216                         ia6 = ifatoia6(ro->ro_rt->rt_ifa);
  217         }
  218 
  219         /*
  220          * Use preferred source address if :
  221          * - destination is not onlink
  222          * - preferred source address is set
  223          * - output interface is UP
  224          */
  225         if (ro->ro_rt && !(ro->ro_rt->rt_flags & RTF_LLINFO) &&
  226             !(ro->ro_rt->rt_flags & RTF_HOST)) {
  227                 ip6_source = rtable_getsource(rtableid, AF_INET6);
  228                 if (ip6_source != NULL) {
  229                         struct ifaddr *ifa;
  230                         if ((ifa = ifa_ifwithaddr(ip6_source, rtableid)) !=
  231                             NULL && ISSET(ifa->ifa_ifp->if_flags, IFF_UP)) {
  232                                 *in6src = &satosin6(ip6_source)->sin6_addr;
  233                                 return (0);
  234                         }
  235                 }
  236         }
  237 
  238         if (ia6 == NULL)
  239                 return (EHOSTUNREACH);  /* no route */
  240 
  241         *in6src = &ia6->ia_addr.sin6_addr;
  242         return (0);
  243 }
  244 
  245 /*
  246  * Return an IPv6 address, which is the most appropriate for a given
  247  * destination and multicast options.
  248  * If necessary, this function lookups the routing table and returns
  249  * an entry to the caller for later use.
  250  */
  251 int
  252 in6_selectsrc(struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
  253     struct ip6_moptions *mopts, unsigned int rtableid)
  254 {
  255         struct ifnet *ifp = NULL;
  256         struct in6_addr *dst;
  257         struct in6_ifaddr *ia6 = NULL;
  258 
  259         dst = &dstsock->sin6_addr;
  260 
  261         /*
  262          * If the destination address is a link-local unicast address or
  263          * a link/interface-local multicast address, and if the outgoing
  264          * interface is specified by the sin6_scope_id filed, use an address
  265          * associated with the interface.
  266          * XXX: We're now trying to define more specific semantics of
  267          *      sin6_scope_id field, so this part will be rewritten in
  268          *      the near future.
  269          */
  270         if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst) ||
  271              IN6_IS_ADDR_MC_INTFACELOCAL(dst)) && dstsock->sin6_scope_id) {
  272                 ifp = if_get(dstsock->sin6_scope_id);
  273                 if (ifp == NULL)
  274                         return (ENXIO); /* XXX: better error? */
  275 
  276                 ia6 = in6_ifawithscope(ifp, dst, rtableid);
  277                 if_put(ifp);
  278 
  279                 if (ia6 == NULL)
  280                         return (EADDRNOTAVAIL);
  281 
  282                 *in6src = &ia6->ia_addr.sin6_addr;
  283                 return (0);
  284         }
  285 
  286         /*
  287          * If the destination address is a multicast address and
  288          * the outgoing interface for the address is specified
  289          * by the caller, use an address associated with the interface.
  290          * Even if the outgoing interface is not specified, we also
  291          * choose a loopback interface as the outgoing interface.
  292          */
  293         if (IN6_IS_ADDR_MULTICAST(dst)) {
  294                 ifp = mopts ? if_get(mopts->im6o_ifidx) : NULL;
  295 
  296                 if (!ifp && dstsock->sin6_scope_id)
  297                         ifp = if_get(htons(dstsock->sin6_scope_id));
  298 
  299                 if (ifp) {
  300                         ia6 = in6_ifawithscope(ifp, dst, rtableid);
  301                         if_put(ifp);
  302 
  303                         if (ia6 == NULL)
  304                                 return (EADDRNOTAVAIL);
  305 
  306                         *in6src = &ia6->ia_addr.sin6_addr;
  307                         return (0);
  308                 }
  309         }
  310 
  311         return (EADDRNOTAVAIL);
  312 }
  313 
  314 struct rtentry *
  315 in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
  316     struct route_in6 *ro, unsigned int rtableid)
  317 {
  318         struct in6_addr *dst;
  319 
  320         dst = &dstsock->sin6_addr;
  321 
  322         /*
  323          * Use a cached route if it exists and is valid, else try to allocate
  324          * a new one.
  325          */
  326         if (ro) {
  327                 if (rtisvalid(ro->ro_rt))
  328                         KASSERT(sin6tosa(&ro->ro_dst)->sa_family == AF_INET6);
  329                 if (!rtisvalid(ro->ro_rt) ||
  330                     !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, dst)) {
  331                         rtfree(ro->ro_rt);
  332                         ro->ro_rt = NULL;
  333                 }
  334                 if (ro->ro_rt == NULL) {
  335                         struct sockaddr_in6 *sa6;
  336 
  337                         /* No route yet, so try to acquire one */
  338                         bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
  339                         ro->ro_tableid = rtableid;
  340                         sa6 = &ro->ro_dst;
  341                         *sa6 = *dstsock;
  342                         sa6->sin6_scope_id = 0;
  343                         ro->ro_tableid = rtableid;
  344                         ro->ro_rt = rtalloc_mpath(sin6tosa(&ro->ro_dst),
  345                             NULL, ro->ro_tableid);
  346                 }
  347 
  348                 /*
  349                  * Check if the outgoing interface conflicts with
  350                  * the interface specified by ipi6_ifindex (if specified).
  351                  * Note that loopback interface is always okay.
  352                  * (this may happen when we are sending a packet to one of
  353                  *  our own addresses.)
  354                  */
  355                 if (opts && opts->ip6po_pktinfo &&
  356                     opts->ip6po_pktinfo->ipi6_ifindex) {
  357                         if (ro->ro_rt != NULL &&
  358                             !ISSET(ro->ro_rt->rt_flags, RTF_LOCAL) &&
  359                             ro->ro_rt->rt_ifidx !=
  360                             opts->ip6po_pktinfo->ipi6_ifindex) {
  361                                 return (NULL);
  362                         }
  363                 }
  364 
  365                 return (ro->ro_rt);
  366         }
  367 
  368         return (NULL);
  369 }
  370 
  371 int
  372 in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
  373     struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
  374     u_int rtableid)
  375 {
  376         struct rtentry *rt = NULL;
  377         struct in6_pktinfo *pi = NULL;
  378 
  379         /* If the caller specify the outgoing interface explicitly, use it. */
  380         if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
  381                 *retifp = if_get(pi->ipi6_ifindex);
  382                 if (*retifp != NULL)
  383                         return (0);
  384         }
  385 
  386         /*
  387          * If the destination address is a multicast address and the outgoing
  388          * interface for the address is specified by the caller, use it.
  389          */
  390         if (IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) &&
  391             mopts != NULL && (*retifp = if_get(mopts->im6o_ifidx)) != NULL)
  392                 return (0);
  393 
  394         rt = in6_selectroute(dstsock, opts, ro, rtableid);
  395         if (rt == NULL)
  396                 return (EHOSTUNREACH);
  397 
  398         /*
  399          * do not use a rejected or black hole route.
  400          * XXX: this check should be done in the L2 output routine.
  401          * However, if we skipped this check here, we'd see the following
  402          * scenario:
  403          * - install a rejected route for a scoped address prefix
  404          *   (like fe80::/10)
  405          * - send a packet to a destination that matches the scoped prefix,
  406          *   with ambiguity about the scope zone.
  407          * - pick the outgoing interface from the route, and disambiguate the
  408          *   scope zone with the interface.
  409          * - ip6_output() would try to get another route with the "new"
  410          *   destination, which may be valid.
  411          * - we'd see no error on output.
  412          * Although this may not be very harmful, it should still be confusing.
  413          * We thus reject the case here.
  414          */
  415         if (rt && (rt->rt_flags & (RTF_REJECT | RTF_BLACKHOLE)))
  416                 return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
  417 
  418         if (rt != NULL)
  419                 *retifp = if_get(rt->rt_ifidx);
  420 
  421         return (0);
  422 }
  423 
  424 int
  425 in6_selecthlim(struct inpcb *in6p)
  426 {
  427         if (in6p && in6p->inp_hops >= 0)
  428                 return (in6p->inp_hops);
  429 
  430         return (ip6_defhlim);
  431 }
  432 
  433 /*
  434  * generate kernel-internal form (scopeid embedded into s6_addr16[1]).
  435  * If the address scope of is link-local, embed the interface index in the
  436  * address.  The routine determines our precedence
  437  * between advanced API scope/interface specification and basic API
  438  * specification.
  439  *
  440  * this function should be nuked in the future, when we get rid of
  441  * embedded scopeid thing.
  442  *
  443  * XXX actually, it is over-specification to return ifp against sin6_scope_id.
  444  * there can be multiple interfaces that belong to a particular scope zone
  445  * (in specification, we have 1:N mapping between a scope zone and interfaces).
  446  * we may want to change the function to return something other than ifp.
  447  */
  448 int
  449 in6_embedscope(struct in6_addr *in6, const struct sockaddr_in6 *sin6,
  450     struct inpcb *in6p)
  451 {
  452         struct ifnet *ifp = NULL;
  453         u_int32_t scopeid;
  454 
  455         *in6 = sin6->sin6_addr;
  456         scopeid = sin6->sin6_scope_id;
  457 
  458         /*
  459          * don't try to read sin6->sin6_addr beyond here, since the caller may
  460          * ask us to overwrite existing sockaddr_in6
  461          */
  462 
  463         if (IN6_IS_SCOPE_EMBED(in6)) {
  464                 struct in6_pktinfo *pi;
  465 
  466                 /*
  467                  * KAME assumption: link id == interface id
  468                  */
  469 
  470                 if (in6p && in6p->inp_outputopts6 &&
  471                     (pi = in6p->inp_outputopts6->ip6po_pktinfo) &&
  472                     pi->ipi6_ifindex) {
  473                         ifp = if_get(pi->ipi6_ifindex);
  474                         if (ifp == NULL)
  475                                 return ENXIO;  /* XXX EINVAL? */
  476                         in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
  477                 } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
  478                     in6p->inp_moptions6 &&
  479                     (ifp = if_get(in6p->inp_moptions6->im6o_ifidx))) {
  480                         in6->s6_addr16[1] = htons(ifp->if_index);
  481                 } else if (scopeid) {
  482                         ifp = if_get(scopeid);
  483                         if (ifp == NULL)
  484                                 return ENXIO;  /* XXX EINVAL? */
  485                         /*XXX assignment to 16bit from 32bit variable */
  486                         in6->s6_addr16[1] = htons(scopeid & 0xffff);
  487                 }
  488                 if_put(ifp);
  489         }
  490 
  491         return 0;
  492 }
  493 
  494 /*
  495  * generate standard sockaddr_in6 from embedded form.
  496  * touches sin6_addr and sin6_scope_id only.
  497  *
  498  * this function should be nuked in the future, when we get rid of
  499  * embedded scopeid thing.
  500  */
  501 void
  502 in6_recoverscope(struct sockaddr_in6 *sin6, const struct in6_addr *in6)
  503 {
  504         u_int32_t scopeid;
  505 
  506         sin6->sin6_addr = *in6;
  507 
  508         /*
  509          * don't try to read *in6 beyond here, since the caller may
  510          * ask us to overwrite existing sockaddr_in6
  511          */
  512 
  513         sin6->sin6_scope_id = 0;
  514         if (IN6_IS_SCOPE_EMBED(in6)) {
  515                 /*
  516                  * KAME assumption: link id == interface id
  517                  */
  518                 scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]);
  519                 if (scopeid) {
  520                         sin6->sin6_addr.s6_addr16[1] = 0;
  521                         sin6->sin6_scope_id = scopeid;
  522                 }
  523         }
  524 }
  525 
  526 /*
  527  * just clear the embedded scope identifier.
  528  */
  529 void
  530 in6_clearscope(struct in6_addr *addr)
  531 {
  532         if (IN6_IS_SCOPE_EMBED(addr))
  533                 addr->s6_addr16[1] = 0;
  534 }

Cache object: 6101863f627ea3f9f1da225d0cbac799


[ 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.