nd6_nbr.c revision 279564
1139826Simp/*- 253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 353541Sshin * All rights reserved. 453541Sshin * 553541Sshin * Redistribution and use in source and binary forms, with or without 653541Sshin * modification, are permitted provided that the following conditions 753541Sshin * are met: 853541Sshin * 1. Redistributions of source code must retain the above copyright 953541Sshin * notice, this list of conditions and the following disclaimer. 1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1153541Sshin * notice, this list of conditions and the following disclaimer in the 1253541Sshin * documentation and/or other materials provided with the distribution. 1353541Sshin * 3. Neither the name of the project nor the names of its contributors 1453541Sshin * may be used to endorse or promote products derived from this software 1553541Sshin * without specific prior written permission. 1653541Sshin * 1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2053541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2753541Sshin * SUCH DAMAGE. 28174510Sobrien * 29174510Sobrien * $KAME: nd6_nbr.c,v 1.86 2002/01/21 02:33:04 jinmei Exp $ 3053541Sshin */ 3153541Sshin 32174510Sobrien#include <sys/cdefs.h> 33174510Sobrien__FBSDID("$FreeBSD: head/sys/netinet6/nd6_nbr.c 279564 2015-03-03 10:50:03Z ae $"); 34174510Sobrien 3562587Sitojun#include "opt_inet.h" 3662587Sitojun#include "opt_inet6.h" 37142215Sglebius#include "opt_ipsec.h" 38178167Sqingli#include "opt_mpath.h" 3955009Sshin 4053541Sshin#include <sys/param.h> 4153541Sshin#include <sys/systm.h> 4253541Sshin#include <sys/malloc.h> 43279531Shrs#include <sys/libkern.h> 44186119Sqingli#include <sys/lock.h> 45186119Sqingli#include <sys/rwlock.h> 4653541Sshin#include <sys/mbuf.h> 4753541Sshin#include <sys/socket.h> 4853541Sshin#include <sys/sockio.h> 4953541Sshin#include <sys/time.h> 5053541Sshin#include <sys/kernel.h> 5153541Sshin#include <sys/errno.h> 52279531Shrs#include <sys/sysctl.h> 5353541Sshin#include <sys/syslog.h> 5453541Sshin#include <sys/queue.h> 5578064Sume#include <sys/callout.h> 56275593Smarkj#include <sys/refcount.h> 5753541Sshin 5853541Sshin#include <net/if.h> 5953541Sshin#include <net/if_types.h> 6053541Sshin#include <net/if_dl.h> 61147306Sbrooks#include <net/if_var.h> 6253541Sshin#include <net/route.h> 63178167Sqingli#ifdef RADIX_MPATH 64178167Sqingli#include <net/radix_mpath.h> 65178167Sqingli#endif 66279531Shrs#include <net/vnet.h> 6753541Sshin 6853541Sshin#include <netinet/in.h> 6953541Sshin#include <netinet/in_var.h> 70186119Sqingli#include <net/if_llatbl.h> 71186119Sqingli#define L3_ADDR_SIN6(le) ((struct sockaddr_in6 *) L3_ADDR(le)) 7253541Sshin#include <netinet6/in6_var.h> 73151477Ssuz#include <netinet6/in6_ifattach.h> 7462587Sitojun#include <netinet/ip6.h> 7553541Sshin#include <netinet6/ip6_var.h> 76148385Sume#include <netinet6/scope6_var.h> 7753541Sshin#include <netinet6/nd6.h> 7862587Sitojun#include <netinet/icmp6.h> 79211193Swill#include <netinet/ip_carp.h> 80211501Sanchie#include <netinet6/send.h> 8153541Sshin 8262587Sitojun#define SDL(s) ((struct sockaddr_dl *)s) 8353541Sshin 8462587Sitojunstruct dadq; 85279531Shrsstatic struct dadq *nd6_dad_find(struct ifaddr *, struct nd_opt_nonce *); 86274347Smelifarostatic void nd6_dad_add(struct dadq *dp); 87274347Smelifarostatic void nd6_dad_del(struct dadq *dp); 88275593Smarkjstatic void nd6_dad_rele(struct dadq *); 89175162Sobrienstatic void nd6_dad_starttimer(struct dadq *, int); 90175162Sobrienstatic void nd6_dad_stoptimer(struct dadq *); 91191816Szecstatic void nd6_dad_timer(struct dadq *); 92274347Smelifarostatic void nd6_dad_duplicated(struct ifaddr *, struct dadq *); 93175162Sobrienstatic void nd6_dad_ns_output(struct dadq *, struct ifaddr *); 94279531Shrsstatic void nd6_dad_ns_input(struct ifaddr *, struct nd_opt_nonce *); 95175162Sobrienstatic void nd6_dad_na_input(struct ifaddr *); 96231852Sbzstatic void nd6_na_output_fib(struct ifnet *, const struct in6_addr *, 97231852Sbz const struct in6_addr *, u_long, int, struct sockaddr *, u_int); 98279564Saestatic void nd6_ns_output_fib(struct ifnet *, const struct in6_addr *, 99279564Sae const struct in6_addr *, struct llentry *, uint8_t *, u_int); 10053541Sshin 101279531Shrsstatic VNET_DEFINE(int, dad_enhanced) = 1; 102279531Shrs#define V_dad_enhanced VNET(dad_enhanced) 103279531Shrs 104279531ShrsSYSCTL_DECL(_net_inet6_ip6); 105279531ShrsSYSCTL_INT(_net_inet6_ip6, OID_AUTO, dad_enhanced, CTLFLAG_VNET | CTLFLAG_RW, 106279531Shrs &VNET_NAME(dad_enhanced), 0, 107279531Shrs "Enable Enhanced DAD, which adds a random nonce to NS messages for DAD."); 108279531Shrs 109266857Shrsstatic VNET_DEFINE(int, dad_maxtry) = 15; /* max # of *tries* to 110266857Shrs transmit DAD packet */ 111195727Srwatson#define V_dad_maxtry VNET(dad_maxtry) 112195699Srwatson 11353541Sshin/* 114108470Sschweikh * Input a Neighbor Solicitation Message. 11553541Sshin * 11653541Sshin * Based on RFC 2461 117148987Sume * Based on RFC 2462 (duplicate address detection) 11853541Sshin */ 11953541Sshinvoid 120171259Sdelphijnd6_ns_input(struct mbuf *m, int off, int icmp6len) 12153541Sshin{ 12253541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 12353541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 12462587Sitojun struct nd_neighbor_solicit *nd_ns; 12553541Sshin struct in6_addr saddr6 = ip6->ip6_src; 12653541Sshin struct in6_addr daddr6 = ip6->ip6_dst; 12762587Sitojun struct in6_addr taddr6; 12853541Sshin struct in6_addr myaddr6; 12953541Sshin char *lladdr = NULL; 130142215Sglebius struct ifaddr *ifa = NULL; 13153541Sshin int lladdrlen = 0; 13253541Sshin int anycast = 0, proxy = 0, tentative = 0; 13353541Sshin int tlladdr; 134222728Shrs int rflag; 13553541Sshin union nd_opts ndopts; 136219562Sbz struct sockaddr_dl proxydl; 137165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 13853541Sshin 139222728Shrs rflag = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0; 140222728Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && V_ip6_norbit_raif) 141222728Shrs rflag = 0; 14278064Sume#ifndef PULLDOWN_TEST 14378064Sume IP6_EXTHDR_CHECK(m, off, icmp6len,); 14478064Sume nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); 14578064Sume#else 14678064Sume IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); 14778064Sume if (nd_ns == NULL) { 148190964Srwatson ICMP6STAT_INC(icp6s_tooshort); 14978064Sume return; 15078064Sume } 15178064Sume#endif 15278064Sume ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ 15378064Sume taddr6 = nd_ns->nd_ns_target; 154148385Sume if (in6_setscope(&taddr6, ifp, NULL) != 0) 155148385Sume goto bad; 15678064Sume 15753541Sshin if (ip6->ip6_hlim != 255) { 15878064Sume nd6log((LOG_ERR, 15978064Sume "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n", 160165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 161165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 16278064Sume goto bad; 16353541Sshin } 16453541Sshin 16553541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { 166148987Sume /* dst has to be a solicited node multicast address. */ 167120941Sume if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL && 16895023Ssuz /* don't check ifindex portion */ 169120941Sume daddr6.s6_addr32[1] == 0 && 170120941Sume daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE && 171120941Sume daddr6.s6_addr8[12] == 0xff) { 17295023Ssuz ; /* good */ 17353541Sshin } else { 17478064Sume nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " 175120941Sume "(wrong ip6 dst)\n")); 17653541Sshin goto bad; 17753541Sshin } 178185348Szec } else if (!V_nd6_onlink_ns_rfc4861) { 179183529Scperciva struct sockaddr_in6 src_sa6; 180183529Scperciva 181183529Scperciva /* 182183529Scperciva * According to recent IETF discussions, it is not a good idea 183183529Scperciva * to accept a NS from an address which would not be deemed 184183529Scperciva * to be a neighbor otherwise. This point is expected to be 185183529Scperciva * clarified in future revisions of the specification. 186183529Scperciva */ 187183529Scperciva bzero(&src_sa6, sizeof(src_sa6)); 188183529Scperciva src_sa6.sin6_family = AF_INET6; 189183529Scperciva src_sa6.sin6_len = sizeof(src_sa6); 190183529Scperciva src_sa6.sin6_addr = saddr6; 191186119Sqingli if (nd6_is_addr_neighbor(&src_sa6, ifp) == 0) { 192183529Scperciva nd6log((LOG_INFO, "nd6_ns_input: " 193183529Scperciva "NS packet from non-neighbor\n")); 194183529Scperciva goto bad; 195183529Scperciva } 19653541Sshin } 19753541Sshin 19853541Sshin if (IN6_IS_ADDR_MULTICAST(&taddr6)) { 19978064Sume nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n")); 20053541Sshin goto bad; 20153541Sshin } 20253541Sshin 20353541Sshin icmp6len -= sizeof(*nd_ns); 20453541Sshin nd6_option_init(nd_ns + 1, icmp6len, &ndopts); 20553541Sshin if (nd6_options(&ndopts) < 0) { 20678064Sume nd6log((LOG_INFO, 20778064Sume "nd6_ns_input: invalid ND option, ignored\n")); 20878064Sume /* nd6_options have incremented stats */ 20978064Sume goto freeit; 21053541Sshin } 21153541Sshin 21253541Sshin if (ndopts.nd_opts_src_lladdr) { 21395023Ssuz lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 21453541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 21553541Sshin } 216120941Sume 21753541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) { 21878064Sume nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " 21978064Sume "(link-layer address option)\n")); 22053541Sshin goto bad; 22153541Sshin } 22253541Sshin 22353541Sshin /* 22453541Sshin * Attaching target link-layer address to the NA? 22553541Sshin * (RFC 2461 7.2.4) 22653541Sshin * 22753541Sshin * NS IP dst is unicast/anycast MUST NOT add 22853541Sshin * NS IP dst is solicited-node multicast MUST add 22953541Sshin * 23053541Sshin * In implementation, we add target link-layer address by default. 23153541Sshin * We do not add one in MUST NOT cases. 23253541Sshin */ 23353541Sshin if (!IN6_IS_ADDR_MULTICAST(&daddr6)) 23453541Sshin tlladdr = 0; 23553541Sshin else 23653541Sshin tlladdr = 1; 23753541Sshin 23853541Sshin /* 23953541Sshin * Target address (taddr6) must be either: 24053541Sshin * (1) Valid unicast/anycast address for my receiving interface, 24153541Sshin * (2) Unicast address for which I'm offering proxy service, or 24253541Sshin * (3) "tentative" address on which DAD is being performed. 24353541Sshin */ 24453541Sshin /* (1) and (3) check. */ 245142215Sglebius if (ifp->if_carp) 246211157Swill ifa = (*carp_iamatch6_p)(ifp, &taddr6); 247228571Sglebius else 248142215Sglebius ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); 24953541Sshin 25053541Sshin /* (2) check. */ 251151465Ssuz if (ifa == NULL) { 252257985Sae struct route_in6 ro; 253121765Ssam int need_proxy; 25453541Sshin 255257985Sae bzero(&ro, sizeof(ro)); 256257985Sae ro.ro_dst.sin6_len = sizeof(struct sockaddr_in6); 257257985Sae ro.ro_dst.sin6_family = AF_INET6; 258257985Sae ro.ro_dst.sin6_addr = taddr6; 25953541Sshin 260231852Sbz /* Always use the default FIB. */ 261178167Sqingli#ifdef RADIX_MPATH 262264976Smelifaro rtalloc_mpath_fib((struct route *)&ro, ntohl(taddr6.s6_addr32[3]), 263231852Sbz RT_DEFAULT_FIB); 264178167Sqingli#else 265257985Sae in6_rtalloc(&ro, RT_DEFAULT_FIB); 266178167Sqingli#endif 267257985Sae need_proxy = (ro.ro_rt && 268257985Sae (ro.ro_rt->rt_flags & RTF_ANNOUNCE) != 0 && 269257985Sae ro.ro_rt->rt_gateway->sa_family == AF_LINK); 270257985Sae if (ro.ro_rt != NULL) { 271219562Sbz if (need_proxy) 272257985Sae proxydl = *SDL(ro.ro_rt->rt_gateway); 273257985Sae RTFREE(ro.ro_rt); 274219562Sbz } 275121765Ssam if (need_proxy) { 27653541Sshin /* 27762587Sitojun * proxy NDP for single entry 27853541Sshin */ 27962587Sitojun ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 28062587Sitojun IN6_IFF_NOTREADY|IN6_IFF_ANYCAST); 281219562Sbz if (ifa) 28253541Sshin proxy = 1; 28353541Sshin } 28453541Sshin } 285151479Ssuz if (ifa == NULL) { 28653541Sshin /* 28778064Sume * We've got an NS packet, and we don't have that adddress 28853541Sshin * assigned for us. We MUST silently ignore it. 28953541Sshin * See RFC2461 7.2.3. 29053541Sshin */ 29162587Sitojun goto freeit; 29253541Sshin } 29353541Sshin myaddr6 = *IFA_IN6(ifa); 29453541Sshin anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST; 29553541Sshin tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE; 29653541Sshin if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED) 29762587Sitojun goto freeit; 29853541Sshin 29953541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 300120941Sume nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s " 30153541Sshin "(if %d, NS packet %d)\n", 302165118Sbz ip6_sprintf(ip6bufs, &taddr6), 303120941Sume ifp->if_addrlen, lladdrlen - 2)); 30478064Sume goto bad; 30553541Sshin } 30653541Sshin 30753541Sshin if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) { 308120941Sume nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n", 309165118Sbz ip6_sprintf(ip6bufs, &saddr6))); 31062587Sitojun goto freeit; 31153541Sshin } 31253541Sshin 31353541Sshin /* 31453541Sshin * We have neighbor solicitation packet, with target address equals to 31553541Sshin * one of my tentative address. 31653541Sshin * 31753541Sshin * src addr how to process? 31853541Sshin * --- --- 31953541Sshin * multicast of course, invalid (rejected in ip6_input) 32053541Sshin * unicast somebody is doing address resolution -> ignore 32153541Sshin * unspec dup address detection 32253541Sshin * 32353541Sshin * The processing is defined in RFC 2462. 32453541Sshin */ 32553541Sshin if (tentative) { 32653541Sshin /* 32753541Sshin * If source address is unspecified address, it is for 328148987Sume * duplicate address detection. 32953541Sshin * 33053541Sshin * If not, the packet is for addess resolution; 33153541Sshin * silently ignore it. 33253541Sshin */ 33353541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 334279531Shrs nd6_dad_ns_input(ifa, ndopts.nd_opts_nonce); 33553541Sshin 33662587Sitojun goto freeit; 33753541Sshin } 33853541Sshin 33953541Sshin /* 34053541Sshin * If the source address is unspecified address, entries must not 34153541Sshin * be created or updated. 34253541Sshin * It looks that sender is performing DAD. Output NA toward 34353541Sshin * all-node multicast address, to tell the sender that I'm using 34453541Sshin * the address. 34553541Sshin * S bit ("solicited") must be zero. 34653541Sshin */ 34753541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { 348148385Sume struct in6_addr in6_all; 349148385Sume 350148385Sume in6_all = in6addr_linklocal_allnodes; 351148385Sume if (in6_setscope(&in6_all, ifp, NULL) != 0) 352148385Sume goto bad; 353231852Sbz nd6_na_output_fib(ifp, &in6_all, &taddr6, 354120941Sume ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | 355231852Sbz rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, 356231852Sbz M_GETFIB(m)); 35762587Sitojun goto freeit; 35853541Sshin } 35953541Sshin 360120941Sume nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, 361120941Sume ND_NEIGHBOR_SOLICIT, 0); 36253541Sshin 363231852Sbz nd6_na_output_fib(ifp, &saddr6, &taddr6, 364120941Sume ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | 365222728Shrs rflag | ND_NA_FLAG_SOLICITED, tlladdr, 366231852Sbz proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m)); 36762587Sitojun freeit: 368194760Srwatson if (ifa != NULL) 369194760Srwatson ifa_free(ifa); 37062587Sitojun m_freem(m); 37153541Sshin return; 37253541Sshin 37353541Sshin bad: 374165118Sbz nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", 375165118Sbz ip6_sprintf(ip6bufs, &saddr6))); 376165118Sbz nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", 377165118Sbz ip6_sprintf(ip6bufs, &daddr6))); 378165118Sbz nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", 379165118Sbz ip6_sprintf(ip6bufs, &taddr6))); 380190964Srwatson ICMP6STAT_INC(icp6s_badns); 381194760Srwatson if (ifa != NULL) 382194760Srwatson ifa_free(ifa); 38362587Sitojun m_freem(m); 38453541Sshin} 38553541Sshin 38653541Sshin/* 387108470Sschweikh * Output a Neighbor Solicitation Message. Caller specifies: 38853541Sshin * - ICMP6 header source IP6 address 38953541Sshin * - ND6 header target IP6 address 39053541Sshin * - ND6 header source datalink address 39153541Sshin * 39253541Sshin * Based on RFC 2461 393148987Sume * Based on RFC 2462 (duplicate address detection) 394171259Sdelphij * 395279531Shrs * ln - for source address determination 396279531Shrs * nonce - If non-NULL, NS is used for duplicate address detection and 397279531Shrs * the value (length is ND_OPT_NONCE_LEN) is used as a random nonce. 39853541Sshin */ 399279564Saestatic void 400279564Saend6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6, 401279564Sae const struct in6_addr *taddr6, struct llentry *ln, uint8_t *nonce, 402279564Sae u_int fibnum) 40353541Sshin{ 40453541Sshin struct mbuf *m; 405211501Sanchie struct m_tag *mtag; 40653541Sshin struct ip6_hdr *ip6; 40753541Sshin struct nd_neighbor_solicit *nd_ns; 40853541Sshin struct ip6_moptions im6o; 40953541Sshin int icmp6len; 41062587Sitojun int maxlen; 41153541Sshin caddr_t mac; 412148385Sume struct route_in6 ro; 413120941Sume 41453541Sshin if (IN6_IS_ADDR_MULTICAST(taddr6)) 41553541Sshin return; 41653541Sshin 41762587Sitojun /* estimate the size of message */ 41862587Sitojun maxlen = sizeof(*ip6) + sizeof(*nd_ns); 41962587Sitojun maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; 42062587Sitojun if (max_linkhdr + maxlen >= MCLBYTES) { 42162587Sitojun#ifdef DIAGNOSTIC 422279564Sae printf("%s: max_linkhdr + maxlen >= MCLBYTES " 423279564Sae "(%d + %d > %d)\n", __func__, max_linkhdr, maxlen, 424279564Sae MCLBYTES); 42562587Sitojun#endif 42653541Sshin return; 42762587Sitojun } 42853541Sshin 429248328Sglebius if (max_linkhdr + maxlen > MHLEN) 430248328Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 431248328Sglebius else 432248328Sglebius m = m_gethdr(M_NOWAIT, MT_DATA); 43362587Sitojun if (m == NULL) 43462587Sitojun return; 435279564Sae M_SETFIB(m, fibnum); 43662587Sitojun 437215559Sbz bzero(&ro, sizeof(ro)); 438215559Sbz 43953541Sshin if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) { 44053541Sshin m->m_flags |= M_MCAST; 44153541Sshin im6o.im6o_multicast_ifp = ifp; 44253541Sshin im6o.im6o_multicast_hlim = 255; 44353541Sshin im6o.im6o_multicast_loop = 0; 44453541Sshin } 44553541Sshin 44653541Sshin icmp6len = sizeof(*nd_ns); 44753541Sshin m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len; 448276692Srwatson m->m_data += max_linkhdr; /* or M_ALIGN() equivalent? */ 44953541Sshin 45053541Sshin /* fill neighbor solicitation packet */ 45153541Sshin ip6 = mtod(m, struct ip6_hdr *); 45253541Sshin ip6->ip6_flow = 0; 45362587Sitojun ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 45462587Sitojun ip6->ip6_vfc |= IPV6_VERSION; 45553541Sshin /* ip6->ip6_plen will be set later */ 45653541Sshin ip6->ip6_nxt = IPPROTO_ICMPV6; 45753541Sshin ip6->ip6_hlim = 255; 45853541Sshin if (daddr6) 45953541Sshin ip6->ip6_dst = *daddr6; 46053541Sshin else { 46153541Sshin ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL; 462148385Sume ip6->ip6_dst.s6_addr16[1] = 0; 46353541Sshin ip6->ip6_dst.s6_addr32[1] = 0; 46453541Sshin ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE; 46553541Sshin ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3]; 46653541Sshin ip6->ip6_dst.s6_addr8[12] = 0xff; 467148385Sume if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0) 468148385Sume goto bad; 46953541Sshin } 470279531Shrs if (nonce == NULL) { 471194760Srwatson struct ifaddr *ifa; 472194760Srwatson 47353541Sshin /* 47453541Sshin * RFC2461 7.2.2: 47553541Sshin * "If the source address of the packet prompting the 47653541Sshin * solicitation is the same as one of the addresses assigned 47753541Sshin * to the outgoing interface, that address SHOULD be placed 47853541Sshin * in the IP Source Address of the outgoing solicitation. 47953541Sshin * Otherwise, any one of the addresses assigned to the 48053541Sshin * interface should be used." 48153541Sshin * 48253541Sshin * We use the source address for the prompting packet 48353541Sshin * (saddr6), if: 48453541Sshin * - saddr6 is given from the caller (by giving "ln"), and 48553541Sshin * - saddr6 belongs to the outgoing interface. 486148385Sume * Otherwise, we perform the source address selection as usual. 48753541Sshin */ 488216022Sbz struct in6_addr *hsrc; 48953541Sshin 490216022Sbz hsrc = NULL; 491216022Sbz if (ln != NULL) { 492216022Sbz LLE_RLOCK(ln); 493216022Sbz if (ln->la_hold != NULL) { 494216022Sbz struct ip6_hdr *hip6; /* hold ip6 */ 495216022Sbz 496216022Sbz /* 497216022Sbz * assuming every packet in la_hold has the same IP 498216022Sbz * header 499216022Sbz */ 500216022Sbz hip6 = mtod(ln->la_hold, struct ip6_hdr *); 501216022Sbz /* XXX pullup? */ 502216022Sbz if (sizeof(*hip6) < ln->la_hold->m_len) { 503216022Sbz ip6->ip6_src = hip6->ip6_src; 504216022Sbz hsrc = &hip6->ip6_src; 505216022Sbz } 506216022Sbz } 507216022Sbz LLE_RUNLOCK(ln); 508148385Sume } 509194760Srwatson if (hsrc && (ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, 510194760Srwatson hsrc)) != NULL) { 511216022Sbz /* ip6_src set already. */ 512194760Srwatson ifa_free(ifa); 513194760Srwatson } else { 514148385Sume int error; 515148385Sume struct sockaddr_in6 dst_sa; 516216022Sbz struct in6_addr src_in; 517231852Sbz struct ifnet *oifp; 518148385Sume 519148385Sume bzero(&dst_sa, sizeof(dst_sa)); 520148385Sume dst_sa.sin6_family = AF_INET6; 521148385Sume dst_sa.sin6_len = sizeof(dst_sa); 522148385Sume dst_sa.sin6_addr = ip6->ip6_dst; 523148385Sume 524231852Sbz oifp = ifp; 525194777Sbz error = in6_selectsrc(&dst_sa, NULL, 526231852Sbz NULL, &ro, NULL, &oifp, &src_in); 527194777Sbz if (error) { 528165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 529279564Sae nd6log((LOG_DEBUG, "%s: source can't be " 530279564Sae "determined: dst=%s, error=%d\n", __func__, 531165118Sbz ip6_sprintf(ip6buf, &dst_sa.sin6_addr), 532165118Sbz error)); 533148385Sume goto bad; 53453541Sshin } 535216022Sbz ip6->ip6_src = src_in; 53653541Sshin } 53753541Sshin } else { 53853541Sshin /* 53953541Sshin * Source address for DAD packet must always be IPv6 54053541Sshin * unspecified address. (0::0) 541148385Sume * We actually don't have to 0-clear the address (we did it 542148385Sume * above), but we do so here explicitly to make the intention 543148385Sume * clearer. 54453541Sshin */ 545216022Sbz bzero(&ip6->ip6_src, sizeof(ip6->ip6_src)); 54653541Sshin } 54753541Sshin nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1); 54853541Sshin nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; 54953541Sshin nd_ns->nd_ns_code = 0; 55053541Sshin nd_ns->nd_ns_reserved = 0; 55153541Sshin nd_ns->nd_ns_target = *taddr6; 552121315Sume in6_clearscope(&nd_ns->nd_ns_target); /* XXX */ 55353541Sshin 55453541Sshin /* 55553541Sshin * Add source link-layer address option. 55653541Sshin * 55753541Sshin * spec implementation 55853541Sshin * --- --- 55953541Sshin * DAD packet MUST NOT do not add the option 56053541Sshin * there's no link layer address: 56153541Sshin * impossible do not add the option 56253541Sshin * there's link layer address: 56353541Sshin * Multicast NS MUST add one add the option 56453541Sshin * Unicast NS SHOULD add one add the option 56553541Sshin */ 566279531Shrs if (nonce == NULL && (mac = nd6_ifptomac(ifp))) { 56753541Sshin int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; 56853541Sshin struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1); 56953541Sshin /* 8 byte alignments... */ 57053541Sshin optlen = (optlen + 7) & ~7; 571120941Sume 57253541Sshin m->m_pkthdr.len += optlen; 57353541Sshin m->m_len += optlen; 57453541Sshin icmp6len += optlen; 57553541Sshin bzero((caddr_t)nd_opt, optlen); 57653541Sshin nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; 57753541Sshin nd_opt->nd_opt_len = optlen >> 3; 57853541Sshin bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen); 57953541Sshin } 580279531Shrs /* 581279531Shrs * Add a Nonce option (RFC 3971) to detect looped back NS messages. 582279531Shrs * This behavior is documented as Enhanced Duplicate Address 583279531Shrs * Detection in draft-ietf-6man-enhanced-dad-13. 584279531Shrs * net.inet6.ip6.dad_enhanced=0 disables this. 585279531Shrs */ 586279531Shrs if (V_dad_enhanced != 0 && nonce != NULL) { 587279531Shrs int optlen = sizeof(struct nd_opt_hdr) + ND_OPT_NONCE_LEN; 588279531Shrs struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1); 589279531Shrs /* 8-byte alignment is required. */ 590279531Shrs optlen = (optlen + 7) & ~7; 59153541Sshin 592279531Shrs m->m_pkthdr.len += optlen; 593279531Shrs m->m_len += optlen; 594279531Shrs icmp6len += optlen; 595279531Shrs bzero((caddr_t)nd_opt, optlen); 596279531Shrs nd_opt->nd_opt_type = ND_OPT_NONCE; 597279531Shrs nd_opt->nd_opt_len = optlen >> 3; 598279531Shrs bcopy(nonce, (caddr_t)(nd_opt + 1), ND_OPT_NONCE_LEN); 599279531Shrs } 60053541Sshin ip6->ip6_plen = htons((u_short)icmp6len); 60153541Sshin nd_ns->nd_ns_cksum = 0; 602120941Sume nd_ns->nd_ns_cksum = 603120941Sume in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len); 60453541Sshin 605211501Sanchie if (send_sendso_input_hook != NULL) { 606211501Sanchie mtag = m_tag_get(PACKET_TAG_ND_OUTGOING, 607211501Sanchie sizeof(unsigned short), M_NOWAIT); 608211501Sanchie if (mtag == NULL) 609211501Sanchie goto bad; 610211501Sanchie *(unsigned short *)(mtag + 1) = nd_ns->nd_ns_type; 611211501Sanchie m_tag_prepend(m, mtag); 612211501Sanchie } 613211501Sanchie 614279531Shrs ip6_output(m, NULL, &ro, (nonce != NULL) ? IPV6_UNSPECSRC : 0, 615279531Shrs &im6o, NULL, NULL); 616148385Sume icmp6_ifstat_inc(ifp, ifs6_out_msg); 617148385Sume icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); 618190964Srwatson ICMP6STAT_INC(icp6s_outhist[ND_NEIGHBOR_SOLICIT]); 619148385Sume 620238092Sglebius /* We don't cache this route. */ 621238092Sglebius RO_RTFREE(&ro); 622238092Sglebius 623148385Sume return; 624148385Sume 625148385Sume bad: 626148385Sume if (ro.ro_rt) { 627148385Sume RTFREE(ro.ro_rt); 628148385Sume } 629148385Sume m_freem(m); 630148385Sume return; 63153541Sshin} 63253541Sshin 633279564Sae#ifndef BURN_BRIDGES 634279564Saevoid 635279564Saend6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, 636279564Sae const struct in6_addr *taddr6, struct llentry *ln, uint8_t *nonce) 637279564Sae{ 638279564Sae 639279564Sae nd6_ns_output_fib(ifp, daddr6, taddr6, ln, nonce, RT_DEFAULT_FIB); 640279564Sae} 641279564Sae#endif 64253541Sshin/* 64353541Sshin * Neighbor advertisement input handling. 64453541Sshin * 64553541Sshin * Based on RFC 2461 646148987Sume * Based on RFC 2462 (duplicate address detection) 64762587Sitojun * 64862587Sitojun * the following items are not implemented yet: 64962587Sitojun * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) 65062587Sitojun * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) 65153541Sshin */ 65253541Sshinvoid 653171259Sdelphijnd6_na_input(struct mbuf *m, int off, int icmp6len) 65453541Sshin{ 65553541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 65653541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 65762587Sitojun struct nd_neighbor_advert *nd_na; 65853541Sshin struct in6_addr daddr6 = ip6->ip6_dst; 65962587Sitojun struct in6_addr taddr6; 66062587Sitojun int flags; 66162587Sitojun int is_router; 66262587Sitojun int is_solicited; 66362587Sitojun int is_override; 66453541Sshin char *lladdr = NULL; 66553541Sshin int lladdrlen = 0; 666186468Skmacy int checklink = 0; 66753541Sshin struct ifaddr *ifa; 668186119Sqingli struct llentry *ln = NULL; 66953541Sshin union nd_opts ndopts; 670186119Sqingli struct mbuf *chain = NULL; 671186119Sqingli struct sockaddr_in6 sin6; 672165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 67353541Sshin 67453541Sshin if (ip6->ip6_hlim != 255) { 67578064Sume nd6log((LOG_ERR, 67678064Sume "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n", 677165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 678165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 67978064Sume goto bad; 68062587Sitojun } 68162587Sitojun 68262587Sitojun#ifndef PULLDOWN_TEST 68362587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 68462587Sitojun nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off); 68562587Sitojun#else 68662587Sitojun IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len); 68762587Sitojun if (nd_na == NULL) { 688190964Srwatson ICMP6STAT_INC(icp6s_tooshort); 68953541Sshin return; 69053541Sshin } 69162587Sitojun#endif 692148385Sume 69362587Sitojun flags = nd_na->nd_na_flags_reserved; 69462587Sitojun is_router = ((flags & ND_NA_FLAG_ROUTER) != 0); 69562587Sitojun is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0); 69662587Sitojun is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0); 697276844Smelifaro memset(&sin6, 0, sizeof(sin6)); 69853541Sshin 699148385Sume taddr6 = nd_na->nd_na_target; 700148385Sume if (in6_setscope(&taddr6, ifp, NULL)) 701150202Ssuz goto bad; /* XXX: impossible */ 70253541Sshin 70353541Sshin if (IN6_IS_ADDR_MULTICAST(&taddr6)) { 70478064Sume nd6log((LOG_ERR, 70553541Sshin "nd6_na_input: invalid target address %s\n", 706165118Sbz ip6_sprintf(ip6bufs, &taddr6))); 70778064Sume goto bad; 70853541Sshin } 70953541Sshin if (IN6_IS_ADDR_MULTICAST(&daddr6)) 71053541Sshin if (is_solicited) { 71178064Sume nd6log((LOG_ERR, 71278064Sume "nd6_na_input: a solicited adv is multicasted\n")); 71378064Sume goto bad; 71453541Sshin } 71553541Sshin 71653541Sshin icmp6len -= sizeof(*nd_na); 71753541Sshin nd6_option_init(nd_na + 1, icmp6len, &ndopts); 71853541Sshin if (nd6_options(&ndopts) < 0) { 71978064Sume nd6log((LOG_INFO, 72078064Sume "nd6_na_input: invalid ND option, ignored\n")); 72178064Sume /* nd6_options have incremented stats */ 72262587Sitojun goto freeit; 72353541Sshin } 72453541Sshin 72553541Sshin if (ndopts.nd_opts_tgt_lladdr) { 72653541Sshin lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); 72753541Sshin lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3; 72853541Sshin } 72953541Sshin 730228571Sglebius /* 731228571Sglebius * This effectively disables the DAD check on a non-master CARP 732228571Sglebius * address. 733228571Sglebius */ 734228571Sglebius if (ifp->if_carp) 735228571Sglebius ifa = (*carp_iamatch6_p)(ifp, &taddr6); 736228571Sglebius else 737228571Sglebius ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); 73853541Sshin 73953541Sshin /* 74053541Sshin * Target address matches one of my interface address. 74153541Sshin * 74253541Sshin * If my address is tentative, this means that there's somebody 74353541Sshin * already using the same address as mine. This indicates DAD failure. 74453541Sshin * This is defined in RFC 2462. 74553541Sshin * 74653541Sshin * Otherwise, process as defined in RFC 2461. 74753541Sshin */ 74853541Sshin if (ifa 74953541Sshin && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) { 750194760Srwatson ifa_free(ifa); 75153541Sshin nd6_dad_na_input(ifa); 75262587Sitojun goto freeit; 75353541Sshin } 75453541Sshin 75595023Ssuz /* Just for safety, maybe unnecessary. */ 75653541Sshin if (ifa) { 757194760Srwatson ifa_free(ifa); 75853541Sshin log(LOG_ERR, 75953541Sshin "nd6_na_input: duplicate IP6 address %s\n", 760165118Sbz ip6_sprintf(ip6bufs, &taddr6)); 76162587Sitojun goto freeit; 76253541Sshin } 76353541Sshin 76453541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 765120941Sume nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s " 766165118Sbz "(if %d, NA packet %d)\n", ip6_sprintf(ip6bufs, &taddr6), 767120941Sume ifp->if_addrlen, lladdrlen - 2)); 76878064Sume goto bad; 76953541Sshin } 77053541Sshin 77153541Sshin /* 772120941Sume * If no neighbor cache entry is found, NA SHOULD silently be 773120941Sume * discarded. 77453541Sshin */ 775260187Sae IF_AFDATA_RLOCK(ifp); 776186119Sqingli ln = nd6_lookup(&taddr6, LLE_EXCLUSIVE, ifp); 777260187Sae IF_AFDATA_RUNLOCK(ifp); 778186119Sqingli if (ln == NULL) { 77962587Sitojun goto freeit; 780186119Sqingli } 78153541Sshin 78253541Sshin if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { 78353541Sshin /* 78453541Sshin * If the link-layer has address, and no lladdr option came, 78553541Sshin * discard the packet. 78653541Sshin */ 787186119Sqingli if (ifp->if_addrlen && lladdr == NULL) { 78862587Sitojun goto freeit; 789186119Sqingli } 79053541Sshin 79153541Sshin /* 79253541Sshin * Record link-layer address, and update the state. 79353541Sshin */ 794186119Sqingli bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen); 795186119Sqingli ln->la_flags |= LLE_VALID; 796245925Snp EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED); 79753541Sshin if (is_solicited) { 79853541Sshin ln->ln_state = ND6_LLINFO_REACHABLE; 79962587Sitojun ln->ln_byhint = 0; 800151539Ssuz if (!ND6_LLINFO_PERMANENT(ln)) { 801186119Sqingli nd6_llinfo_settimer_locked(ln, 802186119Sqingli (long)ND_IFINFO(ln->lle_tbl->llt_ifp)->reachable * hz); 803120941Sume } 80478064Sume } else { 80553541Sshin ln->ln_state = ND6_LLINFO_STALE; 806186119Sqingli nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz); 80778064Sume } 80878064Sume if ((ln->ln_router = is_router) != 0) { 80978064Sume /* 81078064Sume * This means a router's state has changed from 81178064Sume * non-reachable to probably reachable, and might 81278064Sume * affect the status of associated prefixes.. 81378064Sume */ 814186468Skmacy checklink = 1; 81578064Sume } 81653541Sshin } else { 81753541Sshin int llchange; 81853541Sshin 81953541Sshin /* 82053541Sshin * Check if the link-layer address has changed or not. 82153541Sshin */ 822151465Ssuz if (lladdr == NULL) 82353541Sshin llchange = 0; 82453541Sshin else { 825186119Sqingli if (ln->la_flags & LLE_VALID) { 826186119Sqingli if (bcmp(lladdr, &ln->ll_addr, ifp->if_addrlen)) 82753541Sshin llchange = 1; 82853541Sshin else 82953541Sshin llchange = 0; 83053541Sshin } else 83153541Sshin llchange = 1; 83253541Sshin } 83353541Sshin 83453541Sshin /* 83553541Sshin * This is VERY complex. Look at it with care. 83653541Sshin * 83753541Sshin * override solicit lladdr llchange action 83853541Sshin * (L: record lladdr) 83953541Sshin * 84053541Sshin * 0 0 n -- (2c) 84153541Sshin * 0 0 y n (2b) L 84253541Sshin * 0 0 y y (1) REACHABLE->STALE 84353541Sshin * 0 1 n -- (2c) *->REACHABLE 84453541Sshin * 0 1 y n (2b) L *->REACHABLE 84553541Sshin * 0 1 y y (1) REACHABLE->STALE 84653541Sshin * 1 0 n -- (2a) 84753541Sshin * 1 0 y n (2a) L 84853541Sshin * 1 0 y y (2a) L *->STALE 84953541Sshin * 1 1 n -- (2a) *->REACHABLE 85053541Sshin * 1 1 y n (2a) L *->REACHABLE 85153541Sshin * 1 1 y y (2a) L *->REACHABLE 85253541Sshin */ 853151539Ssuz if (!is_override && (lladdr != NULL && llchange)) { /* (1) */ 85453541Sshin /* 85553541Sshin * If state is REACHABLE, make it STALE. 85653541Sshin * no other updates should be done. 85753541Sshin */ 85878064Sume if (ln->ln_state == ND6_LLINFO_REACHABLE) { 85953541Sshin ln->ln_state = ND6_LLINFO_STALE; 860186119Sqingli nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz); 86178064Sume } 86262587Sitojun goto freeit; 86353541Sshin } else if (is_override /* (2a) */ 864151465Ssuz || (!is_override && (lladdr != NULL && !llchange)) /* (2b) */ 865151465Ssuz || lladdr == NULL) { /* (2c) */ 86653541Sshin /* 86753541Sshin * Update link-local address, if any. 86853541Sshin */ 869151465Ssuz if (lladdr != NULL) { 870186119Sqingli bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen); 871186119Sqingli ln->la_flags |= LLE_VALID; 872245925Snp EVENTHANDLER_INVOKE(lle_event, ln, 873245925Snp LLENTRY_RESOLVED); 87453541Sshin } 87553541Sshin 87653541Sshin /* 87753541Sshin * If solicited, make the state REACHABLE. 87853541Sshin * If not solicited and the link-layer address was 87953541Sshin * changed, make it STALE. 88053541Sshin */ 88153541Sshin if (is_solicited) { 88253541Sshin ln->ln_state = ND6_LLINFO_REACHABLE; 88362587Sitojun ln->ln_byhint = 0; 884151539Ssuz if (!ND6_LLINFO_PERMANENT(ln)) { 885186119Sqingli nd6_llinfo_settimer_locked(ln, 886151539Ssuz (long)ND_IFINFO(ifp)->reachable * hz); 88753541Sshin } 88853541Sshin } else { 889151465Ssuz if (lladdr != NULL && llchange) { 89053541Sshin ln->ln_state = ND6_LLINFO_STALE; 891186119Sqingli nd6_llinfo_settimer_locked(ln, 892181803Sbz (long)V_nd6_gctimer * hz); 89378064Sume } 89453541Sshin } 89553541Sshin } 89653541Sshin 89753541Sshin if (ln->ln_router && !is_router) { 89853541Sshin /* 89953541Sshin * The peer dropped the router flag. 90053541Sshin * Remove the sender from the Default Router List and 90153541Sshin * update the Destination Cache entries. 90253541Sshin */ 90353541Sshin struct nd_defrouter *dr; 90453541Sshin struct in6_addr *in6; 90553541Sshin 906186119Sqingli in6 = &L3_ADDR_SIN6(ln)->sin6_addr; 90795023Ssuz 90895023Ssuz /* 90995023Ssuz * Lock to protect the default router list. 91095023Ssuz * XXX: this might be unnecessary, since this function 91195023Ssuz * is only called under the network software interrupt 912120941Sume * context. However, we keep it just for safety. 91395023Ssuz */ 914186119Sqingli dr = defrouter_lookup(in6, ln->lle_tbl->llt_ifp); 91553541Sshin if (dr) 91653541Sshin defrtrlist_del(dr); 917222728Shrs else if (ND_IFINFO(ln->lle_tbl->llt_ifp)->flags & 918222728Shrs ND6_IFF_ACCEPT_RTADV) { 91953541Sshin /* 92053541Sshin * Even if the neighbor is not in the default 92153541Sshin * router list, the neighbor may be used 92253541Sshin * as a next hop for some destinations 92353541Sshin * (e.g. redirect case). So we must 92453541Sshin * call rt6_flush explicitly. 92553541Sshin */ 926128422Sluigi rt6_flush(&ip6->ip6_src, ifp); 92753541Sshin } 92853541Sshin } 92953541Sshin ln->ln_router = is_router; 93053541Sshin } 931186119Sqingli /* XXX - QL 932186119Sqingli * Does this matter? 933186119Sqingli * rt->rt_flags &= ~RTF_REJECT; 934186119Sqingli */ 935186119Sqingli ln->la_asked = 0; 936276844Smelifaro if (ln->la_hold != NULL) 937276844Smelifaro nd6_grab_holdchain(ln, &chain, &sin6); 938186119Sqingli freeit: 939276844Smelifaro if (ln != NULL) 940186119Sqingli LLE_WUNLOCK(ln); 94162587Sitojun 942276844Smelifaro if (chain != NULL) 943276844Smelifaro nd6_flush_holdchain(ifp, ifp, chain, &sin6); 944276844Smelifaro 945186468Skmacy if (checklink) 946186468Skmacy pfxlist_onlink_check(); 947186468Skmacy 94862587Sitojun m_freem(m); 94978064Sume return; 95078064Sume 95178064Sume bad: 952186160Skmacy if (ln != NULL) 953186119Sqingli LLE_WUNLOCK(ln); 954186119Sqingli 955190964Srwatson ICMP6STAT_INC(icp6s_badna); 95678064Sume m_freem(m); 95753541Sshin} 95853541Sshin 95953541Sshin/* 96053541Sshin * Neighbor advertisement output handling. 96153541Sshin * 96253541Sshin * Based on RFC 2461 96353541Sshin * 96462587Sitojun * the following items are not implemented yet: 96562587Sitojun * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) 96662587Sitojun * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) 967171259Sdelphij * 968171259Sdelphij * tlladdr - 1 if include target link-layer address 969171259Sdelphij * sdl0 - sockaddr_dl (= proxy NA) or NULL 97053541Sshin */ 971231852Sbzstatic void 972231852Sbznd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0, 973171259Sdelphij const struct in6_addr *taddr6, u_long flags, int tlladdr, 974231852Sbz struct sockaddr *sdl0, u_int fibnum) 97553541Sshin{ 97653541Sshin struct mbuf *m; 977211501Sanchie struct m_tag *mtag; 978231852Sbz struct ifnet *oifp; 97953541Sshin struct ip6_hdr *ip6; 98053541Sshin struct nd_neighbor_advert *nd_na; 98153541Sshin struct ip6_moptions im6o; 982194777Sbz struct in6_addr src, daddr6; 983148385Sume struct sockaddr_in6 dst_sa; 984148385Sume int icmp6len, maxlen, error; 98592733Speter caddr_t mac = NULL; 986148385Sume struct route_in6 ro; 98762587Sitojun 988148385Sume bzero(&ro, sizeof(ro)); 989148385Sume 990148385Sume daddr6 = *daddr6_0; /* make a local copy for modification */ 991148385Sume 99262587Sitojun /* estimate the size of message */ 99362587Sitojun maxlen = sizeof(*ip6) + sizeof(*nd_na); 99462587Sitojun maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; 99562587Sitojun if (max_linkhdr + maxlen >= MCLBYTES) { 99662587Sitojun#ifdef DIAGNOSTIC 99762587Sitojun printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES " 99862587Sitojun "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES); 99962587Sitojun#endif 100053541Sshin return; 100162587Sitojun } 100253541Sshin 1003248328Sglebius if (max_linkhdr + maxlen > MHLEN) 1004248328Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1005248328Sglebius else 1006248328Sglebius m = m_gethdr(M_NOWAIT, MT_DATA); 100762587Sitojun if (m == NULL) 100862587Sitojun return; 1009231852Sbz M_SETFIB(m, fibnum); 101062587Sitojun 1011148385Sume if (IN6_IS_ADDR_MULTICAST(&daddr6)) { 101253541Sshin m->m_flags |= M_MCAST; 101353541Sshin im6o.im6o_multicast_ifp = ifp; 101453541Sshin im6o.im6o_multicast_hlim = 255; 101553541Sshin im6o.im6o_multicast_loop = 0; 101653541Sshin } 101753541Sshin 101853541Sshin icmp6len = sizeof(*nd_na); 101953541Sshin m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len; 1020276692Srwatson m->m_data += max_linkhdr; /* or M_ALIGN() equivalent? */ 102153541Sshin 102253541Sshin /* fill neighbor advertisement packet */ 102353541Sshin ip6 = mtod(m, struct ip6_hdr *); 102453541Sshin ip6->ip6_flow = 0; 102562587Sitojun ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 102662587Sitojun ip6->ip6_vfc |= IPV6_VERSION; 102753541Sshin ip6->ip6_nxt = IPPROTO_ICMPV6; 102853541Sshin ip6->ip6_hlim = 255; 1029148385Sume if (IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { 103053541Sshin /* reply to DAD */ 1031153227Sume daddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL; 1032153227Sume daddr6.s6_addr16[1] = 0; 1033153227Sume daddr6.s6_addr32[1] = 0; 1034153227Sume daddr6.s6_addr32[2] = 0; 1035153227Sume daddr6.s6_addr32[3] = IPV6_ADDR_INT32_ONE; 1036148385Sume if (in6_setscope(&daddr6, ifp, NULL)) 1037148385Sume goto bad; 1038148385Sume 103953541Sshin flags &= ~ND_NA_FLAG_SOLICITED; 1040148385Sume } 1041148385Sume ip6->ip6_dst = daddr6; 1042148385Sume bzero(&dst_sa, sizeof(struct sockaddr_in6)); 1043148385Sume dst_sa.sin6_family = AF_INET6; 1044148385Sume dst_sa.sin6_len = sizeof(struct sockaddr_in6); 1045148385Sume dst_sa.sin6_addr = daddr6; 104653541Sshin 104753541Sshin /* 104853541Sshin * Select a source whose scope is the same as that of the dest. 104953541Sshin */ 1050148385Sume bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa)); 1051231852Sbz oifp = ifp; 1052231852Sbz error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, &oifp, &src); 1053194777Sbz if (error) { 1054165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 1055148385Sume nd6log((LOG_DEBUG, "nd6_na_output: source can't be " 1056148385Sume "determined: dst=%s, error=%d\n", 1057165118Sbz ip6_sprintf(ip6buf, &dst_sa.sin6_addr), error)); 1058148385Sume goto bad; 105953541Sshin } 1060194777Sbz ip6->ip6_src = src; 106153541Sshin nd_na = (struct nd_neighbor_advert *)(ip6 + 1); 106253541Sshin nd_na->nd_na_type = ND_NEIGHBOR_ADVERT; 106353541Sshin nd_na->nd_na_code = 0; 106453541Sshin nd_na->nd_na_target = *taddr6; 1065121315Sume in6_clearscope(&nd_na->nd_na_target); /* XXX */ 106653541Sshin 106753541Sshin /* 106853541Sshin * "tlladdr" indicates NS's condition for adding tlladdr or not. 106953541Sshin * see nd6_ns_input() for details. 107053541Sshin * Basically, if NS packet is sent to unicast/anycast addr, 107153541Sshin * target lladdr option SHOULD NOT be included. 107253541Sshin */ 107362587Sitojun if (tlladdr) { 107462587Sitojun /* 107562587Sitojun * sdl0 != NULL indicates proxy NA. If we do proxy, use 107662587Sitojun * lladdr in sdl0. If we are not proxying (sending NA for 107762587Sitojun * my address) use lladdr configured for the interface. 107862587Sitojun */ 1079142215Sglebius if (sdl0 == NULL) { 1080142215Sglebius if (ifp->if_carp) 1081211157Swill mac = (*carp_macmatch6_p)(ifp, m, taddr6); 1082142215Sglebius if (mac == NULL) 1083142215Sglebius mac = nd6_ifptomac(ifp); 1084142215Sglebius } else if (sdl0->sa_family == AF_LINK) { 108562587Sitojun struct sockaddr_dl *sdl; 108662587Sitojun sdl = (struct sockaddr_dl *)sdl0; 108762587Sitojun if (sdl->sdl_alen == ifp->if_addrlen) 108862587Sitojun mac = LLADDR(sdl); 108962587Sitojun } 109062587Sitojun } 109162587Sitojun if (tlladdr && mac) { 109253541Sshin int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; 109353541Sshin struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1); 1094120941Sume 109553541Sshin /* roundup to 8 bytes alignment! */ 109653541Sshin optlen = (optlen + 7) & ~7; 109753541Sshin 109853541Sshin m->m_pkthdr.len += optlen; 109953541Sshin m->m_len += optlen; 110053541Sshin icmp6len += optlen; 110153541Sshin bzero((caddr_t)nd_opt, optlen); 110253541Sshin nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; 110353541Sshin nd_opt->nd_opt_len = optlen >> 3; 110453541Sshin bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen); 110553541Sshin } else 110653541Sshin flags &= ~ND_NA_FLAG_OVERRIDE; 110753541Sshin 110853541Sshin ip6->ip6_plen = htons((u_short)icmp6len); 110953541Sshin nd_na->nd_na_flags_reserved = flags; 111053541Sshin nd_na->nd_na_cksum = 0; 111153541Sshin nd_na->nd_na_cksum = 1112120941Sume in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len); 111353541Sshin 1114211501Sanchie if (send_sendso_input_hook != NULL) { 1115211501Sanchie mtag = m_tag_get(PACKET_TAG_ND_OUTGOING, 1116211501Sanchie sizeof(unsigned short), M_NOWAIT); 1117211501Sanchie if (mtag == NULL) 1118211501Sanchie goto bad; 1119211501Sanchie *(unsigned short *)(mtag + 1) = nd_na->nd_na_type; 1120211501Sanchie m_tag_prepend(m, mtag); 1121211501Sanchie } 1122211501Sanchie 1123148385Sume ip6_output(m, NULL, &ro, 0, &im6o, NULL, NULL); 1124148385Sume icmp6_ifstat_inc(ifp, ifs6_out_msg); 1125148385Sume icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); 1126190964Srwatson ICMP6STAT_INC(icp6s_outhist[ND_NEIGHBOR_ADVERT]); 1127148385Sume 1128238092Sglebius /* We don't cache this route. */ 1129238092Sglebius RO_RTFREE(&ro); 1130238092Sglebius 1131148385Sume return; 1132148385Sume 1133148385Sume bad: 1134148385Sume if (ro.ro_rt) { 1135148385Sume RTFREE(ro.ro_rt); 1136148385Sume } 1137148385Sume m_freem(m); 1138148385Sume return; 113953541Sshin} 114053541Sshin 1141231852Sbz#ifndef BURN_BRIDGES 1142231852Sbzvoid 1143231852Sbznd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0, 1144231852Sbz const struct in6_addr *taddr6, u_long flags, int tlladdr, 1145231852Sbz struct sockaddr *sdl0) 1146231852Sbz{ 1147231852Sbz 1148231852Sbz nd6_na_output_fib(ifp, daddr6_0, taddr6, flags, tlladdr, sdl0, 1149231852Sbz RT_DEFAULT_FIB); 1150231852Sbz} 1151231852Sbz#endif 1152231852Sbz 115353541Sshincaddr_t 1154171259Sdelphijnd6_ifptomac(struct ifnet *ifp) 115553541Sshin{ 115653541Sshin switch (ifp->if_type) { 115753541Sshin case IFT_ARCNET: 115853541Sshin case IFT_ETHER: 115953541Sshin case IFT_FDDI: 116078064Sume case IFT_IEEE1394: 116178468Ssumikawa#ifdef IFT_L2VLAN 116278468Ssumikawa case IFT_L2VLAN: 116378468Ssumikawa#endif 116478064Sume#ifdef IFT_IEEE80211 116578064Sume case IFT_IEEE80211: 116678064Sume#endif 1167219819Sjeff case IFT_INFINIBAND: 1168149829Sthompsa case IFT_BRIDGE: 1169120049Smdodd case IFT_ISO88025: 1170147306Sbrooks return IF_LLADDR(ifp); 117153541Sshin default: 117253541Sshin return NULL; 117353541Sshin } 117453541Sshin} 117553541Sshin 117653541Sshinstruct dadq { 117760938Sjake TAILQ_ENTRY(dadq) dad_list; 117853541Sshin struct ifaddr *dad_ifa; 117953541Sshin int dad_count; /* max NS to send */ 118062587Sitojun int dad_ns_tcount; /* # of trials to send NS */ 118153541Sshin int dad_ns_ocount; /* NS sent so far */ 118253541Sshin int dad_ns_icount; 118353541Sshin int dad_na_icount; 1184279531Shrs int dad_ns_lcount; /* looped back NS */ 118578064Sume struct callout dad_timer_ch; 1186191816Szec struct vnet *dad_vnet; 1187275593Smarkj u_int dad_refcnt; 1188279531Shrs#define ND_OPT_NONCE_LEN32 \ 1189279531Shrs ((ND_OPT_NONCE_LEN + sizeof(uint32_t) - 1)/sizeof(uint32_t)) 1190279531Shrs uint32_t dad_nonce[ND_OPT_NONCE_LEN32]; 119153541Sshin}; 119253541Sshin 1193215701Sdimstatic VNET_DEFINE(TAILQ_HEAD(, dadq), dadq); 1194266857Shrsstatic VNET_DEFINE(struct rwlock, dad_rwlock); 1195266857Shrs#define V_dadq VNET(dadq) 1196266857Shrs#define V_dad_rwlock VNET(dad_rwlock) 1197195699Srwatson 1198266857Shrs#define DADQ_RLOCK() rw_rlock(&V_dad_rwlock) 1199266857Shrs#define DADQ_RUNLOCK() rw_runlock(&V_dad_rwlock) 1200266857Shrs#define DADQ_WLOCK() rw_wlock(&V_dad_rwlock) 1201266857Shrs#define DADQ_WUNLOCK() rw_wunlock(&V_dad_rwlock) 1202266857Shrs 1203274347Smelifarostatic void 1204274347Smelifarond6_dad_add(struct dadq *dp) 1205274347Smelifaro{ 1206274347Smelifaro 1207274347Smelifaro DADQ_WLOCK(); 1208275593Smarkj TAILQ_INSERT_TAIL(&V_dadq, dp, dad_list); 1209274347Smelifaro DADQ_WUNLOCK(); 1210274347Smelifaro} 1211274347Smelifaro 1212274347Smelifarostatic void 1213274347Smelifarond6_dad_del(struct dadq *dp) 1214274347Smelifaro{ 1215274347Smelifaro 1216274347Smelifaro DADQ_WLOCK(); 1217275593Smarkj TAILQ_REMOVE(&V_dadq, dp, dad_list); 1218274347Smelifaro DADQ_WUNLOCK(); 1219275593Smarkj nd6_dad_rele(dp); 1220274347Smelifaro} 1221274347Smelifaro 122253541Sshinstatic struct dadq * 1223279531Shrsnd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *n) 122453541Sshin{ 122553541Sshin struct dadq *dp; 1226279531Shrs char ip6buf[INET6_ADDRSTRLEN]; 122753541Sshin 1228266857Shrs DADQ_RLOCK(); 1229279531Shrs TAILQ_FOREACH(dp, &V_dadq, dad_list) { 1230279531Shrs if (dp->dad_ifa != ifa) 1231279531Shrs continue; 1232279531Shrs /* 1233279531Shrs * Skip if the nonce matches the received one. 1234279531Shrs * +2 in the length is required because of type and 1235279531Shrs * length fields are included in a header. 1236279531Shrs */ 1237279531Shrs if (n != NULL && 1238279531Shrs n->nd_opt_nonce_len == (ND_OPT_NONCE_LEN + 2) / 8 && 1239279531Shrs memcmp(&n->nd_opt_nonce[0], &dp->dad_nonce[0], 1240279531Shrs ND_OPT_NONCE_LEN) == 0) { 1241279531Shrs log(LOG_ERR, "%s: a looped back NS message is " 1242279531Shrs "detected during DAD for %s.\n", 1243279531Shrs if_name(ifa->ifa_ifp), 1244279531Shrs ip6_sprintf(ip6buf, IFA_IN6(ifa))); 1245279531Shrs dp->dad_ns_lcount++; 1246279531Shrs continue; 1247275593Smarkj } 1248279531Shrs refcount_acquire(&dp->dad_refcnt); 1249279531Shrs break; 1250279531Shrs } 1251266857Shrs DADQ_RUNLOCK(); 1252226340Sglebius 1253275700Smarkj return (dp); 125453541Sshin} 125553541Sshin 125678064Sumestatic void 1257171259Sdelphijnd6_dad_starttimer(struct dadq *dp, int ticks) 125878064Sume{ 125978064Sume 126078064Sume callout_reset(&dp->dad_timer_ch, ticks, 1261191816Szec (void (*)(void *))nd6_dad_timer, (void *)dp); 126278064Sume} 126378064Sume 126478064Sumestatic void 1265171259Sdelphijnd6_dad_stoptimer(struct dadq *dp) 126678064Sume{ 126778064Sume 1268275593Smarkj callout_drain(&dp->dad_timer_ch); 126978064Sume} 127078064Sume 1271275593Smarkjstatic void 1272275593Smarkjnd6_dad_rele(struct dadq *dp) 1273275593Smarkj{ 1274275593Smarkj 1275275593Smarkj if (refcount_release(&dp->dad_refcnt)) { 1276275593Smarkj ifa_free(dp->dad_ifa); 1277275593Smarkj free(dp, M_IP6NDP); 1278275593Smarkj } 1279275593Smarkj} 1280275593Smarkj 1281275593Smarkjvoid 1282275593Smarkjnd6_dad_init(void) 1283275593Smarkj{ 1284275593Smarkj 1285275593Smarkj rw_init(&V_dad_rwlock, "nd6 DAD queue"); 1286275593Smarkj TAILQ_INIT(&V_dadq); 1287275593Smarkj} 1288275593Smarkj 128953541Sshin/* 1290148987Sume * Start Duplicate Address Detection (DAD) for specified interface address. 129153541Sshin */ 129253541Sshinvoid 1293171259Sdelphijnd6_dad_start(struct ifaddr *ifa, int delay) 129453541Sshin{ 129553541Sshin struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; 129653541Sshin struct dadq *dp; 1297165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 129853541Sshin 129953541Sshin /* 130053541Sshin * If we don't need DAD, don't do it. 130153541Sshin * There are several cases: 130253541Sshin * - DAD is disabled (ip6_dad_count == 0) 130353541Sshin * - the interface address is anycast 130453541Sshin */ 130553541Sshin if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) { 130662587Sitojun log(LOG_DEBUG, 130762587Sitojun "nd6_dad_start: called with non-tentative address " 130853541Sshin "%s(%s)\n", 1309165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 131053541Sshin ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); 131153541Sshin return; 131253541Sshin } 131353541Sshin if (ia->ia6_flags & IN6_IFF_ANYCAST) { 131453541Sshin ia->ia6_flags &= ~IN6_IFF_TENTATIVE; 131553541Sshin return; 131653541Sshin } 1317181803Sbz if (!V_ip6_dad_count) { 131853541Sshin ia->ia6_flags &= ~IN6_IFF_TENTATIVE; 131953541Sshin return; 132053541Sshin } 1321151465Ssuz if (ifa->ifa_ifp == NULL) 132253541Sshin panic("nd6_dad_start: ifa->ifa_ifp == NULL"); 1323120941Sume if (!(ifa->ifa_ifp->if_flags & IFF_UP)) { 132453541Sshin return; 1325120941Sume } 1326197138Shrs if (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED) 1327197138Shrs return; 1328279531Shrs if ((dp = nd6_dad_find(ifa, NULL)) != NULL) { 132953541Sshin /* DAD already in progress */ 1330275593Smarkj nd6_dad_rele(dp); 133153541Sshin return; 133253541Sshin } 133353541Sshin 1334275593Smarkj dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT | M_ZERO); 133553541Sshin if (dp == NULL) { 133662587Sitojun log(LOG_ERR, "nd6_dad_start: memory allocation failed for " 133753541Sshin "%s(%s)\n", 1338165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 133953541Sshin ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); 134053541Sshin return; 134153541Sshin } 134278064Sume callout_init(&dp->dad_timer_ch, 0); 1343191816Szec#ifdef VIMAGE 1344191816Szec dp->dad_vnet = curvnet; 1345191816Szec#endif 134678064Sume nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), 1347165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 134853541Sshin 134953541Sshin /* 135053541Sshin * Send NS packet for DAD, ip6_dad_count times. 135153541Sshin * Note that we must delay the first transmission, if this is the 135253541Sshin * first packet to be sent from the interface after interface 135353541Sshin * (re)initialization. 135453541Sshin */ 135553541Sshin dp->dad_ifa = ifa; 1356275593Smarkj ifa_ref(dp->dad_ifa); 1357181803Sbz dp->dad_count = V_ip6_dad_count; 135853541Sshin dp->dad_ns_icount = dp->dad_na_icount = 0; 135962587Sitojun dp->dad_ns_ocount = dp->dad_ns_tcount = 0; 1360279531Shrs dp->dad_ns_lcount = 0; 1361275593Smarkj refcount_init(&dp->dad_refcnt, 1); 1362274347Smelifaro nd6_dad_add(dp); 1363151539Ssuz if (delay == 0) { 136462587Sitojun nd6_dad_ns_output(dp, ifa); 1365121161Sume nd6_dad_starttimer(dp, 1366151539Ssuz (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); 136753541Sshin } else { 1368151539Ssuz nd6_dad_starttimer(dp, delay); 136953541Sshin } 137053541Sshin} 137153541Sshin 137278064Sume/* 137378064Sume * terminate DAD unconditionally. used for address removals. 137478064Sume */ 137578064Sumevoid 1376171259Sdelphijnd6_dad_stop(struct ifaddr *ifa) 137778064Sume{ 137878064Sume struct dadq *dp; 137978064Sume 1380279531Shrs dp = nd6_dad_find(ifa, NULL); 138178064Sume if (!dp) { 138278064Sume /* DAD wasn't started yet */ 138378064Sume return; 138478064Sume } 138578064Sume 138678064Sume nd6_dad_stoptimer(dp); 138778064Sume 1388275593Smarkj /* 1389275593Smarkj * The DAD queue entry may have been removed by nd6_dad_timer() while 1390275593Smarkj * we were waiting for it to stop, so re-do the lookup. 1391275593Smarkj */ 1392275593Smarkj nd6_dad_rele(dp); 1393279531Shrs if (nd6_dad_find(ifa, NULL) == NULL) 1394275593Smarkj return; 1395275593Smarkj 1396274347Smelifaro nd6_dad_del(dp); 1397275593Smarkj nd6_dad_rele(dp); 139878064Sume} 139978064Sume 140053541Sshinstatic void 1401191816Szecnd6_dad_timer(struct dadq *dp) 140253541Sshin{ 1403183550Szec CURVNET_SET(dp->dad_vnet); 1404191816Szec struct ifaddr *ifa = dp->dad_ifa; 1405266248Shrs struct ifnet *ifp = dp->dad_ifa->ifa_ifp; 140653541Sshin struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; 1407165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 140853541Sshin 140953541Sshin /* Sanity check */ 141053541Sshin if (ia == NULL) { 141162587Sitojun log(LOG_ERR, "nd6_dad_timer: called with null parameter\n"); 1412275593Smarkj goto err; 141353541Sshin } 1414266248Shrs if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) { 1415266248Shrs /* Do not need DAD for ifdisabled interface. */ 1416266248Shrs log(LOG_ERR, "nd6_dad_timer: cancel DAD on %s because of " 1417266248Shrs "ND6_IFF_IFDISABLED.\n", ifp->if_xname); 1418275593Smarkj goto err; 1419266248Shrs } 142053541Sshin if (ia->ia6_flags & IN6_IFF_DUPLICATED) { 142162587Sitojun log(LOG_ERR, "nd6_dad_timer: called with duplicated address " 142253541Sshin "%s(%s)\n", 1423165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 142453541Sshin ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); 1425275593Smarkj goto err; 142653541Sshin } 142753541Sshin if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) { 142862587Sitojun log(LOG_ERR, "nd6_dad_timer: called with non-tentative address " 142953541Sshin "%s(%s)\n", 1430165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 143153541Sshin ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); 1432275593Smarkj goto err; 143353541Sshin } 143453541Sshin 143562587Sitojun /* timeouted with IFF_{RUNNING,UP} check */ 1436181803Sbz if (dp->dad_ns_tcount > V_dad_maxtry) { 143778064Sume nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n", 1438120941Sume if_name(ifa->ifa_ifp))); 1439275593Smarkj goto err; 144062587Sitojun } 144162587Sitojun 144253541Sshin /* Need more checks? */ 144353541Sshin if (dp->dad_ns_ocount < dp->dad_count) { 144453541Sshin /* 144553541Sshin * We have more NS to go. Send NS packet for DAD. 144653541Sshin */ 144762587Sitojun nd6_dad_ns_output(dp, ifa); 1448120941Sume nd6_dad_starttimer(dp, 1449151539Ssuz (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); 1450275593Smarkj goto done; 145153541Sshin } else { 145253541Sshin /* 145353541Sshin * We have transmitted sufficient number of DAD packets. 145453541Sshin * See what we've got. 145553541Sshin */ 1456275593Smarkj if (dp->dad_ns_icount > 0 || dp->dad_na_icount > 0) 1457275593Smarkj /* We've seen NS or NA, means DAD has failed. */ 1458274347Smelifaro nd6_dad_duplicated(ifa, dp); 1459275593Smarkj else { 146053541Sshin /* 146153541Sshin * We are done with DAD. No NA came, no NS came. 1462266248Shrs * No duplicate address found. Check IFDISABLED flag 1463266248Shrs * again in case that it is changed between the 1464266248Shrs * beginning of this function and here. 146553541Sshin */ 1466266248Shrs if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) == 0) 1467266248Shrs ia->ia6_flags &= ~IN6_IFF_TENTATIVE; 146853541Sshin 146978064Sume nd6log((LOG_DEBUG, 147062587Sitojun "%s: DAD complete for %s - no duplicates found\n", 147162587Sitojun if_name(ifa->ifa_ifp), 1472165118Sbz ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 147353541Sshin } 147453541Sshin } 1475275593Smarkjerr: 1476275593Smarkj nd6_dad_del(dp); 147753541Sshindone: 1478183550Szec CURVNET_RESTORE(); 147953541Sshin} 148053541Sshin 1481275593Smarkjstatic void 1482274347Smelifarond6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp) 148353541Sshin{ 148453541Sshin struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; 1485151477Ssuz struct ifnet *ifp; 1486165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 148753541Sshin 148878064Sume log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: " 1489279531Shrs "NS in/out/loopback=%d/%d/%d, NA in=%d\n", 1490165118Sbz if_name(ifa->ifa_ifp), ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 1491279531Shrs dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_ns_lcount, 1492279531Shrs dp->dad_na_icount); 149353541Sshin 149453541Sshin ia->ia6_flags &= ~IN6_IFF_TENTATIVE; 149553541Sshin ia->ia6_flags |= IN6_IFF_DUPLICATED; 149653541Sshin 1497151477Ssuz ifp = ifa->ifa_ifp; 149862587Sitojun log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n", 1499165118Sbz if_name(ifp), ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)); 150062587Sitojun log(LOG_ERR, "%s: manual intervention required\n", 1501151477Ssuz if_name(ifp)); 150253541Sshin 1503151477Ssuz /* 1504151477Ssuz * If the address is a link-local address formed from an interface 1505151477Ssuz * identifier based on the hardware address which is supposed to be 1506151477Ssuz * uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP 1507151477Ssuz * operation on the interface SHOULD be disabled. 1508197138Shrs * [RFC 4862, Section 5.4.5] 1509151477Ssuz */ 1510151477Ssuz if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) { 1511151477Ssuz struct in6_addr in6; 1512151477Ssuz 1513151477Ssuz /* 1514151477Ssuz * To avoid over-reaction, we only apply this logic when we are 1515151477Ssuz * very sure that hardware addresses are supposed to be unique. 1516151477Ssuz */ 1517151477Ssuz switch (ifp->if_type) { 1518151477Ssuz case IFT_ETHER: 1519151477Ssuz case IFT_FDDI: 1520151477Ssuz case IFT_ATM: 1521151477Ssuz case IFT_IEEE1394: 1522151477Ssuz#ifdef IFT_IEEE80211 1523151477Ssuz case IFT_IEEE80211: 1524151477Ssuz#endif 1525219819Sjeff case IFT_INFINIBAND: 1526151477Ssuz in6 = ia->ia_addr.sin6_addr; 1527151477Ssuz if (in6_get_hw_ifid(ifp, &in6) == 0 && 1528151477Ssuz IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) { 1529151477Ssuz ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; 1530151477Ssuz log(LOG_ERR, "%s: possible hardware address " 1531151477Ssuz "duplication detected, disable IPv6\n", 1532151477Ssuz if_name(ifp)); 1533151477Ssuz } 1534151477Ssuz break; 1535151477Ssuz } 1536151477Ssuz } 153753541Sshin} 153853541Sshin 153962587Sitojunstatic void 1540171259Sdelphijnd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa) 154162587Sitojun{ 154262587Sitojun struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; 154362587Sitojun struct ifnet *ifp = ifa->ifa_ifp; 1544279531Shrs int i; 154562587Sitojun 154662587Sitojun dp->dad_ns_tcount++; 154762587Sitojun if ((ifp->if_flags & IFF_UP) == 0) { 154862587Sitojun return; 154962587Sitojun } 1550148887Srwatson if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 155162587Sitojun return; 155262587Sitojun } 155362587Sitojun 155462587Sitojun dp->dad_ns_ocount++; 1555279531Shrs if (V_dad_enhanced != 0) { 1556279531Shrs for (i = 0; i < ND_OPT_NONCE_LEN32; i++) 1557279531Shrs dp->dad_nonce[i] = arc4random(); 1558279531Shrs /* 1559279531Shrs * XXXHRS: Note that in the case that 1560279531Shrs * DupAddrDetectTransmits > 1, multiple NS messages with 1561279531Shrs * different nonces can be looped back in an unexpected 1562279531Shrs * order. The current implementation recognizes only 1563279531Shrs * the latest nonce on the sender side. Practically it 1564279531Shrs * should work well in almost all cases. 1565279531Shrs */ 1566279559Shrs } 1567279559Shrs nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1568279559Shrs (uint8_t *)&dp->dad_nonce[0]); 156962587Sitojun} 157062587Sitojun 157162587Sitojunstatic void 1572279531Shrsnd6_dad_ns_input(struct ifaddr *ifa, struct nd_opt_nonce *ndopt_nonce) 157353541Sshin{ 157453541Sshin struct in6_ifaddr *ia; 157553541Sshin struct ifnet *ifp; 157678064Sume const struct in6_addr *taddr6; 157753541Sshin struct dadq *dp; 157853541Sshin 1579151465Ssuz if (ifa == NULL) 158053541Sshin panic("ifa == NULL in nd6_dad_ns_input"); 158153541Sshin 158253541Sshin ia = (struct in6_ifaddr *)ifa; 158353541Sshin ifp = ifa->ifa_ifp; 158453541Sshin taddr6 = &ia->ia_addr.sin6_addr; 1585279531Shrs /* Ignore Nonce option when Enhanced DAD is disabled. */ 1586279531Shrs if (V_dad_enhanced == 0) 1587279531Shrs ndopt_nonce = NULL; 1588279531Shrs dp = nd6_dad_find(ifa, ndopt_nonce); 1589275593Smarkj if (dp == NULL) 1590275593Smarkj return; 159153541Sshin 1592275593Smarkj dp->dad_ns_icount++; 1593275593Smarkj nd6_dad_rele(dp); 159453541Sshin} 159553541Sshin 159662587Sitojunstatic void 1597171259Sdelphijnd6_dad_na_input(struct ifaddr *ifa) 159853541Sshin{ 159953541Sshin struct dadq *dp; 160053541Sshin 1601151465Ssuz if (ifa == NULL) 160253541Sshin panic("ifa == NULL in nd6_dad_na_input"); 160353541Sshin 1604279531Shrs dp = nd6_dad_find(ifa, NULL); 1605275593Smarkj if (dp != NULL) { 160653541Sshin dp->dad_na_icount++; 1607275593Smarkj nd6_dad_rele(dp); 1608275593Smarkj } 160953541Sshin} 1610