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 /*      $FreeBSD: src/sys/netinet6/in6_src.c,v 1.1.2.3 2002/02/26 18:02:06 ume Exp $    */
    2 /*      $KAME: in6_src.c,v 1.37 2001/03/29 05:34:31 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 "opt_inet.h"
   65 #include "opt_inet6.h"
   66 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/jail.h>
   70 #include <sys/kernel.h>
   71 #include <sys/malloc.h>
   72 #include <sys/mbuf.h>
   73 #include <sys/protosw.h>
   74 #include <sys/socket.h>
   75 #include <sys/socketvar.h>
   76 #include <sys/sockio.h>
   77 #include <sys/sysctl.h>
   78 #include <sys/errno.h>
   79 #include <sys/time.h>
   80 #include <sys/proc.h>
   81 #include <sys/priv.h>
   82 
   83 #include <net/if.h>
   84 #include <net/route.h>
   85 
   86 #include <netinet/in.h>
   87 #include <netinet/in_var.h>
   88 #include <netinet/in_systm.h>
   89 #include <netinet/ip.h>
   90 #include <netinet/in_pcb.h>
   91 #include <netinet6/in6_var.h>
   92 #include <netinet/ip6.h>
   93 #include <netinet6/in6_pcb.h>
   94 #include <netinet6/ip6_var.h>
   95 #include <netinet6/nd6.h>
   96 #ifdef ENABLE_DEFAULT_SCOPE
   97 #include <netinet6/scope6_var.h>
   98 #endif
   99 
  100 #include <net/net_osdep.h>
  101 
  102 #define ADDR_LABEL_NOTAPP (-1)
  103 struct in6_addrpolicy defaultaddrpolicy;
  104 
  105 static void     init_policy_queue(void);
  106 static int      add_addrsel_policyent(struct in6_addrpolicy *);
  107 static int      delete_addrsel_policyent(struct in6_addrpolicy *);
  108 static int      walk_addrsel_policy(int (*)(struct in6_addrpolicy *, void *),
  109                                     void *);
  110 static int      dump_addrsel_policyent(struct in6_addrpolicy *, void *);
  111 
  112 
  113 /*
  114  * Return an IPv6 address, which is the most appropriate for a given
  115  * destination and user specified options.
  116  * If necessary, this function lookups the routing table and returns
  117  * an entry to the caller for later use.
  118  */
  119 struct in6_addr *
  120 in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
  121               struct ip6_moptions *mopts, struct route_in6 *ro,
  122               struct in6_addr *laddr, int *errorp, struct thread *td)
  123 {
  124         struct sockaddr_in6 jsin6;
  125         struct ucred *cred = NULL;
  126         struct in6_addr *dst;
  127         struct in6_ifaddr *ia6 = NULL;
  128         struct in6_pktinfo *pi = NULL;
  129         int jailed = 0;
  130 
  131         if (td && td->td_proc && td->td_proc->p_ucred)
  132                 cred = td->td_proc->p_ucred;
  133         if (cred && cred->cr_prison)
  134                 jailed = 1;
  135         jsin6.sin6_family = AF_INET6;
  136         dst = &dstsock->sin6_addr;
  137         *errorp = 0;
  138 
  139         /*
  140          * If the source address is explicitly specified by the caller,
  141          * use it.
  142          */
  143         if (opts && (pi = opts->ip6po_pktinfo) &&
  144             !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
  145                 jsin6.sin6_addr = pi->ipi6_addr;
  146                 if (jailed && !jailed_ip(cred->cr_prison,
  147                     (struct sockaddr *)&jsin6)) {
  148                         return(0);
  149                 } else {
  150                         return (&pi->ipi6_addr);
  151                 }
  152         }
  153 
  154         /*
  155          * If the source address is not specified but the socket(if any)
  156          * is already bound, use the bound address.
  157          */
  158         if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
  159                 jsin6.sin6_addr = *laddr;
  160                 if (jailed && !jailed_ip(cred->cr_prison,
  161                     (struct sockaddr *)&jsin6)) {
  162                         return(0);
  163                 } else {
  164                         return (laddr);
  165                 }
  166         }
  167 
  168         /*
  169          * If the caller doesn't specify the source address but
  170          * the outgoing interface, use an address associated with
  171          * the interface.
  172          */
  173         if (pi && pi->ipi6_ifindex) {
  174                 /* XXX boundary check is assumed to be already done. */
  175                 ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
  176                                        dst);
  177 
  178                 if (ia6 && jailed) {
  179                         jsin6.sin6_addr = (&ia6->ia_addr)->sin6_addr;
  180                         if (!jailed_ip(cred->cr_prison,
  181                                 (struct sockaddr *)&jsin6))
  182                                 ia6 = NULL;
  183                 }
  184 
  185                 if (ia6 == NULL) {
  186                         *errorp = EADDRNOTAVAIL;
  187                         return (0);
  188                 }
  189                 return (&satosin6(&ia6->ia_addr)->sin6_addr);
  190         }
  191 
  192         /*
  193          * If the destination address is a link-local unicast address or
  194          * a multicast address, and if the outgoing interface is specified
  195          * by the sin6_scope_id filed, use an address associated with the
  196          * interface.
  197          * XXX: We're now trying to define more specific semantics of
  198          *      sin6_scope_id field, so this part will be rewritten in
  199          *      the near future.
  200          */
  201         if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
  202             dstsock->sin6_scope_id) {
  203                 /*
  204                  * I'm not sure if boundary check for scope_id is done
  205                  * somewhere...
  206                  */
  207                 if (dstsock->sin6_scope_id < 0 ||
  208                     if_index < dstsock->sin6_scope_id) {
  209                         *errorp = ENXIO; /* XXX: better error? */
  210                         return (0);
  211                 }
  212                 ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
  213                                        dst);
  214 
  215                 if (ia6 && jailed) {
  216                         jsin6.sin6_addr = (&ia6->ia_addr)->sin6_addr;
  217                         if (!jailed_ip(cred->cr_prison,
  218                                 (struct sockaddr *)&jsin6))
  219                                 ia6 = NULL;
  220                 }
  221 
  222                 if (ia6 == NULL) {
  223                         *errorp = EADDRNOTAVAIL;
  224                         return (0);
  225                 }
  226                 return (&satosin6(&ia6->ia_addr)->sin6_addr);
  227         }
  228 
  229         /*
  230          * If the destination address is a multicast address and
  231          * the outgoing interface for the address is specified
  232          * by the caller, use an address associated with the interface.
  233          * There is a sanity check here; if the destination has node-local
  234          * scope, the outgoing interfacde should be a loopback address.
  235          * Even if the outgoing interface is not specified, we also
  236          * choose a loopback interface as the outgoing interface.
  237          */
  238         if (!jailed && IN6_IS_ADDR_MULTICAST(dst)) {
  239                 struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
  240 
  241                 if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
  242                         ifp = &loif[0];
  243                 }
  244 
  245                 if (ifp) {
  246                         ia6 = in6_ifawithscope(ifp, dst);
  247                         if (ia6 == NULL) {
  248                                 *errorp = EADDRNOTAVAIL;
  249                                 return (0);
  250                         }
  251                         return (&satosin6(&ia6->ia_addr)->sin6_addr);
  252                 }
  253         }
  254 
  255         /*
  256          * If the next hop address for the packet is specified
  257          * by caller, use an address associated with the route
  258          * to the next hop.
  259          */
  260         {
  261                 struct sockaddr_in6 *sin6_next;
  262                 struct rtentry *rt;
  263 
  264                 if (opts && opts->ip6po_nexthop) {
  265                         sin6_next = satosin6(opts->ip6po_nexthop);
  266                         rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
  267                         if (rt) {
  268                                 ia6 = in6_ifawithscope(rt->rt_ifp, dst);
  269                                 if (ia6 == NULL)
  270                                         ia6 = ifatoia6(rt->rt_ifa);
  271                         }
  272                         if (ia6 && jailed) {
  273                                 jsin6.sin6_addr = (&ia6->ia_addr)->sin6_addr;
  274                                 if (!jailed_ip(cred->cr_prison,
  275                                         (struct sockaddr *)&jsin6))
  276                                         ia6 = NULL;
  277                         }
  278 
  279                         if (ia6 == NULL) {
  280                                 *errorp = EADDRNOTAVAIL;
  281                                 return (0);
  282                         }
  283                         return (&satosin6(&ia6->ia_addr)->sin6_addr);
  284                 }
  285         }
  286 
  287         /*
  288          * If route is known or can be allocated now,
  289          * our src addr is taken from the i/f, else punt.
  290          */
  291         if (ro) {
  292                 if (ro->ro_rt &&
  293                     (!(ro->ro_rt->rt_flags & RTF_UP) ||
  294                      satosin6(&ro->ro_dst)->sin6_family != AF_INET6 ||
  295                      !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr,
  296                                          dst))) {
  297                         RTFREE(ro->ro_rt);
  298                         ro->ro_rt = NULL;
  299                 }
  300                 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
  301                         struct sockaddr_in6 *sa6;
  302 
  303                         /* No route yet, so try to acquire one */
  304                         bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
  305                         sa6 = &ro->ro_dst;
  306                         sa6->sin6_family = AF_INET6;
  307                         sa6->sin6_len = sizeof(struct sockaddr_in6);
  308                         sa6->sin6_addr = *dst;
  309                         sa6->sin6_scope_id = dstsock->sin6_scope_id;
  310                         if (!jailed && IN6_IS_ADDR_MULTICAST(dst)) {
  311                                 ro->ro_rt =
  312                                   rtpurelookup((struct sockaddr *)&ro->ro_dst);
  313                         } else {
  314                                 rtalloc((struct route *)ro);
  315                         }
  316                 }
  317 
  318                 /*
  319                  * in_pcbconnect() checks out IFF_LOOPBACK to skip using
  320                  * the address. But we don't know why it does so.
  321                  * It is necessary to ensure the scope even for lo0
  322                  * so doesn't check out IFF_LOOPBACK.
  323                  */
  324 
  325                 if (ro->ro_rt) {
  326                         ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
  327                         if (ia6 && jailed) {
  328                                 jsin6.sin6_addr = (&ia6->ia_addr)->sin6_addr;
  329                                 if (!jailed_ip(cred->cr_prison,
  330                                         (struct sockaddr *)&jsin6))
  331                                         ia6 = NULL;
  332                         }
  333 
  334                         if (ia6 == NULL) /* xxx scope error ?*/
  335                                 ia6 = ifatoia6(ro->ro_rt->rt_ifa);
  336 
  337                         if (ia6 && jailed) {
  338                                 jsin6.sin6_addr = (&ia6->ia_addr)->sin6_addr;
  339                                 if (!jailed_ip(cred->cr_prison,
  340                                         (struct sockaddr *)&jsin6))
  341                                         ia6 = NULL;
  342                         }
  343                 }
  344 #if 0
  345                 /*
  346                  * xxx The followings are necessary? (kazu)
  347                  * I don't think so.
  348                  * It's for SO_DONTROUTE option in IPv4.(jinmei)
  349                  */
  350                 if (ia6 == 0) {
  351                         struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
  352 
  353                         sin6->sin6_addr = *dst;
  354 
  355                         ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
  356                         if (ia6 == 0)
  357                                 ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
  358                         if (ia6 == 0)
  359                                 return (0);
  360                         return (&satosin6(&ia6->ia_addr)->sin6_addr);
  361                 }
  362 #endif /* 0 */
  363                 if (ia6 == NULL) {
  364                         *errorp = EHOSTUNREACH; /* no route */
  365                         return (0);
  366                 }
  367                 return (&satosin6(&ia6->ia_addr)->sin6_addr);
  368         }
  369 
  370         *errorp = EADDRNOTAVAIL;
  371         return (0);
  372 }
  373 
  374 /*
  375  * Default hop limit selection. The precedence is as follows:
  376  * 1. Hoplimit value specified via ioctl.
  377  * 2. (If the outgoing interface is detected) the current
  378  *     hop limit of the interface specified by router advertisement.
  379  * 3. The system default hoplimit.
  380 */
  381 int
  382 in6_selecthlim(struct in6pcb *in6p, struct ifnet *ifp)
  383 {
  384         if (in6p && in6p->in6p_hops >= 0)
  385                 return (in6p->in6p_hops);
  386         else if (ifp)
  387                 return (ND_IFINFO(ifp)->chlim);
  388         else
  389                 return (ip6_defhlim);
  390 }
  391 
  392 /*
  393  * XXX: this is borrowed from in6_pcbbind(). If possible, we should
  394  * share this function by all *bsd*...
  395  */
  396 int
  397 in6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct thread *td)
  398 {
  399         struct socket *so = inp->inp_socket;
  400         u_int16_t lport = 0, first, last, *lastport;
  401         int count, error = 0, wild = 0;
  402         struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
  403         struct ucred *cred = NULL;
  404 
  405         /* XXX: this is redundant when called from in6_pcbbind */
  406         if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
  407                 wild = INPLOOKUP_WILDCARD;
  408         if (td->td_proc && td->td_proc->p_ucred)
  409                 cred = td->td_proc->p_ucred;
  410 
  411         inp->inp_flags |= INP_ANONPORT;
  412 
  413         if (inp->inp_flags & INP_HIGHPORT) {
  414                 first = ipport_hifirstauto;     /* sysctl */
  415                 last  = ipport_hilastauto;
  416                 lastport = &pcbinfo->lasthi;
  417         } else if (inp->inp_flags & INP_LOWPORT) {
  418                 if ((error = priv_check(td, PRIV_ROOT)) != 0)
  419                         return error;
  420                 first = ipport_lowfirstauto;    /* 1023 */
  421                 last  = ipport_lowlastauto;     /* 600 */
  422                 lastport = &pcbinfo->lastlow;
  423         } else {
  424                 first = ipport_firstauto;       /* sysctl */
  425                 last  = ipport_lastauto;
  426                 lastport = &pcbinfo->lastport;
  427         }
  428         /*
  429          * Simple check to ensure all ports are not used up causing
  430          * a deadlock here.
  431          *
  432          * We split the two cases (up and down) so that the direction
  433          * is not being tested on each round of the loop.
  434          */
  435         if (first > last) {
  436                 /*
  437                  * counting down
  438                  */
  439                 count = first - last;
  440 
  441                 do {
  442                         if (count-- < 0) {      /* completely used? */
  443                                 /*
  444                                  * Undo any address bind that may have
  445                                  * occurred above.
  446                                  */
  447                                 inp->in6p_laddr = kin6addr_any;
  448                                 return (EAGAIN);
  449                         }
  450                         --*lastport;
  451                         if (*lastport > first || *lastport < last)
  452                                 *lastport = first;
  453                         lport = htons(*lastport);
  454                 } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
  455                          lport, wild, cred));
  456         } else {
  457                 /*
  458                  * counting up
  459                  */
  460                 count = last - first;
  461 
  462                 do {
  463                         if (count-- < 0) {      /* completely used? */
  464                                 /*
  465                                  * Undo any address bind that may have
  466                                  * occurred above.
  467                                  */
  468                                 inp->in6p_laddr = kin6addr_any;
  469                                 return (EAGAIN);
  470                         }
  471                         ++*lastport;
  472                         if (*lastport < first || *lastport > last)
  473                                 *lastport = first;
  474                         lport = htons(*lastport);
  475                 } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
  476                          lport, wild, cred));
  477         }
  478 
  479         inp->inp_lport = lport;
  480         if (in_pcbinsporthash(inp) != 0) {
  481                 inp->in6p_laddr = kin6addr_any;
  482                 inp->inp_lport = 0;
  483                 return (EAGAIN);
  484         }
  485 
  486         return (0);
  487 }
  488 
  489 /*
  490  * generate kernel-internal form (scopeid embedded into s6_addr16[1]).
  491  * If the address scope of is link-local, embed the interface index in the
  492  * address.  The routine determines our precedence
  493  * between advanced API scope/interface specification and basic API
  494  * specification.
  495  *
  496  * this function should be nuked in the future, when we get rid of
  497  * embedded scopeid thing.
  498  *
  499  * XXX actually, it is over-specification to return ifp against sin6_scope_id.
  500  * there can be multiple interfaces that belong to a particular scope zone
  501  * (in specification, we have 1:N mapping between a scope zone and interfaces).
  502  * we may want to change the function to return something other than ifp.
  503  */
  504 int
  505 in6_embedscope(struct in6_addr *in6,
  506                const struct sockaddr_in6 *sin6,
  507 #ifdef HAVE_NRL_INPCB
  508                struct inpcb *in6p,
  509 #define in6p_outputopts inp_outputopts6
  510 #define in6p_moptions   inp_moptions6
  511 #else
  512                struct in6pcb *in6p,
  513 #endif
  514                struct ifnet **ifpp)
  515 {
  516         struct ifnet *ifp = NULL;
  517         u_int32_t scopeid;
  518 
  519         *in6 = sin6->sin6_addr;
  520         scopeid = sin6->sin6_scope_id;
  521         if (ifpp)
  522                 *ifpp = NULL;
  523 
  524         /*
  525          * don't try to read sin6->sin6_addr beyond here, since the caller may
  526          * ask us to overwrite existing sockaddr_in6
  527          */
  528 
  529 #ifdef ENABLE_DEFAULT_SCOPE
  530         if (scopeid == 0)
  531                 scopeid = scope6_addr2default(in6);
  532 #endif
  533 
  534         if (IN6_IS_SCOPE_LINKLOCAL(in6)) {
  535                 struct in6_pktinfo *pi;
  536 
  537                 /*
  538                  * KAME assumption: link id == interface id
  539                  */
  540 
  541                 if (in6p && in6p->in6p_outputopts &&
  542                     (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
  543                     pi->ipi6_ifindex) {
  544                         ifp = ifindex2ifnet[pi->ipi6_ifindex];
  545                         in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
  546                 } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
  547                            in6p->in6p_moptions &&
  548                            in6p->in6p_moptions->im6o_multicast_ifp) {
  549                         ifp = in6p->in6p_moptions->im6o_multicast_ifp;
  550                         in6->s6_addr16[1] = htons(ifp->if_index);
  551                 } else if (scopeid) {
  552                         /* boundary check */
  553                         if (scopeid < 0 || if_index < scopeid)
  554                                 return ENXIO;  /* XXX EINVAL? */
  555                         ifp = ifindex2ifnet[scopeid];
  556                         /*XXX assignment to 16bit from 32bit variable */
  557                         in6->s6_addr16[1] = htons(scopeid & 0xffff);
  558                 }
  559 
  560                 if (ifpp)
  561                         *ifpp = ifp;
  562         }
  563 
  564         return 0;
  565 }
  566 #ifdef HAVE_NRL_INPCB
  567 #undef in6p_outputopts
  568 #undef in6p_moptions
  569 #endif
  570 
  571 /*
  572  * generate standard sockaddr_in6 from embedded form.
  573  * touches sin6_addr and sin6_scope_id only.
  574  *
  575  * this function should be nuked in the future, when we get rid of
  576  * embedded scopeid thing.
  577  */
  578 int
  579 in6_recoverscope(struct sockaddr_in6 *sin6, const struct in6_addr *in6,
  580                  struct ifnet *ifp)
  581 {
  582         u_int32_t scopeid;
  583 
  584         sin6->sin6_addr = *in6;
  585 
  586         /*
  587          * don't try to read *in6 beyond here, since the caller may
  588          * ask us to overwrite existing sockaddr_in6
  589          */
  590 
  591         sin6->sin6_scope_id = 0;
  592         if (IN6_IS_SCOPE_LINKLOCAL(in6)) {
  593                 /*
  594                  * KAME assumption: link id == interface id
  595                  */
  596                 scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]);
  597                 if (scopeid) {
  598                         /* sanity check */
  599                         if (scopeid < 0 || if_index < scopeid)
  600                                 return ENXIO;
  601                         if (ifp && ifp->if_index != scopeid)
  602                                 return ENXIO;
  603                         sin6->sin6_addr.s6_addr16[1] = 0;
  604                         sin6->sin6_scope_id = scopeid;
  605                 }
  606         }
  607 
  608         return 0;
  609 }
  610 
  611 /*
  612  * just clear the embedded scope identifer.
  613  * XXX: currently used for bsdi4 only as a supplement function.
  614  */
  615 void
  616 in6_clearscope(struct in6_addr *addr)
  617 {
  618         if (IN6_IS_SCOPE_LINKLOCAL(addr))
  619                 addr->s6_addr16[1] = 0;
  620 }
  621 
  622 void
  623 addrsel_policy_init(void)
  624 {
  625 
  626         init_policy_queue();
  627 
  628         /* initialize the "last resort" policy */
  629         bzero(&defaultaddrpolicy, sizeof(defaultaddrpolicy));
  630         defaultaddrpolicy.label = ADDR_LABEL_NOTAPP;
  631 }
  632 
  633 /*
  634  * Subroutines to manage the address selection policy table via sysctl.
  635  */
  636 struct walkarg {
  637         struct sysctl_req *w_req;
  638 };
  639 
  640 static int in6_src_sysctl(SYSCTL_HANDLER_ARGS);
  641 SYSCTL_DECL(_net_inet6_ip6);
  642 SYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy,
  643         CTLFLAG_RD, in6_src_sysctl, "Address selection policy");
  644 
  645 static int
  646 in6_src_sysctl(SYSCTL_HANDLER_ARGS)
  647 {
  648         struct walkarg w;
  649 
  650         if (req->newptr)
  651                 return EPERM;
  652 
  653         bzero(&w, sizeof(w));
  654         w.w_req = req;
  655 
  656         return (walk_addrsel_policy(dump_addrsel_policyent, &w));
  657 }
  658 
  659 int
  660 in6_src_ioctl(u_long cmd, caddr_t data)
  661 {
  662         int i;
  663         struct in6_addrpolicy ent0;
  664 
  665         if (cmd != SIOCAADDRCTL_POLICY && cmd != SIOCDADDRCTL_POLICY)
  666                 return (EOPNOTSUPP); /* check for safety */
  667 
  668         ent0 = *(struct in6_addrpolicy *)data;
  669 
  670         if (ent0.label == ADDR_LABEL_NOTAPP)
  671                 return (EINVAL);
  672         /* check if the prefix mask is consecutive. */
  673         if (in6_mask2len(&ent0.addrmask.sin6_addr, NULL) < 0)
  674                 return (EINVAL);
  675         /* clear trailing garbages (if any) of the prefix address. */
  676         for (i = 0; i < 4; i++) {
  677                 ent0.addr.sin6_addr.s6_addr32[i] &=
  678                         ent0.addrmask.sin6_addr.s6_addr32[i];
  679         }
  680         ent0.use = 0;
  681 
  682         switch (cmd) {
  683         case SIOCAADDRCTL_POLICY:
  684                 return (add_addrsel_policyent(&ent0));
  685         case SIOCDADDRCTL_POLICY:
  686                 return (delete_addrsel_policyent(&ent0));
  687         }
  688 
  689         return (0);             /* XXX: compromise compilers */
  690 }
  691 
  692 /*
  693  * The followings are implementation of the policy table using a
  694  * simple tail queue.
  695  * XXX such details should be hidden.
  696  * XXX implementation using binary tree should be more efficient.
  697  */
  698 struct addrsel_policyent {
  699         TAILQ_ENTRY(addrsel_policyent) ape_entry;
  700         struct in6_addrpolicy ape_policy;
  701 };
  702 
  703 TAILQ_HEAD(addrsel_policyhead, addrsel_policyent);
  704 
  705 struct addrsel_policyhead addrsel_policytab;
  706 
  707 static void
  708 init_policy_queue(void)
  709 {
  710         TAILQ_INIT(&addrsel_policytab);
  711 }
  712 
  713 static int
  714 add_addrsel_policyent(struct in6_addrpolicy *newpolicy)
  715 {
  716         struct addrsel_policyent *new, *pol;
  717 
  718         /* duplication check */
  719         for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
  720              pol = TAILQ_NEXT(pol, ape_entry)) {
  721                 if (SA6_ARE_ADDR_EQUAL(&newpolicy->addr,
  722                                        &pol->ape_policy.addr) &&
  723                     SA6_ARE_ADDR_EQUAL(&newpolicy->addrmask,
  724                                        &pol->ape_policy.addrmask)) {
  725                         return (EEXIST);        /* or override it? */
  726                 }
  727         }
  728 
  729         new = kmalloc(sizeof(*new), M_IFADDR, M_WAITOK | M_ZERO);
  730 
  731         /* XXX: should validate entry */
  732         new->ape_policy = *newpolicy;
  733 
  734         TAILQ_INSERT_TAIL(&addrsel_policytab, new, ape_entry);
  735 
  736         return (0);
  737 }
  738 
  739 static int
  740 delete_addrsel_policyent(struct in6_addrpolicy *key)
  741 {
  742         struct addrsel_policyent *pol;
  743 
  744         /* search for the entry in the table */
  745         for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
  746              pol = TAILQ_NEXT(pol, ape_entry)) {
  747                 if (SA6_ARE_ADDR_EQUAL(&key->addr, &pol->ape_policy.addr) &&
  748                     SA6_ARE_ADDR_EQUAL(&key->addrmask,
  749                                        &pol->ape_policy.addrmask)) {
  750                         break;
  751                 }
  752         }
  753         if (pol == NULL)
  754                 return (ESRCH);
  755 
  756         TAILQ_REMOVE(&addrsel_policytab, pol, ape_entry);
  757         kfree(pol, M_IFADDR);
  758 
  759         return (0);
  760 }
  761 
  762 static int
  763 walk_addrsel_policy(int(*callback)(struct in6_addrpolicy *, void *), void *w)
  764 {
  765         struct addrsel_policyent *pol;
  766         int error = 0;
  767 
  768         for (pol = TAILQ_FIRST(&addrsel_policytab); pol;
  769              pol = TAILQ_NEXT(pol, ape_entry)) {
  770                 if ((error = (*callback)(&pol->ape_policy, w)) != 0)
  771                         return (error);
  772         }
  773 
  774         return (error);
  775 }
  776 
  777 static int
  778 dump_addrsel_policyent(struct in6_addrpolicy *pol, void *arg)
  779 {
  780         int error = 0;
  781         struct walkarg *w = arg;
  782 
  783         error = SYSCTL_OUT(w->w_req, pol, sizeof(*pol));
  784 
  785         return (error);
  786 }

Cache object: 32afa89294bd2f28bd8c73af7576441a


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