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

Cache object: 379339160b61e37bc392c43ed767e707


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