root/netinet6/in6_src.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. in6_selectsrc
  2. selectroute
  3. in6_selectroute
  4. in6_selecthlim
  5. in6_embedscope
  6. in6_recoverscope
  7. in6_clearscope

    1 /*      $OpenBSD: in6_src.c,v 1.22 2006/12/11 11:26:05 itojun 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/malloc.h>
   67 #include <sys/mbuf.h>
   68 #include <sys/protosw.h>
   69 #include <sys/socket.h>
   70 #include <sys/socketvar.h>
   71 #include <sys/ioctl.h>
   72 #include <sys/errno.h>
   73 #include <sys/time.h>
   74 #include <sys/proc.h>
   75 
   76 #include <net/if.h>
   77 #include <net/route.h>
   78 
   79 #include <netinet/in.h>
   80 #include <netinet/in_var.h>
   81 #include <netinet/in_systm.h>
   82 #include <netinet/ip.h>
   83 #include <netinet/in_pcb.h>
   84 #include <netinet6/in6_var.h>
   85 #include <netinet/ip6.h>
   86 #include <netinet6/ip6_var.h>
   87 #include <netinet6/nd6.h>
   88 
   89 static int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
   90         struct ip6_moptions *, struct route_in6 *, struct ifnet **,
   91         struct rtentry **, int);
   92 
   93 /*
   94  * Return an IPv6 address, which is the most appropriate for a given
   95  * destination and user specified options.
   96  * If necessary, this function lookups the routing table and returns
   97  * an entry to the caller for later use.
   98  */
   99 struct in6_addr *
  100 in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
  101         struct sockaddr_in6 *dstsock;
  102         struct ip6_pktopts *opts;
  103         struct ip6_moptions *mopts;
  104         struct route_in6 *ro;
  105         struct in6_addr *laddr;
  106         int *errorp;
  107 {
  108         struct in6_addr *dst;
  109         struct in6_ifaddr *ia6 = 0;
  110         struct in6_pktinfo *pi = NULL;
  111 
  112         dst = &dstsock->sin6_addr;
  113         *errorp = 0;
  114 
  115         /*
  116          * If the source address is explicitly specified by the caller,
  117          * use it.
  118          */
  119         if (opts && (pi = opts->ip6po_pktinfo) &&
  120             !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
  121                 return (&pi->ipi6_addr);
  122 
  123         /*
  124          * If the source address is not specified but the socket(if any)
  125          * is already bound, use the bound address.
  126          */
  127         if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
  128                 return (laddr);
  129 
  130         /*
  131          * If the caller doesn't specify the source address but
  132          * the outgoing interface, use an address associated with
  133          * the interface.
  134          */
  135         if (pi && pi->ipi6_ifindex) {
  136                 /* XXX boundary check is assumed to be already done. */
  137                 ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
  138                                        dst);
  139                 if (ia6 == 0) {
  140                         *errorp = EADDRNOTAVAIL;
  141                         return (0);
  142                 }
  143                 return (&satosin6(&ia6->ia_addr)->sin6_addr);
  144         }
  145 
  146         /*
  147          * If the destination address is a link-local unicast address or
  148          * a link/interface-local multicast address, and if the outgoing
  149          * interface is specified by the sin6_scope_id filed, use an address
  150          * associated with the interface.
  151          * XXX: We're now trying to define more specific semantics of
  152          *      sin6_scope_id field, so this part will be rewritten in
  153          *      the near future.
  154          */
  155         if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MC_LINKLOCAL(dst) ||
  156              IN6_IS_ADDR_MC_INTFACELOCAL(dst)) && dstsock->sin6_scope_id) {
  157                 /*
  158                  * I'm not sure if boundary check for scope_id is done
  159                  * somewhere...
  160                  */
  161                 if (dstsock->sin6_scope_id < 0 ||
  162                     if_indexlim <= dstsock->sin6_scope_id ||
  163                     !ifindex2ifnet[dstsock->sin6_scope_id]) {
  164                         *errorp = ENXIO; /* XXX: better error? */
  165                         return (0);
  166                 }
  167                 ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
  168                                        dst);
  169                 if (ia6 == 0) {
  170                         *errorp = EADDRNOTAVAIL;
  171                         return (0);
  172                 }
  173                 return (&satosin6(&ia6->ia_addr)->sin6_addr);
  174         }
  175 
  176         /*
  177          * If the destination address is a multicast address and
  178          * the outgoing interface for the address is specified
  179          * by the caller, use an address associated with the interface.
  180          * Even if the outgoing interface is not specified, we also
  181          * choose a loopback interface as the outgoing interface.
  182          */
  183         if (IN6_IS_ADDR_MULTICAST(dst)) {
  184                 struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
  185 
  186                 if (!ifp && dstsock->sin6_scope_id)
  187                         ifp = ifindex2ifnet[htons(dstsock->sin6_scope_id)];
  188 
  189                 if (ifp) {
  190                         ia6 = in6_ifawithscope(ifp, dst);
  191                         if (ia6 == 0) {
  192                                 *errorp = EADDRNOTAVAIL;
  193                                 return (0);
  194                         }
  195                         return (&satosin6(&ia6->ia_addr)->sin6_addr);
  196                 }
  197         }
  198 
  199         /*
  200          * If the next hop address for the packet is specified
  201          * by caller, use an address associated with the route
  202          * to the next hop.
  203          */
  204         {
  205                 struct sockaddr_in6 *sin6_next;
  206                 struct rtentry *rt;
  207 
  208                 if (opts && opts->ip6po_nexthop) {
  209                         sin6_next = satosin6(opts->ip6po_nexthop);
  210                         rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
  211                         if (rt) {
  212                                 ia6 = in6_ifawithscope(rt->rt_ifp, dst);
  213                                 if (ia6 == 0)
  214                                         ia6 = ifatoia6(rt->rt_ifa);
  215                         }
  216                         if (ia6 == 0) {
  217                                 *errorp = EADDRNOTAVAIL;
  218                                 return (0);
  219                         }
  220                         return (&satosin6(&ia6->ia_addr)->sin6_addr);
  221                 }
  222         }
  223 
  224         /*
  225          * If route is known or can be allocated now,
  226          * our src addr is taken from the i/f, else punt.
  227          */
  228         if (ro) {
  229                 if (ro->ro_rt &&
  230                     !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
  231                         RTFREE(ro->ro_rt);
  232                         ro->ro_rt = (struct rtentry *)0;
  233                 }
  234                 if (ro->ro_rt == (struct rtentry *)0 ||
  235                     ro->ro_rt->rt_ifp == (struct ifnet *)0) {
  236                         struct sockaddr_in6 *sa6;
  237 
  238                         /* No route yet, so try to acquire one */
  239                         bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
  240                         sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
  241                         sa6->sin6_family = AF_INET6;
  242                         sa6->sin6_len = sizeof(struct sockaddr_in6);
  243                         sa6->sin6_addr = *dst;
  244                         sa6->sin6_scope_id = dstsock->sin6_scope_id;
  245                         if (IN6_IS_ADDR_MULTICAST(dst)) {
  246                                 ro->ro_rt = rtalloc1(&((struct route *)ro)
  247                                                      ->ro_dst, 0, 0);
  248                         } else {
  249                                 rtalloc_mpath((struct route *)ro, NULL, 0);
  250                         }
  251                 }
  252 
  253                 /*
  254                  * in_pcbconnect() checks out IFF_LOOPBACK to skip using
  255                  * the address. But we don't know why it does so.
  256                  * It is necessary to ensure the scope even for lo0
  257                  * so doesn't check out IFF_LOOPBACK.
  258                  */
  259 
  260                 if (ro->ro_rt) {
  261                         ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
  262                         if (ia6 == 0) /* xxx scope error ?*/
  263                                 ia6 = ifatoia6(ro->ro_rt->rt_ifa);
  264                 }
  265 #if 0
  266                 /*
  267                  * xxx The followings are necessary? (kazu)
  268                  * I don't think so.
  269                  * It's for SO_DONTROUTE option in IPv4.(jinmei)
  270                  */
  271                 if (ia6 == 0) {
  272                         struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
  273 
  274                         sin6->sin6_addr = *dst;
  275 
  276                         ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
  277                         if (ia6 == 0)
  278                                 ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
  279                         if (ia6 == 0)
  280                                 return (0);
  281                         return (&satosin6(&ia6->ia_addr)->sin6_addr);
  282                 }
  283 #endif /* 0 */
  284                 if (ia6 == 0) {
  285                         *errorp = EHOSTUNREACH; /* no route */
  286                         return (0);
  287                 }
  288                 return (&satosin6(&ia6->ia_addr)->sin6_addr);
  289         }
  290 
  291         *errorp = EADDRNOTAVAIL;
  292         return (0);
  293 }
  294 
  295 static int
  296 selectroute(dstsock, opts, mopts, ro, retifp, retrt, norouteok)
  297         struct sockaddr_in6 *dstsock;
  298         struct ip6_pktopts *opts;
  299         struct ip6_moptions *mopts;
  300         struct route_in6 *ro;
  301         struct ifnet **retifp;
  302         struct rtentry **retrt;
  303         int norouteok;
  304 {
  305         int error = 0;
  306         struct ifnet *ifp = NULL;
  307         struct rtentry *rt = NULL;
  308         struct sockaddr_in6 *sin6_next;
  309         struct in6_pktinfo *pi = NULL;
  310         struct in6_addr *dst;
  311 
  312         dst = &dstsock->sin6_addr;
  313 
  314 #if 0
  315         if (dstsock->sin6_addr.s6_addr32[0] == 0 &&
  316             dstsock->sin6_addr.s6_addr32[1] == 0 &&
  317             !IN6_IS_ADDR_LOOPBACK(&dstsock->sin6_addr)) {
  318                 printf("in6_selectroute: strange destination %s\n",
  319                        ip6_sprintf(&dstsock->sin6_addr));
  320         } else {
  321                 printf("in6_selectroute: destination = %s%%%d\n",
  322                        ip6_sprintf(&dstsock->sin6_addr),
  323                        dstsock->sin6_scope_id); /* for debug */
  324         }
  325 #endif
  326 
  327         /* If the caller specify the outgoing interface explicitly, use it. */
  328         if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) {
  329                 /* XXX boundary check is assumed to be already done. */
  330                 ifp = ifindex2ifnet[pi->ipi6_ifindex];
  331                 if (ifp != NULL &&
  332                     (norouteok || retrt == NULL ||
  333                      IN6_IS_ADDR_MULTICAST(dst))) {
  334                         /*
  335                          * we do not have to check or get the route for
  336                          * multicast.
  337                          */
  338                         goto done;
  339                 } else
  340                         goto getroute;
  341         }
  342 
  343         /*
  344          * If the destination address is a multicast address and the outgoing
  345          * interface for the address is specified by the caller, use it.
  346          */
  347         if (IN6_IS_ADDR_MULTICAST(dst) &&
  348             mopts != NULL && (ifp = mopts->im6o_multicast_ifp) != NULL) {
  349                 goto done; /* we do not need a route for multicast. */
  350         }
  351 
  352   getroute:
  353         /*
  354          * If the next hop address for the packet is specified by the caller,
  355          * use it as the gateway.
  356          */
  357         if (opts && opts->ip6po_nexthop) {
  358                 struct route_in6 *ron;
  359 
  360                 sin6_next = satosin6(opts->ip6po_nexthop);
  361 
  362                 /* at this moment, we only support AF_INET6 next hops */
  363                 if (sin6_next->sin6_family != AF_INET6) {
  364                         error = EAFNOSUPPORT; /* or should we proceed? */
  365                         goto done;
  366                 }
  367 
  368                 /*
  369                  * If the next hop is an IPv6 address, then the node identified
  370                  * by that address must be a neighbor of the sending host.
  371                  */
  372                 ron = &opts->ip6po_nextroute;
  373                 if ((ron->ro_rt &&
  374                     (ron->ro_rt->rt_flags & (RTF_UP | RTF_GATEWAY)) !=
  375                     RTF_UP) ||
  376                     !IN6_ARE_ADDR_EQUAL(&satosin6(&ron->ro_dst)->sin6_addr,
  377                     &sin6_next->sin6_addr)) {
  378                         if (ron->ro_rt) {
  379                                 RTFREE(ron->ro_rt);
  380                                 ron->ro_rt = NULL;
  381                         }
  382                         *satosin6(&ron->ro_dst) = *sin6_next;
  383                 }
  384                 if (ron->ro_rt == NULL) {
  385                         rtalloc((struct route *)ron); /* multi path case? */
  386                         if (ron->ro_rt == NULL ||
  387                             (ron->ro_rt->rt_flags & RTF_GATEWAY)) {
  388                                 if (ron->ro_rt) {
  389                                         RTFREE(ron->ro_rt);
  390                                         ron->ro_rt = NULL;
  391                                 }
  392                                 error = EHOSTUNREACH;
  393                                 goto done;
  394                         }
  395                 }
  396                 if (!nd6_is_addr_neighbor(sin6_next, ron->ro_rt->rt_ifp)) {
  397                         RTFREE(ron->ro_rt);
  398                         ron->ro_rt = NULL;
  399                         error = EHOSTUNREACH;
  400                         goto done;
  401                 }
  402                 rt = ron->ro_rt;
  403                 ifp = rt->rt_ifp;
  404 
  405                 /*
  406                  * When cloning is required, try to allocate a route to the
  407                  * destination so that the caller can store path MTU
  408                  * information.
  409                  */
  410                 goto done;
  411         }
  412 
  413         /*
  414          * Use a cached route if it exists and is valid, else try to allocate
  415          * a new one.  Note that we should check the address family of the
  416          * cached destination, in case of sharing the cache with IPv4.
  417          */
  418         if (ro) {
  419                 if (ro->ro_rt &&
  420                     (!(ro->ro_rt->rt_flags & RTF_UP) ||
  421                      ((struct sockaddr *)(&ro->ro_dst))->sa_family != AF_INET6 ||
  422                      !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,
  423                      dst))) {
  424                         RTFREE(ro->ro_rt);
  425                         ro->ro_rt = (struct rtentry *)NULL;
  426                 }
  427                 if (ro->ro_rt == (struct rtentry *)NULL) {
  428                         struct sockaddr_in6 *sa6;
  429 
  430                         /* No route yet, so try to acquire one */
  431                         bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
  432                         sa6 = (struct sockaddr_in6 *)&ro->ro_dst;
  433                         *sa6 = *dstsock;
  434                         sa6->sin6_scope_id = 0;
  435                         rtalloc_mpath((struct route *)ro, NULL, 0);
  436                 }
  437 
  438                 /*
  439                  * do not care about the result if we have the nexthop
  440                  * explicitly specified.
  441                  */
  442                 if (opts && opts->ip6po_nexthop)
  443                         goto done;
  444 
  445                 if (ro->ro_rt) {
  446                         ifp = ro->ro_rt->rt_ifp;
  447 
  448                         if (ifp == NULL) { /* can this really happen? */
  449                                 RTFREE(ro->ro_rt);
  450                                 ro->ro_rt = NULL;
  451                         }
  452                 }
  453                 if (ro->ro_rt == NULL)
  454                         error = EHOSTUNREACH;
  455                 rt = ro->ro_rt;
  456 
  457                 /*
  458                  * Check if the outgoing interface conflicts with
  459                  * the interface specified by ipi6_ifindex (if specified).
  460                  * Note that loopback interface is always okay.
  461                  * (this may happen when we are sending a packet to one of
  462                  *  our own addresses.)
  463                  */
  464                 if (opts && opts->ip6po_pktinfo &&
  465                     opts->ip6po_pktinfo->ipi6_ifindex) {
  466                         if (!(ifp->if_flags & IFF_LOOPBACK) &&
  467                             ifp->if_index !=
  468                             opts->ip6po_pktinfo->ipi6_ifindex) {
  469                                 error = EHOSTUNREACH;
  470                                 goto done;
  471                         }
  472                 }
  473         }
  474 
  475   done:
  476         if (ifp == NULL && rt == NULL) {
  477                 /*
  478                  * This can happen if the caller did not pass a cached route
  479                  * nor any other hints.  We treat this case an error.
  480                  */
  481                 error = EHOSTUNREACH;
  482         }
  483         if (error == EHOSTUNREACH)
  484                 ip6stat.ip6s_noroute++;
  485 
  486         if (retifp != NULL)
  487                 *retifp = ifp;
  488         if (retrt != NULL)
  489                 *retrt = rt;    /* rt may be NULL */
  490 
  491         return (error);
  492 }
  493 
  494 int
  495 in6_selectroute(dstsock, opts, mopts, ro, retifp, retrt)
  496         struct sockaddr_in6 *dstsock;
  497         struct ip6_pktopts *opts;
  498         struct ip6_moptions *mopts;
  499         struct route_in6 *ro;
  500         struct ifnet **retifp;
  501         struct rtentry **retrt;
  502 {
  503 
  504         return (selectroute(dstsock, opts, mopts, ro, retifp, retrt, 0));
  505 }
  506 
  507 /*
  508  * Default hop limit selection. The precedence is as follows:
  509  * 1. Hoplimit value specified via ioctl.
  510  * 2. (If the outgoing interface is detected) the current
  511  *     hop limit of the interface specified by router advertisement.
  512  * 3. The system default hoplimit.
  513 */
  514 #define in6pcb          inpcb
  515 #define in6p_hops       inp_hops        
  516 int
  517 in6_selecthlim(in6p, ifp)
  518         struct in6pcb *in6p;
  519         struct ifnet *ifp;
  520 {
  521         if (in6p && in6p->in6p_hops >= 0)
  522                 return (in6p->in6p_hops);
  523         else if (ifp)
  524                 return (ND_IFINFO(ifp)->chlim);
  525         else
  526                 return (ip6_defhlim);
  527 }
  528 #undef in6pcb
  529 #undef in6p_hops
  530 
  531 /*
  532  * generate kernel-internal form (scopeid embedded into s6_addr16[1]).
  533  * If the address scope of is link-local, embed the interface index in the
  534  * address.  The routine determines our precedence
  535  * between advanced API scope/interface specification and basic API
  536  * specification.
  537  *
  538  * this function should be nuked in the future, when we get rid of
  539  * embedded scopeid thing.
  540  *
  541  * XXX actually, it is over-specification to return ifp against sin6_scope_id.
  542  * there can be multiple interfaces that belong to a particular scope zone
  543  * (in specification, we have 1:N mapping between a scope zone and interfaces).
  544  * we may want to change the function to return something other than ifp.
  545  */
  546 int
  547 in6_embedscope(in6, sin6, in6p, ifpp)
  548         struct in6_addr *in6;
  549         const struct sockaddr_in6 *sin6;
  550         struct inpcb *in6p;
  551 #define in6p_outputopts inp_outputopts6
  552 #define in6p_moptions   inp_moptions6
  553         struct ifnet **ifpp;
  554 {
  555         struct ifnet *ifp = NULL;
  556         u_int32_t scopeid;
  557 
  558         *in6 = sin6->sin6_addr;
  559         scopeid = sin6->sin6_scope_id;
  560         if (ifpp)
  561                 *ifpp = NULL;
  562 
  563         /*
  564          * don't try to read sin6->sin6_addr beyond here, since the caller may
  565          * ask us to overwrite existing sockaddr_in6
  566          */
  567 
  568         if (IN6_IS_SCOPE_EMBED(in6)) {
  569                 struct in6_pktinfo *pi;
  570 
  571                 /*
  572                  * KAME assumption: link id == interface id
  573                  */
  574 
  575                 if (in6p && in6p->in6p_outputopts &&
  576                     (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
  577                     pi->ipi6_ifindex) {
  578                         ifp = ifindex2ifnet[pi->ipi6_ifindex];
  579                         in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
  580                 } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
  581                            in6p->in6p_moptions &&
  582                            in6p->in6p_moptions->im6o_multicast_ifp) {
  583                         ifp = in6p->in6p_moptions->im6o_multicast_ifp;
  584                         in6->s6_addr16[1] = htons(ifp->if_index);
  585                 } else if (scopeid) {
  586                         /* boundary check */
  587                         if (scopeid < 0 || if_indexlim <= scopeid ||
  588                             !ifindex2ifnet[scopeid])
  589                                 return ENXIO;  /* XXX EINVAL? */
  590                         ifp = ifindex2ifnet[scopeid];
  591                         /*XXX assignment to 16bit from 32bit variable */
  592                         in6->s6_addr16[1] = htons(scopeid & 0xffff);
  593                 }
  594 
  595                 if (ifpp)
  596                         *ifpp = ifp;
  597         }
  598 
  599         return 0;
  600 }
  601 #undef in6p_outputopts
  602 #undef in6p_moptions
  603 
  604 /*
  605  * generate standard sockaddr_in6 from embedded form.
  606  * touches sin6_addr and sin6_scope_id only.
  607  *
  608  * this function should be nuked in the future, when we get rid of
  609  * embedded scopeid thing.
  610  */
  611 int
  612 in6_recoverscope(sin6, in6, ifp)
  613         struct sockaddr_in6 *sin6;
  614         const struct in6_addr *in6;
  615         struct ifnet *ifp;
  616 {
  617         u_int32_t scopeid;
  618 
  619         sin6->sin6_addr = *in6;
  620 
  621         /*
  622          * don't try to read *in6 beyond here, since the caller may
  623          * ask us to overwrite existing sockaddr_in6
  624          */
  625 
  626         sin6->sin6_scope_id = 0;
  627         if (IN6_IS_SCOPE_EMBED(in6)) {
  628                 /*
  629                  * KAME assumption: link id == interface id
  630                  */
  631                 scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]);
  632                 if (scopeid) {
  633                         /* sanity check */
  634                         if (scopeid < 0 || if_indexlim <= scopeid ||
  635                             !ifindex2ifnet[scopeid])
  636                                 return ENXIO;
  637                         if (ifp && ifp->if_index != scopeid)
  638                                 return ENXIO;
  639                         sin6->sin6_addr.s6_addr16[1] = 0;
  640                         sin6->sin6_scope_id = scopeid;
  641                 }
  642         }
  643 
  644         return 0;
  645 }
  646 
  647 /*
  648  * just clear the embedded scope identifer.
  649  */
  650 void
  651 in6_clearscope(addr)
  652         struct in6_addr *addr;
  653 {
  654         if (IN6_IS_SCOPE_EMBED(addr))
  655                 addr->s6_addr16[1] = 0;
  656 }

/* [<][>][^][v][top][bottom][index][help] */