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/bsd/netinet6/in6_prefix.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 /*      $KAME: in6_prefix.c,v 1.27 2000/03/29 23:13:13 itojun Exp $     */
    2 
    3 /*
    4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the project nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Copyright (c) 1982, 1986, 1991, 1993
   34  *      The Regents of the University of California.  All rights reserved.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  * 3. All advertising materials mentioning features or use of this software
   45  *    must display the following acknowledgement:
   46  *      This product includes software developed by the University of
   47  *      California, Berkeley and its contributors.
   48  * 4. Neither the name of the University nor the names of its contributors
   49  *    may be used to endorse or promote products derived from this software
   50  *    without specific prior written permission.
   51  *
   52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   62  * SUCH DAMAGE.
   63  *
   64  *      @(#)in.c        8.2 (Berkeley) 11/15/93
   65  */
   66 
   67 #include <sys/param.h>
   68 #include <sys/malloc.h>
   69 #include <sys/kernel.h>
   70 #include <sys/socket.h>
   71 #include <sys/socketvar.h>
   72 #include <sys/sockio.h>
   73 #include <sys/systm.h>
   74 #include <sys/syslog.h>
   75 #include <sys/proc.h>
   76 
   77 #include <net/if.h>
   78 
   79 #include <netinet/in.h>
   80 #include <netinet/in_var.h>
   81 #include <netinet/ip6.h>
   82 #include <netinet6/in6_prefix.h>
   83 #include <netinet6/ip6_var.h>
   84 
   85 #ifdef __APPLE__
   86 #define M_IP6RR         M_IP6MISC
   87 #define M_RR_ADDR       M_IP6MISC
   88 #else
   89 static MALLOC_DEFINE(M_IP6RR, "ip6rr", "IPv6 Router Renumbering Prefix");
   90 static MALLOC_DEFINE(M_RR_ADDR, "rp_addr", "IPv6 Router Renumbering Ifid");
   91 #endif
   92 
   93 struct rr_prhead rr_prefix;
   94 
   95 #include <net/net_osdep.h>
   96 
   97 static void     add_each_addr __P((struct socket *so, struct rr_prefix *rpp,
   98                                    struct rp_addr *rap));
   99 static int create_ra_entry __P((struct rp_addr **rapp));
  100 static int add_each_prefix __P((struct socket *so, struct rr_prefix *rpp));
  101 static void free_rp_entries __P((struct rr_prefix *rpp));
  102 static int link_stray_ia6s __P((struct rr_prefix *rpp));
  103 static void     rp_remove __P((struct rr_prefix *rpp));
  104 
  105 /*
  106  * Copy bits from src to tgt, from off bit for len bits.
  107  * Caller must specify collect tgtsize and srcsize.
  108  */
  109 static void
  110 bit_copy(char *tgt, u_int tgtsize, char *src, u_int srcsize,
  111          u_int off, u_int len)
  112 {
  113         char *sp, *tp;
  114 
  115         /* arg values check */
  116         if (srcsize < off || srcsize < (off + len) ||
  117             tgtsize < off || tgtsize < (off + len)) {
  118                 log(LOG_ERR,
  119                     "in6_prefix.c: bit_copy: invalid args: srcsize %d,\n"
  120                     "tgtsize %d, off %d, len %d\n", srcsize, tgtsize, off,
  121                     len);
  122                 return;
  123         }
  124 
  125         /* search start point */
  126         for (sp = src, tp = tgt; off >= 8; sp++, tp++)
  127                 off-=8;
  128         /* copy starting bits */
  129         if (off) {
  130                 char setbit;
  131                 int startbits;
  132 
  133                 startbits = min((8 - off), len);
  134 
  135                 for (setbit = (0x80 >> off); startbits;
  136                      setbit >>= 1, startbits--, len--)
  137                                 *tp  |= (setbit & *sp);
  138                 tp++;
  139                 sp++;
  140         }
  141         /* copy midium bits */
  142         for (; len >= 8; sp++, tp++) {
  143                 *tp = *sp;
  144                 len-=8;
  145         }
  146         /* copy ending bits */
  147         if (len) {
  148                 char setbit;
  149 
  150                 for (setbit = 0x80; len; setbit >>= 1, len--)
  151                         *tp  |= (setbit & *sp);
  152         }
  153 }
  154 
  155 static struct ifprefix *
  156 in6_prefixwithifp(struct ifnet *ifp, int plen, struct in6_addr *dst)
  157 {
  158         struct ifprefix *ifpr;
  159 
  160         /* search matched prefix */
  161         for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
  162              ifpr = TAILQ_NEXT(ifpr, ifpr_list))
  163         {
  164                 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
  165                     ifpr->ifpr_type != IN6_PREFIX_RR)
  166                         continue;
  167                 if (plen <= in6_matchlen(dst, IFPR_IN6(ifpr)))
  168                         break;
  169         }
  170         return (ifpr);
  171 }
  172 
  173 /*
  174  * Search prefix which matches arg prefix as specified in
  175  * draft-ietf-ipngwg-router-renum-08.txt
  176  */
  177 static struct rr_prefix *
  178 search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr)
  179 {
  180         struct ifprefix *ifpr;
  181         struct ifaddr *ifa;
  182         struct rr_prefix *rpp;
  183 
  184         /* search matched prefix */
  185         ifpr = in6_prefixwithifp(ifp, ipr->ipr_plen,
  186                                  &ipr->ipr_prefix.sin6_addr);
  187         if (ifpr != NULL)
  188                 return ifpr2rp(ifpr);
  189 
  190         /*
  191          * search matched addr, and then search prefix
  192          * which matches the addr
  193          */
  194 
  195         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
  196         {
  197                 if (ifa->ifa_addr->sa_family != AF_INET6)
  198                         continue;
  199                 if (ipr->ipr_plen <=
  200                     in6_matchlen(&ipr->ipr_prefix.sin6_addr, IFA_IN6(ifa)))
  201                         break;
  202         }
  203         if (ifa == NULL)
  204                 return NULL;
  205 
  206         rpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr);
  207         if (rpp != 0)
  208                 return rpp;
  209 
  210         for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
  211              ifpr = TAILQ_NEXT(ifpr, ifpr_list))
  212         {
  213                 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
  214                     ifpr->ifpr_type != IN6_PREFIX_RR)
  215                         continue;
  216                 if (ifpr->ifpr_plen <= in6_matchlen(IFA_IN6(ifa),
  217                                                     IFPR_IN6(ifpr)))
  218                         break;
  219         }
  220         if (ifpr != NULL)
  221                 log(LOG_ERR,  "in6_prefix.c: search_matched_prefix: addr %s"
  222                     "has no pointer to prefix %s\n", ip6_sprintf(IFA_IN6(ifa)),
  223                     ip6_sprintf(IFPR_IN6(ifpr)));
  224         return ifpr2rp(ifpr);
  225 }
  226 
  227 /*
  228  * Search prefix which matches arg prefix as specified in
  229  * draft-ietf-ipngwg-router-renum-08.txt, and mark it if exists.
  230  * Return 1 if anything matched, and 0 if nothing matched.
  231  */
  232 static int
  233 mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr)
  234 {
  235         struct ifprefix *ifpr;
  236         struct ifaddr *ifa;
  237         int matchlen, matched = 0;
  238 
  239         /* search matched prefixes */
  240         for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
  241              ifpr = TAILQ_NEXT(ifpr, ifpr_list))
  242         {
  243                 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
  244                     ifpr->ifpr_type != IN6_PREFIX_RR)
  245                         continue;
  246                 matchlen = in6_matchlen(&irr->irr_matchprefix.sin6_addr,
  247                                         IFPR_IN6(ifpr));
  248                 if (irr->irr_m_minlen > ifpr->ifpr_plen ||
  249                     irr->irr_m_maxlen < ifpr->ifpr_plen ||
  250                     irr->irr_m_len > matchlen)
  251                         continue;
  252                 matched = 1;
  253                 ifpr2rp(ifpr)->rp_statef_addmark = 1;
  254                 if (cmd == SIOCCIFPREFIX_IN6)
  255                         ifpr2rp(ifpr)->rp_statef_delmark = 1;
  256         }
  257 
  258         /*
  259          * search matched addr, and then search prefixes
  260          * which matche the addr
  261          */
  262         TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
  263         {
  264                 struct rr_prefix *rpp;
  265 
  266                 if (ifa->ifa_addr->sa_family != AF_INET6)
  267                         continue;
  268                 matchlen = in6_matchlen(&irr->irr_matchprefix.sin6_addr,
  269                                         IFA_IN6(ifa));
  270                 if (irr->irr_m_minlen > matchlen ||
  271                     irr->irr_m_maxlen < matchlen || irr->irr_m_len > matchlen)
  272                         continue;
  273                 rpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr);
  274                 if (rpp != 0) {
  275                         matched = 1;
  276                         rpp->rp_statef_addmark = 1;
  277                         if (cmd == SIOCCIFPREFIX_IN6)
  278                                 rpp->rp_statef_delmark = 1;
  279                 } else
  280                         log(LOG_WARNING, "in6_prefix.c: mark_matched_prefixes:"
  281                             "no back pointer to ifprefix for %s. "
  282                             "ND autoconfigured addr?\n",
  283                             ip6_sprintf(IFA_IN6(ifa)));
  284         }
  285         return matched;
  286 }
  287 
  288 /*
  289  * Mark global prefixes as to be deleted.
  290  */
  291 static void
  292 delmark_global_prefixes(struct ifnet *ifp, struct in6_rrenumreq *irr)
  293 {
  294         struct ifprefix *ifpr;
  295 
  296         /* search matched prefixes */
  297         for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
  298              ifpr = TAILQ_NEXT(ifpr, ifpr_list))
  299         {
  300                 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
  301                     ifpr->ifpr_type != IN6_PREFIX_RR)
  302                         continue;
  303                 /* mark delete global prefix */
  304                 if (in6_addrscope(RP_IN6(ifpr2rp(ifpr))) ==
  305                     IPV6_ADDR_SCOPE_GLOBAL)
  306                         ifpr2rp(ifpr)->rp_statef_delmark = 1;
  307         }
  308 }
  309 
  310 /* Unmark prefixes */
  311 static void
  312 unmark_prefixes(struct ifnet *ifp)
  313 {
  314         struct ifprefix *ifpr;
  315 
  316         /* unmark all prefix */
  317         for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
  318              ifpr = TAILQ_NEXT(ifpr, ifpr_list))
  319         {
  320                 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
  321                     ifpr->ifpr_type != IN6_PREFIX_RR)
  322                         continue;
  323                 /* unmark prefix */
  324                 ifpr2rp(ifpr)->rp_statef_addmark = 0;
  325                 ifpr2rp(ifpr)->rp_statef_delmark = 0;
  326         }
  327 }
  328 
  329 static void
  330 init_prefix_ltimes(struct rr_prefix *rpp)
  331 {
  332 
  333         if (rpp->rp_pltime == RR_INFINITE_LIFETIME ||
  334             rpp->rp_rrf_decrprefd == 0)
  335                 rpp->rp_preferred = 0;
  336         else
  337                 rpp->rp_preferred = time_second + rpp->rp_pltime;
  338         if (rpp->rp_vltime == RR_INFINITE_LIFETIME ||
  339             rpp->rp_rrf_decrvalid == 0)
  340                 rpp->rp_expire = 0;
  341         else
  342                 rpp->rp_expire = time_second + rpp->rp_vltime;
  343 }
  344 
  345 static int
  346 rr_are_ifid_equal(struct in6_addr *ii1, struct in6_addr *ii2, int ii_len)
  347 {
  348         int ii_bytelen, ii_bitlen;
  349         int p_bytelen, p_bitlen;
  350 
  351         /* sanity check */
  352         if (1 > ii_len ||
  353             ii_len > 124) { /* as RFC2373, prefix is at least 4 bit */
  354                 log(LOG_ERR, "rr_are_ifid_equal: invalid ifid length(%d)\n",
  355                     ii_len);
  356                 return(0);
  357         }
  358 
  359         ii_bytelen = ii_len / 8;
  360         ii_bitlen = ii_len % 8;
  361 
  362         p_bytelen = sizeof(struct in6_addr) - ii_bytelen - 1;
  363         p_bitlen = 8 - ii_bitlen;
  364 
  365         if (bcmp(ii1->s6_addr + p_bytelen + 1, ii2->s6_addr + p_bytelen + 1,
  366                  ii_bytelen))
  367                 return(0);
  368         if (((ii1->s6_addr[p_bytelen] << p_bitlen) & 0xff) !=
  369             ((ii2->s6_addr[p_bytelen] << p_bitlen) & 0xff))
  370                 return(0);
  371 
  372         return(1);
  373 }
  374 
  375 static struct rp_addr *
  376 search_ifidwithprefix(struct rr_prefix *rpp, struct in6_addr *ifid)
  377 {
  378         struct rp_addr *rap;
  379 
  380         LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry)
  381         {
  382                 if (rr_are_ifid_equal(ifid, &rap->ra_ifid,
  383                                       (sizeof(struct in6_addr) << 3) -
  384                                       rpp->rp_plen))
  385                         break;
  386         }
  387         return rap;
  388 }
  389 
  390 static int
  391 assign_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
  392 {
  393         int error = 0;
  394         struct rp_addr *rap;
  395         int s;
  396 
  397         if ((error = create_ra_entry(&rap)) != 0)
  398                 return error;
  399 
  400         /* copy interface id part */
  401         bit_copy((caddr_t)&rap->ra_ifid, sizeof(rap->ra_ifid) << 3,
  402                  (caddr_t)IA6_IN6(ia),
  403                  sizeof(*IA6_IN6(ia)) << 3, rpp->rp_plen, iilen);
  404         /* link to ia, and put into list */
  405         rap->ra_addr = ia;
  406         ifaref(&rap->ra_addr->ia_ifa);
  407 #if 0 /* Can't do this now, because rpp may be on th stack. should fix it? */
  408         ia->ia6_ifpr = rp2ifpr(rpp);
  409 #endif
  410         s = splnet();
  411         LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
  412         splx(s);
  413 
  414         return 0;
  415 }
  416 
  417 /*
  418  * add a link-local address to an interface.  we will add new interface address
  419  * (prefix database + new interface id).
  420  */
  421 static int
  422 in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia)
  423 {
  424         struct rr_prefix *rpp;
  425         struct rp_addr *rap;
  426         struct socket so;
  427         int error, s;
  428 
  429         if ((error = create_ra_entry(&rap)) != 0)
  430                 return(error);
  431         /* copy interface id part */
  432         bit_copy((caddr_t)&rap->ra_ifid, sizeof(rap->ra_ifid) << 3,
  433                  (caddr_t)IA6_IN6(ia), sizeof(*IA6_IN6(ia)) << 3,
  434                  64, (sizeof(rap->ra_ifid) << 3) - 64);
  435         /* XXX: init dummy so */
  436         bzero(&so, sizeof(so));
  437         /* insert into list */
  438         LIST_FOREACH(rpp, &rr_prefix, rp_entry)
  439         {
  440                 /*
  441                  * do not attempt to add an address, if ifp does not match
  442                  */
  443                 if (rpp->rp_ifp != ia->ia_ifp)
  444                         continue;
  445 
  446                 s = splnet();
  447                 LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
  448                 splx(s);
  449                 add_each_addr(&so, rpp, rap);
  450         }
  451         return 0;
  452 }
  453 
  454 /*
  455  * add an address to an interface.  if the interface id portion is new,
  456  * we will add new interface address (prefix database + new interface id).
  457  */
  458 int
  459 in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
  460 {
  461         int plen = (sizeof(*IA6_IN6(ia)) << 3) - iilen;
  462         struct ifprefix *ifpr;
  463         struct rp_addr *rap;
  464         int error = 0;
  465 
  466         if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia)))
  467                 return(in6_prefix_add_llifid(iilen, ia));
  468         ifpr = in6_prefixwithifp(ia->ia_ifp, plen, IA6_IN6(ia));
  469         if (ifpr == NULL) {
  470                 struct rr_prefix rp;
  471                 struct socket so;
  472                 int pplen = (plen == 128) ? 64 : plen; /* XXX hardcoded 64 is bad */
  473 
  474                 /* allocate a prefix for ia, with default properties */
  475 
  476                 /* init rp */
  477                 bzero(&rp, sizeof(rp));
  478                 rp.rp_type = IN6_PREFIX_RR;
  479                 rp.rp_ifp = ia->ia_ifp;
  480                 rp.rp_plen = pplen;
  481                 rp.rp_prefix.sin6_len = sizeof(rp.rp_prefix);
  482                 rp.rp_prefix.sin6_family = AF_INET6;
  483                 bit_copy((char *)RP_IN6(&rp), sizeof(*RP_IN6(&rp)) << 3,
  484                          (char *)&ia->ia_addr.sin6_addr,
  485                          sizeof(ia->ia_addr.sin6_addr) << 3,
  486                          0, pplen);
  487                 rp.rp_vltime = rp.rp_pltime = RR_INFINITE_LIFETIME;
  488                 rp.rp_raf_onlink = 1;
  489                 rp.rp_raf_auto = 1;
  490                 /* Is some FlagMasks for rrf necessary? */
  491                 rp.rp_rrf_decrvalid = rp.rp_rrf_decrprefd = 0;
  492                 rp.rp_origin = PR_ORIG_RR; /* can be renumbered */
  493 
  494                 /* create ra_entry */
  495                 error = link_stray_ia6s(&rp);
  496                 if (error != 0) {
  497                         free_rp_entries(&rp);
  498                         return error;
  499                 }
  500 
  501                 /* XXX: init dummy so */
  502                 bzero(&so, sizeof(so));
  503 
  504                 error = add_each_prefix(&so, &rp);
  505 
  506                 /* free each rp_addr entry */
  507                 free_rp_entries(&rp);
  508 
  509                 if (error != 0)
  510                         return error;
  511 
  512                 /* search again */
  513                 ifpr = in6_prefixwithifp(ia->ia_ifp, pplen, IA6_IN6(ia));
  514                 if (ifpr == NULL)
  515                         return 0;
  516         }
  517         rap = search_ifidwithprefix(ifpr2rp(ifpr), IA6_IN6(ia));
  518         if (rap != NULL) {
  519                 if (rap->ra_addr == NULL) {
  520                         rap->ra_addr = ia;
  521                         ifaref(&rap->ra_addr->ia_ifa);
  522                 } else if (rap->ra_addr != ia) {
  523                         /* There may be some inconsistencies between addrs. */
  524                         log(LOG_ERR, "ip6_prefix.c: addr %s/%d matched prefix"
  525                             " already has another ia %p(%s) on its ifid list\n",
  526                             ip6_sprintf(IA6_IN6(ia)), plen,
  527                             rap->ra_addr,
  528                             ip6_sprintf(IA6_IN6(rap->ra_addr)));
  529                         return EADDRINUSE /* XXX */;
  530                 }
  531                 ia->ia6_ifpr = ifpr;
  532                 return 0;
  533         }
  534         error = assign_ra_entry(ifpr2rp(ifpr), iilen, ia);
  535         if (error == 0)
  536                 ia->ia6_ifpr = ifpr;
  537         return (error);
  538 }
  539 
  540 void
  541 in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia)
  542 {
  543         struct rp_addr *rap;
  544 
  545         if (ia->ia6_ifpr == NULL)
  546                 return;
  547         rap = search_ifidwithprefix(ifpr2rp(ia->ia6_ifpr), IA6_IN6(ia));
  548         if (rap != NULL) {
  549                 int s = splnet();
  550                 LIST_REMOVE(rap, ra_entry);
  551                 splx(s);
  552                 if (rap->ra_addr)
  553                         ifafree(&rap->ra_addr->ia_ifa);
  554                 FREE(rap, M_RR_ADDR);
  555         }
  556 
  557         if (LIST_EMPTY(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead))
  558                 rp_remove(ifpr2rp(ia->ia6_ifpr));
  559 }
  560 
  561 void
  562 in6_purgeprefix(ifp)
  563         struct ifnet *ifp;
  564 {
  565         struct ifprefix *ifpr, *nextifpr;
  566 
  567         /* delete prefixes before ifnet goes away */
  568         for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr;
  569              ifpr = nextifpr)
  570         {
  571                 nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
  572                 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
  573                     ifpr->ifpr_type != IN6_PREFIX_RR)
  574                         continue;
  575                 (void)delete_each_prefix(ifpr2rp(ifpr), PR_ORIG_KERNEL);
  576         }
  577 }
  578 
  579 static void
  580 add_each_addr(struct socket *so, struct rr_prefix *rpp, struct rp_addr *rap)
  581 {
  582         struct in6_ifaddr *ia6;
  583         struct in6_aliasreq ifra;
  584         int error;
  585 
  586         /* init ifra */
  587         bzero(&ifra, sizeof(ifra));
  588         strncpy(ifra.ifra_name, if_name(rpp->rp_ifp), sizeof(ifra.ifra_name));
  589         ifra.ifra_addr.sin6_family = ifra.ifra_prefixmask.sin6_family =
  590                 AF_INET6;
  591         ifra.ifra_addr.sin6_len = ifra.ifra_prefixmask.sin6_len =
  592                 sizeof(ifra.ifra_addr);
  593         /* copy prefix part */
  594         bit_copy((char *)&ifra.ifra_addr.sin6_addr,
  595                  sizeof(ifra.ifra_addr.sin6_addr) << 3,
  596                  (char *)RP_IN6(rpp), sizeof(*RP_IN6(rpp)) << 3,
  597                  0, rpp->rp_plen);
  598         /* copy interface id part */
  599         bit_copy((char *)&ifra.ifra_addr.sin6_addr,
  600                  sizeof(ifra.ifra_addr.sin6_addr) << 3,
  601                  (char *)&rap->ra_ifid, sizeof(rap->ra_ifid) << 3,
  602                  rpp->rp_plen, (sizeof(rap->ra_ifid) << 3) - rpp->rp_plen);
  603         in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, rpp->rp_plen);
  604         /* don't care ifra_flags for now */
  605 
  606         /*
  607          * XXX: if we did this with finite lifetime values, the lifetimes would
  608          *      decrese in time and never incremented.
  609          *      we should need more clarifications on the prefix mechanism...
  610          */
  611         ifra.ifra_lifetime.ia6t_vltime = rpp->rp_vltime;
  612         ifra.ifra_lifetime.ia6t_pltime = rpp->rp_pltime;
  613 
  614         ia6 = in6ifa_ifpwithaddr(rpp->rp_ifp, &ifra.ifra_addr.sin6_addr);
  615         if (ia6 != NULL) {
  616                 if (ia6->ia6_ifpr == NULL) {
  617                         /* link this addr and the prefix each other */
  618                         if (rap->ra_addr)
  619                                 ifafree(&rap->ra_addr->ia_ifa);
  620                         rap->ra_addr = ia6;
  621                         ifaref(&rap->ra_addr->ia_ifa);
  622                         ia6->ia6_ifpr = rp2ifpr(rpp);
  623                         return;
  624                 }
  625                 if (ia6->ia6_ifpr == rp2ifpr(rpp)) {
  626                         if (rap->ra_addr)
  627                                 ifafree(&rap->ra_addr->ia_ifa);
  628                         rap->ra_addr = ia6;
  629                         ifaref(&rap->ra_addr->ia_ifa);
  630                         return;
  631                 }
  632                 /*
  633                  * The addr is already assigned to other
  634                  * prefix.
  635                  * There may be some inconsistencies between
  636                  * prefixes.
  637                  * e.g. overraped prefixes with common starting
  638                  *      part and different plefixlen.
  639                  *      Or, completely duplicated prefixes?
  640                  * log it and return.
  641                  */
  642                 log(LOG_ERR,
  643                     "in6_prefix.c: add_each_addr: addition of an addr %s/%d "
  644                     "failed because there is already another addr %s/%d\n",
  645                     ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen,
  646                     ip6_sprintf(IA6_IN6(ia6)),
  647                     in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL));
  648                 return;
  649         }
  650         /* propagate ANYCAST flag if it is set for ancestor addr */
  651         if (rap->ra_flags.anycast != 0)
  652                 ifra.ifra_flags |= IN6_IFF_ANYCAST;
  653         error = in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, rpp->rp_ifp,
  654                             current_proc());
  655         if (error != 0) {
  656                 log(LOG_ERR, "in6_prefix.c: add_each_addr: addition of an addr"
  657                     "%s/%d failed because in6_control failed for error %d\n",
  658                     ip6_sprintf(&ifra.ifra_addr.sin6_addr), rpp->rp_plen,
  659                     error);
  660                 return;
  661         }
  662 
  663         /*
  664          * link beween this addr and the prefix will be done
  665          * in in6_prefix_add_ifid
  666          */
  667 }
  668 
  669 static int
  670 rrpr_update(struct socket *so, struct rr_prefix *new)
  671 {
  672         struct rr_prefix *rpp;
  673         struct ifprefix *ifpr;
  674         struct rp_addr *rap;
  675         int s;
  676 
  677         /* search existing prefix */
  678         for (ifpr = TAILQ_FIRST(&new->rp_ifp->if_prefixhead); ifpr;
  679              ifpr = TAILQ_NEXT(ifpr, ifpr_list))
  680         {
  681                 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
  682                     ifpr->ifpr_type != IN6_PREFIX_RR)
  683                         continue;
  684                 if (ifpr->ifpr_plen == new->rp_plen &&
  685                     in6_are_prefix_equal(IFPR_IN6(ifpr), RP_IN6(new),
  686                                          ifpr->ifpr_plen))
  687                         break;
  688         }
  689         rpp = ifpr2rp(ifpr);
  690         if (rpp != NULL) {
  691                 /*
  692                  * We got a prefix which we have seen in the past.
  693                  */
  694                 /*
  695                  * If the origin of the already-installed prefix is more
  696                  * preferable than the new one, ignore installation request.
  697                  */
  698                 if (rpp->rp_origin > new->rp_origin)
  699                         return(EPERM);
  700 
  701                 /* update prefix information */
  702                 rpp->rp_flags.prf_ra = new->rp_flags.prf_ra;
  703                 if (rpp->rp_origin >= PR_ORIG_RR)
  704                         rpp->rp_flags.prf_rr = new->rp_flags.prf_rr;
  705                 rpp->rp_vltime = new->rp_vltime;
  706                 rpp->rp_pltime = new->rp_pltime;
  707                 rpp->rp_expire = new->rp_expire;
  708                 rpp->rp_preferred = new->rp_preferred;
  709                 rpp->rp_statef_delmark = 0; /* cancel deletion */
  710                 /*
  711                  * Interface id related update.
  712                  *  add rp_addr entries in new into rpp, if they have not
  713                  *  been already included in rpp.
  714                  */
  715                 while (!LIST_EMPTY(&new->rp_addrhead))
  716                 {
  717                         rap = LIST_FIRST(&new->rp_addrhead);
  718                         LIST_REMOVE(rap, ra_entry);
  719                         if (search_ifidwithprefix(rpp, &rap->ra_ifid)
  720                             != NULL) {
  721                                 if (rap->ra_addr)
  722                                         ifafree(&rap->ra_addr->ia_ifa);
  723                                 FREE(rap, M_RR_ADDR);
  724                                 continue;
  725                         }
  726                         s = splnet();
  727                         LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
  728                         splx(s);
  729                 }
  730         } else {
  731                 /*
  732                  * We got a fresh prefix.
  733                  */
  734                 /* create new prefix */
  735                 rpp = (struct rr_prefix *)_MALLOC(sizeof(*rpp), M_IP6RR,
  736                                                  M_NOWAIT);
  737                 if (rpp == NULL) {
  738                         log(LOG_ERR, "in6_prefix.c: rrpr_update:%d"
  739                             ": ENOBUFS for rr_prefix\n", __LINE__);
  740                         return(ENOBUFS);
  741                 }
  742                 /* initilization */
  743                 *rpp = *new;
  744                 LIST_INIT(&rpp->rp_addrhead);
  745                 /*  move rp_addr entries of new to rpp */
  746                 while (!LIST_EMPTY(&new->rp_addrhead))
  747                 {
  748                         rap = LIST_FIRST(&new->rp_addrhead);
  749                         LIST_REMOVE(rap, ra_entry);
  750                         LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
  751                 }
  752 
  753                 /* let rp_ifpr.ifpr_prefix point rr_prefix. */
  754                 rpp->rp_ifpr.ifpr_prefix = (struct sockaddr *)&rpp->rp_prefix;
  755                 /* link rr_prefix entry to if_prefixlist */
  756                 {
  757                         struct ifnet *ifp = rpp->rp_ifp;
  758                         struct ifprefix *ifpr;
  759 
  760                         if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead))
  761                             != NULL) {
  762                                 for ( ; TAILQ_NEXT(ifpr, ifpr_list);
  763                                       ifpr = TAILQ_NEXT(ifpr, ifpr_list))
  764                                         continue;
  765                                 TAILQ_NEXT(ifpr, ifpr_list) = rp2ifpr(rpp);
  766                         } else
  767                                 TAILQ_FIRST(&ifp->if_prefixhead) =
  768                                         rp2ifpr(rpp);
  769                         rp2ifpr(rpp)->ifpr_type = IN6_PREFIX_RR;
  770                 }
  771                 /* link rr_prefix entry to rr_prefix list */
  772                 s = splnet();
  773                 LIST_INSERT_HEAD(&rr_prefix, rpp, rp_entry);
  774                 splx(s);
  775         }
  776 
  777         if (!new->rp_raf_auto)
  778                 return 0;
  779 
  780         /*
  781          * Add an address for each interface id, if it is not yet
  782          * If it existed but not pointing to the prefix yet,
  783          * init the prefix pointer.
  784          */
  785         LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry)
  786         {
  787                 if (rap->ra_addr != NULL) {
  788                         if (rap->ra_addr->ia6_ifpr == NULL)
  789                                 rap->ra_addr->ia6_ifpr = rp2ifpr(rpp);
  790                         continue;
  791                 }
  792                 add_each_addr(so, rpp, rap);
  793         }
  794         return 0;
  795 }
  796 
  797 static int
  798 add_each_prefix(struct socket *so, struct rr_prefix *rpp)
  799 {
  800         init_prefix_ltimes(rpp);
  801         return(rrpr_update(so, rpp));
  802 }
  803 
  804 static void
  805 rp_remove(struct rr_prefix *rpp)
  806 {
  807         int s;
  808 
  809         s = splnet();
  810         /* unlink rp_entry from if_prefixlist */
  811         {
  812                 struct ifnet *ifp = rpp->rp_ifp;
  813                 struct ifprefix *ifpr;
  814 
  815                 if ((ifpr = TAILQ_FIRST(&ifp->if_prefixhead)) == rp2ifpr(rpp))
  816                         TAILQ_FIRST(&ifp->if_prefixhead) =
  817                                 TAILQ_NEXT(ifpr, ifpr_list);
  818                 else {
  819                         while (TAILQ_NEXT(ifpr, ifpr_list) != NULL &&
  820                                (TAILQ_NEXT(ifpr, ifpr_list) != rp2ifpr(rpp)))
  821                                 ifpr = TAILQ_NEXT(ifpr, ifpr_list);
  822                         if (TAILQ_NEXT(ifpr, ifpr_list))
  823                                 TAILQ_NEXT(ifpr, ifpr_list) =
  824                                         TAILQ_NEXT(rp2ifpr(rpp), ifpr_list);
  825                         else
  826                                 printf("Couldn't unlink rr_prefix from ifp\n");
  827                 }
  828         }
  829         /* unlink rp_entry from rr_prefix list */
  830         LIST_REMOVE(rpp, rp_entry);
  831         splx(s);
  832         FREE(rpp, M_IP6RR);
  833 }
  834 
  835 static int
  836 create_ra_entry(struct rp_addr **rapp)
  837 {
  838         *rapp = (struct rp_addr *)_MALLOC(sizeof(struct rp_addr), M_RR_ADDR,
  839                                          M_NOWAIT);
  840         if (*rapp == NULL) {
  841                 log(LOG_ERR, "in6_prefix.c: init_newprefix:%d: ENOBUFS"
  842                     "for rp_addr\n", __LINE__);
  843                 return ENOBUFS;
  844         }
  845         bzero(*rapp, sizeof(*(*rapp)));
  846 
  847         return 0;
  848 }
  849 
  850 static int
  851 init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr,
  852                struct rr_prefix *rpp)
  853 {
  854         struct rp_addr *orap;
  855 
  856         /* init rp */
  857         bzero(rpp, sizeof(*rpp));
  858         rpp->rp_type = IN6_PREFIX_RR;
  859         rpp->rp_ifp = ifpr->ifpr_ifp;
  860         rpp->rp_plen = ifpr->ifpr_plen;
  861         rpp->rp_prefix.sin6_len = sizeof(rpp->rp_prefix);
  862         rpp->rp_prefix.sin6_family = AF_INET6;
  863         bit_copy((char *)RP_IN6(rpp), sizeof(*RP_IN6(rpp)) << 3,
  864                  (char *)&irr->irr_useprefix.sin6_addr,
  865                  sizeof(irr->irr_useprefix.sin6_addr) << 3,
  866                  0, irr->irr_u_uselen);
  867         /* copy keeplen part if necessary as necessary len */
  868         if (irr->irr_u_uselen < ifpr->ifpr_plen)
  869                 bit_copy((char *)RP_IN6(rpp), sizeof(*RP_IN6(rpp)) << 3,
  870                          (char *)IFPR_IN6(ifpr), sizeof(*IFPR_IN6(ifpr)) << 3,
  871                          irr->irr_u_uselen,
  872                          min(ifpr->ifpr_plen - irr->irr_u_uselen,
  873                              irr->irr_u_keeplen));
  874         LIST_FOREACH(orap, &(ifpr2rp(ifpr)->rp_addrhead), ra_entry)
  875         {
  876                 struct rp_addr *rap;
  877                 int error = 0;
  878 
  879                 if ((error = create_ra_entry(&rap)) != 0)
  880                         return error;
  881                 rap->ra_ifid = orap->ra_ifid;
  882                 rap->ra_flags.anycast = (orap->ra_addr != NULL &&
  883                                          (orap->ra_addr->ia6_flags &
  884                                           IN6_IFF_ANYCAST) != 0) ? 1 : 0;
  885                 LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
  886         }
  887         rpp->rp_vltime = irr->irr_vltime;
  888         rpp->rp_pltime = irr->irr_pltime;
  889         rpp->rp_raf_onlink = irr->irr_raf_mask_onlink ? irr->irr_raf_onlink :
  890                 ifpr2rp(ifpr)->rp_raf_onlink;
  891         rpp->rp_raf_auto = irr->irr_raf_mask_auto ? irr->irr_raf_auto :
  892                 ifpr2rp(ifpr)->rp_raf_auto;
  893         /* Is some FlagMasks for rrf necessary? */
  894         rpp->rp_rrf = irr->irr_rrf;
  895         rpp->rp_origin = irr->irr_origin;
  896 
  897         return 0;
  898 }
  899 
  900 static void
  901 free_rp_entries(struct rr_prefix *rpp)
  902 {
  903         /*
  904          * This func is only called with rpp on stack(not on list).
  905          * So no splnet() here
  906          */
  907         while (!LIST_EMPTY(&rpp->rp_addrhead))
  908         {
  909                 struct rp_addr *rap;
  910 
  911                 rap = LIST_FIRST(&rpp->rp_addrhead);
  912                 LIST_REMOVE(rap, ra_entry);
  913                 if (rap->ra_addr)
  914                         ifafree(&rap->ra_addr->ia_ifa);
  915                 FREE(rap, M_RR_ADDR);
  916         }
  917 }
  918 
  919 static int
  920 add_useprefixes(struct socket *so, struct ifnet *ifp,
  921                 struct in6_rrenumreq *irr)
  922 {
  923         struct ifprefix *ifpr, *nextifpr;
  924         struct rr_prefix rp;
  925         int error = 0;
  926 
  927         /* add prefixes to each of marked prefix */
  928         for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr)
  929         {
  930                 nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
  931                 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
  932                     ifpr->ifpr_type != IN6_PREFIX_RR)
  933                         continue;
  934                 if (ifpr2rp(ifpr)->rp_statef_addmark) {
  935                         if ((error = init_newprefix(irr, ifpr, &rp)) != 0)
  936                                 break;
  937                         error = add_each_prefix(so, &rp);
  938                 }
  939         }
  940         /* free each rp_addr entry */
  941         free_rp_entries(&rp);
  942 
  943         return error;
  944 }
  945 
  946 static void
  947 unprefer_prefix(struct rr_prefix *rpp)
  948 {
  949         struct rp_addr *rap;
  950 
  951         for (rap = rpp->rp_addrhead.lh_first; rap != NULL;
  952              rap = rap->ra_entry.le_next) {
  953                 if (rap->ra_addr == NULL)
  954                         continue;
  955                 rap->ra_addr->ia6_lifetime.ia6t_preferred = time_second;
  956                 rap->ra_addr->ia6_lifetime.ia6t_pltime = 0;
  957         }
  958 }
  959 
  960 int
  961 delete_each_prefix(struct rr_prefix *rpp, u_char origin)
  962 {
  963         int error = 0;
  964 
  965         if (rpp->rp_origin > origin)
  966                 return(EPERM);
  967 
  968         while (rpp->rp_addrhead.lh_first != NULL) {
  969                 struct rp_addr *rap;
  970                 int s;
  971 
  972                 s = splnet();
  973                 rap = LIST_FIRST(&rpp->rp_addrhead);
  974                 if (rap == NULL) {
  975                         splx(s);
  976                         break;
  977                 }
  978                 LIST_REMOVE(rap, ra_entry);
  979                 splx(s);
  980                 if (rap->ra_addr == NULL) {
  981                         FREE(rap, M_RR_ADDR);
  982                         continue;
  983                 }
  984                 rap->ra_addr->ia6_ifpr = NULL;
  985 
  986                 in6_purgeaddr(&rap->ra_addr->ia_ifa);
  987                 ifafree(&rap->ra_addr->ia_ifa);
  988                 FREE(rap, M_RR_ADDR);
  989         }
  990         rp_remove(rpp);
  991 
  992         return error;
  993 }
  994 
  995 static void
  996 delete_prefixes(struct ifnet *ifp, u_char origin)
  997 {
  998         struct ifprefix *ifpr, *nextifpr;
  999 
 1000         /* delete prefixes marked as tobe deleted */
 1001         for (ifpr = TAILQ_FIRST(&ifp->if_prefixhead); ifpr; ifpr = nextifpr)
 1002         {
 1003                 nextifpr = TAILQ_NEXT(ifpr, ifpr_list);
 1004                 if (ifpr->ifpr_prefix->sa_family != AF_INET6 ||
 1005                     ifpr->ifpr_type != IN6_PREFIX_RR)
 1006                         continue;
 1007                 if (ifpr2rp(ifpr)->rp_statef_delmark)
 1008                         (void)delete_each_prefix(ifpr2rp(ifpr), origin);
 1009         }
 1010 }
 1011 
 1012 static int
 1013 link_stray_ia6s(struct rr_prefix *rpp)
 1014 {
 1015         struct ifaddr *ifa;
 1016 
 1017         for (ifa = rpp->rp_ifp->if_addrlist.tqh_first; ifa;
 1018              ifa = ifa->ifa_list.tqe_next)
 1019         {
 1020                 struct rp_addr *rap;
 1021                 struct rr_prefix *orpp;
 1022                 int error = 0;
 1023 
 1024                 if (ifa->ifa_addr->sa_family != AF_INET6)
 1025                         continue;
 1026                 if (rpp->rp_plen > in6_matchlen(RP_IN6(rpp), IFA_IN6(ifa)))
 1027                         continue;
 1028 
 1029                 orpp = ifpr2rp(((struct in6_ifaddr *)ifa)->ia6_ifpr);
 1030                 if (orpp != NULL) {
 1031                         if (!in6_are_prefix_equal(RP_IN6(orpp), RP_IN6(rpp),
 1032                                                   rpp->rp_plen))
 1033                                 log(LOG_ERR, "in6_prefix.c: link_stray_ia6s:"
 1034                                     "addr %s/%d already linked to a prefix"
 1035                                     "and it matches also %s/%d\n",
 1036                                     ip6_sprintf(IFA_IN6(ifa)), orpp->rp_plen,
 1037                                     ip6_sprintf(RP_IN6(rpp)),
 1038                                     rpp->rp_plen);
 1039                         continue;
 1040                 }
 1041                 if ((error = assign_ra_entry(rpp,
 1042                                               (sizeof(rap->ra_ifid) << 3) -
 1043                                               rpp->rp_plen,
 1044                                               (struct in6_ifaddr *)ifa)) != 0)
 1045                         return error;
 1046         }
 1047         return 0;
 1048 }
 1049 
 1050 /* XXX assumes that permission is already checked by the caller */
 1051 int
 1052 in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
 1053                  struct ifnet *ifp)
 1054 {
 1055         struct rr_prefix *rpp, rp_tmp;
 1056         struct rp_addr *rap;
 1057         struct in6_prefixreq *ipr = (struct in6_prefixreq *)data;
 1058         struct in6_rrenumreq *irr = (struct in6_rrenumreq *)data;
 1059         struct ifaddr *ifa;
 1060         int error = 0;
 1061 
 1062         /*
 1063          * Failsafe for errneous address config program.
 1064          * Let's hope rrenumd don't make a mistakes.
 1065          */
 1066         if (ipr->ipr_origin <= PR_ORIG_RA)
 1067                 ipr->ipr_origin = PR_ORIG_STATIC;
 1068 
 1069         switch (cmd) {
 1070         case SIOCSGIFPREFIX_IN6:
 1071                 delmark_global_prefixes(ifp, irr);
 1072                 /* FALL THROUGH */
 1073         case SIOCAIFPREFIX_IN6:
 1074         case SIOCCIFPREFIX_IN6:
 1075                 /* check if preferred lifetime > valid lifetime */
 1076                 if (irr->irr_pltime > irr->irr_vltime) {
 1077                         log(LOG_NOTICE,
 1078                             "in6_prefix_ioctl: preferred lifetime"
 1079                             "(%ld) is greater than valid lifetime(%ld)\n",
 1080                             (u_long)irr->irr_pltime, (u_long)irr->irr_vltime);
 1081                         error = EINVAL;
 1082                         break;
 1083                 }
 1084                 if (mark_matched_prefixes(cmd, ifp, irr)) {
 1085                         if (irr->irr_u_uselen != 0)
 1086                                 if ((error = add_useprefixes(so, ifp, irr))
 1087                                     != 0)
 1088                                         goto failed;
 1089                         if (cmd != SIOCAIFPREFIX_IN6)
 1090                                 delete_prefixes(ifp, irr->irr_origin);
 1091                 } else
 1092                         return (EADDRNOTAVAIL);
 1093         failed:
 1094                 unmark_prefixes(ifp);
 1095                 break;
 1096         case SIOCGIFPREFIX_IN6:
 1097                 rpp = search_matched_prefix(ifp, ipr);
 1098                 if (rpp == NULL || ifp != rpp->rp_ifp)
 1099                         return (EADDRNOTAVAIL);
 1100 
 1101                 ipr->ipr_origin = rpp->rp_origin;
 1102                 ipr->ipr_plen = rpp->rp_plen;
 1103                 ipr->ipr_vltime = rpp->rp_vltime;
 1104                 ipr->ipr_pltime = rpp->rp_pltime;
 1105                 ipr->ipr_flags = rpp->rp_flags;
 1106                 ipr->ipr_prefix = rpp->rp_prefix;
 1107 
 1108                 break;
 1109         case SIOCSIFPREFIX_IN6:
 1110                 /* check if preferred lifetime > valid lifetime */
 1111                 if (ipr->ipr_pltime > ipr->ipr_vltime) {
 1112                         log(LOG_NOTICE,
 1113                             "in6_prefix_ioctl: preferred lifetime"
 1114                             "(%ld) is greater than valid lifetime(%ld)\n",
 1115                             (u_long)ipr->ipr_pltime, (u_long)ipr->ipr_vltime);
 1116                         error = EINVAL;
 1117                         break;
 1118                 }
 1119 
 1120                 /* init rp_tmp */
 1121                 bzero((caddr_t)&rp_tmp, sizeof(rp_tmp));
 1122                 rp_tmp.rp_ifp = ifp;
 1123                 rp_tmp.rp_plen = ipr->ipr_plen;
 1124                 rp_tmp.rp_prefix = ipr->ipr_prefix;
 1125                 rp_tmp.rp_vltime = ipr->ipr_vltime;
 1126                 rp_tmp.rp_pltime = ipr->ipr_pltime;
 1127                 rp_tmp.rp_flags = ipr->ipr_flags;
 1128                 rp_tmp.rp_origin = ipr->ipr_origin;
 1129 
 1130                 /* create rp_addr entries, usually at least for lladdr */
 1131                 if ((error = link_stray_ia6s(&rp_tmp)) != 0) {
 1132                         free_rp_entries(&rp_tmp);
 1133                         break;
 1134                 }
 1135                 for (ifa = ifp->if_addrlist.tqh_first;
 1136                      ifa;
 1137                      ifa = ifa->ifa_list.tqe_next)
 1138                 {
 1139                         if (ifa->ifa_addr == NULL)
 1140                                 continue;       /* just for safety */
 1141                         if (ifa->ifa_addr->sa_family != AF_INET6)
 1142                                 continue;
 1143                         if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa)) == 0)
 1144                                 continue;
 1145 
 1146                         if ((error = create_ra_entry(&rap)) != 0) {
 1147                                 free_rp_entries(&rp_tmp);
 1148                                 goto bad;
 1149                         }
 1150                         /* copy interface id part */
 1151                         bit_copy((caddr_t)&rap->ra_ifid,
 1152                                  sizeof(rap->ra_ifid) << 3,
 1153                                  (caddr_t)IFA_IN6(ifa),
 1154                                  sizeof(*IFA_IN6(ifa)) << 3,
 1155                                  rp_tmp.rp_plen,
 1156                                  (sizeof(rap->ra_ifid) << 3) - rp_tmp.rp_plen);
 1157                         /* insert into list */
 1158                         LIST_INSERT_HEAD(&rp_tmp.rp_addrhead, rap, ra_entry);
 1159                 }
 1160 
 1161                 error = add_each_prefix(so, &rp_tmp);
 1162 
 1163                 /* free each rp_addr entry */
 1164                 free_rp_entries(&rp_tmp);
 1165 
 1166                 break;
 1167         case SIOCDIFPREFIX_IN6:
 1168                 rpp = search_matched_prefix(ifp, ipr);
 1169                 if (rpp == NULL || ifp != rpp->rp_ifp)
 1170                         return (EADDRNOTAVAIL);
 1171 
 1172                 error = delete_each_prefix(rpp, ipr->ipr_origin);
 1173                 break;
 1174         }
 1175  bad:
 1176         return error;
 1177 }
 1178 
 1179 void
 1180 in6_rr_timer_funneled(void *ignored_arg)
 1181 {
 1182 #ifdef __APPLE__
 1183         boolean_t   funnel_state;
 1184         funnel_state = thread_funnel_set(network_flock, TRUE);
 1185 #endif
 1186         in6_rr_timer(ignored_arg);
 1187 #ifdef __APPLE__
 1188         (void) thread_funnel_set(network_flock, FALSE);
 1189 #endif
 1190 }
 1191 
 1192 void
 1193 in6_rr_timer(void *ignored_arg)
 1194 {
 1195         int s;
 1196         struct rr_prefix *rpp;
 1197 
 1198         timeout(in6_rr_timer_funneled, (caddr_t)0, ip6_rr_prune * hz);
 1199 
 1200         s = splnet();
 1201         /* expire */
 1202         rpp = LIST_FIRST(&rr_prefix);
 1203         while (rpp) {
 1204                 if (rpp->rp_expire && rpp->rp_expire < time_second) {
 1205                         struct rr_prefix *next_rpp;
 1206 
 1207                         next_rpp = LIST_NEXT(rpp, rp_entry);
 1208                         delete_each_prefix(rpp, PR_ORIG_KERNEL);
 1209                         rpp = next_rpp;
 1210                         continue;
 1211                 }
 1212                 if (rpp->rp_preferred && rpp->rp_preferred < time_second)
 1213                         unprefer_prefix(rpp);
 1214                 rpp = LIST_NEXT(rpp, rp_entry);
 1215         }
 1216         splx(s);
 1217 }

Cache object: a296124d081fd32a91ed06cc2c0bee2d


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