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

          Line data    Source code
       1             : /*      $OpenBSD: in6_src.c,v 1.81 2016/12/02 11:16:04 mpi 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/protosw.h>
      68             : #include <sys/socket.h>
      69             : #include <sys/socketvar.h>
      70             : #include <sys/ioctl.h>
      71             : #include <sys/errno.h>
      72             : #include <sys/time.h>
      73             : 
      74             : #include <net/if.h>
      75             : #include <net/if_var.h>
      76             : #include <net/route.h>
      77             : 
      78             : #include <netinet/in.h>
      79             : #include <netinet/ip.h>
      80             : #include <netinet/in_pcb.h>
      81             : #include <netinet6/in6_var.h>
      82             : #include <netinet/ip6.h>
      83             : #include <netinet6/ip6_var.h>
      84             : #include <netinet6/nd6.h>
      85             : 
      86             : int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
      87             :     struct ip6_moptions *, struct route_in6 *, struct ifnet **, u_int);
      88             : 
      89             : /*
      90             :  * Return an IPv6 address, which is the most appropriate for a given
      91             :  * destination and pcb. We need the additional opt parameter because
      92             :  * the values set at pcb level can be overriden via cmsg.
      93             :  */
      94             : int
      95           0 : in6_pcbselsrc(struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
      96             :     struct inpcb *inp, struct ip6_pktopts *opts)
      97             : {
      98           0 :         struct ip6_moptions *mopts = inp->inp_moptions6;
      99           0 :         struct route_in6 *ro = &inp->inp_route6;
     100           0 :         struct in6_addr *laddr = &inp->inp_laddr6;
     101           0 :         u_int rtableid = inp->inp_rtableid;
     102           0 :         struct ifnet *ifp = NULL;
     103             :         struct in6_addr *dst;
     104             :         struct in6_ifaddr *ia6 = NULL;
     105             :         struct in6_pktinfo *pi = NULL;
     106             :         int     error;
     107             : 
     108           0 :         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           0 :         if (opts && (pi = opts->ip6po_pktinfo) &&
     117           0 :             !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
     118           0 :                 struct sockaddr_in6 sa6;
     119             : 
     120             :                 /* get the outgoing interface */
     121           0 :                 error = in6_selectif(dstsock, opts, mopts, ro, &ifp, rtableid);
     122           0 :                 if (error)
     123           0 :                         return (error);
     124             : 
     125           0 :                 bzero(&sa6, sizeof(sa6));
     126           0 :                 sa6.sin6_family = AF_INET6;
     127           0 :                 sa6.sin6_len = sizeof(sa6);
     128           0 :                 sa6.sin6_addr = pi->ipi6_addr;
     129             : 
     130           0 :                 if (ifp && IN6_IS_SCOPE_EMBED(&sa6.sin6_addr))
     131           0 :                         sa6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
     132           0 :                 if_put(ifp); /* put reference from in6_selectif */
     133             : 
     134           0 :                 ia6 = ifatoia6(ifa_ifwithaddr(sin6tosa(&sa6), rtableid));
     135           0 :                 if (ia6 == NULL || (ia6->ia6_flags &
     136             :                      (IN6_IFF_ANYCAST|IN6_IFF_TENTATIVE|IN6_IFF_DUPLICATED)))
     137           0 :                         return (EADDRNOTAVAIL);
     138             : 
     139           0 :                 pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */
     140             : 
     141           0 :                 *in6src = &pi->ipi6_addr;
     142           0 :                 return (0);
     143           0 :         }
     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           0 :         if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
     150           0 :                 *in6src = laddr;
     151           0 :                 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           0 :         if (pi && pi->ipi6_ifindex) {
     160           0 :                 ifp = if_get(pi->ipi6_ifindex);
     161           0 :                 if (ifp == NULL)
     162           0 :                         return (ENXIO); /* XXX: better error? */
     163             : 
     164           0 :                 ia6 = in6_ifawithscope(ifp, dst, rtableid);
     165           0 :                 if_put(ifp);
     166             : 
     167           0 :                 if (ia6 == NULL)
     168           0 :                         return (EADDRNOTAVAIL);
     169             : 
     170           0 :                 *in6src = &ia6->ia_addr.sin6_addr;
     171           0 :                 return (0);
     172             :         }
     173             : 
     174           0 :         error = in6_selectsrc(in6src, dstsock, mopts, rtableid);
     175           0 :         if (error != EADDRNOTAVAIL)
     176           0 :                 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           0 :         if (!rtisvalid(ro->ro_rt) || (ro->ro_tableid != rtableid) ||
     183           0 :             !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, dst)) {
     184           0 :                 rtfree(ro->ro_rt);
     185           0 :                 ro->ro_rt = NULL;
     186           0 :         }
     187           0 :         if (ro->ro_rt == NULL) {
     188             :                 struct sockaddr_in6 *sa6;
     189             : 
     190             :                 /* No route yet, so try to acquire one */
     191           0 :                 bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
     192           0 :                 ro->ro_tableid = rtableid;
     193             :                 sa6 = &ro->ro_dst;
     194           0 :                 sa6->sin6_family = AF_INET6;
     195           0 :                 sa6->sin6_len = sizeof(struct sockaddr_in6);
     196           0 :                 sa6->sin6_addr = *dst;
     197           0 :                 sa6->sin6_scope_id = dstsock->sin6_scope_id;
     198           0 :                 ro->ro_rt = rtalloc(sin6tosa(&ro->ro_dst),
     199           0 :                     RT_RESOLVE, ro->ro_tableid);
     200           0 :         }
     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           0 :         if (ro->ro_rt) {
     210           0 :                 ifp = if_get(ro->ro_rt->rt_ifidx);
     211           0 :                 if (ifp != NULL) {
     212           0 :                         ia6 = in6_ifawithscope(ifp, dst, rtableid);
     213           0 :                         if_put(ifp);
     214           0 :                 }
     215           0 :                 if (ia6 == NULL) /* xxx scope error ?*/
     216           0 :                         ia6 = ifatoia6(ro->ro_rt->rt_ifa);
     217             :         }
     218           0 :         if (ia6 == NULL)
     219           0 :                 return (EHOSTUNREACH);  /* no route */
     220             : 
     221           0 :         *in6src = &ia6->ia_addr.sin6_addr;
     222           0 :         return (0);
     223           0 : }
     224             : 
     225             : /*
     226             :  * Return an IPv6 address, which is the most appropriate for a given
     227             :  * destination and multicast options.
     228             :  * If necessary, this function lookups the routing table and returns
     229             :  * an entry to the caller for later use.
     230             :  */
     231             : int
     232           0 : in6_selectsrc(struct in6_addr **in6src, struct sockaddr_in6 *dstsock,
     233             :     struct ip6_moptions *mopts, unsigned int rtableid)
     234             : {
     235             :         struct ifnet *ifp = NULL;
     236             :         struct in6_addr *dst;
     237             :         struct in6_ifaddr *ia6 = NULL;
     238             : 
     239           0 :         dst = &dstsock->sin6_addr;
     240             : 
     241             :         /*
     242             :          * If the destination address is a link-local unicast address or
     243             :          * a link/interface-local multicast address, and if the outgoing
     244             :          * interface is specified by the sin6_scope_id filed, use an address
     245             :          * associated with the interface.
     246             :          * XXX: We're now trying to define more specific semantics of
     247             :          *      sin6_scope_id field, so this part will be rewritten in
     248             :          *      the near future.
     249             :          */
     250           0 :         if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst) ||
     251           0 :              IN6_IS_ADDR_MC_INTFACELOCAL(dst)) && dstsock->sin6_scope_id) {
     252           0 :                 ifp = if_get(dstsock->sin6_scope_id);
     253           0 :                 if (ifp == NULL)
     254           0 :                         return (ENXIO); /* XXX: better error? */
     255             : 
     256           0 :                 ia6 = in6_ifawithscope(ifp, dst, rtableid);
     257           0 :                 if_put(ifp);
     258             : 
     259           0 :                 if (ia6 == NULL)
     260           0 :                         return (EADDRNOTAVAIL);
     261             : 
     262           0 :                 *in6src = &ia6->ia_addr.sin6_addr;
     263           0 :                 return (0);
     264             :         }
     265             : 
     266             :         /*
     267             :          * If the destination address is a multicast address and
     268             :          * the outgoing interface for the address is specified
     269             :          * by the caller, use an address associated with the interface.
     270             :          * Even if the outgoing interface is not specified, we also
     271             :          * choose a loopback interface as the outgoing interface.
     272             :          */
     273           0 :         if (IN6_IS_ADDR_MULTICAST(dst)) {
     274           0 :                 ifp = mopts ? if_get(mopts->im6o_ifidx) : NULL;
     275             : 
     276           0 :                 if (!ifp && dstsock->sin6_scope_id)
     277           0 :                         ifp = if_get(htons(dstsock->sin6_scope_id));
     278             : 
     279           0 :                 if (ifp) {
     280           0 :                         ia6 = in6_ifawithscope(ifp, dst, rtableid);
     281           0 :                         if_put(ifp);
     282             : 
     283           0 :                         if (ia6 == NULL)
     284           0 :                                 return (EADDRNOTAVAIL);
     285             : 
     286           0 :                         *in6src = &ia6->ia_addr.sin6_addr;
     287           0 :                         return (0);
     288             :                 }
     289             :         }
     290             : 
     291           0 :         return (EADDRNOTAVAIL);
     292           0 : }
     293             : 
     294             : struct rtentry *
     295           0 : in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
     296             :     struct route_in6 *ro, unsigned int rtableid)
     297             : {
     298             :         struct in6_addr *dst;
     299             : 
     300           0 :         dst = &dstsock->sin6_addr;
     301             : 
     302             :         /*
     303             :          * Use a cached route if it exists and is valid, else try to allocate
     304             :          * a new one.
     305             :          */
     306           0 :         if (ro) {
     307           0 :                 if (rtisvalid(ro->ro_rt))
     308           0 :                         KASSERT(sin6tosa(&ro->ro_dst)->sa_family == AF_INET6);
     309           0 :                 if (!rtisvalid(ro->ro_rt) ||
     310           0 :                     !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, dst)) {
     311           0 :                         rtfree(ro->ro_rt);
     312           0 :                         ro->ro_rt = NULL;
     313           0 :                 }
     314           0 :                 if (ro->ro_rt == NULL) {
     315             :                         struct sockaddr_in6 *sa6;
     316             : 
     317             :                         /* No route yet, so try to acquire one */
     318           0 :                         bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
     319           0 :                         ro->ro_tableid = rtableid;
     320             :                         sa6 = &ro->ro_dst;
     321           0 :                         *sa6 = *dstsock;
     322           0 :                         sa6->sin6_scope_id = 0;
     323           0 :                         ro->ro_tableid = rtableid;
     324           0 :                         ro->ro_rt = rtalloc_mpath(sin6tosa(&ro->ro_dst),
     325           0 :                             NULL, ro->ro_tableid);
     326           0 :                 }
     327             : 
     328             :                 /*
     329             :                  * Check if the outgoing interface conflicts with
     330             :                  * the interface specified by ipi6_ifindex (if specified).
     331             :                  * Note that loopback interface is always okay.
     332             :                  * (this may happen when we are sending a packet to one of
     333             :                  *  our own addresses.)
     334             :                  */
     335           0 :                 if (opts && opts->ip6po_pktinfo &&
     336           0 :                     opts->ip6po_pktinfo->ipi6_ifindex) {
     337           0 :                         if (ro->ro_rt != NULL &&
     338           0 :                             !ISSET(ro->ro_rt->rt_flags, RTF_LOCAL) &&
     339           0 :                             ro->ro_rt->rt_ifidx !=
     340             :                             opts->ip6po_pktinfo->ipi6_ifindex) {
     341           0 :                                 return (NULL);
     342             :                         }
     343             :                 }
     344             : 
     345           0 :                 return (ro->ro_rt);
     346             :         }
     347             : 
     348           0 :         return (NULL);
     349           0 : }
     350             : 
     351             : int
     352           0 : in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
     353             :     struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
     354             :     u_int rtableid)
     355             : {
     356             :         struct rtentry *rt = NULL;
     357             :         struct in6_pktinfo *pi = NULL;
     358             : 
     359             :         /* If the caller specify the outgoing interface explicitly, use it. */
     360           0 :         if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
     361           0 :                 *retifp = if_get(pi->ipi6_ifindex);
     362           0 :                 if (*retifp != NULL)
     363           0 :                         return (0);
     364             :         }
     365             : 
     366             :         /*
     367             :          * If the destination address is a multicast address and the outgoing
     368             :          * interface for the address is specified by the caller, use it.
     369             :          */
     370           0 :         if (IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) &&
     371           0 :             mopts != NULL && (*retifp = if_get(mopts->im6o_ifidx)) != NULL)
     372           0 :                 return (0);
     373             : 
     374           0 :         rt = in6_selectroute(dstsock, opts, ro, rtableid);
     375           0 :         if (rt == NULL)
     376           0 :                 return (EHOSTUNREACH);
     377             : 
     378             :         /*
     379             :          * do not use a rejected or black hole route.
     380             :          * XXX: this check should be done in the L2 output routine.
     381             :          * However, if we skipped this check here, we'd see the following
     382             :          * scenario:
     383             :          * - install a rejected route for a scoped address prefix
     384             :          *   (like fe80::/10)
     385             :          * - send a packet to a destination that matches the scoped prefix,
     386             :          *   with ambiguity about the scope zone.
     387             :          * - pick the outgoing interface from the route, and disambiguate the
     388             :          *   scope zone with the interface.
     389             :          * - ip6_output() would try to get another route with the "new"
     390             :          *   destination, which may be valid.
     391             :          * - we'd see no error on output.
     392             :          * Although this may not be very harmful, it should still be confusing.
     393             :          * We thus reject the case here.
     394             :          */
     395           0 :         if (rt && (rt->rt_flags & (RTF_REJECT | RTF_BLACKHOLE)))
     396           0 :                 return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
     397             : 
     398           0 :         if (rt != NULL)
     399           0 :                 *retifp = if_get(rt->rt_ifidx);
     400             : 
     401           0 :         return (0);
     402           0 : }
     403             : 
     404             : int
     405           0 : in6_selecthlim(struct inpcb *in6p)
     406             : {
     407           0 :         if (in6p && in6p->inp_hops >= 0)
     408           0 :                 return (in6p->inp_hops);
     409             : 
     410           0 :         return (ip6_defhlim);
     411           0 : }
     412             : 
     413             : /*
     414             :  * generate kernel-internal form (scopeid embedded into s6_addr16[1]).
     415             :  * If the address scope of is link-local, embed the interface index in the
     416             :  * address.  The routine determines our precedence
     417             :  * between advanced API scope/interface specification and basic API
     418             :  * specification.
     419             :  *
     420             :  * this function should be nuked in the future, when we get rid of
     421             :  * embedded scopeid thing.
     422             :  *
     423             :  * XXX actually, it is over-specification to return ifp against sin6_scope_id.
     424             :  * there can be multiple interfaces that belong to a particular scope zone
     425             :  * (in specification, we have 1:N mapping between a scope zone and interfaces).
     426             :  * we may want to change the function to return something other than ifp.
     427             :  */
     428             : int
     429           0 : in6_embedscope(struct in6_addr *in6, const struct sockaddr_in6 *sin6,
     430             :     struct inpcb *in6p)
     431             : {
     432             :         struct ifnet *ifp = NULL;
     433             :         u_int32_t scopeid;
     434             : 
     435           0 :         *in6 = sin6->sin6_addr;
     436           0 :         scopeid = sin6->sin6_scope_id;
     437             : 
     438             :         /*
     439             :          * don't try to read sin6->sin6_addr beyond here, since the caller may
     440             :          * ask us to overwrite existing sockaddr_in6
     441             :          */
     442             : 
     443           0 :         if (IN6_IS_SCOPE_EMBED(in6)) {
     444             :                 struct in6_pktinfo *pi;
     445             : 
     446             :                 /*
     447             :                  * KAME assumption: link id == interface id
     448             :                  */
     449             : 
     450           0 :                 if (in6p && in6p->inp_outputopts6 &&
     451           0 :                     (pi = in6p->inp_outputopts6->ip6po_pktinfo) &&
     452           0 :                     pi->ipi6_ifindex) {
     453           0 :                         ifp = if_get(pi->ipi6_ifindex);
     454           0 :                         if (ifp == NULL)
     455           0 :                                 return ENXIO;  /* XXX EINVAL? */
     456           0 :                         in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
     457           0 :                 } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
     458           0 :                     in6p->inp_moptions6 &&
     459           0 :                     (ifp = if_get(in6p->inp_moptions6->im6o_ifidx))) {
     460           0 :                         in6->s6_addr16[1] = htons(ifp->if_index);
     461           0 :                 } else if (scopeid) {
     462           0 :                         ifp = if_get(scopeid);
     463           0 :                         if (ifp == NULL)
     464           0 :                                 return ENXIO;  /* XXX EINVAL? */
     465             :                         /*XXX assignment to 16bit from 32bit variable */
     466           0 :                         in6->s6_addr16[1] = htons(scopeid & 0xffff);
     467           0 :                 }
     468           0 :                 if_put(ifp);
     469           0 :         }
     470             : 
     471           0 :         return 0;
     472           0 : }
     473             : 
     474             : /*
     475             :  * generate standard sockaddr_in6 from embedded form.
     476             :  * touches sin6_addr and sin6_scope_id only.
     477             :  *
     478             :  * this function should be nuked in the future, when we get rid of
     479             :  * embedded scopeid thing.
     480             :  */
     481             : void
     482           0 : in6_recoverscope(struct sockaddr_in6 *sin6, const struct in6_addr *in6)
     483             : {
     484             :         u_int32_t scopeid;
     485             : 
     486           0 :         sin6->sin6_addr = *in6;
     487             : 
     488             :         /*
     489             :          * don't try to read *in6 beyond here, since the caller may
     490             :          * ask us to overwrite existing sockaddr_in6
     491             :          */
     492             : 
     493           0 :         sin6->sin6_scope_id = 0;
     494           0 :         if (IN6_IS_SCOPE_EMBED(in6)) {
     495             :                 /*
     496             :                  * KAME assumption: link id == interface id
     497             :                  */
     498           0 :                 scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]);
     499           0 :                 if (scopeid) {
     500           0 :                         sin6->sin6_addr.s6_addr16[1] = 0;
     501           0 :                         sin6->sin6_scope_id = scopeid;
     502           0 :                 }
     503             :         }
     504           0 : }
     505             : 
     506             : /*
     507             :  * just clear the embedded scope identifer.
     508             :  */
     509             : void
     510           0 : in6_clearscope(struct in6_addr *addr)
     511             : {
     512           0 :         if (IN6_IS_SCOPE_EMBED(addr))
     513           0 :                 addr->s6_addr16[1] = 0;
     514           0 : }

Generated by: LCOV version 1.13