nd6_nbr.c revision 211157
1139826Simp/*- 2191672Sbms * 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 12191672Sbms * documentation and/or other materials provided with the distribution. 13191672Sbms * 3. Neither the name of the project nor the names of its contributors 14191672Sbms * may be used to endorse or promote products derived from this software 1553541Sshin * without specific prior written permission. 16191672Sbms * 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 19191672Sbms * 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 27174510Sobrien * SUCH DAMAGE. 28174510Sobrien * 2953541Sshin * $KAME: nd6_nbr.c,v 1.86 2002/01/21 02:33:04 jinmei Exp $ 3053541Sshin */ 31139826Simp 3253541Sshin#include <sys/cdefs.h> 3353541Sshin__FBSDID("$FreeBSD: head/sys/netinet6/nd6_nbr.c 211157 2010-08-11 00:51:50Z will $"); 3453541Sshin 3553541Sshin#include "opt_inet.h" 3653541Sshin#include "opt_inet6.h" 3753541Sshin#include "opt_ipsec.h" 3853541Sshin#include "opt_mpath.h" 3953541Sshin 4053541Sshin#include <sys/param.h> 4153541Sshin#include <sys/systm.h> 4253541Sshin#include <sys/malloc.h> 4353541Sshin#include <sys/lock.h> 4453541Sshin#include <sys/rwlock.h> 4553541Sshin#include <sys/mbuf.h> 4653541Sshin#include <sys/socket.h> 4753541Sshin#include <sys/sockio.h> 4853541Sshin#include <sys/time.h> 4953541Sshin#include <sys/kernel.h> 5053541Sshin#include <sys/errno.h> 5153541Sshin#include <sys/syslog.h> 5253541Sshin#include <sys/queue.h> 5353541Sshin#include <sys/callout.h> 5453541Sshin 5553541Sshin#include <net/if.h> 5653541Sshin#include <net/if_types.h> 5753541Sshin#include <net/if_dl.h> 5853541Sshin#include <net/if_var.h> 5953541Sshin#include <net/route.h> 6053541Sshin#ifdef RADIX_MPATH 6153541Sshin#include <net/radix_mpath.h> 6253541Sshin#endif 6353541Sshin 6453541Sshin#include <netinet/in.h> 6553541Sshin#include <netinet/in_var.h> 66174510Sobrien#include <net/if_llatbl.h> 67174510Sobrien#define L3_ADDR_SIN6(le) ((struct sockaddr_in6 *) L3_ADDR(le)) 68174510Sobrien#include <netinet6/in6_var.h> 6962587Sitojun#include <netinet6/in6_ifattach.h> 7062587Sitojun#include <netinet/ip6.h> 7155009Sshin#include <netinet6/ip6_var.h> 7253541Sshin#include <netinet6/scope6_var.h> 7353541Sshin#include <netinet6/nd6.h> 7453541Sshin#include <netinet/icmp6.h> 7553541Sshin 7653541Sshin#define SDL(s) ((struct sockaddr_dl *)s) 77191672Sbms 78151539Ssuzstruct dadq; 79151539Ssuzstatic struct dadq *nd6_dad_find(struct ifaddr *); 80126603Sumestatic void nd6_dad_starttimer(struct dadq *, int); 81191672Sbmsstatic void nd6_dad_stoptimer(struct dadq *); 82181803Sbzstatic void nd6_dad_timer(struct dadq *); 8353541Sshinstatic void nd6_dad_ns_output(struct dadq *, struct ifaddr *); 8453541Sshinstatic void nd6_dad_ns_input(struct ifaddr *); 85191672Sbmsstatic void nd6_dad_na_input(struct ifaddr *); 86191672Sbms 8753541Sshinstruct ifaddr *(*carp_iamatch6_p)(struct ifnet *, struct in6_addr *); 8853541Sshincaddr_t (*carp_macmatch6_p)(struct ifnet *, struct mbuf *, 8953541Sshin const struct in6_addr *); 90151539Ssuz 9162587SitojunVNET_DEFINE(int, dad_ignore_ns) = 0; /* ignore NS in DAD - specwise incorrect*/ 9253541SshinVNET_DEFINE(int, dad_maxtry) = 15; /* max # of *tries* to transmit DAD packet */ 93148385Sume#define V_dad_ignore_ns VNET(dad_ignore_ns) 9462587Sitojun#define V_dad_maxtry VNET(dad_maxtry) 95191672Sbms 9653541Sshin/* 9753541Sshin * Input a Neighbor Solicitation Message. 98191672Sbms * 99191672Sbms * Based on RFC 2461 100191672Sbms * Based on RFC 2462 (duplicate address detection) 101191672Sbms */ 102191672Sbmsvoid 103191672Sbmsnd6_ns_input(struct mbuf *m, int off, int icmp6len) 104191672Sbms{ 105191672Sbms struct ifnet *ifp = m->m_pkthdr.rcvif; 106191672Sbms struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 107191672Sbms struct nd_neighbor_solicit *nd_ns; 108191672Sbms struct in6_addr saddr6 = ip6->ip6_src; 109191672Sbms struct in6_addr daddr6 = ip6->ip6_dst; 110191672Sbms struct in6_addr taddr6; 111191672Sbms struct in6_addr myaddr6; 112191672Sbms char *lladdr = NULL; 113191672Sbms struct ifaddr *ifa = NULL; 114191672Sbms int lladdrlen = 0; 115191672Sbms int anycast = 0, proxy = 0, tentative = 0; 116191672Sbms int tlladdr; 117191672Sbms union nd_opts ndopts; 118191672Sbms struct sockaddr_dl *proxydl = NULL; 119191672Sbms char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 120191672Sbms 121192923Sbms#ifndef PULLDOWN_TEST 122191672Sbms IP6_EXTHDR_CHECK(m, off, icmp6len,); 123192923Sbms nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); 124191672Sbms#else 125191672Sbms IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len); 126191672Sbms if (nd_ns == NULL) { 127191672Sbms ICMP6STAT_INC(icp6s_tooshort); 128191672Sbms return; 129191672Sbms } 130191672Sbms#endif 131191672Sbms ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */ 132191672Sbms taddr6 = nd_ns->nd_ns_target; 133191672Sbms if (in6_setscope(&taddr6, ifp, NULL) != 0) 134191672Sbms goto bad; 135191672Sbms 136191672Sbms if (ip6->ip6_hlim != 255) { 137191672Sbms nd6log((LOG_ERR, 138191672Sbms "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n", 139191672Sbms ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 140191672Sbms ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 141191672Sbms goto bad; 142191672Sbms } 143191672Sbms 144191672Sbms if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { 145191672Sbms /* dst has to be a solicited node multicast address. */ 146191672Sbms if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL && 147191672Sbms /* don't check ifindex portion */ 14853541Sshin daddr6.s6_addr32[1] == 0 && 149191672Sbms daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE && 150191672Sbms daddr6.s6_addr8[12] == 0xff) { 151191672Sbms ; /* good */ 152191672Sbms } else { 153191672Sbms nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " 154191672Sbms "(wrong ip6 dst)\n")); 155191672Sbms goto bad; 156191672Sbms } 157191672Sbms } else if (!V_nd6_onlink_ns_rfc4861) { 158191672Sbms struct sockaddr_in6 src_sa6; 159191672Sbms 160191672Sbms /* 161191672Sbms * According to recent IETF discussions, it is not a good idea 162191672Sbms * to accept a NS from an address which would not be deemed 163191672Sbms * to be a neighbor otherwise. This point is expected to be 164191672Sbms * clarified in future revisions of the specification. 165191672Sbms */ 166191672Sbms bzero(&src_sa6, sizeof(src_sa6)); 167191672Sbms src_sa6.sin6_family = AF_INET6; 168191672Sbms src_sa6.sin6_len = sizeof(src_sa6); 169191672Sbms src_sa6.sin6_addr = saddr6; 170191672Sbms if (nd6_is_addr_neighbor(&src_sa6, ifp) == 0) { 171191672Sbms nd6log((LOG_INFO, "nd6_ns_input: " 172191672Sbms "NS packet from non-neighbor\n")); 173191672Sbms goto bad; 174191672Sbms } 175191672Sbms } 176191672Sbms 177191672Sbms if (IN6_IS_ADDR_MULTICAST(&taddr6)) { 178191672Sbms nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n")); 179191672Sbms goto bad; 180191672Sbms } 181191672Sbms 182191672Sbms icmp6len -= sizeof(*nd_ns); 183191672Sbms nd6_option_init(nd_ns + 1, icmp6len, &ndopts); 184191672Sbms if (nd6_options(&ndopts) < 0) { 185191672Sbms nd6log((LOG_INFO, 186191672Sbms "nd6_ns_input: invalid ND option, ignored\n")); 187191672Sbms /* nd6_options have incremented stats */ 188191672Sbms goto freeit; 189191672Sbms } 190191672Sbms 191191672Sbms if (ndopts.nd_opts_src_lladdr) { 192191672Sbms lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 19353541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 194191672Sbms } 195191672Sbms 19653541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) { 197191672Sbms nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet " 198191672Sbms "(link-layer address option)\n")); 199191672Sbms goto bad; 20053541Sshin } 201191672Sbms 20253541Sshin /* 203195699Srwatson * Attaching target link-layer address to the NA? 204195699Srwatson * (RFC 2461 7.2.4) 205195699Srwatson * 206195699Srwatson * NS IP dst is unicast/anycast MUST NOT add 207195699Srwatson * NS IP dst is solicited-node multicast MUST add 20853541Sshin * 209195727Srwatson * In implementation, we add target link-layer address by default. 210195727Srwatson * We do not add one in MUST NOT cases. 211195727Srwatson */ 212195727Srwatson if (!IN6_IS_ADDR_MULTICAST(&daddr6)) 213195727Srwatson tlladdr = 0; 214195699Srwatson else 215191672Sbms tlladdr = 1; 21653541Sshin 217191672Sbms /* 218191672Sbms * Target address (taddr6) must be either: 219191672Sbms * (1) Valid unicast/anycast address for my receiving interface, 220191672Sbms * (2) Unicast address for which I'm offering proxy service, or 221191672Sbms * (3) "tentative" address on which DAD is being performed. 222191672Sbms */ 223195699Srwatson /* (1) and (3) check. */ 224195699Srwatson if (ifp->if_carp) 225195699Srwatson ifa = (*carp_iamatch6_p)(ifp, &taddr6); 226191672Sbms if (ifa == NULL) 227191672Sbms ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); 228191672Sbms 229191672Sbms /* (2) check. */ 230191672Sbms if (ifa == NULL) { 231191672Sbms struct rtentry *rt; 232191672Sbms struct sockaddr_in6 tsin6; 233191672Sbms int need_proxy; 234192923Sbms#ifdef RADIX_MPATH 235192923Sbms struct route_in6 ro; 236192923Sbms#endif 237192923Sbms 238192923Sbms bzero(&tsin6, sizeof tsin6); 239191672Sbms tsin6.sin6_len = sizeof(struct sockaddr_in6); 240191672Sbms tsin6.sin6_family = AF_INET6; 241191672Sbms tsin6.sin6_addr = taddr6; 242191672Sbms 243191672Sbms#ifdef RADIX_MPATH 244191672Sbms bzero(&ro, sizeof(ro)); 245191672Sbms ro.ro_dst = tsin6; 246191672Sbms rtalloc_mpath((struct route *)&ro, RTF_ANNOUNCE); 247191672Sbms rt = ro.ro_rt; 248191672Sbms#else 249191672Sbms rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0); 250191672Sbms#endif 251191672Sbms need_proxy = (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 && 252191672Sbms rt->rt_gateway->sa_family == AF_LINK); 253191672Sbms if (rt) 254191672Sbms RTFREE_LOCKED(rt); 255191672Sbms if (need_proxy) { 256191672Sbms /* 257191672Sbms * proxy NDP for single entry 258191672Sbms */ 259191672Sbms ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 260191672Sbms IN6_IFF_NOTREADY|IN6_IFF_ANYCAST); 261191672Sbms if (ifa) { 262191672Sbms proxy = 1; 263191672Sbms proxydl = SDL(rt->rt_gateway); 264191672Sbms } 26553541Sshin } 266191672Sbms } 267191672Sbms if (ifa == NULL) { 268191672Sbms /* 269191672Sbms * We've got an NS packet, and we don't have that adddress 270191672Sbms * assigned for us. We MUST silently ignore it. 271191672Sbms * See RFC2461 7.2.3. 272191672Sbms */ 273191672Sbms goto freeit; 274191672Sbms } 275191672Sbms myaddr6 = *IFA_IN6(ifa); 276191672Sbms anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST; 277191672Sbms tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE; 278191672Sbms if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED) 279191672Sbms goto freeit; 280191672Sbms 281191672Sbms if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 282191672Sbms nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s " 283191672Sbms "(if %d, NS packet %d)\n", 284191672Sbms ip6_sprintf(ip6bufs, &taddr6), 285191672Sbms ifp->if_addrlen, lladdrlen - 2)); 286191672Sbms goto bad; 287191672Sbms } 288191672Sbms 289191672Sbms if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) { 290191672Sbms nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n", 291191672Sbms ip6_sprintf(ip6bufs, &saddr6))); 292191672Sbms goto freeit; 293191846Szec } 294191672Sbms 295191672Sbms /* 296191672Sbms * We have neighbor solicitation packet, with target address equals to 297191672Sbms * one of my tentative address. 298191672Sbms * 299191672Sbms * src addr how to process? 300191672Sbms * --- --- 301191672Sbms * multicast of course, invalid (rejected in ip6_input) 302191672Sbms * unicast somebody is doing address resolution -> ignore 303191672Sbms * unspec dup address detection 304191672Sbms * 305191672Sbms * The processing is defined in RFC 2462. 306191672Sbms */ 307191672Sbms if (tentative) { 308191672Sbms /* 309191672Sbms * If source address is unspecified address, it is for 31053541Sshin * duplicate address detection. 311191672Sbms * 312191672Sbms * If not, the packet is for addess resolution; 313191672Sbms * silently ignore it. 31453541Sshin */ 315191672Sbms if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 31653541Sshin nd6_dad_ns_input(ifa); 317191672Sbms 318191672Sbms goto freeit; 319191672Sbms } 320191672Sbms 321191672Sbms /* 322191672Sbms * If the source address is unspecified address, entries must not 323191672Sbms * be created or updated. 324191672Sbms * It looks that sender is performing DAD. Output NA toward 325191672Sbms * all-node multicast address, to tell the sender that I'm using 326191672Sbms * the address. 327191672Sbms * S bit ("solicited") must be zero. 328191672Sbms */ 329191672Sbms if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) { 330191672Sbms struct in6_addr in6_all; 331191672Sbms 332191672Sbms in6_all = in6addr_linklocal_allnodes; 333191672Sbms if (in6_setscope(&in6_all, ifp, NULL) != 0) 334191672Sbms goto bad; 33553541Sshin nd6_na_output(ifp, &in6_all, &taddr6, 33653541Sshin ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | 337191672Sbms (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0), 338191672Sbms tlladdr, (struct sockaddr *)proxydl); 339191672Sbms goto freeit; 340191672Sbms } 341191672Sbms 342191672Sbms nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, 343191672Sbms ND_NEIGHBOR_SOLICIT, 0); 344191672Sbms 345191672Sbms nd6_na_output(ifp, &saddr6, &taddr6, 346191672Sbms ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) | 347151539Ssuz (V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED, 348191672Sbms tlladdr, (struct sockaddr *)proxydl); 349191672Sbms freeit: 350191672Sbms if (ifa != NULL) 351191672Sbms ifa_free(ifa); 352191672Sbms m_freem(m); 353151539Ssuz return; 354191672Sbms 355191672Sbms bad: 356191672Sbms nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", 357191672Sbms ip6_sprintf(ip6bufs, &saddr6))); 358191672Sbms nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", 359191672Sbms ip6_sprintf(ip6bufs, &daddr6))); 360191672Sbms nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", 361191672Sbms ip6_sprintf(ip6bufs, &taddr6))); 362191672Sbms ICMP6STAT_INC(icp6s_badns); 363191672Sbms if (ifa != NULL) 364191672Sbms ifa_free(ifa); 365191672Sbms m_freem(m); 366191672Sbms} 367191672Sbms 368191672Sbms/* 369191672Sbms * Output a Neighbor Solicitation Message. Caller specifies: 370191672Sbms * - ICMP6 header source IP6 address 371191672Sbms * - ND6 header target IP6 address 372191672Sbms * - ND6 header source datalink address 373151539Ssuz * 374151539Ssuz * Based on RFC 2461 375191672Sbms * Based on RFC 2462 (duplicate address detection) 376191672Sbms * 377191672Sbms * ln - for source address determination 378191672Sbms * dad - duplicate address detection 379191672Sbms */ 380191672Sbmsvoid 381191672Sbmsnd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, 382191672Sbms const struct in6_addr *taddr6, struct llentry *ln, int dad) 383191672Sbms{ 384191672Sbms struct mbuf *m; 385191672Sbms struct ip6_hdr *ip6; 386191672Sbms struct nd_neighbor_solicit *nd_ns; 387191672Sbms struct in6_addr *src, src_in; 388191672Sbms struct ip6_moptions im6o; 389191672Sbms int icmp6len; 390191672Sbms int maxlen; 391191672Sbms caddr_t mac; 392191672Sbms struct route_in6 ro; 393151539Ssuz 394151539Ssuz bzero(&ro, sizeof(ro)); 395191672Sbms 396191672Sbms if (IN6_IS_ADDR_MULTICAST(taddr6)) 397191672Sbms return; 398191672Sbms 399151539Ssuz /* estimate the size of message */ 400191672Sbms maxlen = sizeof(*ip6) + sizeof(*nd_ns); 401151539Ssuz maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; 402191672Sbms if (max_linkhdr + maxlen >= MCLBYTES) { 403151539Ssuz#ifdef DIAGNOSTIC 404191672Sbms printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES " 405191672Sbms "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES); 406191672Sbms#endif 407191672Sbms return; 408191672Sbms } 409191672Sbms 410191672Sbms MGETHDR(m, M_DONTWAIT, MT_DATA); 411191672Sbms if (m && max_linkhdr + maxlen >= MHLEN) { 412191672Sbms MCLGET(m, M_DONTWAIT); 413151539Ssuz if ((m->m_flags & M_EXT) == 0) { 414151539Ssuz m_free(m); 415191672Sbms m = NULL; 416191672Sbms } 417191672Sbms } 418191672Sbms if (m == NULL) 419191672Sbms return; 420191672Sbms m->m_pkthdr.rcvif = NULL; 421191672Sbms 422191672Sbms if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) { 423191672Sbms m->m_flags |= M_MCAST; 424191672Sbms im6o.im6o_multicast_ifp = ifp; 425191672Sbms im6o.im6o_multicast_hlim = 255; 426191672Sbms im6o.im6o_multicast_loop = 0; 427191672Sbms } 428191672Sbms 429151539Ssuz icmp6len = sizeof(*nd_ns); 430151539Ssuz m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len; 431191672Sbms m->m_data += max_linkhdr; /* or MH_ALIGN() equivalent? */ 432151539Ssuz 433191672Sbms /* fill neighbor solicitation packet */ 434191672Sbms ip6 = mtod(m, struct ip6_hdr *); 435151539Ssuz ip6->ip6_flow = 0; 436191672Sbms ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 437191672Sbms ip6->ip6_vfc |= IPV6_VERSION; 438191672Sbms /* ip6->ip6_plen will be set later */ 439191672Sbms ip6->ip6_nxt = IPPROTO_ICMPV6; 440191672Sbms ip6->ip6_hlim = 255; 441151539Ssuz if (daddr6) 442151539Ssuz ip6->ip6_dst = *daddr6; 443191672Sbms else { 444151539Ssuz ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL; 445151539Ssuz ip6->ip6_dst.s6_addr16[1] = 0; 446191672Sbms ip6->ip6_dst.s6_addr32[1] = 0; 447191672Sbms ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE; 448191672Sbms ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3]; 449191672Sbms ip6->ip6_dst.s6_addr8[12] = 0xff; 450191672Sbms if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0) 451191672Sbms goto bad; 452191672Sbms } 453151539Ssuz if (!dad) { 454191672Sbms struct ifaddr *ifa; 455151539Ssuz 456191672Sbms /* 457191672Sbms * RFC2461 7.2.2: 458151539Ssuz * "If the source address of the packet prompting the 459191672Sbms * solicitation is the same as one of the addresses assigned 460191672Sbms * to the outgoing interface, that address SHOULD be placed 461191672Sbms * in the IP Source Address of the outgoing solicitation. 462191672Sbms * Otherwise, any one of the addresses assigned to the 463191672Sbms * interface should be used." 464191672Sbms * 465191672Sbms * We use the source address for the prompting packet 466191672Sbms * (saddr6), if: 467191672Sbms * - saddr6 is given from the caller (by giving "ln"), and 468191672Sbms * - saddr6 belongs to the outgoing interface. 469191672Sbms * Otherwise, we perform the source address selection as usual. 470191672Sbms */ 471191672Sbms struct ip6_hdr *hip6; /* hold ip6 */ 472191672Sbms struct in6_addr *hsrc = NULL; 473191672Sbms 474191672Sbms if ((ln != NULL) && ln->la_hold) { 475191672Sbms /* 476191672Sbms * assuming every packet in la_hold has the same IP 477191672Sbms * header 478191672Sbms */ 479191672Sbms hip6 = mtod(ln->la_hold, struct ip6_hdr *); 480191672Sbms /* XXX pullup? */ 481191672Sbms if (sizeof(*hip6) < ln->la_hold->m_len) 482191672Sbms hsrc = &hip6->ip6_src; 483191672Sbms else 484191672Sbms hsrc = NULL; 485191672Sbms } 486191672Sbms if (hsrc && (ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, 487191672Sbms hsrc)) != NULL) { 488191672Sbms src = hsrc; 489191672Sbms ifa_free(ifa); 490191672Sbms } else { 491191672Sbms int error; 492191672Sbms struct sockaddr_in6 dst_sa; 493191672Sbms 494191672Sbms bzero(&dst_sa, sizeof(dst_sa)); 495191672Sbms dst_sa.sin6_family = AF_INET6; 496191672Sbms dst_sa.sin6_len = sizeof(dst_sa); 497191672Sbms dst_sa.sin6_addr = ip6->ip6_dst; 498191672Sbms 499191672Sbms error = in6_selectsrc(&dst_sa, NULL, 500191672Sbms NULL, &ro, NULL, NULL, &src_in); 501191672Sbms if (error) { 502191672Sbms char ip6buf[INET6_ADDRSTRLEN]; 503191672Sbms nd6log((LOG_DEBUG, 504191672Sbms "nd6_ns_output: source can't be " 505191672Sbms "determined: dst=%s, error=%d\n", 506191672Sbms ip6_sprintf(ip6buf, &dst_sa.sin6_addr), 507191672Sbms error)); 508191672Sbms goto bad; 509191672Sbms } 510191672Sbms src = &src_in; 511191672Sbms } 512191672Sbms } else { 513191672Sbms /* 514191672Sbms * Source address for DAD packet must always be IPv6 515191672Sbms * unspecified address. (0::0) 516191672Sbms * We actually don't have to 0-clear the address (we did it 517191672Sbms * above), but we do so here explicitly to make the intention 518191672Sbms * clearer. 519191672Sbms */ 520191672Sbms bzero(&src_in, sizeof(src_in)); 521191672Sbms src = &src_in; 522191672Sbms } 523191672Sbms ip6->ip6_src = *src; 524191672Sbms nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1); 525191672Sbms nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; 526191672Sbms nd_ns->nd_ns_code = 0; 527191672Sbms nd_ns->nd_ns_reserved = 0; 528191672Sbms nd_ns->nd_ns_target = *taddr6; 529191672Sbms in6_clearscope(&nd_ns->nd_ns_target); /* XXX */ 530191672Sbms 531191672Sbms /* 532191672Sbms * Add source link-layer address option. 533191672Sbms * 534191672Sbms * spec implementation 535191672Sbms * --- --- 536191672Sbms * DAD packet MUST NOT do not add the option 537191672Sbms * there's no link layer address: 538191672Sbms * impossible do not add the option 539191672Sbms * there's link layer address: 540191672Sbms * Multicast NS MUST add one add the option 541191672Sbms * Unicast NS SHOULD add one add the option 542191672Sbms */ 543191672Sbms if (!dad && (mac = nd6_ifptomac(ifp))) { 544191672Sbms int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; 545191672Sbms struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1); 546191672Sbms /* 8 byte alignments... */ 547191672Sbms optlen = (optlen + 7) & ~7; 548191672Sbms 549191672Sbms m->m_pkthdr.len += optlen; 550191672Sbms m->m_len += optlen; 551191672Sbms icmp6len += optlen; 552151539Ssuz bzero((caddr_t)nd_opt, optlen); 553151539Ssuz nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; 554191672Sbms nd_opt->nd_opt_len = optlen >> 3; 555151539Ssuz bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen); 556151539Ssuz } 557191672Sbms 558191672Sbms ip6->ip6_plen = htons((u_short)icmp6len); 559191672Sbms nd_ns->nd_ns_cksum = 0; 560191672Sbms nd_ns->nd_ns_cksum = 561191672Sbms in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len); 562191672Sbms 56353541Sshin ip6_output(m, NULL, &ro, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL, NULL); 564191672Sbms icmp6_ifstat_inc(ifp, ifs6_out_msg); 56553541Sshin icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); 56653541Sshin ICMP6STAT_INC(icp6s_outhist[ND_NEIGHBOR_SOLICIT]); 567191672Sbms 568191672Sbms if (ro.ro_rt) { /* we don't cache this route. */ 569191672Sbms RTFREE(ro.ro_rt); 570191672Sbms } 571191672Sbms return; 572191672Sbms 573191672Sbms bad: 574191672Sbms if (ro.ro_rt) { 575191672Sbms RTFREE(ro.ro_rt); 576191672Sbms } 577191672Sbms m_freem(m); 578191672Sbms return; 579191672Sbms} 580191672Sbms 581191672Sbms/* 582191672Sbms * Neighbor advertisement input handling. 583191672Sbms * 584191672Sbms * Based on RFC 2461 585191672Sbms * Based on RFC 2462 (duplicate address detection) 586191672Sbms * 587191672Sbms * the following items are not implemented yet: 588191672Sbms * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) 589191672Sbms * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) 590191672Sbms */ 591191672Sbmsvoid 592191672Sbmsnd6_na_input(struct mbuf *m, int off, int icmp6len) 593191672Sbms{ 594191672Sbms struct ifnet *ifp = m->m_pkthdr.rcvif; 595191672Sbms struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 596191672Sbms struct nd_neighbor_advert *nd_na; 597191672Sbms struct in6_addr daddr6 = ip6->ip6_dst; 598191672Sbms struct in6_addr taddr6; 599191672Sbms int flags; 600191672Sbms int is_router; 601191672Sbms int is_solicited; 602191672Sbms int is_override; 603191672Sbms char *lladdr = NULL; 604191672Sbms int lladdrlen = 0; 605191672Sbms int checklink = 0; 606191672Sbms struct ifaddr *ifa; 607191672Sbms struct llentry *ln = NULL; 608191672Sbms union nd_opts ndopts; 609191672Sbms struct mbuf *chain = NULL; 610192923Sbms struct sockaddr_in6 sin6; 611192923Sbms char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 612192923Sbms 613191672Sbms if (ip6->ip6_hlim != 255) { 614191672Sbms nd6log((LOG_ERR, 615191672Sbms "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n", 616192923Sbms ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 617191672Sbms ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 618191672Sbms goto bad; 619191672Sbms } 620191672Sbms 621192923Sbms#ifndef PULLDOWN_TEST 622191672Sbms IP6_EXTHDR_CHECK(m, off, icmp6len,); 623191672Sbms nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off); 624191672Sbms#else 625191672Sbms IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len); 626191672Sbms if (nd_na == NULL) { 627192923Sbms ICMP6STAT_INC(icp6s_tooshort); 628192923Sbms return; 629192923Sbms } 630192923Sbms#endif 631192923Sbms 632192923Sbms flags = nd_na->nd_na_flags_reserved; 633192923Sbms is_router = ((flags & ND_NA_FLAG_ROUTER) != 0); 634192923Sbms is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0); 635192923Sbms is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0); 636192923Sbms 637192923Sbms taddr6 = nd_na->nd_na_target; 638192923Sbms if (in6_setscope(&taddr6, ifp, NULL)) 639192923Sbms goto bad; /* XXX: impossible */ 640192923Sbms 641192923Sbms if (IN6_IS_ADDR_MULTICAST(&taddr6)) { 642192923Sbms nd6log((LOG_ERR, 643192923Sbms "nd6_na_input: invalid target address %s\n", 644192923Sbms ip6_sprintf(ip6bufs, &taddr6))); 645192923Sbms goto bad; 646192923Sbms } 647192923Sbms if (IN6_IS_ADDR_MULTICAST(&daddr6)) 648192923Sbms if (is_solicited) { 649192923Sbms nd6log((LOG_ERR, 650192923Sbms "nd6_na_input: a solicited adv is multicasted\n")); 651192923Sbms goto bad; 652192923Sbms } 653192923Sbms 654192923Sbms icmp6len -= sizeof(*nd_na); 655192923Sbms nd6_option_init(nd_na + 1, icmp6len, &ndopts); 656192923Sbms if (nd6_options(&ndopts) < 0) { 657192923Sbms nd6log((LOG_INFO, 658192923Sbms "nd6_na_input: invalid ND option, ignored\n")); 659192923Sbms /* nd6_options have incremented stats */ 660192923Sbms goto freeit; 661192923Sbms } 662192923Sbms 663192923Sbms if (ndopts.nd_opts_tgt_lladdr) { 664192923Sbms lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1); 665192923Sbms lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3; 666192923Sbms } 667192923Sbms 668192923Sbms ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); 669192923Sbms 670192923Sbms /* 671191672Sbms * Target address matches one of my interface address. 672192547Sbms * 673191672Sbms * If my address is tentative, this means that there's somebody 674191672Sbms * already using the same address as mine. This indicates DAD failure. 67553541Sshin * This is defined in RFC 2462. 676191672Sbms * 67753541Sshin * Otherwise, process as defined in RFC 2461. 678192923Sbms */ 679192923Sbms if (ifa 680191672Sbms && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) { 681191672Sbms ifa_free(ifa); 682192923Sbms nd6_dad_na_input(ifa); 683191672Sbms goto freeit; 684191672Sbms } 685191672Sbms 686192923Sbms /* Just for safety, maybe unnecessary. */ 687191672Sbms if (ifa) { 688192923Sbms ifa_free(ifa); 689192923Sbms log(LOG_ERR, 690192923Sbms "nd6_na_input: duplicate IP6 address %s\n", 691192923Sbms ip6_sprintf(ip6bufs, &taddr6)); 692192923Sbms goto freeit; 693192923Sbms } 694192923Sbms 695192923Sbms if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 696192923Sbms nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s " 697192923Sbms "(if %d, NA packet %d)\n", ip6_sprintf(ip6bufs, &taddr6), 698192923Sbms ifp->if_addrlen, lladdrlen - 2)); 699192923Sbms goto bad; 700192923Sbms } 701192923Sbms 702191672Sbms /* 703191672Sbms * If no neighbor cache entry is found, NA SHOULD silently be 704191672Sbms * discarded. 705191672Sbms */ 706191672Sbms IF_AFDATA_LOCK(ifp); 707191672Sbms ln = nd6_lookup(&taddr6, LLE_EXCLUSIVE, ifp); 708191672Sbms IF_AFDATA_UNLOCK(ifp); 709191672Sbms if (ln == NULL) { 710191672Sbms goto freeit; 711191672Sbms } 712191672Sbms 713192923Sbms if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { 714192923Sbms /* 71553541Sshin * If the link-layer has address, and no lladdr option came, 716191672Sbms * discard the packet. 717192547Sbms */ 718191672Sbms if (ifp->if_addrlen && lladdr == NULL) { 719191672Sbms goto freeit; 720191672Sbms } 721191672Sbms 72253541Sshin /* 72353541Sshin * Record link-layer address, and update the state. 724191672Sbms */ 725191672Sbms bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen); 726191672Sbms ln->la_flags |= LLE_VALID; 727191672Sbms if (is_solicited) { 728191672Sbms ln->ln_state = ND6_LLINFO_REACHABLE; 729191672Sbms ln->ln_byhint = 0; 730191672Sbms if (!ND6_LLINFO_PERMANENT(ln)) { 731191672Sbms nd6_llinfo_settimer_locked(ln, 732191672Sbms (long)ND_IFINFO(ln->lle_tbl->llt_ifp)->reachable * hz); 733191672Sbms } 734191672Sbms } else { 735191672Sbms ln->ln_state = ND6_LLINFO_STALE; 736191672Sbms nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz); 737191672Sbms } 738191672Sbms if ((ln->ln_router = is_router) != 0) { 739191672Sbms /* 740191672Sbms * This means a router's state has changed from 74153541Sshin * non-reachable to probably reachable, and might 742191672Sbms * affect the status of associated prefixes.. 743191672Sbms */ 744191672Sbms checklink = 1; 74553541Sshin } 746191672Sbms } else { 747191672Sbms int llchange; 748191672Sbms 749191672Sbms /* 750191672Sbms * Check if the link-layer address has changed or not. 751191672Sbms */ 752191672Sbms if (lladdr == NULL) 753191672Sbms llchange = 0; 754191672Sbms else { 755191672Sbms if (ln->la_flags & LLE_VALID) { 756191672Sbms if (bcmp(lladdr, &ln->ll_addr, ifp->if_addrlen)) 757191672Sbms llchange = 1; 758191672Sbms else 759191672Sbms llchange = 0; 760191672Sbms } else 761191672Sbms llchange = 1; 762191672Sbms } 763191672Sbms 764191672Sbms /* 765191672Sbms * This is VERY complex. Look at it with care. 766191672Sbms * 767191672Sbms * override solicit lladdr llchange action 768191672Sbms * (L: record lladdr) 769191672Sbms * 770191672Sbms * 0 0 n -- (2c) 771191672Sbms * 0 0 y n (2b) L 772191672Sbms * 0 0 y y (1) REACHABLE->STALE 773191672Sbms * 0 1 n -- (2c) *->REACHABLE 774191672Sbms * 0 1 y n (2b) L *->REACHABLE 775191672Sbms * 0 1 y y (1) REACHABLE->STALE 776191672Sbms * 1 0 n -- (2a) 777191672Sbms * 1 0 y n (2a) L 778191672Sbms * 1 0 y y (2a) L *->STALE 779191672Sbms * 1 1 n -- (2a) *->REACHABLE 780148385Sume * 1 1 y n (2a) L *->REACHABLE 78153541Sshin * 1 1 y y (2a) L *->REACHABLE 78253541Sshin */ 783191672Sbms if (!is_override && (lladdr != NULL && llchange)) { /* (1) */ 784191672Sbms /* 785191672Sbms * If state is REACHABLE, make it STALE. 786191672Sbms * no other updates should be done. 787191672Sbms */ 788191672Sbms if (ln->ln_state == ND6_LLINFO_REACHABLE) { 789191672Sbms ln->ln_state = ND6_LLINFO_STALE; 790191672Sbms nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz); 791191672Sbms } 792191672Sbms goto freeit; 793191672Sbms } else if (is_override /* (2a) */ 79453541Sshin || (!is_override && (lladdr != NULL && !llchange)) /* (2b) */ 795191672Sbms || lladdr == NULL) { /* (2c) */ 796191672Sbms /* 797191672Sbms * Update link-local address, if any. 798191672Sbms */ 799192923Sbms if (lladdr != NULL) { 800191672Sbms bcopy(lladdr, &ln->ll_addr, ifp->if_addrlen); 801191672Sbms ln->la_flags |= LLE_VALID; 802192923Sbms } 803192923Sbms 804192923Sbms /* 80553541Sshin * If solicited, make the state REACHABLE. 806192923Sbms * If not solicited and the link-layer address was 807191672Sbms * changed, make it STALE. 808192923Sbms */ 809192923Sbms if (is_solicited) { 810192923Sbms ln->ln_state = ND6_LLINFO_REACHABLE; 811192923Sbms ln->ln_byhint = 0; 812192923Sbms if (!ND6_LLINFO_PERMANENT(ln)) { 813192923Sbms nd6_llinfo_settimer_locked(ln, 814192923Sbms (long)ND_IFINFO(ifp)->reachable * hz); 815192923Sbms } 816192923Sbms } else { 817192923Sbms if (lladdr != NULL && llchange) { 818192923Sbms ln->ln_state = ND6_LLINFO_STALE; 819192923Sbms nd6_llinfo_settimer_locked(ln, 820192923Sbms (long)V_nd6_gctimer * hz); 821191672Sbms } 822191672Sbms } 823191672Sbms } 824191672Sbms 825192923Sbms if (ln->ln_router && !is_router) { 826192923Sbms /* 82778064Sume * The peer dropped the router flag. 828192923Sbms * Remove the sender from the Default Router List and 829192923Sbms * update the Destination Cache entries. 830192923Sbms */ 83178064Sume struct nd_defrouter *dr; 832191672Sbms struct in6_addr *in6; 833191672Sbms 834191672Sbms in6 = &L3_ADDR_SIN6(ln)->sin6_addr; 835191672Sbms 836191672Sbms /* 837191672Sbms * Lock to protect the default router list. 838191672Sbms * XXX: this might be unnecessary, since this function 839191672Sbms * is only called under the network software interrupt 840191672Sbms * context. However, we keep it just for safety. 841191672Sbms */ 842191672Sbms dr = defrouter_lookup(in6, ln->lle_tbl->llt_ifp); 843191672Sbms if (dr) 844191672Sbms defrtrlist_del(dr); 845191672Sbms else if (!V_ip6_forwarding) { 846191672Sbms /* 847191672Sbms * Even if the neighbor is not in the default 848191672Sbms * router list, the neighbor may be used 849191672Sbms * as a next hop for some destinations 850191672Sbms * (e.g. redirect case). So we must 851191672Sbms * call rt6_flush explicitly. 852192923Sbms */ 853192923Sbms rt6_flush(&ip6->ip6_src, ifp); 854192923Sbms } 855192923Sbms } 856192923Sbms ln->ln_router = is_router; 857192923Sbms } 858192923Sbms /* XXX - QL 859192923Sbms * Does this matter? 860192923Sbms * rt->rt_flags &= ~RTF_REJECT; 861192923Sbms */ 862192923Sbms ln->la_asked = 0; 863192923Sbms if (ln->la_hold) { 864192923Sbms struct mbuf *m_hold, *m_hold_next; 865192923Sbms 866192923Sbms /* 867192923Sbms * reset the la_hold in advance, to explicitly 868192923Sbms * prevent a la_hold lookup in nd6_output() 869192923Sbms * (wouldn't happen, though...) 870192923Sbms */ 871192923Sbms for (m_hold = ln->la_hold, ln->la_hold = NULL; 872192923Sbms m_hold; m_hold = m_hold_next) { 873192923Sbms m_hold_next = m_hold->m_nextpkt; 874192923Sbms m_hold->m_nextpkt = NULL; 875192923Sbms /* 876192923Sbms * we assume ifp is not a loopback here, so just set 877192923Sbms * the 2nd argument as the 1st one. 878192923Sbms */ 879191672Sbms nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln, &chain); 880192547Sbms } 881191672Sbms } 882191672Sbms freeit: 883191672Sbms if (ln != NULL) { 884191672Sbms if (chain) 885191672Sbms memcpy(&sin6, L3_ADDR_SIN6(ln), sizeof(sin6)); 886192923Sbms LLE_WUNLOCK(ln); 887192923Sbms 888192923Sbms if (chain) 889192923Sbms nd6_output_flush(ifp, ifp, chain, &sin6, NULL); 890192923Sbms } 891192923Sbms if (checklink) 892192923Sbms pfxlist_onlink_check(); 893192923Sbms 894191672Sbms m_freem(m); 895191672Sbms return; 896191672Sbms 897191672Sbms bad: 898191672Sbms if (ln != NULL) 899192547Sbms LLE_WUNLOCK(ln); 900191672Sbms 901191672Sbms ICMP6STAT_INC(icp6s_badna); 902192923Sbms m_freem(m); 90353541Sshin} 904191672Sbms 905192547Sbms/* 906191672Sbms * Neighbor advertisement output handling. 907191672Sbms * 908192547Sbms * Based on RFC 2461 909191672Sbms * 910191672Sbms * the following items are not implemented yet: 911191672Sbms * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) 912191672Sbms * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) 913191672Sbms * 914192923Sbms * tlladdr - 1 if include target link-layer address 915192923Sbms * sdl0 - sockaddr_dl (= proxy NA) or NULL 916192562Sbms */ 917192562Sbmsvoid 918191672Sbmsnd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0, 919191672Sbms const struct in6_addr *taddr6, u_long flags, int tlladdr, 920191672Sbms struct sockaddr *sdl0) 921191672Sbms{ 922191672Sbms struct mbuf *m; 923191672Sbms struct ip6_hdr *ip6; 924191672Sbms struct nd_neighbor_advert *nd_na; 925191672Sbms struct ip6_moptions im6o; 926191672Sbms struct in6_addr src, daddr6; 927191672Sbms struct sockaddr_in6 dst_sa; 928191672Sbms int icmp6len, maxlen, error; 929191672Sbms caddr_t mac = NULL; 930191672Sbms struct route_in6 ro; 931191672Sbms 932191672Sbms bzero(&ro, sizeof(ro)); 933191672Sbms 934191672Sbms daddr6 = *daddr6_0; /* make a local copy for modification */ 935191672Sbms 936191672Sbms /* estimate the size of message */ 937191672Sbms maxlen = sizeof(*ip6) + sizeof(*nd_na); 938191672Sbms maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7; 939191672Sbms if (max_linkhdr + maxlen >= MCLBYTES) { 940191672Sbms#ifdef DIAGNOSTIC 941191672Sbms printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES " 942191672Sbms "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES); 943191672Sbms#endif 944191672Sbms return; 945191672Sbms } 946191672Sbms 947191672Sbms MGETHDR(m, M_DONTWAIT, MT_DATA); 948191672Sbms if (m && max_linkhdr + maxlen >= MHLEN) { 949192562Sbms MCLGET(m, M_DONTWAIT); 950191672Sbms if ((m->m_flags & M_EXT) == 0) { 951192923Sbms m_free(m); 952192923Sbms m = NULL; 953192923Sbms } 95453541Sshin } 95553541Sshin if (m == NULL) 956191672Sbms return; 957192547Sbms m->m_pkthdr.rcvif = NULL; 958191672Sbms 959191672Sbms if (IN6_IS_ADDR_MULTICAST(&daddr6)) { 960191672Sbms m->m_flags |= M_MCAST; 961191672Sbms im6o.im6o_multicast_ifp = ifp; 962191672Sbms im6o.im6o_multicast_hlim = 255; 963191672Sbms im6o.im6o_multicast_loop = 0; 964191672Sbms } 965191672Sbms 966191672Sbms icmp6len = sizeof(*nd_na); 967191672Sbms m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len; 968191672Sbms m->m_data += max_linkhdr; /* or MH_ALIGN() equivalent? */ 969191672Sbms 970191672Sbms /* fill neighbor advertisement packet */ 971191672Sbms ip6 = mtod(m, struct ip6_hdr *); 972191672Sbms ip6->ip6_flow = 0; 973191672Sbms ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 974191672Sbms ip6->ip6_vfc |= IPV6_VERSION; 975191672Sbms ip6->ip6_nxt = IPPROTO_ICMPV6; 976191672Sbms ip6->ip6_hlim = 255; 977191672Sbms if (IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { 978191672Sbms /* reply to DAD */ 979191672Sbms daddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL; 980191672Sbms daddr6.s6_addr16[1] = 0; 981191672Sbms daddr6.s6_addr32[1] = 0; 982191672Sbms daddr6.s6_addr32[2] = 0; 983191672Sbms daddr6.s6_addr32[3] = IPV6_ADDR_INT32_ONE; 984191672Sbms if (in6_setscope(&daddr6, ifp, NULL)) 985191672Sbms goto bad; 986191672Sbms 987191672Sbms flags &= ~ND_NA_FLAG_SOLICITED; 988191672Sbms } 989191672Sbms ip6->ip6_dst = daddr6; 990191672Sbms bzero(&dst_sa, sizeof(struct sockaddr_in6)); 991191672Sbms dst_sa.sin6_family = AF_INET6; 992191672Sbms dst_sa.sin6_len = sizeof(struct sockaddr_in6); 993191672Sbms dst_sa.sin6_addr = daddr6; 994191672Sbms 995191672Sbms /* 996191672Sbms * Select a source whose scope is the same as that of the dest. 997191672Sbms */ 998191672Sbms bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa)); 999191672Sbms error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, NULL, &src); 1000191672Sbms if (error) { 100153541Sshin char ip6buf[INET6_ADDRSTRLEN]; 1002191672Sbms nd6log((LOG_DEBUG, "nd6_na_output: source can't be " 1003191672Sbms "determined: dst=%s, error=%d\n", 1004191672Sbms ip6_sprintf(ip6buf, &dst_sa.sin6_addr), error)); 1005191672Sbms goto bad; 1006148385Sume } 1007191672Sbms ip6->ip6_src = src; 1008191672Sbms nd_na = (struct nd_neighbor_advert *)(ip6 + 1); 1009191672Sbms nd_na->nd_na_type = ND_NEIGHBOR_ADVERT; 1010191672Sbms nd_na->nd_na_code = 0; 1011191672Sbms nd_na->nd_na_target = *taddr6; 1012191672Sbms in6_clearscope(&nd_na->nd_na_target); /* XXX */ 1013191672Sbms 1014191672Sbms /* 1015191672Sbms * "tlladdr" indicates NS's condition for adding tlladdr or not. 1016191672Sbms * see nd6_ns_input() for details. 1017148385Sume * Basically, if NS packet is sent to unicast/anycast addr, 1018148385Sume * target lladdr option SHOULD NOT be included. 1019148385Sume */ 1020191672Sbms if (tlladdr) { 1021191672Sbms /* 102253541Sshin * sdl0 != NULL indicates proxy NA. If we do proxy, use 1023191672Sbms * lladdr in sdl0. If we are not proxying (sending NA for 1024191672Sbms * my address) use lladdr configured for the interface. 1025191672Sbms */ 1026191672Sbms if (sdl0 == NULL) { 1027191672Sbms if (ifp->if_carp) 1028191672Sbms mac = (*carp_macmatch6_p)(ifp, m, taddr6); 102953541Sshin if (mac == NULL) 1030191672Sbms mac = nd6_ifptomac(ifp); 1031191672Sbms } else if (sdl0->sa_family == AF_LINK) { 1032191672Sbms struct sockaddr_dl *sdl; 1033191672Sbms sdl = (struct sockaddr_dl *)sdl0; 1034191672Sbms if (sdl->sdl_alen == ifp->if_addrlen) 1035191672Sbms mac = LLADDR(sdl); 1036191672Sbms } 1037191672Sbms } 1038191672Sbms if (tlladdr && mac) { 1039191672Sbms int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen; 1040191672Sbms struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1); 1041191672Sbms 1042191672Sbms /* roundup to 8 bytes alignment! */ 1043191672Sbms optlen = (optlen + 7) & ~7; 1044191672Sbms 1045191672Sbms m->m_pkthdr.len += optlen; 104653541Sshin m->m_len += optlen; 1047191672Sbms icmp6len += optlen; 1048191672Sbms bzero((caddr_t)nd_opt, optlen); 1049191672Sbms nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; 1050191672Sbms nd_opt->nd_opt_len = optlen >> 3; 1051191672Sbms bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen); 1052191672Sbms } else 1053191672Sbms flags &= ~ND_NA_FLAG_OVERRIDE; 1054191672Sbms 1055191672Sbms ip6->ip6_plen = htons((u_short)icmp6len); 1056191672Sbms nd_na->nd_na_flags_reserved = flags; 1057191672Sbms nd_na->nd_na_cksum = 0; 1058191672Sbms nd_na->nd_na_cksum = 1059191672Sbms in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len); 1060191672Sbms 1061191672Sbms ip6_output(m, NULL, &ro, 0, &im6o, NULL, NULL); 1062191672Sbms icmp6_ifstat_inc(ifp, ifs6_out_msg); 1063191672Sbms icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); 1064148385Sume ICMP6STAT_INC(icp6s_outhist[ND_NEIGHBOR_ADVERT]); 1065191672Sbms 1066191672Sbms if (ro.ro_rt) { /* we don't cache this route. */ 1067191672Sbms RTFREE(ro.ro_rt); 1068191672Sbms } 1069191672Sbms return; 1070191672Sbms 1071191672Sbms bad: 1072191672Sbms if (ro.ro_rt) { 1073148385Sume RTFREE(ro.ro_rt); 1074191672Sbms } 1075191672Sbms m_freem(m); 1076191672Sbms return; 1077191672Sbms} 1078191672Sbms 1079191672Sbmscaddr_t 1080192923Sbmsnd6_ifptomac(struct ifnet *ifp) 1081192923Sbms{ 1082192923Sbms switch (ifp->if_type) { 1083191672Sbms case IFT_ARCNET: 1084191672Sbms case IFT_ETHER: 1085191672Sbms case IFT_FDDI: 1086192923Sbms case IFT_IEEE1394: 1087191672Sbms#ifdef IFT_L2VLAN 1088192923Sbms case IFT_L2VLAN: 1089191672Sbms#endif 1090191672Sbms#ifdef IFT_IEEE80211 1091191672Sbms case IFT_IEEE80211: 1092191672Sbms#endif 1093191672Sbms#ifdef IFT_CARP 1094191672Sbms case IFT_CARP: 1095192923Sbms#endif 1096192923Sbms case IFT_BRIDGE: 1097192923Sbms case IFT_ISO88025: 1098192923Sbms return IF_LLADDR(ifp); 1099192923Sbms default: 1100192923Sbms return NULL; 1101192923Sbms } 1102191672Sbms} 1103191672Sbms 1104192923Sbmsstruct dadq { 1105192923Sbms TAILQ_ENTRY(dadq) dad_list; 1106192923Sbms struct ifaddr *dad_ifa; 1107192923Sbms int dad_count; /* max NS to send */ 1108192923Sbms int dad_ns_tcount; /* # of trials to send NS */ 1109192923Sbms int dad_ns_ocount; /* NS sent so far */ 1110192923Sbms int dad_ns_icount; 1111192923Sbms int dad_na_icount; 1112192923Sbms struct callout dad_timer_ch; 1113192923Sbms struct vnet *dad_vnet; 1114192923Sbms}; 1115192547Sbms 1116192923Sbmsstatic VNET_DEFINE(TAILQ_HEAD(, dadq), dadq); 1117191672SbmsVNET_DEFINE(int, dad_init) = 0; 1118192923Sbms#define V_dadq VNET(dadq) 1119192923Sbms#define V_dad_init VNET(dad_init) 1120192923Sbms 1121192923Sbmsstatic struct dadq * 1122192547Sbmsnd6_dad_find(struct ifaddr *ifa) 1123192547Sbms{ 1124192923Sbms struct dadq *dp; 1125192923Sbms 1126192923Sbms for (dp = V_dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) { 1127192923Sbms if (dp->dad_ifa == ifa) 1128192923Sbms return dp; 1129191672Sbms } 1130192923Sbms return NULL; 1131191672Sbms} 1132191672Sbms 1133191672Sbmsstatic void 1134191672Sbmsnd6_dad_starttimer(struct dadq *dp, int ticks) 1135191672Sbms{ 1136191672Sbms 1137192547Sbms callout_reset(&dp->dad_timer_ch, ticks, 1138192547Sbms (void (*)(void *))nd6_dad_timer, (void *)dp); 1139192547Sbms} 1140192547Sbms 1141191672Sbmsstatic void 1142191672Sbmsnd6_dad_stoptimer(struct dadq *dp) 1143191672Sbms{ 1144194760Srwatson 1145194760Srwatson callout_stop(&dp->dad_timer_ch); 1146194760Srwatson} 1147191672Sbms 1148194760Srwatson/* 1149194760Srwatson * Start Duplicate Address Detection (DAD) for specified interface address. 1150194760Srwatson */ 1151191672Sbmsvoid 1152191672Sbmsnd6_dad_start(struct ifaddr *ifa, int delay) 1153191672Sbms{ 1154191672Sbms struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; 1155192923Sbms struct dadq *dp; 1156192923Sbms char ip6buf[INET6_ADDRSTRLEN]; 1157192923Sbms 1158192923Sbms if (!V_dad_init) { 1159192923Sbms TAILQ_INIT(&V_dadq); 1160192923Sbms V_dad_init++; 1161192923Sbms } 1162191672Sbms 1163192547Sbms /* 1164191672Sbms * If we don't need DAD, don't do it. 1165191672Sbms * There are several cases: 1166191672Sbms * - DAD is disabled (ip6_dad_count == 0) 1167191672Sbms * - the interface address is anycast 1168191672Sbms */ 1169191672Sbms if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) { 1170191672Sbms log(LOG_DEBUG, 1171191672Sbms "nd6_dad_start: called with non-tentative address " 1172191672Sbms "%s(%s)\n", 1173191672Sbms ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 1174191672Sbms ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); 1175191672Sbms return; 1176191672Sbms } 1177191672Sbms if (ia->ia6_flags & IN6_IFF_ANYCAST) { 1178191672Sbms ia->ia6_flags &= ~IN6_IFF_TENTATIVE; 1179191672Sbms return; 118053541Sshin } 1181191672Sbms if (!V_ip6_dad_count) { 1182191672Sbms ia->ia6_flags &= ~IN6_IFF_TENTATIVE; 118362587Sitojun return; 1184191672Sbms } 1185191672Sbms if (ifa->ifa_ifp == NULL) 1186151539Ssuz panic("nd6_dad_start: ifa->ifa_ifp == NULL"); 1187191672Sbms if (!(ifa->ifa_ifp->if_flags & IFF_UP)) { 1188191672Sbms return; 1189191672Sbms } 1190191672Sbms if (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED) 1191191672Sbms return; 1192191672Sbms if (nd6_dad_find(ifa) != NULL) { 119353541Sshin /* DAD already in progress */ 1194191672Sbms return; 1195191672Sbms } 1196191672Sbms 1197191672Sbms dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT); 1198191672Sbms if (dp == NULL) { 1199191672Sbms log(LOG_ERR, "nd6_dad_start: memory allocation failed for " 1200191672Sbms "%s(%s)\n", 1201191672Sbms ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 1202191672Sbms ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); 1203191672Sbms return; 1204191672Sbms } 1205191672Sbms bzero(dp, sizeof(*dp)); 1206191672Sbms callout_init(&dp->dad_timer_ch, 0); 1207191672Sbms#ifdef VIMAGE 1208191341Srwatson dp->dad_vnet = curvnet; 1209191672Sbms#endif 121053541Sshin TAILQ_INSERT_TAIL(&V_dadq, (struct dadq *)dp, dad_list); 1211191672Sbms 1212192547Sbms nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp), 1213191672Sbms ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 1214191672Sbms 1215120941Sume /* 1216192923Sbms * Send NS packet for DAD, ip6_dad_count times. 1217192923Sbms * Note that we must delay the first transmission, if this is the 1218192923Sbms * first packet to be sent from the interface after interface 1219191672Sbms * (re)initialization. 1220191672Sbms */ 1221120941Sume dp->dad_ifa = ifa; 1222191672Sbms ifa_ref(ifa); /* just for safety */ 1223191672Sbms dp->dad_count = V_ip6_dad_count; 1224191672Sbms dp->dad_ns_icount = dp->dad_na_icount = 0; 1225191672Sbms dp->dad_ns_ocount = dp->dad_ns_tcount = 0; 1226191672Sbms if (delay == 0) { 1227191672Sbms nd6_dad_ns_output(dp, ifa); 1228191672Sbms nd6_dad_starttimer(dp, 1229191672Sbms (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); 1230191672Sbms } else { 1231191672Sbms nd6_dad_starttimer(dp, delay); 1232191672Sbms } 1233191672Sbms} 1234191672Sbms 1235191672Sbms/* 1236191672Sbms * terminate DAD unconditionally. used for address removals. 1237191672Sbms */ 1238191672Sbmsvoid 1239191672Sbmsnd6_dad_stop(struct ifaddr *ifa) 1240191672Sbms{ 1241191672Sbms struct dadq *dp; 1242191672Sbms 1243191672Sbms if (!V_dad_init) 1244191672Sbms return; 1245191672Sbms dp = nd6_dad_find(ifa); 1246191672Sbms if (!dp) { 1247191672Sbms /* DAD wasn't started yet */ 1248191672Sbms return; 1249191672Sbms } 1250191672Sbms 1251191672Sbms nd6_dad_stoptimer(dp); 1252191672Sbms 1253191672Sbms TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list); 1254191672Sbms free(dp, M_IP6NDP); 1255191672Sbms dp = NULL; 1256191672Sbms ifa_free(ifa); 1257191672Sbms} 1258191672Sbms 1259191672Sbmsstatic void 1260191672Sbmsnd6_dad_timer(struct dadq *dp) 1261192923Sbms{ 1262192923Sbms CURVNET_SET(dp->dad_vnet); 1263192923Sbms int s; 1264192923Sbms struct ifaddr *ifa = dp->dad_ifa; 1265191672Sbms struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; 1266191672Sbms char ip6buf[INET6_ADDRSTRLEN]; 1267191672Sbms 1268191672Sbms s = splnet(); /* XXX */ 1269191672Sbms 1270191672Sbms /* Sanity check */ 1271191672Sbms if (ia == NULL) { 1272191672Sbms log(LOG_ERR, "nd6_dad_timer: called with null parameter\n"); 1273191672Sbms goto done; 1274191672Sbms } 1275191672Sbms if (ia->ia6_flags & IN6_IFF_DUPLICATED) { 1276191672Sbms log(LOG_ERR, "nd6_dad_timer: called with duplicated address " 1277191672Sbms "%s(%s)\n", 1278191672Sbms ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 1279191672Sbms ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); 1280192923Sbms goto done; 1281191672Sbms } 1282191672Sbms if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) { 1283191672Sbms log(LOG_ERR, "nd6_dad_timer: called with non-tentative address " 1284191672Sbms "%s(%s)\n", 1285191672Sbms ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 1286191672Sbms ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???"); 1287191672Sbms goto done; 1288191672Sbms } 1289191672Sbms 1290191672Sbms /* timeouted with IFF_{RUNNING,UP} check */ 1291191672Sbms if (dp->dad_ns_tcount > V_dad_maxtry) { 1292191672Sbms nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n", 1293191672Sbms if_name(ifa->ifa_ifp))); 1294191672Sbms 1295191672Sbms TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list); 1296191672Sbms free(dp, M_IP6NDP); 1297191672Sbms dp = NULL; 1298191672Sbms ifa_free(ifa); 1299191672Sbms goto done; 1300191672Sbms } 1301191672Sbms 1302191672Sbms /* Need more checks? */ 1303191672Sbms if (dp->dad_ns_ocount < dp->dad_count) { 1304195760Srwatson /* 1305191672Sbms * We have more NS to go. Send NS packet for DAD. 1306191672Sbms */ 1307191672Sbms nd6_dad_ns_output(dp, ifa); 1308191672Sbms nd6_dad_starttimer(dp, 1309191672Sbms (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000); 1310195760Srwatson } else { 1311191672Sbms /* 1312191672Sbms * We have transmitted sufficient number of DAD packets. 1313191672Sbms * See what we've got. 1314191672Sbms */ 1315191672Sbms int duplicate; 1316191672Sbms 1317191672Sbms duplicate = 0; 1318191672Sbms 1319191672Sbms if (dp->dad_na_icount) { 1320191672Sbms /* 1321191672Sbms * the check is in nd6_dad_na_input(), 1322191672Sbms * but just in case 1323191672Sbms */ 1324191672Sbms duplicate++; 1325191672Sbms } 1326191672Sbms 1327191672Sbms if (dp->dad_ns_icount) { 1328191672Sbms /* We've seen NS, means DAD has failed. */ 1329191672Sbms duplicate++; 1330191672Sbms } 1331191672Sbms 1332191672Sbms if (duplicate) { 1333191672Sbms /* (*dp) will be freed in nd6_dad_duplicated() */ 1334191672Sbms dp = NULL; 1335191672Sbms nd6_dad_duplicated(ifa); 1336191672Sbms } else { 1337191672Sbms /* 1338191672Sbms * We are done with DAD. No NA came, no NS came. 1339191672Sbms * No duplicate address found. 1340191672Sbms */ 1341191672Sbms ia->ia6_flags &= ~IN6_IFF_TENTATIVE; 1342191672Sbms 1343191672Sbms nd6log((LOG_DEBUG, 1344191672Sbms "%s: DAD complete for %s - no duplicates found\n", 1345191672Sbms if_name(ifa->ifa_ifp), 1346191672Sbms ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); 1347191672Sbms 1348191672Sbms TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list); 1349191672Sbms free(dp, M_IP6NDP); 1350191672Sbms dp = NULL; 1351191672Sbms ifa_free(ifa); 1352191672Sbms } 1353191672Sbms } 1354191672Sbms 1355191672Sbmsdone: 1356191672Sbms splx(s); 1357191672Sbms CURVNET_RESTORE(); 1358191672Sbms} 1359191672Sbms 1360191672Sbmsvoid 1361191672Sbmsnd6_dad_duplicated(struct ifaddr *ifa) 1362191672Sbms{ 1363191672Sbms struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; 1364191672Sbms struct ifnet *ifp; 1365191672Sbms struct dadq *dp; 1366191672Sbms char ip6buf[INET6_ADDRSTRLEN]; 1367191672Sbms 1368191672Sbms dp = nd6_dad_find(ifa); 1369191672Sbms if (dp == NULL) { 1370191672Sbms log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n"); 1371191672Sbms return; 1372191672Sbms } 1373191672Sbms 1374191672Sbms log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: " 1375191672Sbms "NS in/out=%d/%d, NA in=%d\n", 1376191672Sbms if_name(ifa->ifa_ifp), ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr), 1377191672Sbms dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount); 1378191672Sbms 1379191672Sbms ia->ia6_flags &= ~IN6_IFF_TENTATIVE; 1380191672Sbms ia->ia6_flags |= IN6_IFF_DUPLICATED; 1381191672Sbms 1382191672Sbms /* We are done with DAD, with duplicate address found. (failure) */ 1383191672Sbms nd6_dad_stoptimer(dp); 1384191672Sbms 1385191672Sbms ifp = ifa->ifa_ifp; 1386191672Sbms log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n", 1387191672Sbms if_name(ifp), ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)); 1388191672Sbms log(LOG_ERR, "%s: manual intervention required\n", 1389191672Sbms if_name(ifp)); 1390191672Sbms 1391191672Sbms /* 1392191672Sbms * If the address is a link-local address formed from an interface 1393191672Sbms * identifier based on the hardware address which is supposed to be 139453541Sshin * uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP 1395191672Sbms * operation on the interface SHOULD be disabled. 1396191672Sbms * [RFC 4862, Section 5.4.5] 1397191672Sbms */ 1398192923Sbms if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) { 1399192923Sbms struct in6_addr in6; 1400192923Sbms 1401192923Sbms /* 1402192923Sbms * To avoid over-reaction, we only apply this logic when we are 1403192923Sbms * very sure that hardware addresses are supposed to be unique. 1404192923Sbms */ 1405191672Sbms switch (ifp->if_type) { 1406191672Sbms case IFT_ETHER: 1407192923Sbms case IFT_FDDI: 1408191672Sbms case IFT_ATM: 1409191672Sbms case IFT_IEEE1394: 1410191672Sbms#ifdef IFT_IEEE80211 1411191672Sbms case IFT_IEEE80211: 1412191672Sbms#endif 1413191672Sbms in6 = ia->ia_addr.sin6_addr; 1414191672Sbms if (in6_get_hw_ifid(ifp, &in6) == 0 && 1415191672Sbms IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) { 141653541Sshin ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED; 1417191672Sbms log(LOG_ERR, "%s: possible hardware address " 1418191672Sbms "duplication detected, disable IPv6\n", 1419191672Sbms if_name(ifp)); 1420191672Sbms } 1421191672Sbms break; 1422191672Sbms } 1423191672Sbms } 1424191672Sbms 1425191672Sbms TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list); 1426191672Sbms free(dp, M_IP6NDP); 1427191672Sbms dp = NULL; 1428191672Sbms ifa_free(ifa); 1429191672Sbms} 1430191672Sbms 1431191672Sbmsstatic void 143253541Sshinnd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa) 143353541Sshin{ 1434191672Sbms struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; 1435191672Sbms struct ifnet *ifp = ifa->ifa_ifp; 1436191672Sbms 1437191672Sbms dp->dad_ns_tcount++; 1438191672Sbms if ((ifp->if_flags & IFF_UP) == 0) { 1439191672Sbms return; 1440191672Sbms } 1441191672Sbms if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1442191672Sbms return; 1443191672Sbms } 1444191672Sbms 1445191672Sbms dp->dad_ns_ocount++; 1446191672Sbms nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1); 1447191672Sbms} 1448191672Sbms 1449191672Sbmsstatic void 1450191672Sbmsnd6_dad_ns_input(struct ifaddr *ifa) 1451191672Sbms{ 1452191672Sbms struct in6_ifaddr *ia; 1453191672Sbms struct ifnet *ifp; 1454191672Sbms const struct in6_addr *taddr6; 1455191672Sbms struct dadq *dp; 1456191672Sbms int duplicate; 1457191672Sbms 1458191672Sbms if (ifa == NULL) 1459191672Sbms panic("ifa == NULL in nd6_dad_ns_input"); 1460191672Sbms 1461191672Sbms ia = (struct in6_ifaddr *)ifa; 1462191672Sbms ifp = ifa->ifa_ifp; 1463191672Sbms taddr6 = &ia->ia_addr.sin6_addr; 1464191672Sbms duplicate = 0; 1465191672Sbms dp = nd6_dad_find(ifa); 1466191672Sbms 1467191672Sbms /* Quickhack - completely ignore DAD NS packets */ 1468191672Sbms if (V_dad_ignore_ns) { 146953541Sshin char ip6buf[INET6_ADDRSTRLEN]; 1470191672Sbms nd6log((LOG_INFO, 1471191672Sbms "nd6_dad_ns_input: ignoring DAD NS packet for " 1472191672Sbms "address %s(%s)\n", ip6_sprintf(ip6buf, taddr6), 1473191672Sbms if_name(ifa->ifa_ifp))); 1474191672Sbms return; 1475191672Sbms } 1476191672Sbms 1477191672Sbms /* 1478191672Sbms * if I'm yet to start DAD, someone else started using this address 1479191672Sbms * first. I have a duplicate and you win. 1480191672Sbms */ 1481191672Sbms if (dp == NULL || dp->dad_ns_ocount == 0) 1482191672Sbms duplicate++; 1483120941Sume 1484191672Sbms /* XXX more checks for loopback situation - see nd6_dad_timer too */ 1485191672Sbms 1486191672Sbms if (duplicate) { 1487191672Sbms dp = NULL; /* will be freed in nd6_dad_duplicated() */ 1488191672Sbms nd6_dad_duplicated(ifa); 1489191672Sbms } else { 1490191672Sbms /* 1491191672Sbms * not sure if I got a duplicate. 1492191672Sbms * increment ns count and see what happens. 1493191672Sbms */ 1494191672Sbms if (dp) 1495191672Sbms dp->dad_ns_icount++; 1496191672Sbms } 1497191672Sbms} 1498191672Sbms 1499191672Sbmsstatic void 1500191672Sbmsnd6_dad_na_input(struct ifaddr *ifa) 1501191672Sbms{ 1502191672Sbms struct dadq *dp; 1503191672Sbms 1504191672Sbms if (ifa == NULL) 1505191672Sbms panic("ifa == NULL in nd6_dad_na_input"); 1506191672Sbms 1507191672Sbms dp = nd6_dad_find(ifa); 1508191672Sbms if (dp) 1509191672Sbms dp->dad_na_icount++; 1510191672Sbms 1511191672Sbms /* remove the address. */ 1512191672Sbms nd6_dad_duplicated(ifa); 1513191672Sbms} 1514191672Sbms