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/nd6_nbr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD: src/sys/netinet6/nd6_nbr.c,v 1.26.2.3 2005/10/03 21:51:32 thompsa Exp $       */
    2 /*      $KAME: nd6_nbr.c,v 1.86 2002/01/21 02:33:04 jinmei 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 #include "opt_inet.h"
   34 #include "opt_inet6.h"
   35 #include "opt_ipsec.h"
   36 #include "opt_carp.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/malloc.h>
   41 #include <sys/mbuf.h>
   42 #include <sys/socket.h>
   43 #include <sys/sockio.h>
   44 #include <sys/time.h>
   45 #include <sys/kernel.h>
   46 #include <sys/errno.h>
   47 #include <sys/syslog.h>
   48 #include <sys/queue.h>
   49 #include <sys/callout.h>
   50 
   51 #include <net/if.h>
   52 #include <net/if_types.h>
   53 #include <net/if_dl.h>
   54 #include <net/route.h>
   55 
   56 #include <netinet/in.h>
   57 #include <netinet/in_var.h>
   58 #include <netinet6/in6_var.h>
   59 #include <netinet/ip6.h>
   60 #include <netinet6/ip6_var.h>
   61 #include <netinet6/nd6.h>
   62 #include <netinet/icmp6.h>
   63 
   64 #ifdef DEV_CARP
   65 #include <netinet/ip_carp.h>
   66 #endif
   67 
   68 #include <net/net_osdep.h>
   69 
   70 #define SDL(s) ((struct sockaddr_dl *)s)
   71 
   72 struct dadq;
   73 static struct dadq *nd6_dad_find __P((struct ifaddr *));
   74 static void nd6_dad_starttimer __P((struct dadq *, int));
   75 static void nd6_dad_stoptimer __P((struct dadq *));
   76 static void nd6_dad_timer __P((struct ifaddr *));
   77 static void nd6_dad_ns_output __P((struct dadq *, struct ifaddr *));
   78 static void nd6_dad_ns_input __P((struct ifaddr *));
   79 static void nd6_dad_na_input __P((struct ifaddr *));
   80 
   81 static int dad_ignore_ns = 0;   /* ignore NS in DAD - specwise incorrect*/
   82 static int dad_maxtry = 15;     /* max # of *tries* to transmit DAD packet */
   83 
   84 /*
   85  * Input a Neighbor Solicitation Message.
   86  *
   87  * Based on RFC 2461
   88  * Based on RFC 2462 (duplicated address detection)
   89  */
   90 void
   91 nd6_ns_input(m, off, icmp6len)
   92         struct mbuf *m;
   93         int off, icmp6len;
   94 {
   95         struct ifnet *ifp = m->m_pkthdr.rcvif;
   96         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
   97         struct nd_neighbor_solicit *nd_ns;
   98         struct in6_addr saddr6 = ip6->ip6_src;
   99         struct in6_addr daddr6 = ip6->ip6_dst;
  100         struct in6_addr taddr6;
  101         struct in6_addr myaddr6;
  102         char *lladdr = NULL;
  103         struct ifaddr *ifa = NULL;
  104         int lladdrlen = 0;
  105         int anycast = 0, proxy = 0, tentative = 0;
  106         int tlladdr;
  107         union nd_opts ndopts;
  108         struct sockaddr_dl *proxydl = NULL;
  109 
  110 #ifndef PULLDOWN_TEST
  111         IP6_EXTHDR_CHECK(m, off, icmp6len,);
  112         nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
  113 #else
  114         IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
  115         if (nd_ns == NULL) {
  116                 icmp6stat.icp6s_tooshort++;
  117                 return;
  118         }
  119 #endif
  120         ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */
  121         taddr6 = nd_ns->nd_ns_target;
  122 
  123         if (ip6->ip6_hlim != 255) {
  124                 nd6log((LOG_ERR,
  125                     "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n",
  126                     ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
  127                     ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
  128                 goto bad;
  129         }
  130 
  131         if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
  132                 /* dst has to be solicited node multicast address. */
  133                 if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL &&
  134                     /* don't check ifindex portion */
  135                     daddr6.s6_addr32[1] == 0 &&
  136                     daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE &&
  137                     daddr6.s6_addr8[12] == 0xff) {
  138                         ; /* good */
  139                 } else {
  140                         nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
  141                             "(wrong ip6 dst)\n"));
  142                         goto bad;
  143                 }
  144         }
  145 
  146         if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
  147                 nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
  148                 goto bad;
  149         }
  150 
  151         if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
  152                 taddr6.s6_addr16[1] = htons(ifp->if_index);
  153 
  154         icmp6len -= sizeof(*nd_ns);
  155         nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
  156         if (nd6_options(&ndopts) < 0) {
  157                 nd6log((LOG_INFO,
  158                     "nd6_ns_input: invalid ND option, ignored\n"));
  159                 /* nd6_options have incremented stats */
  160                 goto freeit;
  161         }
  162 
  163         if (ndopts.nd_opts_src_lladdr) {
  164                 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
  165                 lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
  166         }
  167 
  168         if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) {
  169                 nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
  170                     "(link-layer address option)\n"));
  171                 goto bad;
  172         }
  173 
  174         /*
  175          * Attaching target link-layer address to the NA?
  176          * (RFC 2461 7.2.4)
  177          *
  178          * NS IP dst is unicast/anycast                 MUST NOT add
  179          * NS IP dst is solicited-node multicast        MUST add
  180          *
  181          * In implementation, we add target link-layer address by default.
  182          * We do not add one in MUST NOT cases.
  183          */
  184 #if 0 /* too much! */
  185         ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6);
  186         if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST))
  187                 tlladdr = 0;
  188         else
  189 #endif
  190         if (!IN6_IS_ADDR_MULTICAST(&daddr6))
  191                 tlladdr = 0;
  192         else
  193                 tlladdr = 1;
  194 
  195         /*
  196          * Target address (taddr6) must be either:
  197          * (1) Valid unicast/anycast address for my receiving interface,
  198          * (2) Unicast address for which I'm offering proxy service, or
  199          * (3) "tentative" address on which DAD is being performed.
  200          */
  201         /* (1) and (3) check. */
  202 #ifdef DEV_CARP
  203         if (ifp->if_carp)
  204                 ifa = carp_iamatch6(ifp->if_carp, &taddr6);
  205         if (!ifa)
  206                 ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
  207 #else
  208         ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
  209 #endif
  210 
  211         /* (2) check. */
  212         if (!ifa) {
  213                 struct rtentry *rt;
  214                 struct sockaddr_in6 tsin6;
  215                 int need_proxy;
  216 
  217                 bzero(&tsin6, sizeof tsin6);            
  218                 tsin6.sin6_len = sizeof(struct sockaddr_in6);
  219                 tsin6.sin6_family = AF_INET6;
  220                 tsin6.sin6_addr = taddr6;
  221 
  222                 rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
  223                 need_proxy = (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
  224                     rt->rt_gateway->sa_family == AF_LINK);
  225                 if (rt)
  226                         rtfree(rt);
  227                 if (need_proxy) {
  228                         /*
  229                          * proxy NDP for single entry
  230                          */
  231                         ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
  232                                 IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
  233                         if (ifa) {
  234                                 proxy = 1;
  235                                 proxydl = SDL(rt->rt_gateway);
  236                         }
  237                 }
  238         }
  239         if (!ifa) {
  240                 /*
  241                  * We've got an NS packet, and we don't have that adddress
  242                  * assigned for us.  We MUST silently ignore it.
  243                  * See RFC2461 7.2.3.
  244                  */
  245                 goto freeit;
  246         }
  247         myaddr6 = *IFA_IN6(ifa);
  248         anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
  249         tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
  250         if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
  251                 goto freeit;
  252 
  253         if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
  254                 nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s "
  255                     "(if %d, NS packet %d)\n",
  256                     ip6_sprintf(&taddr6),
  257                     ifp->if_addrlen, lladdrlen - 2));
  258                 goto bad;
  259         }
  260 
  261         if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
  262                 nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
  263                     ip6_sprintf(&saddr6)));
  264                 goto freeit;
  265         }
  266 
  267         /*
  268          * We have neighbor solicitation packet, with target address equals to
  269          * one of my tentative address.
  270          *
  271          * src addr     how to process?
  272          * ---          ---
  273          * multicast    of course, invalid (rejected in ip6_input)
  274          * unicast      somebody is doing address resolution -> ignore
  275          * unspec       dup address detection
  276          *
  277          * The processing is defined in RFC 2462.
  278          */
  279         if (tentative) {
  280                 /*
  281                  * If source address is unspecified address, it is for
  282                  * duplicated address detection.
  283                  *
  284                  * If not, the packet is for addess resolution;
  285                  * silently ignore it.
  286                  */
  287                 if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
  288                         nd6_dad_ns_input(ifa);
  289 
  290                 goto freeit;
  291         }
  292 
  293         /*
  294          * If the source address is unspecified address, entries must not
  295          * be created or updated.
  296          * It looks that sender is performing DAD.  Output NA toward
  297          * all-node multicast address, to tell the sender that I'm using
  298          * the address.
  299          * S bit ("solicited") must be zero.
  300          */
  301         if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
  302                 saddr6 = in6addr_linklocal_allnodes;
  303                 saddr6.s6_addr16[1] = htons(ifp->if_index);
  304                 nd6_na_output(ifp, &saddr6, &taddr6,
  305                     ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
  306                     (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
  307                     tlladdr, (struct sockaddr *)proxydl);
  308                 goto freeit;
  309         }
  310 
  311         nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
  312             ND_NEIGHBOR_SOLICIT, 0);
  313 
  314         nd6_na_output(ifp, &saddr6, &taddr6,
  315             ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
  316             (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
  317             tlladdr, (struct sockaddr *)proxydl);
  318  freeit:
  319         m_freem(m);
  320         return;
  321 
  322  bad:
  323         nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6)));
  324         nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6)));
  325         nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6)));
  326         icmp6stat.icp6s_badns++;
  327         m_freem(m);
  328 }
  329 
  330 /*
  331  * Output a Neighbor Solicitation Message. Caller specifies:
  332  *      - ICMP6 header source IP6 address
  333  *      - ND6 header target IP6 address
  334  *      - ND6 header source datalink address
  335  *
  336  * Based on RFC 2461
  337  * Based on RFC 2462 (duplicated address detection)
  338  */
  339 void
  340 nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
  341         struct ifnet *ifp;
  342         const struct in6_addr *daddr6, *taddr6;
  343         struct llinfo_nd6 *ln;  /* for source address determination */
  344         int dad;        /* duplicated address detection */
  345 {
  346         struct mbuf *m;
  347         struct ip6_hdr *ip6;
  348         struct nd_neighbor_solicit *nd_ns;
  349         struct in6_ifaddr *ia = NULL;
  350         struct ip6_moptions im6o;
  351         int icmp6len;
  352         int maxlen;
  353         caddr_t mac;
  354         struct ifnet *outif = NULL;
  355 
  356         if (IN6_IS_ADDR_MULTICAST(taddr6))
  357                 return;
  358 
  359         /* estimate the size of message */
  360         maxlen = sizeof(*ip6) + sizeof(*nd_ns);
  361         maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
  362         if (max_linkhdr + maxlen >= MCLBYTES) {
  363 #ifdef DIAGNOSTIC
  364                 printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES "
  365                     "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
  366 #endif
  367                 return;
  368         }
  369 
  370         MGETHDR(m, M_DONTWAIT, MT_DATA);
  371         if (m && max_linkhdr + maxlen >= MHLEN) {
  372                 MCLGET(m, M_DONTWAIT);
  373                 if ((m->m_flags & M_EXT) == 0) {
  374                         m_free(m);
  375                         m = NULL;
  376                 }
  377         }
  378         if (m == NULL)
  379                 return;
  380         m->m_pkthdr.rcvif = NULL;
  381 
  382         if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
  383                 m->m_flags |= M_MCAST;
  384                 im6o.im6o_multicast_ifp = ifp;
  385                 im6o.im6o_multicast_hlim = 255;
  386                 im6o.im6o_multicast_loop = 0;
  387         }
  388 
  389         icmp6len = sizeof(*nd_ns);
  390         m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
  391         m->m_data += max_linkhdr;       /* or MH_ALIGN() equivalent? */
  392 
  393         /* fill neighbor solicitation packet */
  394         ip6 = mtod(m, struct ip6_hdr *);
  395         ip6->ip6_flow = 0;
  396         ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
  397         ip6->ip6_vfc |= IPV6_VERSION;
  398         /* ip6->ip6_plen will be set later */
  399         ip6->ip6_nxt = IPPROTO_ICMPV6;
  400         ip6->ip6_hlim = 255;
  401         if (daddr6)
  402                 ip6->ip6_dst = *daddr6;
  403         else {
  404                 ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
  405                 ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
  406                 ip6->ip6_dst.s6_addr32[1] = 0;
  407                 ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
  408                 ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3];
  409                 ip6->ip6_dst.s6_addr8[12] = 0xff;
  410         }
  411         if (!dad) {
  412                 /*
  413                  * RFC2461 7.2.2:
  414                  * "If the source address of the packet prompting the
  415                  * solicitation is the same as one of the addresses assigned
  416                  * to the outgoing interface, that address SHOULD be placed
  417                  * in the IP Source Address of the outgoing solicitation.
  418                  * Otherwise, any one of the addresses assigned to the
  419                  * interface should be used."
  420                  *
  421                  * We use the source address for the prompting packet
  422                  * (saddr6), if:
  423                  * - saddr6 is given from the caller (by giving "ln"), and
  424                  * - saddr6 belongs to the outgoing interface.
  425                  * Otherwise, we perform a scope-wise match.
  426                  */
  427                 struct ip6_hdr *hip6;           /* hold ip6 */
  428                 struct in6_addr *saddr6;
  429 
  430                 if (ln && ln->ln_hold) {
  431                         hip6 = mtod(ln->ln_hold, struct ip6_hdr *);
  432                         /* XXX pullup? */
  433                         if (sizeof(*hip6) < ln->ln_hold->m_len)
  434                                 saddr6 = &hip6->ip6_src;
  435                         else
  436                                 saddr6 = NULL;
  437                 } else
  438                         saddr6 = NULL;
  439                 if (saddr6 && in6ifa_ifpwithaddr(ifp, saddr6))
  440                         bcopy(saddr6, &ip6->ip6_src, sizeof(*saddr6));
  441                 else {
  442                         ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
  443                         if (ia == NULL) {
  444                                 m_freem(m);
  445                                 return;
  446                         }
  447                         ip6->ip6_src = ia->ia_addr.sin6_addr;
  448                 }
  449         } else {
  450                 /*
  451                  * Source address for DAD packet must always be IPv6
  452                  * unspecified address. (0::0)
  453                  */
  454                 bzero(&ip6->ip6_src, sizeof(ip6->ip6_src));
  455         }
  456         nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1);
  457         nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
  458         nd_ns->nd_ns_code = 0;
  459         nd_ns->nd_ns_reserved = 0;
  460         nd_ns->nd_ns_target = *taddr6;
  461         in6_clearscope(&nd_ns->nd_ns_target); /* XXX */
  462 
  463         /*
  464          * Add source link-layer address option.
  465          *
  466          *                              spec            implementation
  467          *                              ---             ---
  468          * DAD packet                   MUST NOT        do not add the option
  469          * there's no link layer address:
  470          *                              impossible      do not add the option
  471          * there's link layer address:
  472          *      Multicast NS            MUST add one    add the option
  473          *      Unicast NS              SHOULD add one  add the option
  474          */
  475         if (!dad && (mac = nd6_ifptomac(ifp))) {
  476                 int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
  477                 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
  478                 /* 8 byte alignments... */
  479                 optlen = (optlen + 7) & ~7;
  480 
  481                 m->m_pkthdr.len += optlen;
  482                 m->m_len += optlen;
  483                 icmp6len += optlen;
  484                 bzero((caddr_t)nd_opt, optlen);
  485                 nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
  486                 nd_opt->nd_opt_len = optlen >> 3;
  487                 bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
  488         }
  489 
  490         ip6->ip6_plen = htons((u_short)icmp6len);
  491         nd_ns->nd_ns_cksum = 0;
  492         nd_ns->nd_ns_cksum =
  493             in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
  494 
  495         ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif, NULL);
  496         if (outif) {
  497                 icmp6_ifstat_inc(outif, ifs6_out_msg);
  498                 icmp6_ifstat_inc(outif, ifs6_out_neighborsolicit);
  499         }
  500         icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++;
  501 }
  502 
  503 /*
  504  * Neighbor advertisement input handling.
  505  *
  506  * Based on RFC 2461
  507  * Based on RFC 2462 (duplicated address detection)
  508  *
  509  * the following items are not implemented yet:
  510  * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
  511  * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
  512  */
  513 void
  514 nd6_na_input(m, off, icmp6len)
  515         struct mbuf *m;
  516         int off, icmp6len;
  517 {
  518         struct ifnet *ifp = m->m_pkthdr.rcvif;
  519         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
  520         struct nd_neighbor_advert *nd_na;
  521         struct in6_addr daddr6 = ip6->ip6_dst;
  522         struct in6_addr taddr6;
  523         int flags;
  524         int is_router;
  525         int is_solicited;
  526         int is_override;
  527         char *lladdr = NULL;
  528         int lladdrlen = 0;
  529         struct ifaddr *ifa;
  530         struct llinfo_nd6 *ln;
  531         struct rtentry *rt;
  532         struct sockaddr_dl *sdl;
  533         union nd_opts ndopts;
  534 
  535         if (ip6->ip6_hlim != 255) {
  536                 nd6log((LOG_ERR,
  537                     "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n",
  538                     ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
  539                     ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
  540                 goto bad;
  541         }
  542 
  543 #ifndef PULLDOWN_TEST
  544         IP6_EXTHDR_CHECK(m, off, icmp6len,);
  545         nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
  546 #else
  547         IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len);
  548         if (nd_na == NULL) {
  549                 icmp6stat.icp6s_tooshort++;
  550                 return;
  551         }
  552 #endif
  553         taddr6 = nd_na->nd_na_target;
  554         flags = nd_na->nd_na_flags_reserved;
  555         is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
  556         is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
  557         is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
  558 
  559         if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
  560                 taddr6.s6_addr16[1] = htons(ifp->if_index);
  561 
  562         if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
  563                 nd6log((LOG_ERR,
  564                     "nd6_na_input: invalid target address %s\n",
  565                     ip6_sprintf(&taddr6)));
  566                 goto bad;
  567         }
  568         if (IN6_IS_ADDR_MULTICAST(&daddr6))
  569                 if (is_solicited) {
  570                         nd6log((LOG_ERR,
  571                             "nd6_na_input: a solicited adv is multicasted\n"));
  572                         goto bad;
  573                 }
  574 
  575         icmp6len -= sizeof(*nd_na);
  576         nd6_option_init(nd_na + 1, icmp6len, &ndopts);
  577         if (nd6_options(&ndopts) < 0) {
  578                 nd6log((LOG_INFO,
  579                     "nd6_na_input: invalid ND option, ignored\n"));
  580                 /* nd6_options have incremented stats */
  581                 goto freeit;
  582         }
  583 
  584         if (ndopts.nd_opts_tgt_lladdr) {
  585                 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
  586                 lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
  587         }
  588 
  589         ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
  590 
  591         /*
  592          * Target address matches one of my interface address.
  593          *
  594          * If my address is tentative, this means that there's somebody
  595          * already using the same address as mine.  This indicates DAD failure.
  596          * This is defined in RFC 2462.
  597          *
  598          * Otherwise, process as defined in RFC 2461.
  599          */
  600         if (ifa
  601          && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
  602                 nd6_dad_na_input(ifa);
  603                 goto freeit;
  604         }
  605 
  606         /* Just for safety, maybe unnecessary. */
  607         if (ifa) {
  608                 log(LOG_ERR,
  609                     "nd6_na_input: duplicate IP6 address %s\n",
  610                     ip6_sprintf(&taddr6));
  611                 goto freeit;
  612         }
  613 
  614         if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
  615                 nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s "
  616                     "(if %d, NA packet %d)\n", ip6_sprintf(&taddr6),
  617                     ifp->if_addrlen, lladdrlen - 2));
  618                 goto bad;
  619         }
  620 
  621         /*
  622          * If no neighbor cache entry is found, NA SHOULD silently be
  623          * discarded.
  624          */
  625         rt = nd6_lookup(&taddr6, 0, ifp);
  626         if ((rt == NULL) ||
  627            ((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) ||
  628            ((sdl = SDL(rt->rt_gateway)) == NULL))
  629                 goto freeit;
  630 
  631         if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
  632                 /*
  633                  * If the link-layer has address, and no lladdr option came,
  634                  * discard the packet.
  635                  */
  636                 if (ifp->if_addrlen && !lladdr)
  637                         goto freeit;
  638 
  639                 /*
  640                  * Record link-layer address, and update the state.
  641                  */
  642                 sdl->sdl_alen = ifp->if_addrlen;
  643                 bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
  644                 if (is_solicited) {
  645                         ln->ln_state = ND6_LLINFO_REACHABLE;
  646                         ln->ln_byhint = 0;
  647                         if (ln->ln_expire) {
  648                                 ln->ln_expire = time_second +
  649                                     ND_IFINFO(rt->rt_ifp)->reachable;
  650                         }
  651                 } else {
  652                         ln->ln_state = ND6_LLINFO_STALE;
  653                         ln->ln_expire = time_second + nd6_gctimer;
  654                 }
  655                 if ((ln->ln_router = is_router) != 0) {
  656                         /*
  657                          * This means a router's state has changed from
  658                          * non-reachable to probably reachable, and might
  659                          * affect the status of associated prefixes..
  660                          */
  661                         pfxlist_onlink_check();
  662                 }
  663         } else {
  664                 int llchange;
  665 
  666                 /*
  667                  * Check if the link-layer address has changed or not.
  668                  */
  669                 if (!lladdr)
  670                         llchange = 0;
  671                 else {
  672                         if (sdl->sdl_alen) {
  673                                 if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen))
  674                                         llchange = 1;
  675                                 else
  676                                         llchange = 0;
  677                         } else
  678                                 llchange = 1;
  679                 }
  680 
  681                 /*
  682                  * This is VERY complex.  Look at it with care.
  683                  *
  684                  * override solicit lladdr llchange     action
  685                  *                                      (L: record lladdr)
  686                  *
  687                  *      0       0       n       --      (2c)
  688                  *      0       0       y       n       (2b) L
  689                  *      0       0       y       y       (1)    REACHABLE->STALE
  690                  *      0       1       n       --      (2c)   *->REACHABLE
  691                  *      0       1       y       n       (2b) L *->REACHABLE
  692                  *      0       1       y       y       (1)    REACHABLE->STALE
  693                  *      1       0       n       --      (2a)
  694                  *      1       0       y       n       (2a) L
  695                  *      1       0       y       y       (2a) L *->STALE
  696                  *      1       1       n       --      (2a)   *->REACHABLE
  697                  *      1       1       y       n       (2a) L *->REACHABLE
  698                  *      1       1       y       y       (2a) L *->REACHABLE
  699                  */
  700                 if (!is_override && (lladdr && llchange)) {        /* (1) */
  701                         /*
  702                          * If state is REACHABLE, make it STALE.
  703                          * no other updates should be done.
  704                          */
  705                         if (ln->ln_state == ND6_LLINFO_REACHABLE) {
  706                                 ln->ln_state = ND6_LLINFO_STALE;
  707                                 ln->ln_expire = time_second + nd6_gctimer;
  708                         }
  709                         goto freeit;
  710                 } else if (is_override                             /* (2a) */
  711                         || (!is_override && (lladdr && !llchange)) /* (2b) */
  712                         || !lladdr) {                              /* (2c) */
  713                         /*
  714                          * Update link-local address, if any.
  715                          */
  716                         if (lladdr) {
  717                                 sdl->sdl_alen = ifp->if_addrlen;
  718                                 bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
  719                         }
  720 
  721                         /*
  722                          * If solicited, make the state REACHABLE.
  723                          * If not solicited and the link-layer address was
  724                          * changed, make it STALE.
  725                          */
  726                         if (is_solicited) {
  727                                 ln->ln_state = ND6_LLINFO_REACHABLE;
  728                                 ln->ln_byhint = 0;
  729                                 if (ln->ln_expire) {
  730                                         ln->ln_expire = time_second +
  731                                             ND_IFINFO(ifp)->reachable;
  732                                 }
  733                         } else {
  734                                 if (lladdr && llchange) {
  735                                         ln->ln_state = ND6_LLINFO_STALE;
  736                                         ln->ln_expire = time_second + nd6_gctimer;
  737                                 }
  738                         }
  739                 }
  740 
  741                 if (ln->ln_router && !is_router) {
  742                         /*
  743                          * The peer dropped the router flag.
  744                          * Remove the sender from the Default Router List and
  745                          * update the Destination Cache entries.
  746                          */
  747                         struct nd_defrouter *dr;
  748                         struct in6_addr *in6;
  749                         int s;
  750 
  751                         in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
  752 
  753                         /*
  754                          * Lock to protect the default router list.
  755                          * XXX: this might be unnecessary, since this function
  756                          * is only called under the network software interrupt
  757                          * context.  However, we keep it just for safety.
  758                          */
  759                         s = splnet();
  760                         dr = defrouter_lookup(in6, ifp);
  761                         if (dr)
  762                                 defrtrlist_del(dr);
  763                         else if (!ip6_forwarding && ip6_accept_rtadv) {
  764                                 /*
  765                                  * Even if the neighbor is not in the default
  766                                  * router list, the neighbor may be used
  767                                  * as a next hop for some destinations
  768                                  * (e.g. redirect case). So we must
  769                                  * call rt6_flush explicitly.
  770                                  */
  771                                 rt6_flush(&ip6->ip6_src, ifp);
  772                         }
  773                         splx(s);
  774                 }
  775                 ln->ln_router = is_router;
  776         }
  777         rt->rt_flags &= ~RTF_REJECT;
  778         ln->ln_asked = 0;
  779         if (ln->ln_hold) {
  780                 /*
  781                  * we assume ifp is not a loopback here, so just set the 2nd
  782                  * argument as the 1st one.
  783                  */
  784                 nd6_output(ifp, ifp, ln->ln_hold,
  785                            (struct sockaddr_in6 *)rt_key(rt), rt);
  786                 ln->ln_hold = NULL;
  787         }
  788 
  789  freeit:
  790         m_freem(m);
  791         return;
  792 
  793  bad:
  794         icmp6stat.icp6s_badna++;
  795         m_freem(m);
  796 }
  797 
  798 /*
  799  * Neighbor advertisement output handling.
  800  *
  801  * Based on RFC 2461
  802  *
  803  * the following items are not implemented yet:
  804  * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
  805  * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
  806  */
  807 void
  808 nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
  809         struct ifnet *ifp;
  810         const struct in6_addr *daddr6, *taddr6;
  811         u_long flags;
  812         int tlladdr;            /* 1 if include target link-layer address */
  813         struct sockaddr *sdl0;  /* sockaddr_dl (= proxy NA) or NULL */
  814 {
  815         struct mbuf *m;
  816         struct ip6_hdr *ip6;
  817         struct nd_neighbor_advert *nd_na;
  818         struct in6_ifaddr *ia = NULL;
  819         struct ip6_moptions im6o;
  820         int icmp6len;
  821         int maxlen;
  822         caddr_t mac = NULL;
  823         struct ifnet *outif = NULL;
  824 
  825         /* estimate the size of message */
  826         maxlen = sizeof(*ip6) + sizeof(*nd_na);
  827         maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
  828         if (max_linkhdr + maxlen >= MCLBYTES) {
  829 #ifdef DIAGNOSTIC
  830                 printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES "
  831                     "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
  832 #endif
  833                 return;
  834         }
  835 
  836         MGETHDR(m, M_DONTWAIT, MT_DATA);
  837         if (m && max_linkhdr + maxlen >= MHLEN) {
  838                 MCLGET(m, M_DONTWAIT);
  839                 if ((m->m_flags & M_EXT) == 0) {
  840                         m_free(m);
  841                         m = NULL;
  842                 }
  843         }
  844         if (m == NULL)
  845                 return;
  846         m->m_pkthdr.rcvif = NULL;
  847 
  848         if (IN6_IS_ADDR_MULTICAST(daddr6)) {
  849                 m->m_flags |= M_MCAST;
  850                 im6o.im6o_multicast_ifp = ifp;
  851                 im6o.im6o_multicast_hlim = 255;
  852                 im6o.im6o_multicast_loop = 0;
  853         }
  854 
  855         icmp6len = sizeof(*nd_na);
  856         m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
  857         m->m_data += max_linkhdr;       /* or MH_ALIGN() equivalent? */
  858 
  859         /* fill neighbor advertisement packet */
  860         ip6 = mtod(m, struct ip6_hdr *);
  861         ip6->ip6_flow = 0;
  862         ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
  863         ip6->ip6_vfc |= IPV6_VERSION;
  864         ip6->ip6_nxt = IPPROTO_ICMPV6;
  865         ip6->ip6_hlim = 255;
  866         if (IN6_IS_ADDR_UNSPECIFIED(daddr6)) {
  867                 /* reply to DAD */
  868                 ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
  869                 ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
  870                 ip6->ip6_dst.s6_addr32[1] = 0;
  871                 ip6->ip6_dst.s6_addr32[2] = 0;
  872                 ip6->ip6_dst.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
  873                 flags &= ~ND_NA_FLAG_SOLICITED;
  874         } else
  875                 ip6->ip6_dst = *daddr6;
  876 
  877         /*
  878          * Select a source whose scope is the same as that of the dest.
  879          */
  880         ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
  881         if (ia == NULL) {
  882                 m_freem(m);
  883                 return;
  884         }
  885         ip6->ip6_src = ia->ia_addr.sin6_addr;
  886         nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
  887         nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
  888         nd_na->nd_na_code = 0;
  889         nd_na->nd_na_target = *taddr6;
  890         in6_clearscope(&nd_na->nd_na_target); /* XXX */
  891 
  892         /*
  893          * "tlladdr" indicates NS's condition for adding tlladdr or not.
  894          * see nd6_ns_input() for details.
  895          * Basically, if NS packet is sent to unicast/anycast addr,
  896          * target lladdr option SHOULD NOT be included.
  897          */
  898         if (tlladdr) {
  899                 /*
  900                  * sdl0 != NULL indicates proxy NA.  If we do proxy, use
  901                  * lladdr in sdl0.  If we are not proxying (sending NA for
  902                  * my address) use lladdr configured for the interface.
  903                  */
  904                 if (sdl0 == NULL) {
  905 #ifdef DEV_CARP
  906                         if (ifp->if_carp)
  907                                 mac = carp_macmatch6(ifp->if_carp, m, taddr6);
  908                         if (mac == NULL)
  909                                 mac = nd6_ifptomac(ifp);
  910 #else
  911                         mac = nd6_ifptomac(ifp);
  912 #endif
  913                 } else if (sdl0->sa_family == AF_LINK) {
  914                         struct sockaddr_dl *sdl;
  915                         sdl = (struct sockaddr_dl *)sdl0;
  916                         if (sdl->sdl_alen == ifp->if_addrlen)
  917                                 mac = LLADDR(sdl);
  918                 }
  919         }
  920         if (tlladdr && mac) {
  921                 int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
  922                 struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
  923 
  924                 /* roundup to 8 bytes alignment! */
  925                 optlen = (optlen + 7) & ~7;
  926 
  927                 m->m_pkthdr.len += optlen;
  928                 m->m_len += optlen;
  929                 icmp6len += optlen;
  930                 bzero((caddr_t)nd_opt, optlen);
  931                 nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
  932                 nd_opt->nd_opt_len = optlen >> 3;
  933                 bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
  934         } else
  935                 flags &= ~ND_NA_FLAG_OVERRIDE;
  936 
  937         ip6->ip6_plen = htons((u_short)icmp6len);
  938         nd_na->nd_na_flags_reserved = flags;
  939         nd_na->nd_na_cksum = 0;
  940         nd_na->nd_na_cksum =
  941             in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
  942 
  943         ip6_output(m, NULL, NULL, 0, &im6o, &outif, NULL);
  944         if (outif) {
  945                 icmp6_ifstat_inc(outif, ifs6_out_msg);
  946                 icmp6_ifstat_inc(outif, ifs6_out_neighboradvert);
  947         }
  948         icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
  949 }
  950 
  951 caddr_t
  952 nd6_ifptomac(ifp)
  953         struct ifnet *ifp;
  954 {
  955         switch (ifp->if_type) {
  956         case IFT_ARCNET:
  957         case IFT_ETHER:
  958         case IFT_FDDI:
  959         case IFT_IEEE1394:
  960 #ifdef IFT_L2VLAN
  961         case IFT_L2VLAN:
  962 #endif
  963 #ifdef IFT_IEEE80211
  964         case IFT_IEEE80211:
  965 #endif
  966 #ifdef IFT_CARP
  967         case IFT_CARP:
  968 #endif
  969         case IFT_BRIDGE:
  970         case IFT_ISO88025:
  971                 return ((caddr_t)(ifp + 1));
  972         default:
  973                 return NULL;
  974         }
  975 }
  976 
  977 TAILQ_HEAD(dadq_head, dadq);
  978 struct dadq {
  979         TAILQ_ENTRY(dadq) dad_list;
  980         struct ifaddr *dad_ifa;
  981         int dad_count;          /* max NS to send */
  982         int dad_ns_tcount;      /* # of trials to send NS */
  983         int dad_ns_ocount;      /* NS sent so far */
  984         int dad_ns_icount;
  985         int dad_na_icount;
  986         struct callout dad_timer_ch;
  987 };
  988 
  989 static struct dadq_head dadq;
  990 static int dad_init = 0;
  991 
  992 static struct dadq *
  993 nd6_dad_find(ifa)
  994         struct ifaddr *ifa;
  995 {
  996         struct dadq *dp;
  997 
  998         for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) {
  999                 if (dp->dad_ifa == ifa)
 1000                         return dp;
 1001         }
 1002         return NULL;
 1003 }
 1004 
 1005 static void
 1006 nd6_dad_starttimer(dp, ticks)
 1007         struct dadq *dp;
 1008         int ticks;
 1009 {
 1010 
 1011         callout_reset(&dp->dad_timer_ch, ticks,
 1012             (void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa);
 1013 }
 1014 
 1015 static void
 1016 nd6_dad_stoptimer(dp)
 1017         struct dadq *dp;
 1018 {
 1019 
 1020         callout_stop(&dp->dad_timer_ch);
 1021 }
 1022 
 1023 /*
 1024  * Start Duplicated Address Detection (DAD) for specified interface address.
 1025  */
 1026 void
 1027 nd6_dad_start(ifa, tick)
 1028         struct ifaddr *ifa;
 1029         int *tick;      /* minimum delay ticks for IFF_UP event */
 1030 {
 1031         struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
 1032         struct dadq *dp;
 1033 
 1034         if (!dad_init) {
 1035                 TAILQ_INIT(&dadq);
 1036                 dad_init++;
 1037         }
 1038 
 1039         /*
 1040          * If we don't need DAD, don't do it.
 1041          * There are several cases:
 1042          * - DAD is disabled (ip6_dad_count == 0)
 1043          * - the interface address is anycast
 1044          */
 1045         if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
 1046                 log(LOG_DEBUG,
 1047                         "nd6_dad_start: called with non-tentative address "
 1048                         "%s(%s)\n",
 1049                         ip6_sprintf(&ia->ia_addr.sin6_addr),
 1050                         ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
 1051                 return;
 1052         }
 1053         if (ia->ia6_flags & IN6_IFF_ANYCAST) {
 1054                 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
 1055                 return;
 1056         }
 1057         if (!ip6_dad_count) {
 1058                 ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
 1059                 return;
 1060         }
 1061         if (!ifa->ifa_ifp)
 1062                 panic("nd6_dad_start: ifa->ifa_ifp == NULL");
 1063         if (!(ifa->ifa_ifp->if_flags & IFF_UP)) {
 1064                 return;
 1065         }
 1066         if (nd6_dad_find(ifa) != NULL) {
 1067                 /* DAD already in progress */
 1068                 return;
 1069         }
 1070 
 1071         dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);
 1072         if (dp == NULL) {
 1073                 log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
 1074                         "%s(%s)\n",
 1075                         ip6_sprintf(&ia->ia_addr.sin6_addr),
 1076                         ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
 1077                 return;
 1078         }
 1079         bzero(dp, sizeof(*dp));
 1080         callout_init(&dp->dad_timer_ch, 0);
 1081         TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
 1082 
 1083         nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
 1084             ip6_sprintf(&ia->ia_addr.sin6_addr)));
 1085 
 1086         /*
 1087          * Send NS packet for DAD, ip6_dad_count times.
 1088          * Note that we must delay the first transmission, if this is the
 1089          * first packet to be sent from the interface after interface
 1090          * (re)initialization.
 1091          */
 1092         dp->dad_ifa = ifa;
 1093         IFAREF(ifa);    /* just for safety */
 1094         dp->dad_count = ip6_dad_count;
 1095         dp->dad_ns_icount = dp->dad_na_icount = 0;
 1096         dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
 1097         if (tick == NULL) {
 1098                 nd6_dad_ns_output(dp, ifa);
 1099                 nd6_dad_starttimer(dp,
 1100                     ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
 1101         } else {
 1102                 int ntick;
 1103 
 1104                 if (*tick == 0)
 1105                         ntick = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
 1106                 else
 1107                         ntick = *tick + arc4random() % (hz / 2);
 1108                 *tick = ntick;
 1109                 nd6_dad_starttimer(dp, ntick);
 1110         }
 1111 }
 1112 
 1113 /*
 1114  * terminate DAD unconditionally.  used for address removals.
 1115  */
 1116 void
 1117 nd6_dad_stop(ifa)
 1118         struct ifaddr *ifa;
 1119 {
 1120         struct dadq *dp;
 1121 
 1122         if (!dad_init)
 1123                 return;
 1124         dp = nd6_dad_find(ifa);
 1125         if (!dp) {
 1126                 /* DAD wasn't started yet */
 1127                 return;
 1128         }
 1129 
 1130         nd6_dad_stoptimer(dp);
 1131 
 1132         TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
 1133         free(dp, M_IP6NDP);
 1134         dp = NULL;
 1135         IFAFREE(ifa);
 1136 }
 1137 
 1138 static void
 1139 nd6_dad_timer(ifa)
 1140         struct ifaddr *ifa;
 1141 {
 1142         int s;
 1143         struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
 1144         struct dadq *dp;
 1145 
 1146         s = splnet();           /* XXX */
 1147 
 1148         /* Sanity check */
 1149         if (ia == NULL) {
 1150                 log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
 1151                 goto done;
 1152         }
 1153         dp = nd6_dad_find(ifa);
 1154         if (dp == NULL) {
 1155                 log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");
 1156                 goto done;
 1157         }
 1158         if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
 1159                 log(LOG_ERR, "nd6_dad_timer: called with duplicated address "
 1160                         "%s(%s)\n",
 1161                         ip6_sprintf(&ia->ia_addr.sin6_addr),
 1162                         ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
 1163                 goto done;
 1164         }
 1165         if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
 1166                 log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
 1167                         "%s(%s)\n",
 1168                         ip6_sprintf(&ia->ia_addr.sin6_addr),
 1169                         ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
 1170                 goto done;
 1171         }
 1172 
 1173         /* timeouted with IFF_{RUNNING,UP} check */
 1174         if (dp->dad_ns_tcount > dad_maxtry) {
 1175                 nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
 1176                     if_name(ifa->ifa_ifp)));
 1177 
 1178                 TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
 1179                 free(dp, M_IP6NDP);
 1180                 dp = NULL;
 1181                 IFAFREE(ifa);
 1182                 goto done;
 1183         }
 1184 
 1185         /* Need more checks? */
 1186         if (dp->dad_ns_ocount < dp->dad_count) {
 1187                 /*
 1188                  * We have more NS to go.  Send NS packet for DAD.
 1189                  */
 1190                 nd6_dad_ns_output(dp, ifa);
 1191                 nd6_dad_starttimer(dp,
 1192                     ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
 1193         } else {
 1194                 /*
 1195                  * We have transmitted sufficient number of DAD packets.
 1196                  * See what we've got.
 1197                  */
 1198                 int duplicate;
 1199 
 1200                 duplicate = 0;
 1201 
 1202                 if (dp->dad_na_icount) {
 1203                         /*
 1204                          * the check is in nd6_dad_na_input(),
 1205                          * but just in case
 1206                          */
 1207                         duplicate++;
 1208                 }
 1209 
 1210                 if (dp->dad_ns_icount) {
 1211 #if 0 /* heuristics */
 1212                         /*
 1213                          * if
 1214                          * - we have sent many(?) DAD NS, and
 1215                          * - the number of NS we sent equals to the
 1216                          *   number of NS we've got, and
 1217                          * - we've got no NA
 1218                          * we may have a faulty network card/driver which
 1219                          * loops back multicasts to myself.
 1220                          */
 1221                         if (3 < dp->dad_count
 1222                          && dp->dad_ns_icount == dp->dad_count
 1223                          && dp->dad_na_icount == 0) {
 1224                                 log(LOG_INFO, "DAD questionable for %s(%s): "
 1225                                     "network card loops back multicast?\n",
 1226                                     ip6_sprintf(&ia->ia_addr.sin6_addr),
 1227                                     if_name(ifa->ifa_ifp));
 1228                                 /* XXX consider it a duplicate or not? */
 1229                                 /* duplicate++; */
 1230                         } else {
 1231                                 /* We've seen NS, means DAD has failed. */
 1232                                 duplicate++;
 1233                         }
 1234 #else
 1235                         /* We've seen NS, means DAD has failed. */
 1236                         duplicate++;
 1237 #endif
 1238                 }
 1239 
 1240                 if (duplicate) {
 1241                         /* (*dp) will be freed in nd6_dad_duplicated() */
 1242                         dp = NULL;
 1243                         nd6_dad_duplicated(ifa);
 1244                 } else {
 1245                         /*
 1246                          * We are done with DAD.  No NA came, no NS came.
 1247                          * duplicated address found.
 1248                          */
 1249                         ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
 1250 
 1251                         nd6log((LOG_DEBUG,
 1252                             "%s: DAD complete for %s - no duplicates found\n",
 1253                             if_name(ifa->ifa_ifp),
 1254                             ip6_sprintf(&ia->ia_addr.sin6_addr)));
 1255 
 1256                         TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
 1257                         free(dp, M_IP6NDP);
 1258                         dp = NULL;
 1259                         IFAFREE(ifa);
 1260                 }
 1261         }
 1262 
 1263 done:
 1264         splx(s);
 1265 }
 1266 
 1267 void
 1268 nd6_dad_duplicated(ifa)
 1269         struct ifaddr *ifa;
 1270 {
 1271         struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
 1272         struct dadq *dp;
 1273 
 1274         dp = nd6_dad_find(ifa);
 1275         if (dp == NULL) {
 1276                 log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");
 1277                 return;
 1278         }
 1279 
 1280         log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
 1281             "NS in/out=%d/%d, NA in=%d\n",
 1282             if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr),
 1283             dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);
 1284 
 1285         ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
 1286         ia->ia6_flags |= IN6_IFF_DUPLICATED;
 1287 
 1288         /* We are done with DAD, with duplicated address found. (failure) */
 1289         nd6_dad_stoptimer(dp);
 1290 
 1291         log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
 1292             if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
 1293         log(LOG_ERR, "%s: manual intervention required\n",
 1294             if_name(ifa->ifa_ifp));
 1295 
 1296         TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
 1297         free(dp, M_IP6NDP);
 1298         dp = NULL;
 1299         IFAFREE(ifa);
 1300 }
 1301 
 1302 static void
 1303 nd6_dad_ns_output(dp, ifa)
 1304         struct dadq *dp;
 1305         struct ifaddr *ifa;
 1306 {
 1307         struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
 1308         struct ifnet *ifp = ifa->ifa_ifp;
 1309 
 1310         dp->dad_ns_tcount++;
 1311         if ((ifp->if_flags & IFF_UP) == 0) {
 1312 #if 0
 1313                 printf("%s: interface down?\n", if_name(ifp));
 1314 #endif
 1315                 return;
 1316         }
 1317         if ((ifp->if_flags & IFF_RUNNING) == 0) {
 1318 #if 0
 1319                 printf("%s: interface not running?\n", if_name(ifp));
 1320 #endif
 1321                 return;
 1322         }
 1323 
 1324         dp->dad_ns_ocount++;
 1325         nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
 1326 }
 1327 
 1328 static void
 1329 nd6_dad_ns_input(ifa)
 1330         struct ifaddr *ifa;
 1331 {
 1332         struct in6_ifaddr *ia;
 1333         struct ifnet *ifp;
 1334         const struct in6_addr *taddr6;
 1335         struct dadq *dp;
 1336         int duplicate;
 1337 
 1338         if (!ifa)
 1339                 panic("ifa == NULL in nd6_dad_ns_input");
 1340 
 1341         ia = (struct in6_ifaddr *)ifa;
 1342         ifp = ifa->ifa_ifp;
 1343         taddr6 = &ia->ia_addr.sin6_addr;
 1344         duplicate = 0;
 1345         dp = nd6_dad_find(ifa);
 1346 
 1347         /* Quickhack - completely ignore DAD NS packets */
 1348         if (dad_ignore_ns) {
 1349                 nd6log((LOG_INFO,
 1350                     "nd6_dad_ns_input: ignoring DAD NS packet for "
 1351                     "address %s(%s)\n", ip6_sprintf(taddr6),
 1352                     if_name(ifa->ifa_ifp)));
 1353                 return;
 1354         }
 1355 
 1356         /*
 1357          * if I'm yet to start DAD, someone else started using this address
 1358          * first.  I have a duplicate and you win.
 1359          */
 1360         if (!dp || dp->dad_ns_ocount == 0)
 1361                 duplicate++;
 1362 
 1363         /* XXX more checks for loopback situation - see nd6_dad_timer too */
 1364 
 1365         if (duplicate) {
 1366                 dp = NULL;      /* will be freed in nd6_dad_duplicated() */
 1367                 nd6_dad_duplicated(ifa);
 1368         } else {
 1369                 /*
 1370                  * not sure if I got a duplicate.
 1371                  * increment ns count and see what happens.
 1372                  */
 1373                 if (dp)
 1374                         dp->dad_ns_icount++;
 1375         }
 1376 }
 1377 
 1378 static void
 1379 nd6_dad_na_input(ifa)
 1380         struct ifaddr *ifa;
 1381 {
 1382         struct dadq *dp;
 1383 
 1384         if (!ifa)
 1385                 panic("ifa == NULL in nd6_dad_na_input");
 1386 
 1387         dp = nd6_dad_find(ifa);
 1388         if (dp)
 1389                 dp->dad_na_icount++;
 1390 
 1391         /* remove the address. */
 1392         nd6_dad_duplicated(ifa);
 1393 }

Cache object: 4ffaf5dd194b8e6b0c24150ba5acdcb4


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