xref: /freebsd/sys/netinet6/nd6_nbr.c (revision 60d8dbbef075d3b39891ed35e124d0f7ef8e5fb9)
1caf43b02SWarner Losh /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
482cd038dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
582cd038dSYoshinobu Inoue  * All rights reserved.
682cd038dSYoshinobu Inoue  *
782cd038dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
882cd038dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
982cd038dSYoshinobu Inoue  * are met:
1082cd038dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
1182cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
1282cd038dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
1382cd038dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
1482cd038dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
1582cd038dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
1682cd038dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
1782cd038dSYoshinobu Inoue  *    without specific prior written permission.
1882cd038dSYoshinobu Inoue  *
1982cd038dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2082cd038dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2182cd038dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2282cd038dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2382cd038dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2482cd038dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2582cd038dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2682cd038dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2782cd038dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2882cd038dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2982cd038dSYoshinobu Inoue  * SUCH DAMAGE.
30b48287a3SDavid E. O'Brien  *
31b48287a3SDavid E. O'Brien  *	$KAME: nd6_nbr.c,v 1.86 2002/01/21 02:33:04 jinmei Exp $
3282cd038dSYoshinobu Inoue  */
3382cd038dSYoshinobu Inoue 
34b48287a3SDavid E. O'Brien #include <sys/cdefs.h>
35686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h"
36686cdd19SJun-ichiro itojun Hagino #include "opt_inet6.h"
37a9771948SGleb Smirnoff #include "opt_ipsec.h"
386a800098SYoshinobu Inoue 
3982cd038dSYoshinobu Inoue #include <sys/param.h>
4082cd038dSYoshinobu Inoue #include <sys/systm.h>
41e2e050c8SConrad Meyer #include <sys/eventhandler.h>
4282cd038dSYoshinobu Inoue #include <sys/malloc.h>
4311d8451dSHiroki Sato #include <sys/libkern.h>
446e6b3f7cSQing Li #include <sys/lock.h>
456e6b3f7cSQing Li #include <sys/rwlock.h>
4682cd038dSYoshinobu Inoue #include <sys/mbuf.h>
4782cd038dSYoshinobu Inoue #include <sys/socket.h>
4882cd038dSYoshinobu Inoue #include <sys/sockio.h>
4982cd038dSYoshinobu Inoue #include <sys/time.h>
5082cd038dSYoshinobu Inoue #include <sys/kernel.h>
5182cd038dSYoshinobu Inoue #include <sys/errno.h>
5211d8451dSHiroki Sato #include <sys/sysctl.h>
5382cd038dSYoshinobu Inoue #include <sys/syslog.h>
5482cd038dSYoshinobu Inoue #include <sys/queue.h>
5533841545SHajimu UMEMOTO #include <sys/callout.h>
56d6ad6a86SMark Johnston #include <sys/refcount.h>
5782cd038dSYoshinobu Inoue 
5882cd038dSYoshinobu Inoue #include <net/if.h>
5982cd038dSYoshinobu Inoue #include <net/if_types.h>
6082cd038dSYoshinobu Inoue #include <net/if_dl.h>
61be4889bbSBrooks Davis #include <net/if_var.h>
623d0d5b21SJustin Hibbits #include <net/if_private.h>
6382cd038dSYoshinobu Inoue #include <net/route.h>
6411d8451dSHiroki Sato #include <net/vnet.h>
6582cd038dSYoshinobu Inoue 
6682cd038dSYoshinobu Inoue #include <netinet/in.h>
6782cd038dSYoshinobu Inoue #include <netinet/in_var.h>
686e6b3f7cSQing Li #include <net/if_llatbl.h>
6982cd038dSYoshinobu Inoue #include <netinet6/in6_var.h>
70d28bde66SSUZUKI Shinsuke #include <netinet6/in6_ifattach.h>
71686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h>
7282cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h>
73a1f7e5f8SHajimu UMEMOTO #include <netinet6/scope6_var.h>
7482cd038dSYoshinobu Inoue #include <netinet6/nd6.h>
75686cdd19SJun-ichiro itojun Hagino #include <netinet/icmp6.h>
769963e8a5SWill Andrews #include <netinet/ip_carp.h>
771db8d1f8SAna Kukec #include <netinet6/send.h>
78686cdd19SJun-ichiro itojun Hagino 
7982cd038dSYoshinobu Inoue #define SDL(s) ((struct sockaddr_dl *)s)
8082cd038dSYoshinobu Inoue 
8182cd038dSYoshinobu Inoue struct dadq;
8211d8451dSHiroki Sato static struct dadq *nd6_dad_find(struct ifaddr *, struct nd_opt_nonce *);
83e0c0711eSAlexander V. Chernikov static void nd6_dad_add(struct dadq *dp);
84e0c0711eSAlexander V. Chernikov static void nd6_dad_del(struct dadq *dp);
85d6ad6a86SMark Johnston static void nd6_dad_rele(struct dadq *);
869a94097cSMark Johnston static void nd6_dad_starttimer(struct dadq *, int);
879233d8f3SDavid E. O'Brien static void nd6_dad_stoptimer(struct dadq *);
889a94097cSMark Johnston static void nd6_dad_timer(void *);
89e0c0711eSAlexander V. Chernikov static void nd6_dad_duplicated(struct ifaddr *, struct dadq *);
906401c828SHiroki Sato static void nd6_dad_ns_output(struct dadq *);
9111d8451dSHiroki Sato static void nd6_dad_ns_input(struct ifaddr *, struct nd_opt_nonce *);
929233d8f3SDavid E. O'Brien static void nd6_dad_na_input(struct ifaddr *);
931b46c7f8SBjoern A. Zeeb static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
941b46c7f8SBjoern A. Zeeb     const struct in6_addr *, u_long, int, struct sockaddr *, u_int);
951eef8a6cSAndrey V. Elsukov static void nd6_ns_output_fib(struct ifnet *, const struct in6_addr *,
9626deb882SAlexander V. Chernikov     const struct in6_addr *, const struct in6_addr *, uint8_t *, u_int);
9782cd038dSYoshinobu Inoue 
98d6cd20ccSKUROSAWA Takahiro static struct ifaddr *nd6_proxy_fill_sdl(struct ifnet *,
99d6cd20ccSKUROSAWA Takahiro     const struct in6_addr *, struct sockaddr_dl *);
100d6cd20ccSKUROSAWA Takahiro 
1015f901c92SAndrew Turner VNET_DEFINE_STATIC(int, dad_enhanced) = 1;
10211d8451dSHiroki Sato #define	V_dad_enhanced			VNET(dad_enhanced)
10311d8451dSHiroki Sato 
10411d8451dSHiroki Sato SYSCTL_DECL(_net_inet6_ip6);
10511d8451dSHiroki Sato SYSCTL_INT(_net_inet6_ip6, OID_AUTO, dad_enhanced, CTLFLAG_VNET | CTLFLAG_RW,
10611d8451dSHiroki Sato     &VNET_NAME(dad_enhanced), 0,
10711d8451dSHiroki Sato     "Enable Enhanced DAD, which adds a random nonce to NS messages for DAD.");
10811d8451dSHiroki Sato 
1095f901c92SAndrew Turner VNET_DEFINE_STATIC(int, dad_maxtry) = 15;	/* max # of *tries* to
11082a9fa4aSHiroki Sato 						   transmit DAD packet */
1111e77c105SRobert Watson #define	V_dad_maxtry			VNET(dad_maxtry)
11282cd038dSYoshinobu Inoue 
1134f96be33SGleb Smirnoff VNET_DEFINE_STATIC(int, nd6_onlink_ns_rfc4861) = 0;
1144f96be33SGleb Smirnoff #define	V_nd6_onlink_ns_rfc4861		VNET(nd6_onlink_ns_rfc4861)
1154f96be33SGleb Smirnoff SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_ONLINKNSRFC4861,
1164f96be33SGleb Smirnoff     nd6_onlink_ns_rfc4861, CTLFLAG_VNET | CTLFLAG_RW,
1174f96be33SGleb Smirnoff     &VNET_NAME(nd6_onlink_ns_rfc4861), 0,
1184f96be33SGleb Smirnoff     "Accept 'on-link' ICMPv6 NS messages in compliance with RFC 4861");
1194f96be33SGleb Smirnoff 
12082cd038dSYoshinobu Inoue /*
121d64ada50SJens Schweikhardt  * Input a Neighbor Solicitation Message.
12282cd038dSYoshinobu Inoue  *
12382cd038dSYoshinobu Inoue  * Based on RFC 2461
124cd0fdcf7SHajimu UMEMOTO  * Based on RFC 2462 (duplicate address detection)
12582cd038dSYoshinobu Inoue  */
12682cd038dSYoshinobu Inoue void
nd6_ns_input(struct mbuf * m,int off,int icmp6len)1271272577eSXin LI nd6_ns_input(struct mbuf *m, int off, int icmp6len)
12882cd038dSYoshinobu Inoue {
129503f4e47SBjoern A. Zeeb 	struct ifnet *ifp;
130503f4e47SBjoern A. Zeeb 	struct ip6_hdr *ip6;
131686cdd19SJun-ichiro itojun Hagino 	struct nd_neighbor_solicit *nd_ns;
132503f4e47SBjoern A. Zeeb 	struct in6_addr daddr6, myaddr6, saddr6, taddr6;
133503f4e47SBjoern A. Zeeb 	struct ifaddr *ifa;
1348b529ca6SBjoern A. Zeeb 	struct sockaddr_dl proxydl;
135503f4e47SBjoern A. Zeeb 	union nd_opts ndopts;
1361d54aa3bSBjoern A. Zeeb 	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
137503f4e47SBjoern A. Zeeb 	char *lladdr;
138503f4e47SBjoern A. Zeeb 	int anycast, lladdrlen, proxy, rflag, tentative, tlladdr;
139503f4e47SBjoern A. Zeeb 
140503f4e47SBjoern A. Zeeb 	ifa = NULL;
14182cd038dSYoshinobu Inoue 
142a4061289SAndrey V. Elsukov 	/* RFC 6980: Nodes MUST silently ignore fragments */
143a4061289SAndrey V. Elsukov 	if(m->m_flags & M_FRAGMENTED)
144a4061289SAndrey V. Elsukov 		goto freeit;
145a4061289SAndrey V. Elsukov 
146503f4e47SBjoern A. Zeeb 	ifp = m->m_pkthdr.rcvif;
147503f4e47SBjoern A. Zeeb 	ip6 = mtod(m, struct ip6_hdr *);
1484caea9b1SMark Johnston 	if (__predict_false(ip6->ip6_hlim != 255)) {
1494caea9b1SMark Johnston 		ICMP6STAT_INC(icp6s_invlhlim);
150503f4e47SBjoern A. Zeeb 		nd6log((LOG_ERR,
151503f4e47SBjoern A. Zeeb 		    "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n",
152503f4e47SBjoern A. Zeeb 		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
153503f4e47SBjoern A. Zeeb 		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
154503f4e47SBjoern A. Zeeb 		goto bads;
155503f4e47SBjoern A. Zeeb 	}
156503f4e47SBjoern A. Zeeb 
157a4adf6ccSBjoern A. Zeeb 	if (m->m_len < off + icmp6len) {
158a61b5cfbSBjoern A. Zeeb 		m = m_pullup(m, off + icmp6len);
159a61b5cfbSBjoern A. Zeeb 		if (m == NULL) {
160a61b5cfbSBjoern A. Zeeb 			IP6STAT_INC(ip6s_exthdrtoolong);
16133841545SHajimu UMEMOTO 			return;
16233841545SHajimu UMEMOTO 		}
163a4adf6ccSBjoern A. Zeeb 	}
164a61b5cfbSBjoern A. Zeeb 	ip6 = mtod(m, struct ip6_hdr *);
165a61b5cfbSBjoern A. Zeeb 	nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
166503f4e47SBjoern A. Zeeb 
167503f4e47SBjoern A. Zeeb 	saddr6 = ip6->ip6_src;
168503f4e47SBjoern A. Zeeb 	daddr6 = ip6->ip6_dst;
16933841545SHajimu UMEMOTO 	taddr6 = nd_ns->nd_ns_target;
170a1f7e5f8SHajimu UMEMOTO 	if (in6_setscope(&taddr6, ifp, NULL) != 0)
171a1f7e5f8SHajimu UMEMOTO 		goto bad;
17233841545SHajimu UMEMOTO 
173503f4e47SBjoern A. Zeeb 	rflag = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0;
174503f4e47SBjoern A. Zeeb 	if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && V_ip6_norbit_raif)
175503f4e47SBjoern A. Zeeb 		rflag = 0;
17682cd038dSYoshinobu Inoue 
17782cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
178cd0fdcf7SHajimu UMEMOTO 		/* dst has to be a solicited node multicast address. */
17907eb2995SHajimu UMEMOTO 		if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL &&
18082cd038dSYoshinobu Inoue 		    /* don't check ifindex portion */
18107eb2995SHajimu UMEMOTO 		    daddr6.s6_addr32[1] == 0 &&
18207eb2995SHajimu UMEMOTO 		    daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE &&
18307eb2995SHajimu UMEMOTO 		    daddr6.s6_addr8[12] == 0xff) {
18482cd038dSYoshinobu Inoue 			; /* good */
18582cd038dSYoshinobu Inoue 		} else {
18633841545SHajimu UMEMOTO 			nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
18733841545SHajimu UMEMOTO 			    "(wrong ip6 dst)\n"));
18882cd038dSYoshinobu Inoue 			goto bad;
18982cd038dSYoshinobu Inoue 		}
19097021c24SMarko Zec 	} else if (!V_nd6_onlink_ns_rfc4861) {
19129a6d781SColin Percival 		struct sockaddr_in6 src_sa6;
19229a6d781SColin Percival 
19329a6d781SColin Percival 		/*
19429a6d781SColin Percival 		 * According to recent IETF discussions, it is not a good idea
19529a6d781SColin Percival 		 * to accept a NS from an address which would not be deemed
19629a6d781SColin Percival 		 * to be a neighbor otherwise.  This point is expected to be
19729a6d781SColin Percival 		 * clarified in future revisions of the specification.
19829a6d781SColin Percival 		 */
19929a6d781SColin Percival 		bzero(&src_sa6, sizeof(src_sa6));
20029a6d781SColin Percival 		src_sa6.sin6_family = AF_INET6;
20129a6d781SColin Percival 		src_sa6.sin6_len = sizeof(src_sa6);
20229a6d781SColin Percival 		src_sa6.sin6_addr = saddr6;
2036e6b3f7cSQing Li 		if (nd6_is_addr_neighbor(&src_sa6, ifp) == 0) {
20429a6d781SColin Percival 			nd6log((LOG_INFO, "nd6_ns_input: "
20529a6d781SColin Percival 				"NS packet from non-neighbor\n"));
20629a6d781SColin Percival 			goto bad;
20729a6d781SColin Percival 		}
20882cd038dSYoshinobu Inoue 	}
20982cd038dSYoshinobu Inoue 
21082cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
21133841545SHajimu UMEMOTO 		nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
21282cd038dSYoshinobu Inoue 		goto bad;
21382cd038dSYoshinobu Inoue 	}
21482cd038dSYoshinobu Inoue 
21582cd038dSYoshinobu Inoue 	icmp6len -= sizeof(*nd_ns);
21682cd038dSYoshinobu Inoue 	nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
21782cd038dSYoshinobu Inoue 	if (nd6_options(&ndopts) < 0) {
21833841545SHajimu UMEMOTO 		nd6log((LOG_INFO,
21933841545SHajimu UMEMOTO 		    "nd6_ns_input: invalid ND option, ignored\n"));
22033841545SHajimu UMEMOTO 		/* nd6_options have incremented stats */
22133841545SHajimu UMEMOTO 		goto freeit;
22282cd038dSYoshinobu Inoue 	}
22382cd038dSYoshinobu Inoue 
224503f4e47SBjoern A. Zeeb 	lladdr = NULL;
225503f4e47SBjoern A. Zeeb 	lladdrlen = 0;
22682cd038dSYoshinobu Inoue 	if (ndopts.nd_opts_src_lladdr) {
22782cd038dSYoshinobu Inoue 		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
22882cd038dSYoshinobu Inoue 		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
22982cd038dSYoshinobu Inoue 	}
23082cd038dSYoshinobu Inoue 
23182cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) {
23233841545SHajimu UMEMOTO 		nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
23333841545SHajimu UMEMOTO 		    "(link-layer address option)\n"));
23482cd038dSYoshinobu Inoue 		goto bad;
23582cd038dSYoshinobu Inoue 	}
23682cd038dSYoshinobu Inoue 
23782cd038dSYoshinobu Inoue 	/*
23882cd038dSYoshinobu Inoue 	 * Attaching target link-layer address to the NA?
23982cd038dSYoshinobu Inoue 	 * (RFC 2461 7.2.4)
24082cd038dSYoshinobu Inoue 	 *
24182cd038dSYoshinobu Inoue 	 * NS IP dst is unicast/anycast			MUST NOT add
24282cd038dSYoshinobu Inoue 	 * NS IP dst is solicited-node multicast	MUST add
24382cd038dSYoshinobu Inoue 	 *
24482cd038dSYoshinobu Inoue 	 * In implementation, we add target link-layer address by default.
24582cd038dSYoshinobu Inoue 	 * We do not add one in MUST NOT cases.
24682cd038dSYoshinobu Inoue 	 */
247d6e82913SSteven Hartland 	if (!IN6_IS_ADDR_MULTICAST(&daddr6))
248d6e82913SSteven Hartland 		tlladdr = 0;
249d6e82913SSteven Hartland 	else
250d6e82913SSteven Hartland 		tlladdr = 1;
25182cd038dSYoshinobu Inoue 
25282cd038dSYoshinobu Inoue 	/*
25382cd038dSYoshinobu Inoue 	 * Target address (taddr6) must be either:
25482cd038dSYoshinobu Inoue 	 * (1) Valid unicast/anycast address for my receiving interface,
25582cd038dSYoshinobu Inoue 	 * (2) Unicast address for which I'm offering proxy service, or
25682cd038dSYoshinobu Inoue 	 * (3) "tentative" address on which DAD is being performed.
25782cd038dSYoshinobu Inoue 	 */
25882cd038dSYoshinobu Inoue 	/* (1) and (3) check. */
259a9771948SGleb Smirnoff 	if (ifp->if_carp)
26054bfbd51SWill Andrews 		ifa = (*carp_iamatch6_p)(ifp, &taddr6);
26108b68b0eSGleb Smirnoff 	else
26282cd038dSYoshinobu Inoue 		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
26382cd038dSYoshinobu Inoue 
26482cd038dSYoshinobu Inoue 	/* (2) check. */
265503f4e47SBjoern A. Zeeb 	proxy = 0;
2662ce62dceSSUZUKI Shinsuke 	if (ifa == NULL) {
267d6cd20ccSKUROSAWA Takahiro 		if ((ifa = nd6_proxy_fill_sdl(ifp, &taddr6, &proxydl)) != NULL)
26882cd038dSYoshinobu Inoue 			proxy = 1;
269686cdd19SJun-ichiro itojun Hagino 	}
2707aa59493SSUZUKI Shinsuke 	if (ifa == NULL) {
27182cd038dSYoshinobu Inoue 		/*
272496432f1SGordon Bergling 		 * We've got an NS packet, and we don't have that address
27382cd038dSYoshinobu Inoue 		 * assigned for us.  We MUST silently ignore it.
27482cd038dSYoshinobu Inoue 		 * See RFC2461 7.2.3.
27582cd038dSYoshinobu Inoue 		 */
276686cdd19SJun-ichiro itojun Hagino 		goto freeit;
27782cd038dSYoshinobu Inoue 	}
278d6e82913SSteven Hartland 	myaddr6 = *IFA_IN6(ifa);
279d6e82913SSteven Hartland 	anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
280d6e82913SSteven Hartland 	tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
28182cd038dSYoshinobu Inoue 	if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
282686cdd19SJun-ichiro itojun Hagino 		goto freeit;
28382cd038dSYoshinobu Inoue 
28482cd038dSYoshinobu Inoue 	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
28507eb2995SHajimu UMEMOTO 		nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s "
28682cd038dSYoshinobu Inoue 		    "(if %d, NS packet %d)\n",
2871d54aa3bSBjoern A. Zeeb 		    ip6_sprintf(ip6bufs, &taddr6),
28807eb2995SHajimu UMEMOTO 		    ifp->if_addrlen, lladdrlen - 2));
28933841545SHajimu UMEMOTO 		goto bad;
29082cd038dSYoshinobu Inoue 	}
29182cd038dSYoshinobu Inoue 
292d6e82913SSteven Hartland 	if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
29307eb2995SHajimu UMEMOTO 		nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
2941d54aa3bSBjoern A. Zeeb 		    ip6_sprintf(ip6bufs, &saddr6)));
295686cdd19SJun-ichiro itojun Hagino 		goto freeit;
29682cd038dSYoshinobu Inoue 	}
29782cd038dSYoshinobu Inoue 
29882cd038dSYoshinobu Inoue 	/*
29982cd038dSYoshinobu Inoue 	 * We have neighbor solicitation packet, with target address equals to
30082cd038dSYoshinobu Inoue 	 * one of my tentative address.
30182cd038dSYoshinobu Inoue 	 *
30282cd038dSYoshinobu Inoue 	 * src addr	how to process?
30382cd038dSYoshinobu Inoue 	 * ---		---
30482cd038dSYoshinobu Inoue 	 * multicast	of course, invalid (rejected in ip6_input)
30582cd038dSYoshinobu Inoue 	 * unicast	somebody is doing address resolution -> ignore
30682cd038dSYoshinobu Inoue 	 * unspec	dup address detection
30782cd038dSYoshinobu Inoue 	 *
30882cd038dSYoshinobu Inoue 	 * The processing is defined in RFC 2462.
30982cd038dSYoshinobu Inoue 	 */
310d6e82913SSteven Hartland 	if (tentative) {
31182cd038dSYoshinobu Inoue 		/*
31282cd038dSYoshinobu Inoue 		 * If source address is unspecified address, it is for
313cd0fdcf7SHajimu UMEMOTO 		 * duplicate address detection.
31482cd038dSYoshinobu Inoue 		 *
31582cd038dSYoshinobu Inoue 		 * If not, the packet is for addess resolution;
31682cd038dSYoshinobu Inoue 		 * silently ignore it.
31782cd038dSYoshinobu Inoue 		 */
31882cd038dSYoshinobu Inoue 		if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
31911d8451dSHiroki Sato 			nd6_dad_ns_input(ifa, ndopts.nd_opts_nonce);
32082cd038dSYoshinobu Inoue 
321686cdd19SJun-ichiro itojun Hagino 		goto freeit;
32282cd038dSYoshinobu Inoue 	}
32382cd038dSYoshinobu Inoue 
32482cd038dSYoshinobu Inoue 	/*
32582cd038dSYoshinobu Inoue 	 * If the source address is unspecified address, entries must not
32682cd038dSYoshinobu Inoue 	 * be created or updated.
32782cd038dSYoshinobu Inoue 	 * It looks that sender is performing DAD.  Output NA toward
32882cd038dSYoshinobu Inoue 	 * all-node multicast address, to tell the sender that I'm using
32982cd038dSYoshinobu Inoue 	 * the address.
33082cd038dSYoshinobu Inoue 	 * S bit ("solicited") must be zero.
33182cd038dSYoshinobu Inoue 	 */
33282cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
333a1f7e5f8SHajimu UMEMOTO 		struct in6_addr in6_all;
334a1f7e5f8SHajimu UMEMOTO 
335a1f7e5f8SHajimu UMEMOTO 		in6_all = in6addr_linklocal_allnodes;
336a1f7e5f8SHajimu UMEMOTO 		if (in6_setscope(&in6_all, ifp, NULL) != 0)
337a1f7e5f8SHajimu UMEMOTO 			goto bad;
338d6e82913SSteven Hartland 		nd6_na_output_fib(ifp, &in6_all, &taddr6,
339d6e82913SSteven Hartland 		    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
340d6e82913SSteven Hartland 		    rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL,
341d6e82913SSteven Hartland 		    M_GETFIB(m));
342686cdd19SJun-ichiro itojun Hagino 		goto freeit;
34382cd038dSYoshinobu Inoue 	}
34482cd038dSYoshinobu Inoue 
34507eb2995SHajimu UMEMOTO 	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
34607eb2995SHajimu UMEMOTO 	    ND_NEIGHBOR_SOLICIT, 0);
34782cd038dSYoshinobu Inoue 
348d6e82913SSteven Hartland 	nd6_na_output_fib(ifp, &saddr6, &taddr6,
349d6e82913SSteven Hartland 	    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
350d6e82913SSteven Hartland 	    rflag | ND_NA_FLAG_SOLICITED, tlladdr,
351d6e82913SSteven Hartland 	    proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
352686cdd19SJun-ichiro itojun Hagino  freeit:
3538c0fec80SRobert Watson 	if (ifa != NULL)
3548c0fec80SRobert Watson 		ifa_free(ifa);
355686cdd19SJun-ichiro itojun Hagino 	m_freem(m);
35682cd038dSYoshinobu Inoue 	return;
35782cd038dSYoshinobu Inoue 
35882cd038dSYoshinobu Inoue  bad:
3591d54aa3bSBjoern A. Zeeb 	nd6log((LOG_ERR, "nd6_ns_input: src=%s\n",
3601d54aa3bSBjoern A. Zeeb 		ip6_sprintf(ip6bufs, &saddr6)));
3611d54aa3bSBjoern A. Zeeb 	nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n",
3621d54aa3bSBjoern A. Zeeb 		ip6_sprintf(ip6bufs, &daddr6)));
3631d54aa3bSBjoern A. Zeeb 	nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n",
3641d54aa3bSBjoern A. Zeeb 		ip6_sprintf(ip6bufs, &taddr6)));
365503f4e47SBjoern A. Zeeb  bads:
366e27b0c87SRobert Watson 	ICMP6STAT_INC(icp6s_badns);
3678c0fec80SRobert Watson 	if (ifa != NULL)
3688c0fec80SRobert Watson 		ifa_free(ifa);
369686cdd19SJun-ichiro itojun Hagino 	m_freem(m);
37082cd038dSYoshinobu Inoue }
37182cd038dSYoshinobu Inoue 
372d6cd20ccSKUROSAWA Takahiro static struct ifaddr *
nd6_proxy_fill_sdl(struct ifnet * ifp,const struct in6_addr * taddr6,struct sockaddr_dl * sdl)373d6cd20ccSKUROSAWA Takahiro nd6_proxy_fill_sdl(struct ifnet *ifp, const struct in6_addr *taddr6,
374d6cd20ccSKUROSAWA Takahiro     struct sockaddr_dl *sdl)
375d6cd20ccSKUROSAWA Takahiro {
376d6cd20ccSKUROSAWA Takahiro 	struct ifaddr *ifa;
377d6cd20ccSKUROSAWA Takahiro 	struct llentry *ln;
378d6cd20ccSKUROSAWA Takahiro 
379d6cd20ccSKUROSAWA Takahiro 	ifa = NULL;
380d6cd20ccSKUROSAWA Takahiro 	ln = nd6_lookup(taddr6, LLE_SF(AF_INET6, 0), ifp);
381d6cd20ccSKUROSAWA Takahiro 	if (ln == NULL)
382d6cd20ccSKUROSAWA Takahiro 		return (ifa);
383d6cd20ccSKUROSAWA Takahiro 	if ((ln->la_flags & (LLE_PUB | LLE_VALID)) == (LLE_PUB | LLE_VALID)) {
384d6cd20ccSKUROSAWA Takahiro 		link_init_sdl(ifp, (struct sockaddr *)sdl, ifp->if_type);
385d6cd20ccSKUROSAWA Takahiro 		sdl->sdl_alen = ifp->if_addrlen;
386d6cd20ccSKUROSAWA Takahiro 		bcopy(ln->ll_addr, &sdl->sdl_data, ifp->if_addrlen);
387d6cd20ccSKUROSAWA Takahiro 		LLE_RUNLOCK(ln);
388d6cd20ccSKUROSAWA Takahiro 		ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
389d6cd20ccSKUROSAWA Takahiro 		    IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
390d6cd20ccSKUROSAWA Takahiro 	} else
391d6cd20ccSKUROSAWA Takahiro 		LLE_RUNLOCK(ln);
392d6cd20ccSKUROSAWA Takahiro 
393d6cd20ccSKUROSAWA Takahiro 	return (ifa);
394d6cd20ccSKUROSAWA Takahiro }
395d6cd20ccSKUROSAWA Takahiro 
39682cd038dSYoshinobu Inoue /*
397d64ada50SJens Schweikhardt  * Output a Neighbor Solicitation Message. Caller specifies:
39882cd038dSYoshinobu Inoue  *	- ICMP6 header source IP6 address
39982cd038dSYoshinobu Inoue  *	- ND6 header target IP6 address
40082cd038dSYoshinobu Inoue  *	- ND6 header source datalink address
40182cd038dSYoshinobu Inoue  *
40282cd038dSYoshinobu Inoue  * Based on RFC 2461
403cd0fdcf7SHajimu UMEMOTO  * Based on RFC 2462 (duplicate address detection)
4041272577eSXin LI  *
4051272577eSXin LI  *    ln - for source address determination
40611d8451dSHiroki Sato  * nonce - If non-NULL, NS is used for duplicate address detection and
40711d8451dSHiroki Sato  *         the value (length is ND_OPT_NONCE_LEN) is used as a random nonce.
40882cd038dSYoshinobu Inoue  */
4091eef8a6cSAndrey V. Elsukov static void
nd6_ns_output_fib(struct ifnet * ifp,const struct in6_addr * saddr6,const struct in6_addr * daddr6,const struct in6_addr * taddr6,uint8_t * nonce,u_int fibnum)41026deb882SAlexander V. Chernikov nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6,
41126deb882SAlexander V. Chernikov     const struct in6_addr *daddr6, const struct in6_addr *taddr6,
41226deb882SAlexander V. Chernikov     uint8_t *nonce, u_int fibnum)
41382cd038dSYoshinobu Inoue {
41482cd038dSYoshinobu Inoue 	struct mbuf *m;
4151db8d1f8SAna Kukec 	struct m_tag *mtag;
41682cd038dSYoshinobu Inoue 	struct ip6_hdr *ip6;
41782cd038dSYoshinobu Inoue 	struct nd_neighbor_solicit *nd_ns;
41882cd038dSYoshinobu Inoue 	struct ip6_moptions im6o;
41982cd038dSYoshinobu Inoue 	int icmp6len;
420686cdd19SJun-ichiro itojun Hagino 	int maxlen;
421a1f7e5f8SHajimu UMEMOTO 
422605284b8SAlexander V. Chernikov 	NET_EPOCH_ASSERT();
423605284b8SAlexander V. Chernikov 
42482cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_MULTICAST(taddr6))
42582cd038dSYoshinobu Inoue 		return;
42682cd038dSYoshinobu Inoue 
427686cdd19SJun-ichiro itojun Hagino 	/* estimate the size of message */
428686cdd19SJun-ichiro itojun Hagino 	maxlen = sizeof(*ip6) + sizeof(*nd_ns);
429686cdd19SJun-ichiro itojun Hagino 	maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
430efb19cf6SAndrey V. Elsukov 	KASSERT(max_linkhdr + maxlen <= MCLBYTES, (
431efb19cf6SAndrey V. Elsukov 	    "%s: max_linkhdr + maxlen > MCLBYTES (%d + %d > %d)",
432efb19cf6SAndrey V. Elsukov 	    __func__, max_linkhdr, maxlen, MCLBYTES));
433686cdd19SJun-ichiro itojun Hagino 
43410e5acc3SGleb Smirnoff 	if (max_linkhdr + maxlen > MHLEN)
43510e5acc3SGleb Smirnoff 		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
43610e5acc3SGleb Smirnoff 	else
43710e5acc3SGleb Smirnoff 		m = m_gethdr(M_NOWAIT, MT_DATA);
438686cdd19SJun-ichiro itojun Hagino 	if (m == NULL)
43982cd038dSYoshinobu Inoue 		return;
4401eef8a6cSAndrey V. Elsukov 	M_SETFIB(m, fibnum);
44182cd038dSYoshinobu Inoue 
44282cd038dSYoshinobu Inoue 	if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
44382cd038dSYoshinobu Inoue 		m->m_flags |= M_MCAST;
44482cd038dSYoshinobu Inoue 		im6o.im6o_multicast_ifp = ifp;
44582cd038dSYoshinobu Inoue 		im6o.im6o_multicast_hlim = 255;
44682cd038dSYoshinobu Inoue 		im6o.im6o_multicast_loop = 0;
44782cd038dSYoshinobu Inoue 	}
44882cd038dSYoshinobu Inoue 
44982cd038dSYoshinobu Inoue 	icmp6len = sizeof(*nd_ns);
45082cd038dSYoshinobu Inoue 	m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
451ed6a66caSRobert Watson 	m->m_data += max_linkhdr;	/* or M_ALIGN() equivalent? */
45282cd038dSYoshinobu Inoue 
45382cd038dSYoshinobu Inoue 	/* fill neighbor solicitation packet */
45482cd038dSYoshinobu Inoue 	ip6 = mtod(m, struct ip6_hdr *);
45582cd038dSYoshinobu Inoue 	ip6->ip6_flow = 0;
456686cdd19SJun-ichiro itojun Hagino 	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
457686cdd19SJun-ichiro itojun Hagino 	ip6->ip6_vfc |= IPV6_VERSION;
45882cd038dSYoshinobu Inoue 	/* ip6->ip6_plen will be set later */
45982cd038dSYoshinobu Inoue 	ip6->ip6_nxt = IPPROTO_ICMPV6;
46082cd038dSYoshinobu Inoue 	ip6->ip6_hlim = 255;
46182cd038dSYoshinobu Inoue 	if (daddr6)
46282cd038dSYoshinobu Inoue 		ip6->ip6_dst = *daddr6;
46382cd038dSYoshinobu Inoue 	else {
46482cd038dSYoshinobu Inoue 		ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
465a1f7e5f8SHajimu UMEMOTO 		ip6->ip6_dst.s6_addr16[1] = 0;
46682cd038dSYoshinobu Inoue 		ip6->ip6_dst.s6_addr32[1] = 0;
46782cd038dSYoshinobu Inoue 		ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
46882cd038dSYoshinobu Inoue 		ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3];
46982cd038dSYoshinobu Inoue 		ip6->ip6_dst.s6_addr8[12] = 0xff;
470a1f7e5f8SHajimu UMEMOTO 		if (in6_setscope(&ip6->ip6_dst, ifp, NULL) != 0)
471a1f7e5f8SHajimu UMEMOTO 			goto bad;
47282cd038dSYoshinobu Inoue 	}
47311d8451dSHiroki Sato 	if (nonce == NULL) {
474ccd69bd5SAndrey V. Elsukov 		char ip6buf[INET6_ADDRSTRLEN];
47526deb882SAlexander V. Chernikov 		struct ifaddr *ifa = NULL;
4768c0fec80SRobert Watson 
47782cd038dSYoshinobu Inoue 		/*
47882cd038dSYoshinobu Inoue 		 * RFC2461 7.2.2:
47982cd038dSYoshinobu Inoue 		 * "If the source address of the packet prompting the
48082cd038dSYoshinobu Inoue 		 * solicitation is the same as one of the addresses assigned
48182cd038dSYoshinobu Inoue 		 * to the outgoing interface, that address SHOULD be placed
48282cd038dSYoshinobu Inoue 		 * in the IP Source Address of the outgoing solicitation.
48382cd038dSYoshinobu Inoue 		 * Otherwise, any one of the addresses assigned to the
48482cd038dSYoshinobu Inoue 		 * interface should be used."
48582cd038dSYoshinobu Inoue 		 *
48682cd038dSYoshinobu Inoue 		 * We use the source address for the prompting packet
48726deb882SAlexander V. Chernikov 		 * (saddr6), if saddr6 belongs to the outgoing interface.
488a1f7e5f8SHajimu UMEMOTO 		 * Otherwise, we perform the source address selection as usual.
48982cd038dSYoshinobu Inoue 		 */
49026deb882SAlexander V. Chernikov 		if (saddr6 != NULL)
49126deb882SAlexander V. Chernikov 			ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, saddr6);
492ccd69bd5SAndrey V. Elsukov 		if (ifa == NULL) {
493a1f7e5f8SHajimu UMEMOTO 			int error;
494601c0b8bSAlexander V. Chernikov 			struct in6_addr dst6, src6;
495601c0b8bSAlexander V. Chernikov 			uint32_t scopeid;
496a1f7e5f8SHajimu UMEMOTO 
497601c0b8bSAlexander V. Chernikov 			in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid);
498559b4296SAlan Somers 			error = in6_selectsrc_addr(fibnum, &dst6,
499601c0b8bSAlexander V. Chernikov 			    scopeid, ifp, &src6, NULL);
50088d166bfSBjoern A. Zeeb 			if (error) {
5011eef8a6cSAndrey V. Elsukov 				nd6log((LOG_DEBUG, "%s: source can't be "
5021eef8a6cSAndrey V. Elsukov 				    "determined: dst=%s, error=%d\n", __func__,
503601c0b8bSAlexander V. Chernikov 				    ip6_sprintf(ip6buf, &dst6),
5041d54aa3bSBjoern A. Zeeb 				    error));
505a1f7e5f8SHajimu UMEMOTO 				goto bad;
506a1f7e5f8SHajimu UMEMOTO 			}
507601c0b8bSAlexander V. Chernikov 			ip6->ip6_src = src6;
508ccd69bd5SAndrey V. Elsukov 		} else
509ccd69bd5SAndrey V. Elsukov 			ip6->ip6_src = *saddr6;
510ccd69bd5SAndrey V. Elsukov 
511ccd69bd5SAndrey V. Elsukov 		if (ifp->if_carp != NULL) {
512ccd69bd5SAndrey V. Elsukov 			/*
513ccd69bd5SAndrey V. Elsukov 			 * Check that selected source address belongs to
514ccd69bd5SAndrey V. Elsukov 			 * CARP addresses.
515ccd69bd5SAndrey V. Elsukov 			 */
516ccd69bd5SAndrey V. Elsukov 			if (ifa == NULL)
517ccd69bd5SAndrey V. Elsukov 				ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
518ccd69bd5SAndrey V. Elsukov 				    &ip6->ip6_src);
519ccd69bd5SAndrey V. Elsukov 			/*
520ccd69bd5SAndrey V. Elsukov 			 * Do not send NS for CARP address if we are not
521ccd69bd5SAndrey V. Elsukov 			 * the CARP master.
522ccd69bd5SAndrey V. Elsukov 			 */
523a3da8329SGleb Smirnoff 			if (ifa != NULL && ifa->ifa_carp != NULL &&
524a3da8329SGleb Smirnoff 			    !(*carp_master_p)(ifa)) {
5250cd2d88dSAndrey V. Elsukov 				nd6log((LOG_DEBUG,
526ccd69bd5SAndrey V. Elsukov 				    "nd6_ns_output: NS from BACKUP CARP address %s\n",
5270cd2d88dSAndrey V. Elsukov 				    ip6_sprintf(ip6buf, &ip6->ip6_src)));
528ccd69bd5SAndrey V. Elsukov 				ifa_free(ifa);
529ccd69bd5SAndrey V. Elsukov 				goto bad;
53082cd038dSYoshinobu Inoue 			}
531ccd69bd5SAndrey V. Elsukov 		}
532ccd69bd5SAndrey V. Elsukov 		if (ifa != NULL)
533ccd69bd5SAndrey V. Elsukov 			ifa_free(ifa);
53482cd038dSYoshinobu Inoue 	} else {
53582cd038dSYoshinobu Inoue 		/*
53682cd038dSYoshinobu Inoue 		 * Source address for DAD packet must always be IPv6
53782cd038dSYoshinobu Inoue 		 * unspecified address. (0::0)
538a1f7e5f8SHajimu UMEMOTO 		 * We actually don't have to 0-clear the address (we did it
539a1f7e5f8SHajimu UMEMOTO 		 * above), but we do so here explicitly to make the intention
540a1f7e5f8SHajimu UMEMOTO 		 * clearer.
54182cd038dSYoshinobu Inoue 		 */
542e6950476SBjoern A. Zeeb 		bzero(&ip6->ip6_src, sizeof(ip6->ip6_src));
54382cd038dSYoshinobu Inoue 	}
54482cd038dSYoshinobu Inoue 	nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1);
54582cd038dSYoshinobu Inoue 	nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
54682cd038dSYoshinobu Inoue 	nd_ns->nd_ns_code = 0;
54782cd038dSYoshinobu Inoue 	nd_ns->nd_ns_reserved = 0;
54882cd038dSYoshinobu Inoue 	nd_ns->nd_ns_target = *taddr6;
5499a4f9608SHajimu UMEMOTO 	in6_clearscope(&nd_ns->nd_ns_target); /* XXX */
55082cd038dSYoshinobu Inoue 
55182cd038dSYoshinobu Inoue 	/*
55282cd038dSYoshinobu Inoue 	 * Add source link-layer address option.
55382cd038dSYoshinobu Inoue 	 *
55482cd038dSYoshinobu Inoue 	 *				spec		implementation
55582cd038dSYoshinobu Inoue 	 *				---		---
55682cd038dSYoshinobu Inoue 	 * DAD packet			MUST NOT	do not add the option
55782cd038dSYoshinobu Inoue 	 * there's no link layer address:
55882cd038dSYoshinobu Inoue 	 *				impossible	do not add the option
55982cd038dSYoshinobu Inoue 	 * there's link layer address:
56082cd038dSYoshinobu Inoue 	 *	Multicast NS		MUST add one	add the option
56182cd038dSYoshinobu Inoue 	 *	Unicast NS		SHOULD add one	add the option
56282cd038dSYoshinobu Inoue 	 */
563bc6abdd9SThomas Steen Rasmussen 	if (nonce == NULL) {
564bc6abdd9SThomas Steen Rasmussen 		struct nd_opt_hdr *nd_opt;
565bc6abdd9SThomas Steen Rasmussen 		char *mac;
566bc6abdd9SThomas Steen Rasmussen 		int optlen;
567bc6abdd9SThomas Steen Rasmussen 
568bc6abdd9SThomas Steen Rasmussen 		mac = NULL;
569bc6abdd9SThomas Steen Rasmussen 		if (ifp->if_carp)
570bc6abdd9SThomas Steen Rasmussen 			mac = (*carp_macmatch6_p)(ifp, m, &ip6->ip6_src);
571bc6abdd9SThomas Steen Rasmussen 		if (mac == NULL)
572bc6abdd9SThomas Steen Rasmussen 			mac = nd6_ifptomac(ifp);
573bc6abdd9SThomas Steen Rasmussen 
574bc6abdd9SThomas Steen Rasmussen 		if (mac != NULL) {
575bc6abdd9SThomas Steen Rasmussen 			nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
576bc6abdd9SThomas Steen Rasmussen 			optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
57782cd038dSYoshinobu Inoue 			/* 8 byte alignments... */
57882cd038dSYoshinobu Inoue 			optlen = (optlen + 7) & ~7;
57982cd038dSYoshinobu Inoue 			m->m_pkthdr.len += optlen;
58082cd038dSYoshinobu Inoue 			m->m_len += optlen;
58182cd038dSYoshinobu Inoue 			icmp6len += optlen;
582bc6abdd9SThomas Steen Rasmussen 			bzero(nd_opt, optlen);
58382cd038dSYoshinobu Inoue 			nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
58482cd038dSYoshinobu Inoue 			nd_opt->nd_opt_len = optlen >> 3;
585bc6abdd9SThomas Steen Rasmussen 			bcopy(mac, nd_opt + 1, ifp->if_addrlen);
586bc6abdd9SThomas Steen Rasmussen 		}
58782cd038dSYoshinobu Inoue 	}
58811d8451dSHiroki Sato 	/*
58911d8451dSHiroki Sato 	 * Add a Nonce option (RFC 3971) to detect looped back NS messages.
59011d8451dSHiroki Sato 	 * This behavior is documented as Enhanced Duplicate Address
591fb583bd2SHiroki Sato 	 * Detection in RFC 7527.
59211d8451dSHiroki Sato 	 * net.inet6.ip6.dad_enhanced=0 disables this.
59311d8451dSHiroki Sato 	 */
59411d8451dSHiroki Sato 	if (V_dad_enhanced != 0 && nonce != NULL) {
59511d8451dSHiroki Sato 		int optlen = sizeof(struct nd_opt_hdr) + ND_OPT_NONCE_LEN;
59611d8451dSHiroki Sato 		struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
59711d8451dSHiroki Sato 		/* 8-byte alignment is required. */
59811d8451dSHiroki Sato 		optlen = (optlen + 7) & ~7;
59982cd038dSYoshinobu Inoue 
60011d8451dSHiroki Sato 		m->m_pkthdr.len += optlen;
60111d8451dSHiroki Sato 		m->m_len += optlen;
60211d8451dSHiroki Sato 		icmp6len += optlen;
60311d8451dSHiroki Sato 		bzero((caddr_t)nd_opt, optlen);
60411d8451dSHiroki Sato 		nd_opt->nd_opt_type = ND_OPT_NONCE;
60511d8451dSHiroki Sato 		nd_opt->nd_opt_len = optlen >> 3;
60611d8451dSHiroki Sato 		bcopy(nonce, (caddr_t)(nd_opt + 1), ND_OPT_NONCE_LEN);
60711d8451dSHiroki Sato 	}
60882cd038dSYoshinobu Inoue 	ip6->ip6_plen = htons((u_short)icmp6len);
60982cd038dSYoshinobu Inoue 	nd_ns->nd_ns_cksum = 0;
61007eb2995SHajimu UMEMOTO 	nd_ns->nd_ns_cksum =
61107eb2995SHajimu UMEMOTO 	    in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
61282cd038dSYoshinobu Inoue 
6131db8d1f8SAna Kukec 	if (send_sendso_input_hook != NULL) {
6141db8d1f8SAna Kukec 		mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
6151db8d1f8SAna Kukec 			sizeof(unsigned short), M_NOWAIT);
6161db8d1f8SAna Kukec 		if (mtag == NULL)
6171db8d1f8SAna Kukec 			goto bad;
6181db8d1f8SAna Kukec 		*(unsigned short *)(mtag + 1) = nd_ns->nd_ns_type;
6191db8d1f8SAna Kukec 		m_tag_prepend(m, mtag);
6201db8d1f8SAna Kukec 	}
6211db8d1f8SAna Kukec 
622357ce739SAlexander V. Chernikov 	ip6_output(m, NULL, NULL, (nonce != NULL) ? IPV6_UNSPECSRC : 0,
62311d8451dSHiroki Sato 	    &im6o, NULL, NULL);
624a1f7e5f8SHajimu UMEMOTO 	icmp6_ifstat_inc(ifp, ifs6_out_msg);
625a1f7e5f8SHajimu UMEMOTO 	icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit);
626*60d8dbbeSKristof Provost 	ICMP6STAT_INC2(icp6s_outhist, ND_NEIGHBOR_SOLICIT);
627a1f7e5f8SHajimu UMEMOTO 
628a1f7e5f8SHajimu UMEMOTO 	return;
629a1f7e5f8SHajimu UMEMOTO 
630a1f7e5f8SHajimu UMEMOTO   bad:
631a1f7e5f8SHajimu UMEMOTO 	m_freem(m);
63282cd038dSYoshinobu Inoue }
63382cd038dSYoshinobu Inoue 
6341eef8a6cSAndrey V. Elsukov #ifndef BURN_BRIDGES
6351eef8a6cSAndrey V. Elsukov void
nd6_ns_output(struct ifnet * ifp,const struct in6_addr * saddr6,const struct in6_addr * daddr6,const struct in6_addr * taddr6,uint8_t * nonce)63626deb882SAlexander V. Chernikov nd6_ns_output(struct ifnet *ifp, const struct in6_addr *saddr6,
63726deb882SAlexander V. Chernikov     const struct in6_addr *daddr6, const struct in6_addr *taddr6,uint8_t *nonce)
6381eef8a6cSAndrey V. Elsukov {
6391eef8a6cSAndrey V. Elsukov 
64026deb882SAlexander V. Chernikov 	nd6_ns_output_fib(ifp, saddr6, daddr6, taddr6, nonce, RT_DEFAULT_FIB);
6411eef8a6cSAndrey V. Elsukov }
6421eef8a6cSAndrey V. Elsukov #endif
64382cd038dSYoshinobu Inoue /*
64482cd038dSYoshinobu Inoue  * Neighbor advertisement input handling.
64582cd038dSYoshinobu Inoue  *
64682cd038dSYoshinobu Inoue  * Based on RFC 2461
647cd0fdcf7SHajimu UMEMOTO  * Based on RFC 2462 (duplicate address detection)
648686cdd19SJun-ichiro itojun Hagino  *
649686cdd19SJun-ichiro itojun Hagino  * the following items are not implemented yet:
650686cdd19SJun-ichiro itojun Hagino  * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
651686cdd19SJun-ichiro itojun Hagino  * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
65282cd038dSYoshinobu Inoue  */
65382cd038dSYoshinobu Inoue void
nd6_na_input(struct mbuf * m,int off,int icmp6len)6541272577eSXin LI nd6_na_input(struct mbuf *m, int off, int icmp6len)
65582cd038dSYoshinobu Inoue {
656503f4e47SBjoern A. Zeeb 	struct ifnet *ifp;
657503f4e47SBjoern A. Zeeb 	struct ip6_hdr *ip6;
65882cd038dSYoshinobu Inoue 	struct ifaddr *ifa;
659503f4e47SBjoern A. Zeeb 	struct llentry *ln;
660503f4e47SBjoern A. Zeeb 	struct mbuf *chain;
661503f4e47SBjoern A. Zeeb 	struct nd_neighbor_advert *nd_na;
662503f4e47SBjoern A. Zeeb 	struct in6_addr daddr6, taddr6;
663503f4e47SBjoern A. Zeeb 	union nd_opts ndopts;
6644fb3a820SAlexander V. Chernikov 	u_char linkhdr[LLE_MAX_LINKHDR];
6651d54aa3bSBjoern A. Zeeb 	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
666503f4e47SBjoern A. Zeeb 	char *lladdr;
667503f4e47SBjoern A. Zeeb 	size_t linkhdrsize;
668503f4e47SBjoern A. Zeeb 	int flags, is_override, is_router, is_solicited;
669503f4e47SBjoern A. Zeeb 	int lladdr_off, lladdrlen, checklink;
670c541bd36SAlexander V. Chernikov 	bool flush_holdchain = false;
67182cd038dSYoshinobu Inoue 
672b8a6e03fSGleb Smirnoff 	NET_EPOCH_ASSERT();
673b8a6e03fSGleb Smirnoff 
674503f4e47SBjoern A. Zeeb 	chain = NULL;
675503f4e47SBjoern A. Zeeb 	ln = NULL;
676503f4e47SBjoern A. Zeeb 	checklink = 0;
677503f4e47SBjoern A. Zeeb 
678a4061289SAndrey V. Elsukov 	/* RFC 6980: Nodes MUST silently ignore fragments */
679a4061289SAndrey V. Elsukov 	if(m->m_flags & M_FRAGMENTED)
680a4061289SAndrey V. Elsukov 		goto freeit;
681a4061289SAndrey V. Elsukov 
682503f4e47SBjoern A. Zeeb 	ifp = m->m_pkthdr.rcvif;
683503f4e47SBjoern A. Zeeb 	ip6 = mtod(m, struct ip6_hdr *);
6844caea9b1SMark Johnston 	if (__predict_false(ip6->ip6_hlim != 255)) {
6854caea9b1SMark Johnston 		ICMP6STAT_INC(icp6s_invlhlim);
68633841545SHajimu UMEMOTO 		nd6log((LOG_ERR,
68733841545SHajimu UMEMOTO 		    "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n",
6881d54aa3bSBjoern A. Zeeb 		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
6891d54aa3bSBjoern A. Zeeb 		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
69033841545SHajimu UMEMOTO 		goto bad;
691686cdd19SJun-ichiro itojun Hagino 	}
692686cdd19SJun-ichiro itojun Hagino 
693a4adf6ccSBjoern A. Zeeb 	if (m->m_len < off + icmp6len) {
694a61b5cfbSBjoern A. Zeeb 		m = m_pullup(m, off + icmp6len);
695a61b5cfbSBjoern A. Zeeb 		if (m == NULL) {
696a61b5cfbSBjoern A. Zeeb 			IP6STAT_INC(ip6s_exthdrtoolong);
69782cd038dSYoshinobu Inoue 			return;
69882cd038dSYoshinobu Inoue 		}
699a4adf6ccSBjoern A. Zeeb 	}
700a61b5cfbSBjoern A. Zeeb 	ip6 = mtod(m, struct ip6_hdr *);
701a61b5cfbSBjoern A. Zeeb 	nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
702a1f7e5f8SHajimu UMEMOTO 
703686cdd19SJun-ichiro itojun Hagino 	flags = nd_na->nd_na_flags_reserved;
704686cdd19SJun-ichiro itojun Hagino 	is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
705686cdd19SJun-ichiro itojun Hagino 	is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
706686cdd19SJun-ichiro itojun Hagino 	is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
70782cd038dSYoshinobu Inoue 
708a1f7e5f8SHajimu UMEMOTO 	taddr6 = nd_na->nd_na_target;
709a1f7e5f8SHajimu UMEMOTO 	if (in6_setscope(&taddr6, ifp, NULL))
7109689258fSSUZUKI Shinsuke 		goto bad;	/* XXX: impossible */
71182cd038dSYoshinobu Inoue 
71282cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
71333841545SHajimu UMEMOTO 		nd6log((LOG_ERR,
71482cd038dSYoshinobu Inoue 		    "nd6_na_input: invalid target address %s\n",
7151d54aa3bSBjoern A. Zeeb 		    ip6_sprintf(ip6bufs, &taddr6)));
71633841545SHajimu UMEMOTO 		goto bad;
71782cd038dSYoshinobu Inoue 	}
718503f4e47SBjoern A. Zeeb 
719503f4e47SBjoern A. Zeeb 	daddr6 = ip6->ip6_dst;
72082cd038dSYoshinobu Inoue 	if (IN6_IS_ADDR_MULTICAST(&daddr6))
72182cd038dSYoshinobu Inoue 		if (is_solicited) {
72233841545SHajimu UMEMOTO 			nd6log((LOG_ERR,
72333841545SHajimu UMEMOTO 			    "nd6_na_input: a solicited adv is multicasted\n"));
72433841545SHajimu UMEMOTO 			goto bad;
72582cd038dSYoshinobu Inoue 		}
72682cd038dSYoshinobu Inoue 
72782cd038dSYoshinobu Inoue 	icmp6len -= sizeof(*nd_na);
72882cd038dSYoshinobu Inoue 	nd6_option_init(nd_na + 1, icmp6len, &ndopts);
72982cd038dSYoshinobu Inoue 	if (nd6_options(&ndopts) < 0) {
73033841545SHajimu UMEMOTO 		nd6log((LOG_INFO,
73133841545SHajimu UMEMOTO 		    "nd6_na_input: invalid ND option, ignored\n"));
73233841545SHajimu UMEMOTO 		/* nd6_options have incremented stats */
733686cdd19SJun-ichiro itojun Hagino 		goto freeit;
73482cd038dSYoshinobu Inoue 	}
73582cd038dSYoshinobu Inoue 
736503f4e47SBjoern A. Zeeb 	lladdr = NULL;
737503f4e47SBjoern A. Zeeb 	lladdrlen = 0;
73882cd038dSYoshinobu Inoue 	if (ndopts.nd_opts_tgt_lladdr) {
73982cd038dSYoshinobu Inoue 		lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
74082cd038dSYoshinobu Inoue 		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
74182cd038dSYoshinobu Inoue 	}
74282cd038dSYoshinobu Inoue 
74382cd038dSYoshinobu Inoue 	ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
744ccd69bd5SAndrey V. Elsukov 	if (ifa != NULL && ifa->ifa_carp != NULL) {
745ccd69bd5SAndrey V. Elsukov 		/*
746ccd69bd5SAndrey V. Elsukov 		 * Silently ignore NAs for CARP addresses if we are not
747ccd69bd5SAndrey V. Elsukov 		 * the CARP master.
748ccd69bd5SAndrey V. Elsukov 		 */
749ccd69bd5SAndrey V. Elsukov 		if (!(*carp_master_p)(ifa)) {
7500cd2d88dSAndrey V. Elsukov 			nd6log((LOG_DEBUG,
751ccd69bd5SAndrey V. Elsukov 			    "nd6_na_input: NA for BACKUP CARP address %s\n",
7520cd2d88dSAndrey V. Elsukov 			    ip6_sprintf(ip6bufs, &taddr6)));
753ccd69bd5SAndrey V. Elsukov 			ifa_free(ifa);
754ccd69bd5SAndrey V. Elsukov 			goto freeit;
755ccd69bd5SAndrey V. Elsukov 		}
756ccd69bd5SAndrey V. Elsukov 	}
75782cd038dSYoshinobu Inoue 	/*
75882cd038dSYoshinobu Inoue 	 * Target address matches one of my interface address.
75982cd038dSYoshinobu Inoue 	 *
76082cd038dSYoshinobu Inoue 	 * If my address is tentative, this means that there's somebody
76182cd038dSYoshinobu Inoue 	 * already using the same address as mine.  This indicates DAD failure.
76282cd038dSYoshinobu Inoue 	 * This is defined in RFC 2462.
76382cd038dSYoshinobu Inoue 	 *
76482cd038dSYoshinobu Inoue 	 * Otherwise, process as defined in RFC 2461.
76582cd038dSYoshinobu Inoue 	 */
76682cd038dSYoshinobu Inoue 	if (ifa
76782cd038dSYoshinobu Inoue 	 && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
76882cd038dSYoshinobu Inoue 		nd6_dad_na_input(ifa);
769ff9f2a36SAndrey V. Elsukov 		ifa_free(ifa);
770686cdd19SJun-ichiro itojun Hagino 		goto freeit;
77182cd038dSYoshinobu Inoue 	}
77282cd038dSYoshinobu Inoue 
77388ff5695SSUZUKI Shinsuke 	/* Just for safety, maybe unnecessary. */
77482cd038dSYoshinobu Inoue 	if (ifa) {
7758c0fec80SRobert Watson 		ifa_free(ifa);
77682cd038dSYoshinobu Inoue 		log(LOG_ERR,
77782cd038dSYoshinobu Inoue 		    "nd6_na_input: duplicate IP6 address %s\n",
7781d54aa3bSBjoern A. Zeeb 		    ip6_sprintf(ip6bufs, &taddr6));
779686cdd19SJun-ichiro itojun Hagino 		goto freeit;
78082cd038dSYoshinobu Inoue 	}
78182cd038dSYoshinobu Inoue 
78282cd038dSYoshinobu Inoue 	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
78307eb2995SHajimu UMEMOTO 		nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s "
7841d54aa3bSBjoern A. Zeeb 		    "(if %d, NA packet %d)\n", ip6_sprintf(ip6bufs, &taddr6),
78507eb2995SHajimu UMEMOTO 		    ifp->if_addrlen, lladdrlen - 2));
78633841545SHajimu UMEMOTO 		goto bad;
78782cd038dSYoshinobu Inoue 	}
78882cd038dSYoshinobu Inoue 
78982cd038dSYoshinobu Inoue 	/*
79007eb2995SHajimu UMEMOTO 	 * If no neighbor cache entry is found, NA SHOULD silently be
79107eb2995SHajimu UMEMOTO 	 * discarded.
79282cd038dSYoshinobu Inoue 	 */
793c541bd36SAlexander V. Chernikov 	ln = nd6_lookup(&taddr6, LLE_SF(AF_INET6, LLE_EXCLUSIVE), ifp);
7946e6b3f7cSQing Li 	if (ln == NULL) {
795686cdd19SJun-ichiro itojun Hagino 		goto freeit;
7966e6b3f7cSQing Li 	}
79782cd038dSYoshinobu Inoue 
798cfad7696SAndrey V. Elsukov 	/*
799cfad7696SAndrey V. Elsukov 	 * Do not try to override static entry.
800cfad7696SAndrey V. Elsukov 	 */
801cfad7696SAndrey V. Elsukov 	if (ln->la_flags & LLE_STATIC)
802cfad7696SAndrey V. Elsukov 		goto freeit;
803cfad7696SAndrey V. Elsukov 
80482cd038dSYoshinobu Inoue 	if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
80582cd038dSYoshinobu Inoue 		/*
80682cd038dSYoshinobu Inoue 		 * If the link-layer has address, and no lladdr option came,
80782cd038dSYoshinobu Inoue 		 * discard the packet.
80882cd038dSYoshinobu Inoue 		 */
8096e6b3f7cSQing Li 		if (ifp->if_addrlen && lladdr == NULL) {
810686cdd19SJun-ichiro itojun Hagino 			goto freeit;
8116e6b3f7cSQing Li 		}
81282cd038dSYoshinobu Inoue 
81382cd038dSYoshinobu Inoue 		/*
81482cd038dSYoshinobu Inoue 		 * Record link-layer address, and update the state.
81582cd038dSYoshinobu Inoue 		 */
8160b79b007SAlexander V. Chernikov 		if (!nd6_try_set_entry_addr(ifp, ln, lladdr))
81712cb7521SAlexander V. Chernikov 			goto freeit;
8180b79b007SAlexander V. Chernikov 
819c541bd36SAlexander V. Chernikov 		flush_holdchain = true;
8201558cb24SAlexander V. Chernikov 		if (is_solicited)
821aa5f023eSAlexander V. Chernikov 			nd6_llinfo_setstate(ln, ND6_LLINFO_REACHABLE);
8221558cb24SAlexander V. Chernikov 		else
823aa5f023eSAlexander V. Chernikov 			nd6_llinfo_setstate(ln, ND6_LLINFO_STALE);
824db98b420SAlexander V. Chernikov 		EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED);
82533841545SHajimu UMEMOTO 		if ((ln->ln_router = is_router) != 0) {
82633841545SHajimu UMEMOTO 			/*
82733841545SHajimu UMEMOTO 			 * This means a router's state has changed from
82833841545SHajimu UMEMOTO 			 * non-reachable to probably reachable, and might
82933841545SHajimu UMEMOTO 			 * affect the status of associated prefixes..
83033841545SHajimu UMEMOTO 			 */
831ee6326a3SKip Macy 			checklink = 1;
83233841545SHajimu UMEMOTO 		}
83382cd038dSYoshinobu Inoue 	} else {
83482cd038dSYoshinobu Inoue 		int llchange;
83582cd038dSYoshinobu Inoue 
83682cd038dSYoshinobu Inoue 		/*
83782cd038dSYoshinobu Inoue 		 * Check if the link-layer address has changed or not.
83882cd038dSYoshinobu Inoue 		 */
8392ce62dceSSUZUKI Shinsuke 		if (lladdr == NULL)
84082cd038dSYoshinobu Inoue 			llchange = 0;
84182cd038dSYoshinobu Inoue 		else {
8426e6b3f7cSQing Li 			if (ln->la_flags & LLE_VALID) {
8434fb3a820SAlexander V. Chernikov 				if (bcmp(lladdr, ln->ll_addr, ifp->if_addrlen))
84482cd038dSYoshinobu Inoue 					llchange = 1;
84582cd038dSYoshinobu Inoue 				else
84682cd038dSYoshinobu Inoue 					llchange = 0;
84782cd038dSYoshinobu Inoue 			} else
84882cd038dSYoshinobu Inoue 				llchange = 1;
84982cd038dSYoshinobu Inoue 		}
85082cd038dSYoshinobu Inoue 
85182cd038dSYoshinobu Inoue 		/*
85282cd038dSYoshinobu Inoue 		 * This is VERY complex.  Look at it with care.
85382cd038dSYoshinobu Inoue 		 *
85482cd038dSYoshinobu Inoue 		 * override solicit lladdr llchange	action
85582cd038dSYoshinobu Inoue 		 *					(L: record lladdr)
85682cd038dSYoshinobu Inoue 		 *
85782cd038dSYoshinobu Inoue 		 *	0	0	n	--	(2c)
85882cd038dSYoshinobu Inoue 		 *	0	0	y	n	(2b) L
85982cd038dSYoshinobu Inoue 		 *	0	0	y	y	(1)    REACHABLE->STALE
86082cd038dSYoshinobu Inoue 		 *	0	1	n	--	(2c)   *->REACHABLE
86182cd038dSYoshinobu Inoue 		 *	0	1	y	n	(2b) L *->REACHABLE
86282cd038dSYoshinobu Inoue 		 *	0	1	y	y	(1)    REACHABLE->STALE
86382cd038dSYoshinobu Inoue 		 *	1	0	n	--	(2a)
86482cd038dSYoshinobu Inoue 		 *	1	0	y	n	(2a) L
86582cd038dSYoshinobu Inoue 		 *	1	0	y	y	(2a) L *->STALE
86682cd038dSYoshinobu Inoue 		 *	1	1	n	--	(2a)   *->REACHABLE
86782cd038dSYoshinobu Inoue 		 *	1	1	y	n	(2a) L *->REACHABLE
86882cd038dSYoshinobu Inoue 		 *	1	1	y	y	(2a) L *->REACHABLE
86982cd038dSYoshinobu Inoue 		 */
8702ce62dceSSUZUKI Shinsuke 		if (!is_override && (lladdr != NULL && llchange)) {  /* (1) */
87182cd038dSYoshinobu Inoue 			/*
87282cd038dSYoshinobu Inoue 			 * If state is REACHABLE, make it STALE.
87382cd038dSYoshinobu Inoue 			 * no other updates should be done.
87482cd038dSYoshinobu Inoue 			 */
875aa5f023eSAlexander V. Chernikov 			if (ln->ln_state == ND6_LLINFO_REACHABLE)
876aa5f023eSAlexander V. Chernikov 				nd6_llinfo_setstate(ln, ND6_LLINFO_STALE);
877686cdd19SJun-ichiro itojun Hagino 			goto freeit;
87882cd038dSYoshinobu Inoue 		} else if (is_override				   /* (2a) */
8792ce62dceSSUZUKI Shinsuke 			|| (!is_override && (lladdr != NULL && !llchange)) /* (2b) */
8802ce62dceSSUZUKI Shinsuke 			|| lladdr == NULL) {			   /* (2c) */
88182cd038dSYoshinobu Inoue 			/*
88282cd038dSYoshinobu Inoue 			 * Update link-local address, if any.
88382cd038dSYoshinobu Inoue 			 */
8842ce62dceSSUZUKI Shinsuke 			if (lladdr != NULL) {
8854fb3a820SAlexander V. Chernikov 				linkhdrsize = sizeof(linkhdr);
8864fb3a820SAlexander V. Chernikov 				if (lltable_calc_llheader(ifp, AF_INET6, lladdr,
8874fb3a820SAlexander V. Chernikov 				    linkhdr, &linkhdrsize, &lladdr_off) != 0)
8884fb3a820SAlexander V. Chernikov 					goto freeit;
8894fb3a820SAlexander V. Chernikov 				if (lltable_try_set_entry_addr(ifp, ln, linkhdr,
890dd91d844SMark Johnston 				    linkhdrsize, lladdr_off) == 0)
89112cb7521SAlexander V. Chernikov 					goto freeit;
89263a97a40SNavdeep Parhar 				EVENTHANDLER_INVOKE(lle_event, ln,
89363a97a40SNavdeep Parhar 				    LLENTRY_RESOLVED);
89482cd038dSYoshinobu Inoue 			}
89582cd038dSYoshinobu Inoue 
89682cd038dSYoshinobu Inoue 			/*
89782cd038dSYoshinobu Inoue 			 * If solicited, make the state REACHABLE.
89882cd038dSYoshinobu Inoue 			 * If not solicited and the link-layer address was
89982cd038dSYoshinobu Inoue 			 * changed, make it STALE.
90082cd038dSYoshinobu Inoue 			 */
9011558cb24SAlexander V. Chernikov 			if (is_solicited)
902aa5f023eSAlexander V. Chernikov 				nd6_llinfo_setstate(ln, ND6_LLINFO_REACHABLE);
9031558cb24SAlexander V. Chernikov 			else {
904aa5f023eSAlexander V. Chernikov 				if (lladdr != NULL && llchange)
905aa5f023eSAlexander V. Chernikov 					nd6_llinfo_setstate(ln, ND6_LLINFO_STALE);
90682cd038dSYoshinobu Inoue 			}
90782cd038dSYoshinobu Inoue 		}
90882cd038dSYoshinobu Inoue 
90982cd038dSYoshinobu Inoue 		if (ln->ln_router && !is_router) {
91082cd038dSYoshinobu Inoue 			/*
91182cd038dSYoshinobu Inoue 			 * The peer dropped the router flag.
91282cd038dSYoshinobu Inoue 			 * Remove the sender from the Default Router List and
91382cd038dSYoshinobu Inoue 			 * update the Destination Cache entries.
91482cd038dSYoshinobu Inoue 			 */
9159a7ee988SAlexander V. Chernikov 			struct ifnet *nd6_ifp;
91682cd038dSYoshinobu Inoue 
9179a7ee988SAlexander V. Chernikov 			nd6_ifp = lltable_get_ifp(ln->lle_tbl);
918ff63037dSMark Johnston 			if (!defrouter_remove(&ln->r_l3addr.addr6, nd6_ifp) &&
919ff63037dSMark Johnston 			    (ND_IFINFO(nd6_ifp)->flags &
920ff63037dSMark Johnston 			     ND6_IFF_ACCEPT_RTADV) != 0)
92182cd038dSYoshinobu Inoue 				/*
92282cd038dSYoshinobu Inoue 				 * Even if the neighbor is not in the default
923ff63037dSMark Johnston 				 * router list, the neighbor may be used as a
924ff63037dSMark Johnston 				 * next hop for some destinations (e.g. redirect
925ff63037dSMark Johnston 				 * case). So we must call rt6_flush explicitly.
92682cd038dSYoshinobu Inoue 				 */
92760348b56SLuigi Rizzo 				rt6_flush(&ip6->ip6_src, ifp);
92882cd038dSYoshinobu Inoue 		}
92982cd038dSYoshinobu Inoue 		ln->ln_router = is_router;
93082cd038dSYoshinobu Inoue 	}
9316e6b3f7cSQing Li         /* XXX - QL
9326e6b3f7cSQing Li 	 *  Does this matter?
9336e6b3f7cSQing Li 	 *  rt->rt_flags &= ~RTF_REJECT;
9346e6b3f7cSQing Li 	 */
9356e6b3f7cSQing Li 	ln->la_asked = 0;
9368482aa77SAlexander V. Chernikov 	if (ln->la_hold != NULL)
9378482aa77SAlexander V. Chernikov 		chain = nd6_grab_holdchain(ln);
938686cdd19SJun-ichiro itojun Hagino  freeit:
939d7968c29SAlexander V. Chernikov 	if (ln != NULL)
9406e6b3f7cSQing Li 		LLE_WUNLOCK(ln);
9416e6b3f7cSQing Li 
942d7968c29SAlexander V. Chernikov 	if (chain != NULL)
9438482aa77SAlexander V. Chernikov 		nd6_flush_holdchain(ifp, ln, chain);
944c541bd36SAlexander V. Chernikov 	if (flush_holdchain)
945c541bd36SAlexander V. Chernikov 		nd6_flush_children_holdchain(ifp, ln);
946d7968c29SAlexander V. Chernikov 
947ee6326a3SKip Macy 	if (checklink)
948ee6326a3SKip Macy 		pfxlist_onlink_check();
949ee6326a3SKip Macy 
950686cdd19SJun-ichiro itojun Hagino 	m_freem(m);
95133841545SHajimu UMEMOTO 	return;
95233841545SHajimu UMEMOTO 
95333841545SHajimu UMEMOTO  bad:
95423ee1bfaSKip Macy 	if (ln != NULL)
9556e6b3f7cSQing Li 		LLE_WUNLOCK(ln);
9566e6b3f7cSQing Li 
957e27b0c87SRobert Watson 	ICMP6STAT_INC(icp6s_badna);
95833841545SHajimu UMEMOTO 	m_freem(m);
95982cd038dSYoshinobu Inoue }
96082cd038dSYoshinobu Inoue 
96182cd038dSYoshinobu Inoue /*
96282cd038dSYoshinobu Inoue  * Neighbor advertisement output handling.
96382cd038dSYoshinobu Inoue  *
96482cd038dSYoshinobu Inoue  * Based on RFC 2461
96582cd038dSYoshinobu Inoue  *
966686cdd19SJun-ichiro itojun Hagino  * the following items are not implemented yet:
967686cdd19SJun-ichiro itojun Hagino  * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
968686cdd19SJun-ichiro itojun Hagino  * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
9691272577eSXin LI  *
9701272577eSXin LI  * tlladdr - 1 if include target link-layer address
9711272577eSXin LI  * sdl0 - sockaddr_dl (= proxy NA) or NULL
97282cd038dSYoshinobu Inoue  */
9731b46c7f8SBjoern A. Zeeb static void
nd6_na_output_fib(struct ifnet * ifp,const struct in6_addr * daddr6_0,const struct in6_addr * taddr6,u_long flags,int tlladdr,struct sockaddr * sdl0,u_int fibnum)9741b46c7f8SBjoern A. Zeeb nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
9751272577eSXin LI     const struct in6_addr *taddr6, u_long flags, int tlladdr,
9761b46c7f8SBjoern A. Zeeb     struct sockaddr *sdl0, u_int fibnum)
97782cd038dSYoshinobu Inoue {
97882cd038dSYoshinobu Inoue 	struct mbuf *m;
9791db8d1f8SAna Kukec 	struct m_tag *mtag;
98082cd038dSYoshinobu Inoue 	struct ip6_hdr *ip6;
98182cd038dSYoshinobu Inoue 	struct nd_neighbor_advert *nd_na;
98282cd038dSYoshinobu Inoue 	struct ip6_moptions im6o;
983601c0b8bSAlexander V. Chernikov 	struct in6_addr daddr6, dst6, src6;
984601c0b8bSAlexander V. Chernikov 	uint32_t scopeid;
985601c0b8bSAlexander V. Chernikov 
986605284b8SAlexander V. Chernikov 	NET_EPOCH_ASSERT();
987605284b8SAlexander V. Chernikov 
988a1f7e5f8SHajimu UMEMOTO 	int icmp6len, maxlen, error;
98941d0e15fSPeter Wemm 	caddr_t mac = NULL;
990a1f7e5f8SHajimu UMEMOTO 
991a1f7e5f8SHajimu UMEMOTO 	daddr6 = *daddr6_0;	/* make a local copy for modification */
99282cd038dSYoshinobu Inoue 
993686cdd19SJun-ichiro itojun Hagino 	/* estimate the size of message */
994686cdd19SJun-ichiro itojun Hagino 	maxlen = sizeof(*ip6) + sizeof(*nd_na);
995686cdd19SJun-ichiro itojun Hagino 	maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
996efb19cf6SAndrey V. Elsukov 	KASSERT(max_linkhdr + maxlen <= MCLBYTES, (
997efb19cf6SAndrey V. Elsukov 	    "%s: max_linkhdr + maxlen > MCLBYTES (%d + %d > %d)",
998efb19cf6SAndrey V. Elsukov 	    __func__, max_linkhdr, maxlen, MCLBYTES));
999686cdd19SJun-ichiro itojun Hagino 
100010e5acc3SGleb Smirnoff 	if (max_linkhdr + maxlen > MHLEN)
100110e5acc3SGleb Smirnoff 		m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
100210e5acc3SGleb Smirnoff 	else
100310e5acc3SGleb Smirnoff 		m = m_gethdr(M_NOWAIT, MT_DATA);
1004686cdd19SJun-ichiro itojun Hagino 	if (m == NULL)
100582cd038dSYoshinobu Inoue 		return;
10061b46c7f8SBjoern A. Zeeb 	M_SETFIB(m, fibnum);
100782cd038dSYoshinobu Inoue 
1008a1f7e5f8SHajimu UMEMOTO 	if (IN6_IS_ADDR_MULTICAST(&daddr6)) {
100982cd038dSYoshinobu Inoue 		m->m_flags |= M_MCAST;
101082cd038dSYoshinobu Inoue 		im6o.im6o_multicast_ifp = ifp;
101182cd038dSYoshinobu Inoue 		im6o.im6o_multicast_hlim = 255;
101282cd038dSYoshinobu Inoue 		im6o.im6o_multicast_loop = 0;
101382cd038dSYoshinobu Inoue 	}
101482cd038dSYoshinobu Inoue 
101582cd038dSYoshinobu Inoue 	icmp6len = sizeof(*nd_na);
101682cd038dSYoshinobu Inoue 	m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
1017ed6a66caSRobert Watson 	m->m_data += max_linkhdr;	/* or M_ALIGN() equivalent? */
101882cd038dSYoshinobu Inoue 
101982cd038dSYoshinobu Inoue 	/* fill neighbor advertisement packet */
102082cd038dSYoshinobu Inoue 	ip6 = mtod(m, struct ip6_hdr *);
102182cd038dSYoshinobu Inoue 	ip6->ip6_flow = 0;
1022686cdd19SJun-ichiro itojun Hagino 	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
1023686cdd19SJun-ichiro itojun Hagino 	ip6->ip6_vfc |= IPV6_VERSION;
102482cd038dSYoshinobu Inoue 	ip6->ip6_nxt = IPPROTO_ICMPV6;
102582cd038dSYoshinobu Inoue 	ip6->ip6_hlim = 255;
1026a1f7e5f8SHajimu UMEMOTO 	if (IN6_IS_ADDR_UNSPECIFIED(&daddr6)) {
102782cd038dSYoshinobu Inoue 		/* reply to DAD */
10284a3df7feSHajimu UMEMOTO 		daddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
10294a3df7feSHajimu UMEMOTO 		daddr6.s6_addr16[1] = 0;
10304a3df7feSHajimu UMEMOTO 		daddr6.s6_addr32[1] = 0;
10314a3df7feSHajimu UMEMOTO 		daddr6.s6_addr32[2] = 0;
10324a3df7feSHajimu UMEMOTO 		daddr6.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
1033a1f7e5f8SHajimu UMEMOTO 		if (in6_setscope(&daddr6, ifp, NULL))
1034a1f7e5f8SHajimu UMEMOTO 			goto bad;
1035a1f7e5f8SHajimu UMEMOTO 
103682cd038dSYoshinobu Inoue 		flags &= ~ND_NA_FLAG_SOLICITED;
1037a1f7e5f8SHajimu UMEMOTO 	}
1038a1f7e5f8SHajimu UMEMOTO 	ip6->ip6_dst = daddr6;
103982cd038dSYoshinobu Inoue 
104082cd038dSYoshinobu Inoue 	/*
104182cd038dSYoshinobu Inoue 	 * Select a source whose scope is the same as that of the dest.
104282cd038dSYoshinobu Inoue 	 */
1043601c0b8bSAlexander V. Chernikov 	in6_splitscope(&daddr6, &dst6, &scopeid);
1044559b4296SAlan Somers 	error = in6_selectsrc_addr(fibnum, &dst6,
1045601c0b8bSAlexander V. Chernikov 	    scopeid, ifp, &src6, NULL);
104688d166bfSBjoern A. Zeeb 	if (error) {
10471d54aa3bSBjoern A. Zeeb 		char ip6buf[INET6_ADDRSTRLEN];
1048a1f7e5f8SHajimu UMEMOTO 		nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
1049a1f7e5f8SHajimu UMEMOTO 		    "determined: dst=%s, error=%d\n",
1050601c0b8bSAlexander V. Chernikov 		    ip6_sprintf(ip6buf, &daddr6), error));
1051a1f7e5f8SHajimu UMEMOTO 		goto bad;
105282cd038dSYoshinobu Inoue 	}
1053601c0b8bSAlexander V. Chernikov 	ip6->ip6_src = src6;
105482cd038dSYoshinobu Inoue 	nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
105582cd038dSYoshinobu Inoue 	nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
105682cd038dSYoshinobu Inoue 	nd_na->nd_na_code = 0;
105782cd038dSYoshinobu Inoue 	nd_na->nd_na_target = *taddr6;
10589a4f9608SHajimu UMEMOTO 	in6_clearscope(&nd_na->nd_na_target); /* XXX */
105982cd038dSYoshinobu Inoue 
106082cd038dSYoshinobu Inoue 	/*
106182cd038dSYoshinobu Inoue 	 * "tlladdr" indicates NS's condition for adding tlladdr or not.
106282cd038dSYoshinobu Inoue 	 * see nd6_ns_input() for details.
106382cd038dSYoshinobu Inoue 	 * Basically, if NS packet is sent to unicast/anycast addr,
106482cd038dSYoshinobu Inoue 	 * target lladdr option SHOULD NOT be included.
106582cd038dSYoshinobu Inoue 	 */
1066686cdd19SJun-ichiro itojun Hagino 	if (tlladdr) {
1067686cdd19SJun-ichiro itojun Hagino 		/*
1068686cdd19SJun-ichiro itojun Hagino 		 * sdl0 != NULL indicates proxy NA.  If we do proxy, use
1069686cdd19SJun-ichiro itojun Hagino 		 * lladdr in sdl0.  If we are not proxying (sending NA for
1070686cdd19SJun-ichiro itojun Hagino 		 * my address) use lladdr configured for the interface.
1071686cdd19SJun-ichiro itojun Hagino 		 */
1072a9771948SGleb Smirnoff 		if (sdl0 == NULL) {
1073a9771948SGleb Smirnoff 			if (ifp->if_carp)
107454bfbd51SWill Andrews 				mac = (*carp_macmatch6_p)(ifp, m, taddr6);
1075a9771948SGleb Smirnoff 			if (mac == NULL)
1076686cdd19SJun-ichiro itojun Hagino 				mac = nd6_ifptomac(ifp);
1077a9771948SGleb Smirnoff 		} else if (sdl0->sa_family == AF_LINK) {
1078686cdd19SJun-ichiro itojun Hagino 			struct sockaddr_dl *sdl;
1079686cdd19SJun-ichiro itojun Hagino 			sdl = (struct sockaddr_dl *)sdl0;
1080686cdd19SJun-ichiro itojun Hagino 			if (sdl->sdl_alen == ifp->if_addrlen)
1081686cdd19SJun-ichiro itojun Hagino 				mac = LLADDR(sdl);
1082686cdd19SJun-ichiro itojun Hagino 		}
1083686cdd19SJun-ichiro itojun Hagino 	}
1084686cdd19SJun-ichiro itojun Hagino 	if (tlladdr && mac) {
108582cd038dSYoshinobu Inoue 		int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
108682cd038dSYoshinobu Inoue 		struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
108782cd038dSYoshinobu Inoue 
108882cd038dSYoshinobu Inoue 		/* roundup to 8 bytes alignment! */
108982cd038dSYoshinobu Inoue 		optlen = (optlen + 7) & ~7;
109082cd038dSYoshinobu Inoue 
109182cd038dSYoshinobu Inoue 		m->m_pkthdr.len += optlen;
109282cd038dSYoshinobu Inoue 		m->m_len += optlen;
109382cd038dSYoshinobu Inoue 		icmp6len += optlen;
109482cd038dSYoshinobu Inoue 		bzero((caddr_t)nd_opt, optlen);
109582cd038dSYoshinobu Inoue 		nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
109682cd038dSYoshinobu Inoue 		nd_opt->nd_opt_len = optlen >> 3;
109782cd038dSYoshinobu Inoue 		bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
109882cd038dSYoshinobu Inoue 	} else
109982cd038dSYoshinobu Inoue 		flags &= ~ND_NA_FLAG_OVERRIDE;
110082cd038dSYoshinobu Inoue 
110182cd038dSYoshinobu Inoue 	ip6->ip6_plen = htons((u_short)icmp6len);
110282cd038dSYoshinobu Inoue 	nd_na->nd_na_flags_reserved = flags;
110382cd038dSYoshinobu Inoue 	nd_na->nd_na_cksum = 0;
110482cd038dSYoshinobu Inoue 	nd_na->nd_na_cksum =
110582cd038dSYoshinobu Inoue 	    in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
110682cd038dSYoshinobu Inoue 
11071db8d1f8SAna Kukec 	if (send_sendso_input_hook != NULL) {
11081db8d1f8SAna Kukec 		mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
11091db8d1f8SAna Kukec 		    sizeof(unsigned short), M_NOWAIT);
11101db8d1f8SAna Kukec 		if (mtag == NULL)
11111db8d1f8SAna Kukec 			goto bad;
11121db8d1f8SAna Kukec 		*(unsigned short *)(mtag + 1) = nd_na->nd_na_type;
11131db8d1f8SAna Kukec 		m_tag_prepend(m, mtag);
11141db8d1f8SAna Kukec 	}
11151db8d1f8SAna Kukec 
1116357ce739SAlexander V. Chernikov 	ip6_output(m, NULL, NULL, 0, &im6o, NULL, NULL);
1117a1f7e5f8SHajimu UMEMOTO 	icmp6_ifstat_inc(ifp, ifs6_out_msg);
1118a1f7e5f8SHajimu UMEMOTO 	icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert);
1119*60d8dbbeSKristof Provost 	ICMP6STAT_INC2(icp6s_outhist, ND_NEIGHBOR_ADVERT);
1120a1f7e5f8SHajimu UMEMOTO 
1121a1f7e5f8SHajimu UMEMOTO 	return;
1122a1f7e5f8SHajimu UMEMOTO 
1123a1f7e5f8SHajimu UMEMOTO   bad:
1124a1f7e5f8SHajimu UMEMOTO 	m_freem(m);
112582cd038dSYoshinobu Inoue }
112682cd038dSYoshinobu Inoue 
11271b46c7f8SBjoern A. Zeeb #ifndef BURN_BRIDGES
11281b46c7f8SBjoern A. Zeeb void
nd6_na_output(struct ifnet * ifp,const struct in6_addr * daddr6_0,const struct in6_addr * taddr6,u_long flags,int tlladdr,struct sockaddr * sdl0)11291b46c7f8SBjoern A. Zeeb nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
11301b46c7f8SBjoern A. Zeeb     const struct in6_addr *taddr6, u_long flags, int tlladdr,
11311b46c7f8SBjoern A. Zeeb     struct sockaddr *sdl0)
11321b46c7f8SBjoern A. Zeeb {
11331b46c7f8SBjoern A. Zeeb 
11341b46c7f8SBjoern A. Zeeb 	nd6_na_output_fib(ifp, daddr6_0, taddr6, flags, tlladdr, sdl0,
11351b46c7f8SBjoern A. Zeeb 	    RT_DEFAULT_FIB);
11361b46c7f8SBjoern A. Zeeb }
11371b46c7f8SBjoern A. Zeeb #endif
11381b46c7f8SBjoern A. Zeeb 
113982cd038dSYoshinobu Inoue caddr_t
nd6_ifptomac(struct ifnet * ifp)11401272577eSXin LI nd6_ifptomac(struct ifnet *ifp)
114182cd038dSYoshinobu Inoue {
114282cd038dSYoshinobu Inoue 	switch (ifp->if_type) {
114382cd038dSYoshinobu Inoue 	case IFT_ETHER:
114433841545SHajimu UMEMOTO 	case IFT_IEEE1394:
114505b6760dSMunechika SUMIKAWA 	case IFT_L2VLAN:
1146e4cd31ddSJeff Roberson 	case IFT_INFINIBAND:
114759280079SAndrew Thompson 	case IFT_BRIDGE:
1148be4889bbSBrooks Davis 		return IF_LLADDR(ifp);
114982cd038dSYoshinobu Inoue 	default:
115082cd038dSYoshinobu Inoue 		return NULL;
115182cd038dSYoshinobu Inoue 	}
115282cd038dSYoshinobu Inoue }
115382cd038dSYoshinobu Inoue 
115482cd038dSYoshinobu Inoue struct dadq {
1155e3975643SJake Burkholder 	TAILQ_ENTRY(dadq) dad_list;
115682cd038dSYoshinobu Inoue 	struct ifaddr *dad_ifa;
115782cd038dSYoshinobu Inoue 	int dad_count;		/* max NS to send */
1158686cdd19SJun-ichiro itojun Hagino 	int dad_ns_tcount;	/* # of trials to send NS */
115982cd038dSYoshinobu Inoue 	int dad_ns_ocount;	/* NS sent so far */
116082cd038dSYoshinobu Inoue 	int dad_ns_icount;
116182cd038dSYoshinobu Inoue 	int dad_na_icount;
116211d8451dSHiroki Sato 	int dad_ns_lcount;	/* looped back NS */
116323e9ffb0SHiroki Sato 	int dad_loopbackprobe;	/* probing state for loopback detection */
116433841545SHajimu UMEMOTO 	struct callout dad_timer_ch;
116521ca7b57SMarko Zec 	struct vnet *dad_vnet;
1166d6ad6a86SMark Johnston 	u_int dad_refcnt;
116711d8451dSHiroki Sato #define	ND_OPT_NONCE_LEN32 \
116811d8451dSHiroki Sato 		((ND_OPT_NONCE_LEN + sizeof(uint32_t) - 1)/sizeof(uint32_t))
116911d8451dSHiroki Sato 	uint32_t dad_nonce[ND_OPT_NONCE_LEN32];
117020cb3e25SJonathan T. Looney 	bool dad_ondadq;	/* on dadq? Protected by DADQ_WLOCK. */
117182cd038dSYoshinobu Inoue };
117282cd038dSYoshinobu Inoue 
11735f901c92SAndrew Turner VNET_DEFINE_STATIC(TAILQ_HEAD(, dadq), dadq);
11745f901c92SAndrew Turner VNET_DEFINE_STATIC(struct rwlock, dad_rwlock);
11751e77c105SRobert Watson #define	V_dadq			VNET(dadq)
117682a9fa4aSHiroki Sato #define	V_dad_rwlock		VNET(dad_rwlock)
117782a9fa4aSHiroki Sato 
11789a94097cSMark Johnston #define	DADQ_LOCKPTR()		(&V_dad_rwlock)
11799a94097cSMark Johnston #define	DADQ_LOCK_INIT()	rw_init(DADQ_LOCKPTR(), "nd6 DAD queue")
11809a94097cSMark Johnston #define	DADQ_RLOCK()		rw_rlock(DADQ_LOCKPTR())
11819a94097cSMark Johnston #define	DADQ_RUNLOCK()		rw_runlock(DADQ_LOCKPTR())
11829a94097cSMark Johnston #define	DADQ_WLOCK()		rw_wlock(DADQ_LOCKPTR())
11839a94097cSMark Johnston #define	DADQ_WUNLOCK()		rw_wunlock(DADQ_LOCKPTR())
11849a94097cSMark Johnston 
11859a94097cSMark Johnston #define	DADQ_LOCK_ASSERT()	rw_assert(DADQ_LOCKPTR(), RA_LOCKED);
11869a94097cSMark Johnston #define	DADQ_RLOCK_ASSERT()	rw_assert(DADQ_LOCKPTR(), RA_RLOCKED);
11879a94097cSMark Johnston #define	DADQ_WLOCK_ASSERT()	rw_assert(DADQ_LOCKPTR(), RA_WLOCKED);
118882cd038dSYoshinobu Inoue 
1189e0c0711eSAlexander V. Chernikov static void
nd6_dad_add(struct dadq * dp)1190e0c0711eSAlexander V. Chernikov nd6_dad_add(struct dadq *dp)
1191e0c0711eSAlexander V. Chernikov {
11929a94097cSMark Johnston 	DADQ_WLOCK_ASSERT();
1193e0c0711eSAlexander V. Chernikov 
1194d6ad6a86SMark Johnston 	TAILQ_INSERT_TAIL(&V_dadq, dp, dad_list);
119520cb3e25SJonathan T. Looney 	dp->dad_ondadq = true;
1196e0c0711eSAlexander V. Chernikov }
1197e0c0711eSAlexander V. Chernikov 
1198e0c0711eSAlexander V. Chernikov static void
nd6_dad_del(struct dadq * dp)1199e0c0711eSAlexander V. Chernikov nd6_dad_del(struct dadq *dp)
1200e0c0711eSAlexander V. Chernikov {
12019a94097cSMark Johnston 	DADQ_WLOCK_ASSERT();
1202e0c0711eSAlexander V. Chernikov 
120320cb3e25SJonathan T. Looney 	if (dp->dad_ondadq) {
120420cb3e25SJonathan T. Looney 		/*
120520cb3e25SJonathan T. Looney 		 * Remove dp from the dadq and release the dadq's
120620cb3e25SJonathan T. Looney 		 * reference.
120720cb3e25SJonathan T. Looney 		 */
1208d6ad6a86SMark Johnston 		TAILQ_REMOVE(&V_dadq, dp, dad_list);
120920cb3e25SJonathan T. Looney 		dp->dad_ondadq = false;
1210d6ad6a86SMark Johnston 		nd6_dad_rele(dp);
12119a94097cSMark Johnston 	}
1212e0c0711eSAlexander V. Chernikov }
1213e0c0711eSAlexander V. Chernikov 
121482cd038dSYoshinobu Inoue static struct dadq *
nd6_dad_find(struct ifaddr * ifa,struct nd_opt_nonce * n)121511d8451dSHiroki Sato nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *n)
121682cd038dSYoshinobu Inoue {
121782cd038dSYoshinobu Inoue 	struct dadq *dp;
121882cd038dSYoshinobu Inoue 
12199a94097cSMark Johnston 	DADQ_LOCK_ASSERT();
12209a94097cSMark Johnston 
122111d8451dSHiroki Sato 	TAILQ_FOREACH(dp, &V_dadq, dad_list) {
122211d8451dSHiroki Sato 		if (dp->dad_ifa != ifa)
122311d8451dSHiroki Sato 			continue;
12249a94097cSMark Johnston 
122511d8451dSHiroki Sato 		/*
122611d8451dSHiroki Sato 		 * Skip if the nonce matches the received one.
122711d8451dSHiroki Sato 		 * +2 in the length is required because of type and
122811d8451dSHiroki Sato 		 * length fields are included in a header.
122911d8451dSHiroki Sato 		 */
123011d8451dSHiroki Sato 		if (n != NULL &&
123111d8451dSHiroki Sato 		    n->nd_opt_nonce_len == (ND_OPT_NONCE_LEN + 2) / 8 &&
123211d8451dSHiroki Sato 		    memcmp(&n->nd_opt_nonce[0], &dp->dad_nonce[0],
123311d8451dSHiroki Sato 		    ND_OPT_NONCE_LEN) == 0) {
123411d8451dSHiroki Sato 			dp->dad_ns_lcount++;
123511d8451dSHiroki Sato 			continue;
123611d8451dSHiroki Sato 		}
1237a37271c3SMark Johnston 		break;
1238d6ad6a86SMark Johnston 	}
1239d5378bb6SGleb Smirnoff 
1240a37271c3SMark Johnston 	return (dp);
124182cd038dSYoshinobu Inoue }
124282cd038dSYoshinobu Inoue 
124333841545SHajimu UMEMOTO static void
nd6_dad_starttimer(struct dadq * dp,int ticks)12449a94097cSMark Johnston nd6_dad_starttimer(struct dadq *dp, int ticks)
124533841545SHajimu UMEMOTO {
12469a94097cSMark Johnston 	DADQ_WLOCK_ASSERT();
124733841545SHajimu UMEMOTO 
12489a94097cSMark Johnston 	callout_reset(&dp->dad_timer_ch, ticks, nd6_dad_timer, dp);
124933841545SHajimu UMEMOTO }
125033841545SHajimu UMEMOTO 
125133841545SHajimu UMEMOTO static void
nd6_dad_stoptimer(struct dadq * dp)12521272577eSXin LI nd6_dad_stoptimer(struct dadq *dp)
125333841545SHajimu UMEMOTO {
1254d6ad6a86SMark Johnston 	callout_drain(&dp->dad_timer_ch);
1255d6ad6a86SMark Johnston }
1256d6ad6a86SMark Johnston 
1257d6ad6a86SMark Johnston static void
nd6_dad_rele(struct dadq * dp)1258d6ad6a86SMark Johnston nd6_dad_rele(struct dadq *dp)
1259d6ad6a86SMark Johnston {
1260d6ad6a86SMark Johnston 	if (refcount_release(&dp->dad_refcnt)) {
12619a94097cSMark Johnston 		KASSERT(!dp->dad_ondadq, ("dp %p still on DAD queue", dp));
1262d6ad6a86SMark Johnston 		ifa_free(dp->dad_ifa);
1263d6ad6a86SMark Johnston 		free(dp, M_IP6NDP);
1264d6ad6a86SMark Johnston 	}
1265d6ad6a86SMark Johnston }
1266d6ad6a86SMark Johnston 
1267d6ad6a86SMark Johnston void
nd6_dad_init(void)1268d6ad6a86SMark Johnston nd6_dad_init(void)
1269d6ad6a86SMark Johnston {
12709a94097cSMark Johnston 	DADQ_LOCK_INIT();
1271d6ad6a86SMark Johnston 	TAILQ_INIT(&V_dadq);
127233841545SHajimu UMEMOTO }
127333841545SHajimu UMEMOTO 
127482cd038dSYoshinobu Inoue /*
1275cd0fdcf7SHajimu UMEMOTO  * Start Duplicate Address Detection (DAD) for specified interface address.
127682cd038dSYoshinobu Inoue  */
127782cd038dSYoshinobu Inoue void
nd6_dad_start(struct ifaddr * ifa,int delay)12781272577eSXin LI nd6_dad_start(struct ifaddr *ifa, int delay)
127982cd038dSYoshinobu Inoue {
128082cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
128182cd038dSYoshinobu Inoue 	struct dadq *dp;
12821d54aa3bSBjoern A. Zeeb 	char ip6buf[INET6_ADDRSTRLEN];
128382cd038dSYoshinobu Inoue 
1284970fe093SMark Johnston 	KASSERT((ia->ia6_flags & IN6_IFF_TENTATIVE) != 0,
1285970fe093SMark Johnston 	    ("starting DAD on non-tentative address %p", ifa));
1286970fe093SMark Johnston 
128782cd038dSYoshinobu Inoue 	/*
128882cd038dSYoshinobu Inoue 	 * If we don't need DAD, don't do it.
128982cd038dSYoshinobu Inoue 	 * There are several cases:
1290970fe093SMark Johnston 	 * - DAD is disabled globally or on the interface
129182cd038dSYoshinobu Inoue 	 * - the interface address is anycast
129282cd038dSYoshinobu Inoue 	 */
1293970fe093SMark Johnston 	if ((ia->ia6_flags & IN6_IFF_ANYCAST) != 0 ||
1294970fe093SMark Johnston 	    V_ip6_dad_count == 0 ||
1295970fe093SMark Johnston 	    (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_NO_DAD) != 0) {
129682cd038dSYoshinobu Inoue 		ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
129782cd038dSYoshinobu Inoue 		return;
129882cd038dSYoshinobu Inoue 	}
1299970fe093SMark Johnston 	if ((ifa->ifa_ifp->if_flags & IFF_UP) == 0 ||
1300970fe093SMark Johnston 	    (ifa->ifa_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
1301970fe093SMark Johnston 	    (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED) != 0)
130282cd038dSYoshinobu Inoue 		return;
1303970fe093SMark Johnston 
13049a94097cSMark Johnston 	DADQ_WLOCK();
130511d8451dSHiroki Sato 	if ((dp = nd6_dad_find(ifa, NULL)) != NULL) {
13066401c828SHiroki Sato 		/*
1307c15064c2SMark Johnston 		 * DAD is already in progress.  Let the existing entry
1308c15064c2SMark Johnston 		 * finish it.
13096401c828SHiroki Sato 		 */
13109a94097cSMark Johnston 		DADQ_WUNLOCK();
131182cd038dSYoshinobu Inoue 		return;
131282cd038dSYoshinobu Inoue 	}
131382cd038dSYoshinobu Inoue 
1314d6ad6a86SMark Johnston 	dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT | M_ZERO);
131582cd038dSYoshinobu Inoue 	if (dp == NULL) {
1316686cdd19SJun-ichiro itojun Hagino 		log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
131782cd038dSYoshinobu Inoue 			"%s(%s)\n",
13181d54aa3bSBjoern A. Zeeb 			ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr),
131982cd038dSYoshinobu Inoue 			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
132082cd038dSYoshinobu Inoue 		return;
132182cd038dSYoshinobu Inoue 	}
13229a94097cSMark Johnston 	callout_init_rw(&dp->dad_timer_ch, DADQ_LOCKPTR(),
13239a94097cSMark Johnston 	    CALLOUT_RETURNUNLOCKED);
132421ca7b57SMarko Zec #ifdef VIMAGE
132521ca7b57SMarko Zec 	dp->dad_vnet = curvnet;
132621ca7b57SMarko Zec #endif
132733841545SHajimu UMEMOTO 	nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
13281d54aa3bSBjoern A. Zeeb 	    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
132982cd038dSYoshinobu Inoue 
133082cd038dSYoshinobu Inoue 	/*
133182cd038dSYoshinobu Inoue 	 * Send NS packet for DAD, ip6_dad_count times.
133282cd038dSYoshinobu Inoue 	 * Note that we must delay the first transmission, if this is the
133382cd038dSYoshinobu Inoue 	 * first packet to be sent from the interface after interface
133482cd038dSYoshinobu Inoue 	 * (re)initialization.
133582cd038dSYoshinobu Inoue 	 */
133682cd038dSYoshinobu Inoue 	dp->dad_ifa = ifa;
1337d6ad6a86SMark Johnston 	ifa_ref(dp->dad_ifa);
1338603724d3SBjoern A. Zeeb 	dp->dad_count = V_ip6_dad_count;
133982cd038dSYoshinobu Inoue 	dp->dad_ns_icount = dp->dad_na_icount = 0;
1340686cdd19SJun-ichiro itojun Hagino 	dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
134123e9ffb0SHiroki Sato 	dp->dad_ns_lcount = dp->dad_loopbackprobe = 0;
134220cb3e25SJonathan T. Looney 
134320cb3e25SJonathan T. Looney 	/* Add this to the dadq and add a reference for the dadq. */
1344d6ad6a86SMark Johnston 	refcount_init(&dp->dad_refcnt, 1);
1345e0c0711eSAlexander V. Chernikov 	nd6_dad_add(dp);
13469a94097cSMark Johnston 	nd6_dad_starttimer(dp, delay);
13479a94097cSMark Johnston 	DADQ_WUNLOCK();
134882cd038dSYoshinobu Inoue }
134982cd038dSYoshinobu Inoue 
135033841545SHajimu UMEMOTO /*
135133841545SHajimu UMEMOTO  * terminate DAD unconditionally.  used for address removals.
135233841545SHajimu UMEMOTO  */
135333841545SHajimu UMEMOTO void
nd6_dad_stop(struct ifaddr * ifa)13541272577eSXin LI nd6_dad_stop(struct ifaddr *ifa)
135533841545SHajimu UMEMOTO {
135633841545SHajimu UMEMOTO 	struct dadq *dp;
135733841545SHajimu UMEMOTO 
13589a94097cSMark Johnston 	DADQ_WLOCK();
135911d8451dSHiroki Sato 	dp = nd6_dad_find(ifa, NULL);
13609a94097cSMark Johnston 	if (dp == NULL) {
13619a94097cSMark Johnston 		DADQ_WUNLOCK();
136233841545SHajimu UMEMOTO 		/* DAD wasn't started yet */
136333841545SHajimu UMEMOTO 		return;
136433841545SHajimu UMEMOTO 	}
136533841545SHajimu UMEMOTO 
13669a94097cSMark Johnston 	/*
13679a94097cSMark Johnston 	 * Acquire a temporary reference so that we can safely stop the callout.
13689a94097cSMark Johnston 	 */
13699a94097cSMark Johnston 	(void)refcount_acquire(&dp->dad_refcnt);
1370e0c0711eSAlexander V. Chernikov 	nd6_dad_del(dp);
13719a94097cSMark Johnston 	DADQ_WUNLOCK();
137220cb3e25SJonathan T. Looney 
13739a94097cSMark Johnston 	nd6_dad_stoptimer(dp);
1374d6ad6a86SMark Johnston 	nd6_dad_rele(dp);
137533841545SHajimu UMEMOTO }
137633841545SHajimu UMEMOTO 
137782cd038dSYoshinobu Inoue static void
nd6_dad_timer(void * arg)13789a94097cSMark Johnston nd6_dad_timer(void *arg)
137982cd038dSYoshinobu Inoue {
13809a94097cSMark Johnston 	struct dadq *dp = arg;
138121ca7b57SMarko Zec 	struct ifaddr *ifa = dp->dad_ifa;
1382705bef54SHiroki Sato 	struct ifnet *ifp = dp->dad_ifa->ifa_ifp;
138382cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
13841d54aa3bSBjoern A. Zeeb 	char ip6buf[INET6_ADDRSTRLEN];
1385be0c32e2SGleb Smirnoff 	struct epoch_tracker et;
138682cd038dSYoshinobu Inoue 
13879a94097cSMark Johnston 	CURVNET_SET(dp->dad_vnet);
1388970fe093SMark Johnston 	KASSERT(ia != NULL, ("DAD entry %p with no address", dp));
1389970fe093SMark Johnston 
1390be0c32e2SGleb Smirnoff 	NET_EPOCH_ENTER(et);
1391705bef54SHiroki Sato 	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) {
1392705bef54SHiroki Sato 		/* Do not need DAD for ifdisabled interface. */
1393705bef54SHiroki Sato 		log(LOG_ERR, "nd6_dad_timer: cancel DAD on %s because of "
1394705bef54SHiroki Sato 		    "ND6_IFF_IFDISABLED.\n", ifp->if_xname);
1395d6ad6a86SMark Johnston 		goto err;
1396705bef54SHiroki Sato 	}
139782cd038dSYoshinobu Inoue 	if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
1398686cdd19SJun-ichiro itojun Hagino 		log(LOG_ERR, "nd6_dad_timer: called with duplicated address "
139982cd038dSYoshinobu Inoue 			"%s(%s)\n",
14001d54aa3bSBjoern A. Zeeb 			ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr),
140182cd038dSYoshinobu Inoue 			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
1402d6ad6a86SMark Johnston 		goto err;
140382cd038dSYoshinobu Inoue 	}
14040ed7d744SMark Johnston 	if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
14050ed7d744SMark Johnston 		log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
14060ed7d744SMark Johnston 			"%s(%s)\n",
14070ed7d744SMark Johnston 			ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr),
14080ed7d744SMark Johnston 			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
14090ed7d744SMark Johnston 		goto err;
14100ed7d744SMark Johnston 	}
141182cd038dSYoshinobu Inoue 
141223e9ffb0SHiroki Sato 	/* Stop DAD if the interface is down even after dad_maxtry attempts. */
141323e9ffb0SHiroki Sato 	if ((dp->dad_ns_tcount > V_dad_maxtry) &&
141423e9ffb0SHiroki Sato 	    (((ifp->if_flags & IFF_UP) == 0) ||
141523e9ffb0SHiroki Sato 	     ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0))) {
14166401c828SHiroki Sato 		nd6log((LOG_INFO, "%s: could not run DAD "
14176401c828SHiroki Sato 		    "because the interface was down or not running.\n",
141833841545SHajimu UMEMOTO 		    if_name(ifa->ifa_ifp)));
1419d6ad6a86SMark Johnston 		goto err;
1420686cdd19SJun-ichiro itojun Hagino 	}
1421686cdd19SJun-ichiro itojun Hagino 
142282cd038dSYoshinobu Inoue 	/* Need more checks? */
142382cd038dSYoshinobu Inoue 	if (dp->dad_ns_ocount < dp->dad_count) {
142482cd038dSYoshinobu Inoue 		/*
142582cd038dSYoshinobu Inoue 		 * We have more NS to go.  Send NS packet for DAD.
142682cd038dSYoshinobu Inoue 		 */
142733841545SHajimu UMEMOTO 		nd6_dad_starttimer(dp,
14289a94097cSMark Johnston 		    (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
14299a94097cSMark Johnston 		nd6_dad_ns_output(dp);
1430d6ad6a86SMark Johnston 		goto done;
143182cd038dSYoshinobu Inoue 	} else {
143282cd038dSYoshinobu Inoue 		/*
143382cd038dSYoshinobu Inoue 		 * We have transmitted sufficient number of DAD packets.
143482cd038dSYoshinobu Inoue 		 * See what we've got.
143582cd038dSYoshinobu Inoue 		 */
14369a94097cSMark Johnston 		if (dp->dad_ns_icount > 0 || dp->dad_na_icount > 0) {
1437d6ad6a86SMark Johnston 			/* We've seen NS or NA, means DAD has failed. */
1438e0c0711eSAlexander V. Chernikov 			nd6_dad_duplicated(ifa, dp);
14399a94097cSMark Johnston 		} else if (V_dad_enhanced != 0 &&
144023e9ffb0SHiroki Sato 		    dp->dad_ns_lcount > 0 &&
144123e9ffb0SHiroki Sato 		    dp->dad_ns_lcount > dp->dad_loopbackprobe) {
144223e9ffb0SHiroki Sato 			/*
144359333867SHiroki Sato 			 * Sec. 4.1 in RFC 7527 requires transmission of
144459333867SHiroki Sato 			 * additional probes until the loopback condition
144559333867SHiroki Sato 			 * becomes clear when a looped back probe is detected.
144623e9ffb0SHiroki Sato 			 */
144723e9ffb0SHiroki Sato 			log(LOG_ERR, "%s: a looped back NS message is "
144823e9ffb0SHiroki Sato 			    "detected during DAD for %s.  "
144923e9ffb0SHiroki Sato 			    "Another DAD probes are being sent.\n",
145023e9ffb0SHiroki Sato 			    if_name(ifa->ifa_ifp),
145123e9ffb0SHiroki Sato 			    ip6_sprintf(ip6buf, IFA_IN6(ifa)));
145223e9ffb0SHiroki Sato 			dp->dad_loopbackprobe = dp->dad_ns_lcount;
145323e9ffb0SHiroki Sato 			/*
145423e9ffb0SHiroki Sato 			 * Send an NS immediately and increase dad_count by
145523e9ffb0SHiroki Sato 			 * V_nd6_mmaxtries - 1.
145623e9ffb0SHiroki Sato 			 */
145723e9ffb0SHiroki Sato 			dp->dad_count =
145823e9ffb0SHiroki Sato 			    dp->dad_ns_ocount + V_nd6_mmaxtries - 1;
145923e9ffb0SHiroki Sato 			nd6_dad_starttimer(dp,
14609a94097cSMark Johnston 			    (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
14619a94097cSMark Johnston 			nd6_dad_ns_output(dp);
146223e9ffb0SHiroki Sato 			goto done;
146323e9ffb0SHiroki Sato 		} else {
146482cd038dSYoshinobu Inoue 			/*
146582cd038dSYoshinobu Inoue 			 * We are done with DAD.  No NA came, no NS came.
1466705bef54SHiroki Sato 			 * No duplicate address found.  Check IFDISABLED flag
1467705bef54SHiroki Sato 			 * again in case that it is changed between the
1468705bef54SHiroki Sato 			 * beginning of this function and here.
146982cd038dSYoshinobu Inoue 			 */
1470705bef54SHiroki Sato 			if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) == 0)
147182cd038dSYoshinobu Inoue 				ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
147282cd038dSYoshinobu Inoue 
147333841545SHajimu UMEMOTO 			nd6log((LOG_DEBUG,
1474686cdd19SJun-ichiro itojun Hagino 			    "%s: DAD complete for %s - no duplicates found\n",
1475686cdd19SJun-ichiro itojun Hagino 			    if_name(ifa->ifa_ifp),
14761d54aa3bSBjoern A. Zeeb 			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
147723e9ffb0SHiroki Sato 			if (dp->dad_ns_lcount > 0)
147823e9ffb0SHiroki Sato 				log(LOG_ERR, "%s: DAD completed while "
147923e9ffb0SHiroki Sato 				    "a looped back NS message is detected "
148023e9ffb0SHiroki Sato 				    "during DAD for %s.\n",
148123e9ffb0SHiroki Sato 				    if_name(ifa->ifa_ifp),
148223e9ffb0SHiroki Sato 				    ip6_sprintf(ip6buf, IFA_IN6(ifa)));
1483d6ad6a86SMark Johnston 		}
1484d6ad6a86SMark Johnston 	}
1485d6ad6a86SMark Johnston err:
1486e0c0711eSAlexander V. Chernikov 	nd6_dad_del(dp);
14879a94097cSMark Johnston 	DADQ_WUNLOCK();
148882cd038dSYoshinobu Inoue done:
1489be0c32e2SGleb Smirnoff 	NET_EPOCH_EXIT(et);
14908b615593SMarko Zec 	CURVNET_RESTORE();
149182cd038dSYoshinobu Inoue }
149282cd038dSYoshinobu Inoue 
1493d6ad6a86SMark Johnston static void
nd6_dad_duplicated(struct ifaddr * ifa,struct dadq * dp)1494e0c0711eSAlexander V. Chernikov nd6_dad_duplicated(struct ifaddr *ifa, struct dadq *dp)
149582cd038dSYoshinobu Inoue {
149682cd038dSYoshinobu Inoue 	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
1497d28bde66SSUZUKI Shinsuke 	struct ifnet *ifp;
14981d54aa3bSBjoern A. Zeeb 	char ip6buf[INET6_ADDRSTRLEN];
149982cd038dSYoshinobu Inoue 
150033841545SHajimu UMEMOTO 	log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
150111d8451dSHiroki Sato 	    "NS in/out/loopback=%d/%d/%d, NA in=%d\n",
15021d54aa3bSBjoern A. Zeeb 	    if_name(ifa->ifa_ifp), ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr),
150311d8451dSHiroki Sato 	    dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_ns_lcount,
150411d8451dSHiroki Sato 	    dp->dad_na_icount);
150582cd038dSYoshinobu Inoue 
150682cd038dSYoshinobu Inoue 	ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
150782cd038dSYoshinobu Inoue 	ia->ia6_flags |= IN6_IFF_DUPLICATED;
150882cd038dSYoshinobu Inoue 
1509d28bde66SSUZUKI Shinsuke 	ifp = ifa->ifa_ifp;
1510686cdd19SJun-ichiro itojun Hagino 	log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
15111d54aa3bSBjoern A. Zeeb 	    if_name(ifp), ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr));
1512686cdd19SJun-ichiro itojun Hagino 	log(LOG_ERR, "%s: manual intervention required\n",
1513d28bde66SSUZUKI Shinsuke 	    if_name(ifp));
1514d28bde66SSUZUKI Shinsuke 
1515d28bde66SSUZUKI Shinsuke 	/*
1516d28bde66SSUZUKI Shinsuke 	 * If the address is a link-local address formed from an interface
1517d28bde66SSUZUKI Shinsuke 	 * identifier based on the hardware address which is supposed to be
1518d28bde66SSUZUKI Shinsuke 	 * uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP
1519d28bde66SSUZUKI Shinsuke 	 * operation on the interface SHOULD be disabled.
1520a283298cSHiroki Sato 	 * [RFC 4862, Section 5.4.5]
1521d28bde66SSUZUKI Shinsuke 	 */
1522d28bde66SSUZUKI Shinsuke 	if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
1523d28bde66SSUZUKI Shinsuke 		struct in6_addr in6;
1524d28bde66SSUZUKI Shinsuke 
1525d28bde66SSUZUKI Shinsuke 		/*
1526d28bde66SSUZUKI Shinsuke 		 * To avoid over-reaction, we only apply this logic when we are
1527d28bde66SSUZUKI Shinsuke 		 * very sure that hardware addresses are supposed to be unique.
1528d28bde66SSUZUKI Shinsuke 		 */
1529d28bde66SSUZUKI Shinsuke 		switch (ifp->if_type) {
1530d28bde66SSUZUKI Shinsuke 		case IFT_ETHER:
1531d28bde66SSUZUKI Shinsuke 		case IFT_ATM:
1532d28bde66SSUZUKI Shinsuke 		case IFT_IEEE1394:
1533e4cd31ddSJeff Roberson 		case IFT_INFINIBAND:
1534d28bde66SSUZUKI Shinsuke 			in6 = ia->ia_addr.sin6_addr;
1535d28bde66SSUZUKI Shinsuke 			if (in6_get_hw_ifid(ifp, &in6) == 0 &&
1536d28bde66SSUZUKI Shinsuke 			    IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &in6)) {
1537d28bde66SSUZUKI Shinsuke 				ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
1538d28bde66SSUZUKI Shinsuke 				log(LOG_ERR, "%s: possible hardware address "
1539d28bde66SSUZUKI Shinsuke 				    "duplication detected, disable IPv6\n",
1540d28bde66SSUZUKI Shinsuke 				    if_name(ifp));
1541d28bde66SSUZUKI Shinsuke 			}
1542d28bde66SSUZUKI Shinsuke 			break;
1543d28bde66SSUZUKI Shinsuke 		}
1544d28bde66SSUZUKI Shinsuke 	}
154582cd038dSYoshinobu Inoue }
154682cd038dSYoshinobu Inoue 
15479a94097cSMark Johnston /*
15489a94097cSMark Johnston  * Transmit a neighbour solicitation for the purpose of DAD.  Returns with the
15499a94097cSMark Johnston  * DAD queue unlocked.
15509a94097cSMark Johnston  */
1551686cdd19SJun-ichiro itojun Hagino static void
nd6_dad_ns_output(struct dadq * dp)15526401c828SHiroki Sato nd6_dad_ns_output(struct dadq *dp)
1553686cdd19SJun-ichiro itojun Hagino {
15546401c828SHiroki Sato 	struct in6_ifaddr *ia = (struct in6_ifaddr *)dp->dad_ifa;
15556401c828SHiroki Sato 	struct ifnet *ifp = dp->dad_ifa->ifa_ifp;
155611d8451dSHiroki Sato 	int i;
1557686cdd19SJun-ichiro itojun Hagino 
15589a94097cSMark Johnston 	DADQ_WLOCK_ASSERT();
15599a94097cSMark Johnston 
1560686cdd19SJun-ichiro itojun Hagino 	dp->dad_ns_tcount++;
1561686cdd19SJun-ichiro itojun Hagino 	if ((ifp->if_flags & IFF_UP) == 0) {
15629a94097cSMark Johnston 		DADQ_WUNLOCK();
1563686cdd19SJun-ichiro itojun Hagino 		return;
1564686cdd19SJun-ichiro itojun Hagino 	}
156513f4c340SRobert Watson 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
15669a94097cSMark Johnston 		DADQ_WUNLOCK();
1567686cdd19SJun-ichiro itojun Hagino 		return;
1568686cdd19SJun-ichiro itojun Hagino 	}
1569686cdd19SJun-ichiro itojun Hagino 
1570686cdd19SJun-ichiro itojun Hagino 	dp->dad_ns_ocount++;
157111d8451dSHiroki Sato 	if (V_dad_enhanced != 0) {
157211d8451dSHiroki Sato 		for (i = 0; i < ND_OPT_NONCE_LEN32; i++)
157311d8451dSHiroki Sato 			dp->dad_nonce[i] = arc4random();
157411d8451dSHiroki Sato 		/*
157511d8451dSHiroki Sato 		 * XXXHRS: Note that in the case that
157611d8451dSHiroki Sato 		 * DupAddrDetectTransmits > 1, multiple NS messages with
157711d8451dSHiroki Sato 		 * different nonces can be looped back in an unexpected
157811d8451dSHiroki Sato 		 * order.  The current implementation recognizes only
157911d8451dSHiroki Sato 		 * the latest nonce on the sender side.  Practically it
158011d8451dSHiroki Sato 		 * should work well in almost all cases.
158111d8451dSHiroki Sato 		 */
15828d560759SHiroki Sato 	}
15839a94097cSMark Johnston 	DADQ_WUNLOCK();
158426deb882SAlexander V. Chernikov 	nd6_ns_output(ifp, NULL, NULL, &ia->ia_addr.sin6_addr,
15858d560759SHiroki Sato 	    (uint8_t *)&dp->dad_nonce[0]);
1586686cdd19SJun-ichiro itojun Hagino }
1587686cdd19SJun-ichiro itojun Hagino 
1588686cdd19SJun-ichiro itojun Hagino static void
nd6_dad_ns_input(struct ifaddr * ifa,struct nd_opt_nonce * ndopt_nonce)158911d8451dSHiroki Sato nd6_dad_ns_input(struct ifaddr *ifa, struct nd_opt_nonce *ndopt_nonce)
159082cd038dSYoshinobu Inoue {
159182cd038dSYoshinobu Inoue 	struct dadq *dp;
159282cd038dSYoshinobu Inoue 
15932ce62dceSSUZUKI Shinsuke 	if (ifa == NULL)
159482cd038dSYoshinobu Inoue 		panic("ifa == NULL in nd6_dad_ns_input");
159582cd038dSYoshinobu Inoue 
159611d8451dSHiroki Sato 	/* Ignore Nonce option when Enhanced DAD is disabled. */
159711d8451dSHiroki Sato 	if (V_dad_enhanced == 0)
159811d8451dSHiroki Sato 		ndopt_nonce = NULL;
15999a94097cSMark Johnston 	DADQ_RLOCK();
160011d8451dSHiroki Sato 	dp = nd6_dad_find(ifa, ndopt_nonce);
16019a94097cSMark Johnston 	if (dp != NULL)
160282cd038dSYoshinobu Inoue 		dp->dad_ns_icount++;
16039a94097cSMark Johnston 	DADQ_RUNLOCK();
160482cd038dSYoshinobu Inoue }
160582cd038dSYoshinobu Inoue 
1606686cdd19SJun-ichiro itojun Hagino static void
nd6_dad_na_input(struct ifaddr * ifa)16071272577eSXin LI nd6_dad_na_input(struct ifaddr *ifa)
160882cd038dSYoshinobu Inoue {
160982cd038dSYoshinobu Inoue 	struct dadq *dp;
161082cd038dSYoshinobu Inoue 
16112ce62dceSSUZUKI Shinsuke 	if (ifa == NULL)
161282cd038dSYoshinobu Inoue 		panic("ifa == NULL in nd6_dad_na_input");
161382cd038dSYoshinobu Inoue 
16149a94097cSMark Johnston 	DADQ_RLOCK();
161511d8451dSHiroki Sato 	dp = nd6_dad_find(ifa, NULL);
16169a94097cSMark Johnston 	if (dp != NULL)
161782cd038dSYoshinobu Inoue 		dp->dad_na_icount++;
16189a94097cSMark Johnston 	DADQ_RUNLOCK();
161982cd038dSYoshinobu Inoue }
1620