nd6_nbr.c revision 128422
162587Sitojun/*	$FreeBSD: head/sys/netinet6/nd6_nbr.c 128422 2004-04-19 08:02:52Z luigi $	*/
295023Ssuz/*	$KAME: nd6_nbr.c,v 1.86 2002/01/21 02:33:04 jinmei Exp $	*/
362587Sitojun
453541Sshin/*
553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
653541Sshin * All rights reserved.
753541Sshin *
853541Sshin * Redistribution and use in source and binary forms, with or without
953541Sshin * modification, are permitted provided that the following conditions
1053541Sshin * are met:
1153541Sshin * 1. Redistributions of source code must retain the above copyright
1253541Sshin *    notice, this list of conditions and the following disclaimer.
1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1453541Sshin *    notice, this list of conditions and the following disclaimer in the
1553541Sshin *    documentation and/or other materials provided with the distribution.
1653541Sshin * 3. Neither the name of the project nor the names of its contributors
1753541Sshin *    may be used to endorse or promote products derived from this software
1853541Sshin *    without specific prior written permission.
1953541Sshin *
2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2353541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3053541Sshin * SUCH DAMAGE.
3153541Sshin */
3253541Sshin
3362587Sitojun#include "opt_inet.h"
3462587Sitojun#include "opt_inet6.h"
3555009Sshin
3653541Sshin#include <sys/param.h>
3753541Sshin#include <sys/systm.h>
3853541Sshin#include <sys/malloc.h>
3953541Sshin#include <sys/mbuf.h>
4053541Sshin#include <sys/socket.h>
4153541Sshin#include <sys/sockio.h>
4253541Sshin#include <sys/time.h>
4353541Sshin#include <sys/kernel.h>
4453541Sshin#include <sys/errno.h>
4553541Sshin#include <sys/syslog.h>
4653541Sshin#include <sys/queue.h>
4778064Sume#include <sys/callout.h>
4853541Sshin
4953541Sshin#include <net/if.h>
5053541Sshin#include <net/if_types.h>
5153541Sshin#include <net/if_dl.h>
5253541Sshin#include <net/route.h>
5353541Sshin
5453541Sshin#include <netinet/in.h>
5553541Sshin#include <netinet/in_var.h>
5653541Sshin#include <netinet6/in6_var.h>
5762587Sitojun#include <netinet/ip6.h>
5853541Sshin#include <netinet6/ip6_var.h>
5953541Sshin#include <netinet6/nd6.h>
6062587Sitojun#include <netinet/icmp6.h>
6153541Sshin
6253541Sshin#include <net/net_osdep.h>
6353541Sshin
6462587Sitojun#define SDL(s) ((struct sockaddr_dl *)s)
6553541Sshin
6662587Sitojunstruct dadq;
6762587Sitojunstatic struct dadq *nd6_dad_find __P((struct ifaddr *));
6878064Sumestatic void nd6_dad_starttimer __P((struct dadq *, int));
6978064Sumestatic void nd6_dad_stoptimer __P((struct dadq *));
7062587Sitojunstatic void nd6_dad_timer __P((struct ifaddr *));
7162587Sitojunstatic void nd6_dad_ns_output __P((struct dadq *, struct ifaddr *));
7262587Sitojunstatic void nd6_dad_ns_input __P((struct ifaddr *));
7362587Sitojunstatic void nd6_dad_na_input __P((struct ifaddr *));
7453541Sshin
7562587Sitojunstatic int dad_ignore_ns = 0;	/* ignore NS in DAD - specwise incorrect*/
7662587Sitojunstatic int dad_maxtry = 15;	/* max # of *tries* to transmit DAD packet */
7753541Sshin
7853541Sshin/*
79108470Sschweikh * Input a Neighbor Solicitation Message.
8053541Sshin *
8153541Sshin * Based on RFC 2461
8253541Sshin * Based on RFC 2462 (duplicated address detection)
8353541Sshin */
8453541Sshinvoid
8553541Sshinnd6_ns_input(m, off, icmp6len)
8653541Sshin	struct mbuf *m;
8753541Sshin	int off, icmp6len;
8853541Sshin{
8953541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
9053541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
9162587Sitojun	struct nd_neighbor_solicit *nd_ns;
9253541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
9353541Sshin	struct in6_addr daddr6 = ip6->ip6_dst;
9462587Sitojun	struct in6_addr taddr6;
9553541Sshin	struct in6_addr myaddr6;
9653541Sshin	char *lladdr = NULL;
9753541Sshin	struct ifaddr *ifa;
9853541Sshin	int lladdrlen = 0;
9953541Sshin	int anycast = 0, proxy = 0, tentative = 0;
10053541Sshin	int tlladdr;
10153541Sshin	union nd_opts ndopts;
10262587Sitojun	struct sockaddr_dl *proxydl = NULL;
10353541Sshin
10478064Sume#ifndef PULLDOWN_TEST
10578064Sume	IP6_EXTHDR_CHECK(m, off, icmp6len,);
10678064Sume	nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
10778064Sume#else
10878064Sume	IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
10978064Sume	if (nd_ns == NULL) {
11078064Sume		icmp6stat.icp6s_tooshort++;
11178064Sume		return;
11278064Sume	}
11378064Sume#endif
11478064Sume	ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */
11578064Sume	taddr6 = nd_ns->nd_ns_target;
11678064Sume
11753541Sshin	if (ip6->ip6_hlim != 255) {
11878064Sume		nd6log((LOG_ERR,
11978064Sume		    "nd6_ns_input: invalid hlim (%d) from %s to %s on %s\n",
12078064Sume		    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
12178064Sume		    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
12278064Sume		goto bad;
12353541Sshin	}
12453541Sshin
12553541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
12653541Sshin		/* dst has to be solicited node multicast address. */
127120941Sume		if (daddr6.s6_addr16[0] == IPV6_ADDR_INT16_MLL &&
12895023Ssuz		    /* don't check ifindex portion */
129120941Sume		    daddr6.s6_addr32[1] == 0 &&
130120941Sume		    daddr6.s6_addr32[2] == IPV6_ADDR_INT32_ONE &&
131120941Sume		    daddr6.s6_addr8[12] == 0xff) {
13295023Ssuz			; /* good */
13353541Sshin		} else {
13478064Sume			nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
135120941Sume			    "(wrong ip6 dst)\n"));
13653541Sshin			goto bad;
13753541Sshin		}
13853541Sshin	}
13953541Sshin
14053541Sshin	if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
14178064Sume		nd6log((LOG_INFO, "nd6_ns_input: bad NS target (multicast)\n"));
14253541Sshin		goto bad;
14353541Sshin	}
14453541Sshin
14553541Sshin	if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
14653541Sshin		taddr6.s6_addr16[1] = htons(ifp->if_index);
14753541Sshin
14853541Sshin	icmp6len -= sizeof(*nd_ns);
14953541Sshin	nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
15053541Sshin	if (nd6_options(&ndopts) < 0) {
15178064Sume		nd6log((LOG_INFO,
15278064Sume		    "nd6_ns_input: invalid ND option, ignored\n"));
15378064Sume		/* nd6_options have incremented stats */
15478064Sume		goto freeit;
15553541Sshin	}
15653541Sshin
15753541Sshin	if (ndopts.nd_opts_src_lladdr) {
15895023Ssuz		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
15953541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
16053541Sshin	}
161120941Sume
16253541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) && lladdr) {
16378064Sume		nd6log((LOG_INFO, "nd6_ns_input: bad DAD packet "
16478064Sume		    "(link-layer address option)\n"));
16553541Sshin		goto bad;
16653541Sshin	}
16753541Sshin
16853541Sshin	/*
16953541Sshin	 * Attaching target link-layer address to the NA?
17053541Sshin	 * (RFC 2461 7.2.4)
17153541Sshin	 *
17253541Sshin	 * NS IP dst is unicast/anycast			MUST NOT add
17353541Sshin	 * NS IP dst is solicited-node multicast	MUST add
17453541Sshin	 *
17553541Sshin	 * In implementation, we add target link-layer address by default.
17653541Sshin	 * We do not add one in MUST NOT cases.
17753541Sshin	 */
17862587Sitojun#if 0 /* too much! */
17962587Sitojun	ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &daddr6);
18062587Sitojun	if (ifa && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST))
18162587Sitojun		tlladdr = 0;
18262587Sitojun	else
18362587Sitojun#endif
18453541Sshin	if (!IN6_IS_ADDR_MULTICAST(&daddr6))
18553541Sshin		tlladdr = 0;
18653541Sshin	else
18753541Sshin		tlladdr = 1;
18853541Sshin
18953541Sshin	/*
19053541Sshin	 * Target address (taddr6) must be either:
19153541Sshin	 * (1) Valid unicast/anycast address for my receiving interface,
19253541Sshin	 * (2) Unicast address for which I'm offering proxy service, or
19353541Sshin	 * (3) "tentative" address on which DAD is being performed.
19453541Sshin	 */
19553541Sshin	/* (1) and (3) check. */
19653541Sshin	ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
19753541Sshin
19853541Sshin	/* (2) check. */
19962587Sitojun	if (!ifa) {
20053541Sshin		struct rtentry *rt;
20153541Sshin		struct sockaddr_in6 tsin6;
202121765Ssam		int need_proxy;
20353541Sshin
20453541Sshin		bzero(&tsin6, sizeof tsin6);
20553541Sshin		tsin6.sin6_len = sizeof(struct sockaddr_in6);
20653541Sshin		tsin6.sin6_family = AF_INET6;
20753541Sshin		tsin6.sin6_addr = taddr6;
20853541Sshin
20953541Sshin		rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
210121765Ssam		need_proxy = (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
211121765Ssam		    rt->rt_gateway->sa_family == AF_LINK);
212121765Ssam		if (rt)
213121765Ssam			rtfree(rt);
214121765Ssam		if (need_proxy) {
21553541Sshin			/*
21662587Sitojun			 * proxy NDP for single entry
21753541Sshin			 */
21862587Sitojun			ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
21962587Sitojun				IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
22062587Sitojun			if (ifa) {
22153541Sshin				proxy = 1;
22262587Sitojun				proxydl = SDL(rt->rt_gateway);
22362587Sitojun			}
22453541Sshin		}
22553541Sshin	}
22653541Sshin	if (!ifa) {
22753541Sshin		/*
22878064Sume		 * We've got an NS packet, and we don't have that adddress
22953541Sshin		 * assigned for us.  We MUST silently ignore it.
23053541Sshin		 * See RFC2461 7.2.3.
23153541Sshin		 */
23262587Sitojun		goto freeit;
23353541Sshin	}
23453541Sshin	myaddr6 = *IFA_IN6(ifa);
23553541Sshin	anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
23653541Sshin	tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
23753541Sshin	if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
23862587Sitojun		goto freeit;
23953541Sshin
24053541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
241120941Sume		nd6log((LOG_INFO, "nd6_ns_input: lladdrlen mismatch for %s "
24253541Sshin		    "(if %d, NS packet %d)\n",
243120941Sume		    ip6_sprintf(&taddr6),
244120941Sume		    ifp->if_addrlen, lladdrlen - 2));
24578064Sume		goto bad;
24653541Sshin	}
24753541Sshin
24853541Sshin	if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
249120941Sume		nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
250120941Sume		    ip6_sprintf(&saddr6)));
25162587Sitojun		goto freeit;
25253541Sshin	}
25353541Sshin
25453541Sshin	/*
25553541Sshin	 * We have neighbor solicitation packet, with target address equals to
25653541Sshin	 * one of my tentative address.
25753541Sshin	 *
25853541Sshin	 * src addr	how to process?
25953541Sshin	 * ---		---
26053541Sshin	 * multicast	of course, invalid (rejected in ip6_input)
26153541Sshin	 * unicast	somebody is doing address resolution -> ignore
26253541Sshin	 * unspec	dup address detection
26353541Sshin	 *
26453541Sshin	 * The processing is defined in RFC 2462.
26553541Sshin	 */
26653541Sshin	if (tentative) {
26753541Sshin		/*
26853541Sshin		 * If source address is unspecified address, it is for
26953541Sshin		 * duplicated address detection.
27053541Sshin		 *
27153541Sshin		 * If not, the packet is for addess resolution;
27253541Sshin		 * silently ignore it.
27353541Sshin		 */
27453541Sshin		if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
27553541Sshin			nd6_dad_ns_input(ifa);
27653541Sshin
27762587Sitojun		goto freeit;
27853541Sshin	}
27953541Sshin
28053541Sshin	/*
28153541Sshin	 * If the source address is unspecified address, entries must not
28253541Sshin	 * be created or updated.
28353541Sshin	 * It looks that sender is performing DAD.  Output NA toward
28453541Sshin	 * all-node multicast address, to tell the sender that I'm using
28553541Sshin	 * the address.
28653541Sshin	 * S bit ("solicited") must be zero.
28753541Sshin	 */
28853541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) {
28953541Sshin		saddr6 = in6addr_linklocal_allnodes;
29053541Sshin		saddr6.s6_addr16[1] = htons(ifp->if_index);
29153541Sshin		nd6_na_output(ifp, &saddr6, &taddr6,
292120941Sume		    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
293120941Sume		    (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0),
294120941Sume		    tlladdr, (struct sockaddr *)proxydl);
29562587Sitojun		goto freeit;
29653541Sshin	}
29753541Sshin
298120941Sume	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
299120941Sume	    ND_NEIGHBOR_SOLICIT, 0);
30053541Sshin
30153541Sshin	nd6_na_output(ifp, &saddr6, &taddr6,
302120941Sume	    ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
303120941Sume	    (ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
304120941Sume	    tlladdr, (struct sockaddr *)proxydl);
30562587Sitojun freeit:
30662587Sitojun	m_freem(m);
30753541Sshin	return;
30853541Sshin
30953541Sshin bad:
31078064Sume	nd6log((LOG_ERR, "nd6_ns_input: src=%s\n", ip6_sprintf(&saddr6)));
31178064Sume	nd6log((LOG_ERR, "nd6_ns_input: dst=%s\n", ip6_sprintf(&daddr6)));
31278064Sume	nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n", ip6_sprintf(&taddr6)));
31378064Sume	icmp6stat.icp6s_badns++;
31462587Sitojun	m_freem(m);
31553541Sshin}
31653541Sshin
31753541Sshin/*
318108470Sschweikh * Output a Neighbor Solicitation Message. Caller specifies:
31953541Sshin *	- ICMP6 header source IP6 address
32053541Sshin *	- ND6 header target IP6 address
32153541Sshin *	- ND6 header source datalink address
32253541Sshin *
32353541Sshin * Based on RFC 2461
32453541Sshin * Based on RFC 2462 (duplicated address detection)
32553541Sshin */
32653541Sshinvoid
32753541Sshinnd6_ns_output(ifp, daddr6, taddr6, ln, dad)
32853541Sshin	struct ifnet *ifp;
32978064Sume	const struct in6_addr *daddr6, *taddr6;
33053541Sshin	struct llinfo_nd6 *ln;	/* for source address determination */
33153541Sshin	int dad;	/* duplicated address detection */
33253541Sshin{
33353541Sshin	struct mbuf *m;
33453541Sshin	struct ip6_hdr *ip6;
33553541Sshin	struct nd_neighbor_solicit *nd_ns;
33653541Sshin	struct in6_ifaddr *ia = NULL;
33753541Sshin	struct ip6_moptions im6o;
33853541Sshin	int icmp6len;
33962587Sitojun	int maxlen;
34053541Sshin	caddr_t mac;
34153541Sshin	struct ifnet *outif = NULL;
342120941Sume
34353541Sshin	if (IN6_IS_ADDR_MULTICAST(taddr6))
34453541Sshin		return;
34553541Sshin
34662587Sitojun	/* estimate the size of message */
34762587Sitojun	maxlen = sizeof(*ip6) + sizeof(*nd_ns);
34862587Sitojun	maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
34962587Sitojun	if (max_linkhdr + maxlen >= MCLBYTES) {
35062587Sitojun#ifdef DIAGNOSTIC
35162587Sitojun		printf("nd6_ns_output: max_linkhdr + maxlen >= MCLBYTES "
35262587Sitojun		    "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
35362587Sitojun#endif
35453541Sshin		return;
35562587Sitojun	}
35653541Sshin
357111119Simp	MGETHDR(m, M_DONTWAIT, MT_DATA);
35862587Sitojun	if (m && max_linkhdr + maxlen >= MHLEN) {
359111119Simp		MCLGET(m, M_DONTWAIT);
36062587Sitojun		if ((m->m_flags & M_EXT) == 0) {
36162587Sitojun			m_free(m);
36262587Sitojun			m = NULL;
36362587Sitojun		}
36462587Sitojun	}
36562587Sitojun	if (m == NULL)
36662587Sitojun		return;
36778064Sume	m->m_pkthdr.rcvif = NULL;
36862587Sitojun
36953541Sshin	if (daddr6 == NULL || IN6_IS_ADDR_MULTICAST(daddr6)) {
37053541Sshin		m->m_flags |= M_MCAST;
37153541Sshin		im6o.im6o_multicast_ifp = ifp;
37253541Sshin		im6o.im6o_multicast_hlim = 255;
37353541Sshin		im6o.im6o_multicast_loop = 0;
37453541Sshin	}
37553541Sshin
37653541Sshin	icmp6len = sizeof(*nd_ns);
37753541Sshin	m->m_pkthdr.len = m->m_len = sizeof(*ip6) + icmp6len;
37895023Ssuz	m->m_data += max_linkhdr;	/* or MH_ALIGN() equivalent? */
37953541Sshin
38053541Sshin	/* fill neighbor solicitation packet */
38153541Sshin	ip6 = mtod(m, struct ip6_hdr *);
38253541Sshin	ip6->ip6_flow = 0;
38362587Sitojun	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
38462587Sitojun	ip6->ip6_vfc |= IPV6_VERSION;
38553541Sshin	/* ip6->ip6_plen will be set later */
38653541Sshin	ip6->ip6_nxt = IPPROTO_ICMPV6;
38753541Sshin	ip6->ip6_hlim = 255;
38853541Sshin	if (daddr6)
38953541Sshin		ip6->ip6_dst = *daddr6;
39053541Sshin	else {
39153541Sshin		ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
39253541Sshin		ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
39353541Sshin		ip6->ip6_dst.s6_addr32[1] = 0;
39453541Sshin		ip6->ip6_dst.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
39553541Sshin		ip6->ip6_dst.s6_addr32[3] = taddr6->s6_addr32[3];
39653541Sshin		ip6->ip6_dst.s6_addr8[12] = 0xff;
39753541Sshin	}
39853541Sshin	if (!dad) {
39953541Sshin		/*
40053541Sshin		 * RFC2461 7.2.2:
40153541Sshin		 * "If the source address of the packet prompting the
40253541Sshin		 * solicitation is the same as one of the addresses assigned
40353541Sshin		 * to the outgoing interface, that address SHOULD be placed
40453541Sshin		 * in the IP Source Address of the outgoing solicitation.
40553541Sshin		 * Otherwise, any one of the addresses assigned to the
40653541Sshin		 * interface should be used."
40753541Sshin		 *
40853541Sshin		 * We use the source address for the prompting packet
40953541Sshin		 * (saddr6), if:
41053541Sshin		 * - saddr6 is given from the caller (by giving "ln"), and
41153541Sshin		 * - saddr6 belongs to the outgoing interface.
41253541Sshin		 * Otherwise, we perform a scope-wise match.
41353541Sshin		 */
41495023Ssuz		struct ip6_hdr *hip6;		/* hold ip6 */
41553541Sshin		struct in6_addr *saddr6;
41653541Sshin
41753541Sshin		if (ln && ln->ln_hold) {
41853541Sshin			hip6 = mtod(ln->ln_hold, struct ip6_hdr *);
41953541Sshin			/* XXX pullup? */
42053541Sshin			if (sizeof(*hip6) < ln->ln_hold->m_len)
42153541Sshin				saddr6 = &hip6->ip6_src;
42253541Sshin			else
42353541Sshin				saddr6 = NULL;
42453541Sshin		} else
42553541Sshin			saddr6 = NULL;
42653541Sshin		if (saddr6 && in6ifa_ifpwithaddr(ifp, saddr6))
42753541Sshin			bcopy(saddr6, &ip6->ip6_src, sizeof(*saddr6));
42853541Sshin		else {
42953541Sshin			ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
43053541Sshin			if (ia == NULL) {
43195023Ssuz				m_freem(m);
43253541Sshin				return;
43353541Sshin			}
43453541Sshin			ip6->ip6_src = ia->ia_addr.sin6_addr;
43553541Sshin		}
43653541Sshin	} else {
43753541Sshin		/*
43853541Sshin		 * Source address for DAD packet must always be IPv6
43953541Sshin		 * unspecified address. (0::0)
44053541Sshin		 */
44153541Sshin		bzero(&ip6->ip6_src, sizeof(ip6->ip6_src));
44253541Sshin	}
44353541Sshin	nd_ns = (struct nd_neighbor_solicit *)(ip6 + 1);
44453541Sshin	nd_ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
44553541Sshin	nd_ns->nd_ns_code = 0;
44653541Sshin	nd_ns->nd_ns_reserved = 0;
44753541Sshin	nd_ns->nd_ns_target = *taddr6;
448121315Sume	in6_clearscope(&nd_ns->nd_ns_target); /* XXX */
44953541Sshin
45053541Sshin	/*
45153541Sshin	 * Add source link-layer address option.
45253541Sshin	 *
45353541Sshin	 *				spec		implementation
45453541Sshin	 *				---		---
45553541Sshin	 * DAD packet			MUST NOT	do not add the option
45653541Sshin	 * there's no link layer address:
45753541Sshin	 *				impossible	do not add the option
45853541Sshin	 * there's link layer address:
45953541Sshin	 *	Multicast NS		MUST add one	add the option
46053541Sshin	 *	Unicast NS		SHOULD add one	add the option
46153541Sshin	 */
46253541Sshin	if (!dad && (mac = nd6_ifptomac(ifp))) {
46353541Sshin		int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
46453541Sshin		struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
46553541Sshin		/* 8 byte alignments... */
46653541Sshin		optlen = (optlen + 7) & ~7;
467120941Sume
46853541Sshin		m->m_pkthdr.len += optlen;
46953541Sshin		m->m_len += optlen;
47053541Sshin		icmp6len += optlen;
47153541Sshin		bzero((caddr_t)nd_opt, optlen);
47253541Sshin		nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
47353541Sshin		nd_opt->nd_opt_len = optlen >> 3;
47453541Sshin		bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
47553541Sshin	}
47653541Sshin
47753541Sshin	ip6->ip6_plen = htons((u_short)icmp6len);
47853541Sshin	nd_ns->nd_ns_cksum = 0;
479120941Sume	nd_ns->nd_ns_cksum =
480120941Sume	    in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
48153541Sshin
482105194Ssam	ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif, NULL);
48353541Sshin	if (outif) {
48453541Sshin		icmp6_ifstat_inc(outif, ifs6_out_msg);
48553541Sshin		icmp6_ifstat_inc(outif, ifs6_out_neighborsolicit);
48653541Sshin	}
48753541Sshin	icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++;
48853541Sshin}
48953541Sshin
49053541Sshin/*
49153541Sshin * Neighbor advertisement input handling.
49253541Sshin *
49353541Sshin * Based on RFC 2461
49453541Sshin * Based on RFC 2462 (duplicated address detection)
49562587Sitojun *
49662587Sitojun * the following items are not implemented yet:
49762587Sitojun * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
49862587Sitojun * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
49953541Sshin */
50053541Sshinvoid
50153541Sshinnd6_na_input(m, off, icmp6len)
50253541Sshin	struct mbuf *m;
50353541Sshin	int off, icmp6len;
50453541Sshin{
50553541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
50653541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
50762587Sitojun	struct nd_neighbor_advert *nd_na;
50853541Sshin	struct in6_addr daddr6 = ip6->ip6_dst;
50962587Sitojun	struct in6_addr taddr6;
51062587Sitojun	int flags;
51162587Sitojun	int is_router;
51262587Sitojun	int is_solicited;
51362587Sitojun	int is_override;
51453541Sshin	char *lladdr = NULL;
51553541Sshin	int lladdrlen = 0;
51653541Sshin	struct ifaddr *ifa;
51753541Sshin	struct llinfo_nd6 *ln;
51853541Sshin	struct rtentry *rt;
51953541Sshin	struct sockaddr_dl *sdl;
52053541Sshin	union nd_opts ndopts;
52153541Sshin
52253541Sshin	if (ip6->ip6_hlim != 255) {
52378064Sume		nd6log((LOG_ERR,
52478064Sume		    "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n",
52578064Sume		    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
52678064Sume		    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
52778064Sume		goto bad;
52862587Sitojun	}
52962587Sitojun
53062587Sitojun#ifndef PULLDOWN_TEST
53162587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
53262587Sitojun	nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off);
53362587Sitojun#else
53462587Sitojun	IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len);
53562587Sitojun	if (nd_na == NULL) {
53662587Sitojun		icmp6stat.icp6s_tooshort++;
53753541Sshin		return;
53853541Sshin	}
53962587Sitojun#endif
54062587Sitojun	taddr6 = nd_na->nd_na_target;
54162587Sitojun	flags = nd_na->nd_na_flags_reserved;
54262587Sitojun	is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
54362587Sitojun	is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
54462587Sitojun	is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
54553541Sshin
54653541Sshin	if (IN6_IS_SCOPE_LINKLOCAL(&taddr6))
54753541Sshin		taddr6.s6_addr16[1] = htons(ifp->if_index);
54853541Sshin
54953541Sshin	if (IN6_IS_ADDR_MULTICAST(&taddr6)) {
55078064Sume		nd6log((LOG_ERR,
55153541Sshin		    "nd6_na_input: invalid target address %s\n",
55278064Sume		    ip6_sprintf(&taddr6)));
55378064Sume		goto bad;
55453541Sshin	}
55553541Sshin	if (IN6_IS_ADDR_MULTICAST(&daddr6))
55653541Sshin		if (is_solicited) {
55778064Sume			nd6log((LOG_ERR,
55878064Sume			    "nd6_na_input: a solicited adv is multicasted\n"));
55978064Sume			goto bad;
56053541Sshin		}
56153541Sshin
56253541Sshin	icmp6len -= sizeof(*nd_na);
56353541Sshin	nd6_option_init(nd_na + 1, icmp6len, &ndopts);
56453541Sshin	if (nd6_options(&ndopts) < 0) {
56578064Sume		nd6log((LOG_INFO,
56678064Sume		    "nd6_na_input: invalid ND option, ignored\n"));
56778064Sume		/* nd6_options have incremented stats */
56862587Sitojun		goto freeit;
56953541Sshin	}
57053541Sshin
57153541Sshin	if (ndopts.nd_opts_tgt_lladdr) {
57253541Sshin		lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
57353541Sshin		lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
57453541Sshin	}
57553541Sshin
57653541Sshin	ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
57753541Sshin
57853541Sshin	/*
57953541Sshin	 * Target address matches one of my interface address.
58053541Sshin	 *
58153541Sshin	 * If my address is tentative, this means that there's somebody
58253541Sshin	 * already using the same address as mine.  This indicates DAD failure.
58353541Sshin	 * This is defined in RFC 2462.
58453541Sshin	 *
58553541Sshin	 * Otherwise, process as defined in RFC 2461.
58653541Sshin	 */
58753541Sshin	if (ifa
58853541Sshin	 && (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
58953541Sshin		nd6_dad_na_input(ifa);
59062587Sitojun		goto freeit;
59153541Sshin	}
59253541Sshin
59395023Ssuz	/* Just for safety, maybe unnecessary. */
59453541Sshin	if (ifa) {
59553541Sshin		log(LOG_ERR,
59653541Sshin		    "nd6_na_input: duplicate IP6 address %s\n",
59753541Sshin		    ip6_sprintf(&taddr6));
59862587Sitojun		goto freeit;
59953541Sshin	}
60053541Sshin
60153541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
602120941Sume		nd6log((LOG_INFO, "nd6_na_input: lladdrlen mismatch for %s "
603120941Sume		    "(if %d, NA packet %d)\n", ip6_sprintf(&taddr6),
604120941Sume		    ifp->if_addrlen, lladdrlen - 2));
60578064Sume		goto bad;
60653541Sshin	}
60753541Sshin
60853541Sshin	/*
609120941Sume	 * If no neighbor cache entry is found, NA SHOULD silently be
610120941Sume	 * discarded.
61153541Sshin	 */
61253541Sshin	rt = nd6_lookup(&taddr6, 0, ifp);
61353541Sshin	if ((rt == NULL) ||
61453541Sshin	   ((ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) ||
61553541Sshin	   ((sdl = SDL(rt->rt_gateway)) == NULL))
61662587Sitojun		goto freeit;
61753541Sshin
61853541Sshin	if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
61953541Sshin		/*
62053541Sshin		 * If the link-layer has address, and no lladdr option came,
62153541Sshin		 * discard the packet.
62253541Sshin		 */
62353541Sshin		if (ifp->if_addrlen && !lladdr)
62462587Sitojun			goto freeit;
62553541Sshin
62653541Sshin		/*
62753541Sshin		 * Record link-layer address, and update the state.
62853541Sshin		 */
62953541Sshin		sdl->sdl_alen = ifp->if_addrlen;
63053541Sshin		bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
63153541Sshin		if (is_solicited) {
63253541Sshin			ln->ln_state = ND6_LLINFO_REACHABLE;
63362587Sitojun			ln->ln_byhint = 0;
634120941Sume			if (ln->ln_expire) {
63553541Sshin				ln->ln_expire = time_second +
636121161Sume				    ND_IFINFO(rt->rt_ifp)->reachable;
637120941Sume			}
63878064Sume		} else {
63953541Sshin			ln->ln_state = ND6_LLINFO_STALE;
64078064Sume			ln->ln_expire = time_second + nd6_gctimer;
64178064Sume		}
64278064Sume		if ((ln->ln_router = is_router) != 0) {
64378064Sume			/*
64478064Sume			 * This means a router's state has changed from
64578064Sume			 * non-reachable to probably reachable, and might
64678064Sume			 * affect the status of associated prefixes..
64778064Sume			 */
64878064Sume			pfxlist_onlink_check();
64978064Sume		}
65053541Sshin	} else {
65153541Sshin		int llchange;
65253541Sshin
65353541Sshin		/*
65453541Sshin		 * Check if the link-layer address has changed or not.
65553541Sshin		 */
65653541Sshin		if (!lladdr)
65753541Sshin			llchange = 0;
65853541Sshin		else {
65953541Sshin			if (sdl->sdl_alen) {
66053541Sshin				if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen))
66153541Sshin					llchange = 1;
66253541Sshin				else
66353541Sshin					llchange = 0;
66453541Sshin			} else
66553541Sshin				llchange = 1;
66653541Sshin		}
66753541Sshin
66853541Sshin		/*
66953541Sshin		 * This is VERY complex.  Look at it with care.
67053541Sshin		 *
67153541Sshin		 * override solicit lladdr llchange	action
67253541Sshin		 *					(L: record lladdr)
67353541Sshin		 *
67453541Sshin		 *	0	0	n	--	(2c)
67553541Sshin		 *	0	0	y	n	(2b) L
67653541Sshin		 *	0	0	y	y	(1)    REACHABLE->STALE
67753541Sshin		 *	0	1	n	--	(2c)   *->REACHABLE
67853541Sshin		 *	0	1	y	n	(2b) L *->REACHABLE
67953541Sshin		 *	0	1	y	y	(1)    REACHABLE->STALE
68053541Sshin		 *	1	0	n	--	(2a)
68153541Sshin		 *	1	0	y	n	(2a) L
68253541Sshin		 *	1	0	y	y	(2a) L *->STALE
68353541Sshin		 *	1	1	n	--	(2a)   *->REACHABLE
68453541Sshin		 *	1	1	y	n	(2a) L *->REACHABLE
68553541Sshin		 *	1	1	y	y	(2a) L *->REACHABLE
68653541Sshin		 */
68753541Sshin		if (!is_override && (lladdr && llchange)) {	   /* (1) */
68853541Sshin			/*
68953541Sshin			 * If state is REACHABLE, make it STALE.
69053541Sshin			 * no other updates should be done.
69153541Sshin			 */
69278064Sume			if (ln->ln_state == ND6_LLINFO_REACHABLE) {
69353541Sshin				ln->ln_state = ND6_LLINFO_STALE;
69478064Sume				ln->ln_expire = time_second + nd6_gctimer;
69578064Sume			}
69662587Sitojun			goto freeit;
69753541Sshin		} else if (is_override				   /* (2a) */
69853541Sshin			|| (!is_override && (lladdr && !llchange)) /* (2b) */
69953541Sshin			|| !lladdr) {				   /* (2c) */
70053541Sshin			/*
70153541Sshin			 * Update link-local address, if any.
70253541Sshin			 */
70353541Sshin			if (lladdr) {
70453541Sshin				sdl->sdl_alen = ifp->if_addrlen;
70553541Sshin				bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);
70653541Sshin			}
70753541Sshin
70853541Sshin			/*
70953541Sshin			 * If solicited, make the state REACHABLE.
71053541Sshin			 * If not solicited and the link-layer address was
71153541Sshin			 * changed, make it STALE.
71253541Sshin			 */
71353541Sshin			if (is_solicited) {
71453541Sshin				ln->ln_state = ND6_LLINFO_REACHABLE;
71562587Sitojun				ln->ln_byhint = 0;
71653541Sshin				if (ln->ln_expire) {
71753541Sshin					ln->ln_expire = time_second +
718121161Sume					    ND_IFINFO(ifp)->reachable;
71953541Sshin				}
72053541Sshin			} else {
72178064Sume				if (lladdr && llchange) {
72253541Sshin					ln->ln_state = ND6_LLINFO_STALE;
72378064Sume					ln->ln_expire = time_second + nd6_gctimer;
72478064Sume				}
72553541Sshin			}
72653541Sshin		}
72753541Sshin
72853541Sshin		if (ln->ln_router && !is_router) {
72953541Sshin			/*
73053541Sshin			 * The peer dropped the router flag.
73153541Sshin			 * Remove the sender from the Default Router List and
73253541Sshin			 * update the Destination Cache entries.
73353541Sshin			 */
73453541Sshin			struct nd_defrouter *dr;
73553541Sshin			struct in6_addr *in6;
73653541Sshin			int s;
73753541Sshin
73853541Sshin			in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;
73995023Ssuz
74095023Ssuz			/*
74195023Ssuz			 * Lock to protect the default router list.
74295023Ssuz			 * XXX: this might be unnecessary, since this function
74395023Ssuz			 * is only called under the network software interrupt
744120941Sume			 * context.  However, we keep it just for safety.
74595023Ssuz			 */
74653541Sshin			s = splnet();
747128422Sluigi			dr = defrouter_lookup(in6, ifp);
74853541Sshin			if (dr)
74953541Sshin				defrtrlist_del(dr);
75053541Sshin			else if (!ip6_forwarding && ip6_accept_rtadv) {
75153541Sshin				/*
75253541Sshin				 * Even if the neighbor is not in the default
75353541Sshin				 * router list, the neighbor may be used
75453541Sshin				 * as a next hop for some destinations
75553541Sshin				 * (e.g. redirect case). So we must
75653541Sshin				 * call rt6_flush explicitly.
75753541Sshin				 */
758128422Sluigi				rt6_flush(&ip6->ip6_src, ifp);
75953541Sshin			}
76053541Sshin			splx(s);
76153541Sshin		}
76253541Sshin		ln->ln_router = is_router;
76353541Sshin	}
76453541Sshin	rt->rt_flags &= ~RTF_REJECT;
76553541Sshin	ln->ln_asked = 0;
76653541Sshin	if (ln->ln_hold) {
76762587Sitojun		/*
76895023Ssuz		 * we assume ifp is not a loopback here, so just set the 2nd
76962587Sitojun		 * argument as the 1st one.
77062587Sitojun		 */
77162587Sitojun		nd6_output(ifp, ifp, ln->ln_hold,
77253541Sshin			   (struct sockaddr_in6 *)rt_key(rt), rt);
773120941Sume		ln->ln_hold = NULL;
77453541Sshin	}
77562587Sitojun
77662587Sitojun freeit:
77762587Sitojun	m_freem(m);
77878064Sume	return;
77978064Sume
78078064Sume bad:
78178064Sume	icmp6stat.icp6s_badna++;
78278064Sume	m_freem(m);
78353541Sshin}
78453541Sshin
78553541Sshin/*
78653541Sshin * Neighbor advertisement output handling.
78753541Sshin *
78853541Sshin * Based on RFC 2461
78953541Sshin *
79062587Sitojun * the following items are not implemented yet:
79162587Sitojun * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
79262587Sitojun * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
79353541Sshin */
79453541Sshinvoid
79562587Sitojunnd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
79653541Sshin	struct ifnet *ifp;
79778064Sume	const struct in6_addr *daddr6, *taddr6;
79853541Sshin	u_long flags;
79962587Sitojun	int tlladdr;		/* 1 if include target link-layer address */
80062587Sitojun	struct sockaddr *sdl0;	/* sockaddr_dl (= proxy NA) or NULL */
80153541Sshin{
80253541Sshin	struct mbuf *m;
80353541Sshin	struct ip6_hdr *ip6;
80453541Sshin	struct nd_neighbor_advert *nd_na;
80553541Sshin	struct in6_ifaddr *ia = NULL;
80653541Sshin	struct ip6_moptions im6o;
80753541Sshin	int icmp6len;
80862587Sitojun	int maxlen;
80992733Speter	caddr_t mac = NULL;
81062587Sitojun	struct ifnet *outif = NULL;
81162587Sitojun
81262587Sitojun	/* estimate the size of message */
81362587Sitojun	maxlen = sizeof(*ip6) + sizeof(*nd_na);
81462587Sitojun	maxlen += (sizeof(struct nd_opt_hdr) + ifp->if_addrlen + 7) & ~7;
81562587Sitojun	if (max_linkhdr + maxlen >= MCLBYTES) {
81662587Sitojun#ifdef DIAGNOSTIC
81762587Sitojun		printf("nd6_na_output: max_linkhdr + maxlen >= MCLBYTES "
81862587Sitojun		    "(%d + %d > %d)\n", max_linkhdr, maxlen, MCLBYTES);
81962587Sitojun#endif
82053541Sshin		return;
82162587Sitojun	}
82253541Sshin
823111119Simp	MGETHDR(m, M_DONTWAIT, MT_DATA);
82462587Sitojun	if (m && max_linkhdr + maxlen >= MHLEN) {
825111119Simp		MCLGET(m, M_DONTWAIT);
82662587Sitojun		if ((m->m_flags & M_EXT) == 0) {
82762587Sitojun			m_free(m);
82862587Sitojun			m = NULL;
82962587Sitojun		}
83062587Sitojun	}
83162587Sitojun	if (m == NULL)
83262587Sitojun		return;
83378064Sume	m->m_pkthdr.rcvif = NULL;
83462587Sitojun
83553541Sshin	if (IN6_IS_ADDR_MULTICAST(daddr6)) {
83653541Sshin		m->m_flags |= M_MCAST;
83753541Sshin		im6o.im6o_multicast_ifp = ifp;
83853541Sshin		im6o.im6o_multicast_hlim = 255;
83953541Sshin		im6o.im6o_multicast_loop = 0;
84053541Sshin	}
84153541Sshin
84253541Sshin	icmp6len = sizeof(*nd_na);
84353541Sshin	m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + icmp6len;
84495023Ssuz	m->m_data += max_linkhdr;	/* or MH_ALIGN() equivalent? */
84553541Sshin
84653541Sshin	/* fill neighbor advertisement packet */
84753541Sshin	ip6 = mtod(m, struct ip6_hdr *);
84853541Sshin	ip6->ip6_flow = 0;
84962587Sitojun	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
85062587Sitojun	ip6->ip6_vfc |= IPV6_VERSION;
85153541Sshin	ip6->ip6_nxt = IPPROTO_ICMPV6;
85253541Sshin	ip6->ip6_hlim = 255;
85353541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(daddr6)) {
85453541Sshin		/* reply to DAD */
85553541Sshin		ip6->ip6_dst.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
85653541Sshin		ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
85753541Sshin		ip6->ip6_dst.s6_addr32[1] = 0;
85853541Sshin		ip6->ip6_dst.s6_addr32[2] = 0;
85953541Sshin		ip6->ip6_dst.s6_addr32[3] = IPV6_ADDR_INT32_ONE;
86053541Sshin		flags &= ~ND_NA_FLAG_SOLICITED;
86153541Sshin	} else
86253541Sshin		ip6->ip6_dst = *daddr6;
86353541Sshin
86453541Sshin	/*
86553541Sshin	 * Select a source whose scope is the same as that of the dest.
86653541Sshin	 */
86753541Sshin	ia = in6_ifawithifp(ifp, &ip6->ip6_dst);
86853541Sshin	if (ia == NULL) {
86953541Sshin		m_freem(m);
87053541Sshin		return;
87153541Sshin	}
87253541Sshin	ip6->ip6_src = ia->ia_addr.sin6_addr;
87353541Sshin	nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
87453541Sshin	nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
87553541Sshin	nd_na->nd_na_code = 0;
87653541Sshin	nd_na->nd_na_target = *taddr6;
877121315Sume	in6_clearscope(&nd_na->nd_na_target); /* XXX */
87853541Sshin
87953541Sshin	/*
88053541Sshin	 * "tlladdr" indicates NS's condition for adding tlladdr or not.
88153541Sshin	 * see nd6_ns_input() for details.
88253541Sshin	 * Basically, if NS packet is sent to unicast/anycast addr,
88353541Sshin	 * target lladdr option SHOULD NOT be included.
88453541Sshin	 */
88562587Sitojun	if (tlladdr) {
88662587Sitojun		/*
88762587Sitojun		 * sdl0 != NULL indicates proxy NA.  If we do proxy, use
88862587Sitojun		 * lladdr in sdl0.  If we are not proxying (sending NA for
88962587Sitojun		 * my address) use lladdr configured for the interface.
89062587Sitojun		 */
89162587Sitojun		if (sdl0 == NULL)
89262587Sitojun			mac = nd6_ifptomac(ifp);
89362587Sitojun		else if (sdl0->sa_family == AF_LINK) {
89462587Sitojun			struct sockaddr_dl *sdl;
89562587Sitojun			sdl = (struct sockaddr_dl *)sdl0;
89662587Sitojun			if (sdl->sdl_alen == ifp->if_addrlen)
89762587Sitojun				mac = LLADDR(sdl);
89862587Sitojun		}
89962587Sitojun	}
90062587Sitojun	if (tlladdr && mac) {
90153541Sshin		int optlen = sizeof(struct nd_opt_hdr) + ifp->if_addrlen;
90253541Sshin		struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
903120941Sume
90453541Sshin		/* roundup to 8 bytes alignment! */
90553541Sshin		optlen = (optlen + 7) & ~7;
90653541Sshin
90753541Sshin		m->m_pkthdr.len += optlen;
90853541Sshin		m->m_len += optlen;
90953541Sshin		icmp6len += optlen;
91053541Sshin		bzero((caddr_t)nd_opt, optlen);
91153541Sshin		nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
91253541Sshin		nd_opt->nd_opt_len = optlen >> 3;
91353541Sshin		bcopy(mac, (caddr_t)(nd_opt + 1), ifp->if_addrlen);
91453541Sshin	} else
91553541Sshin		flags &= ~ND_NA_FLAG_OVERRIDE;
91653541Sshin
91753541Sshin	ip6->ip6_plen = htons((u_short)icmp6len);
91853541Sshin	nd_na->nd_na_flags_reserved = flags;
91953541Sshin	nd_na->nd_na_cksum = 0;
92053541Sshin	nd_na->nd_na_cksum =
921120941Sume	    in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
92253541Sshin
923105194Ssam	ip6_output(m, NULL, NULL, 0, &im6o, &outif, NULL);
92453541Sshin	if (outif) {
92553541Sshin		icmp6_ifstat_inc(outif, ifs6_out_msg);
92653541Sshin		icmp6_ifstat_inc(outif, ifs6_out_neighboradvert);
92753541Sshin	}
92853541Sshin	icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
92953541Sshin}
93053541Sshin
93153541Sshincaddr_t
93253541Sshinnd6_ifptomac(ifp)
93353541Sshin	struct ifnet *ifp;
93453541Sshin{
93553541Sshin	switch (ifp->if_type) {
93653541Sshin	case IFT_ARCNET:
93753541Sshin	case IFT_ETHER:
93853541Sshin	case IFT_FDDI:
93978064Sume	case IFT_IEEE1394:
94078468Ssumikawa#ifdef IFT_L2VLAN
94178468Ssumikawa	case IFT_L2VLAN:
94278468Ssumikawa#endif
94378064Sume#ifdef IFT_IEEE80211
94478064Sume	case IFT_IEEE80211:
94578064Sume#endif
946120049Smdodd	case IFT_ISO88025:
94753541Sshin		return ((caddr_t)(ifp + 1));
94853541Sshin	default:
94953541Sshin		return NULL;
95053541Sshin	}
95153541Sshin}
95253541Sshin
95360938SjakeTAILQ_HEAD(dadq_head, dadq);
95453541Sshinstruct dadq {
95560938Sjake	TAILQ_ENTRY(dadq) dad_list;
95653541Sshin	struct ifaddr *dad_ifa;
95753541Sshin	int dad_count;		/* max NS to send */
95862587Sitojun	int dad_ns_tcount;	/* # of trials to send NS */
95953541Sshin	int dad_ns_ocount;	/* NS sent so far */
96053541Sshin	int dad_ns_icount;
96153541Sshin	int dad_na_icount;
96278064Sume	struct callout dad_timer_ch;
96353541Sshin};
96453541Sshin
96553541Sshinstatic struct dadq_head dadq;
96678064Sumestatic int dad_init = 0;
96753541Sshin
96853541Sshinstatic struct dadq *
96953541Sshinnd6_dad_find(ifa)
97053541Sshin	struct ifaddr *ifa;
97153541Sshin{
97253541Sshin	struct dadq *dp;
97353541Sshin
97462587Sitojun	for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) {
97553541Sshin		if (dp->dad_ifa == ifa)
97653541Sshin			return dp;
97753541Sshin	}
97853541Sshin	return NULL;
97953541Sshin}
98053541Sshin
98178064Sumestatic void
98278064Sumend6_dad_starttimer(dp, ticks)
98378064Sume	struct dadq *dp;
98478064Sume	int ticks;
98578064Sume{
98678064Sume
98778064Sume	callout_reset(&dp->dad_timer_ch, ticks,
98878064Sume	    (void (*) __P((void *)))nd6_dad_timer, (void *)dp->dad_ifa);
98978064Sume}
99078064Sume
99178064Sumestatic void
99278064Sumend6_dad_stoptimer(dp)
99378064Sume	struct dadq *dp;
99478064Sume{
99578064Sume
99678064Sume	callout_stop(&dp->dad_timer_ch);
99778064Sume}
99878064Sume
99953541Sshin/*
100053541Sshin * Start Duplicated Address Detection (DAD) for specified interface address.
100153541Sshin */
100253541Sshinvoid
100353541Sshinnd6_dad_start(ifa, tick)
100453541Sshin	struct ifaddr *ifa;
100553541Sshin	int *tick;	/* minimum delay ticks for IFF_UP event */
100653541Sshin{
100753541Sshin	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
100853541Sshin	struct dadq *dp;
100953541Sshin
101053541Sshin	if (!dad_init) {
101153541Sshin		TAILQ_INIT(&dadq);
101253541Sshin		dad_init++;
101353541Sshin	}
101453541Sshin
101553541Sshin	/*
101653541Sshin	 * If we don't need DAD, don't do it.
101753541Sshin	 * There are several cases:
101853541Sshin	 * - DAD is disabled (ip6_dad_count == 0)
101953541Sshin	 * - the interface address is anycast
102053541Sshin	 */
102153541Sshin	if (!(ia->ia6_flags & IN6_IFF_TENTATIVE)) {
102262587Sitojun		log(LOG_DEBUG,
102362587Sitojun			"nd6_dad_start: called with non-tentative address "
102453541Sshin			"%s(%s)\n",
102553541Sshin			ip6_sprintf(&ia->ia_addr.sin6_addr),
102653541Sshin			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
102753541Sshin		return;
102853541Sshin	}
102953541Sshin	if (ia->ia6_flags & IN6_IFF_ANYCAST) {
103053541Sshin		ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
103153541Sshin		return;
103253541Sshin	}
103353541Sshin	if (!ip6_dad_count) {
103453541Sshin		ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
103553541Sshin		return;
103653541Sshin	}
103753541Sshin	if (!ifa->ifa_ifp)
103853541Sshin		panic("nd6_dad_start: ifa->ifa_ifp == NULL");
1039120941Sume	if (!(ifa->ifa_ifp->if_flags & IFF_UP)) {
104053541Sshin		return;
1041120941Sume	}
104253541Sshin	if (nd6_dad_find(ifa) != NULL) {
104353541Sshin		/* DAD already in progress */
104453541Sshin		return;
104553541Sshin	}
104653541Sshin
104753541Sshin	dp = malloc(sizeof(*dp), M_IP6NDP, M_NOWAIT);
104853541Sshin	if (dp == NULL) {
104962587Sitojun		log(LOG_ERR, "nd6_dad_start: memory allocation failed for "
105053541Sshin			"%s(%s)\n",
105153541Sshin			ip6_sprintf(&ia->ia_addr.sin6_addr),
105253541Sshin			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
105353541Sshin		return;
105453541Sshin	}
105553541Sshin	bzero(dp, sizeof(*dp));
105678064Sume	callout_init(&dp->dad_timer_ch, 0);
105753541Sshin	TAILQ_INSERT_TAIL(&dadq, (struct dadq *)dp, dad_list);
105853541Sshin
105978064Sume	nd6log((LOG_DEBUG, "%s: starting DAD for %s\n", if_name(ifa->ifa_ifp),
106078064Sume	    ip6_sprintf(&ia->ia_addr.sin6_addr)));
106153541Sshin
106253541Sshin	/*
106353541Sshin	 * Send NS packet for DAD, ip6_dad_count times.
106453541Sshin	 * Note that we must delay the first transmission, if this is the
106553541Sshin	 * first packet to be sent from the interface after interface
106653541Sshin	 * (re)initialization.
106753541Sshin	 */
106853541Sshin	dp->dad_ifa = ifa;
106995023Ssuz	IFAREF(ifa);	/* just for safety */
107053541Sshin	dp->dad_count = ip6_dad_count;
107153541Sshin	dp->dad_ns_icount = dp->dad_na_icount = 0;
107262587Sitojun	dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
107395023Ssuz	if (tick == NULL) {
107462587Sitojun		nd6_dad_ns_output(dp, ifa);
1075121161Sume		nd6_dad_starttimer(dp,
1076121161Sume		    ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
107753541Sshin	} else {
107853541Sshin		int ntick;
107953541Sshin
108053541Sshin		if (*tick == 0)
1081121807Sume			ntick = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
108253541Sshin		else
1083121807Sume			ntick = *tick + arc4random() % (hz / 2);
108453541Sshin		*tick = ntick;
108578064Sume		nd6_dad_starttimer(dp, ntick);
108653541Sshin	}
108753541Sshin}
108853541Sshin
108978064Sume/*
109078064Sume * terminate DAD unconditionally.  used for address removals.
109178064Sume */
109278064Sumevoid
109378064Sumend6_dad_stop(ifa)
109478064Sume	struct ifaddr *ifa;
109578064Sume{
109678064Sume	struct dadq *dp;
109778064Sume
109878064Sume	if (!dad_init)
109978064Sume		return;
110078064Sume	dp = nd6_dad_find(ifa);
110178064Sume	if (!dp) {
110278064Sume		/* DAD wasn't started yet */
110378064Sume		return;
110478064Sume	}
110578064Sume
110678064Sume	nd6_dad_stoptimer(dp);
110778064Sume
110878064Sume	TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
110978064Sume	free(dp, M_IP6NDP);
111078064Sume	dp = NULL;
111178064Sume	IFAFREE(ifa);
111278064Sume}
111378064Sume
111453541Sshinstatic void
111553541Sshinnd6_dad_timer(ifa)
111653541Sshin	struct ifaddr *ifa;
111753541Sshin{
111853541Sshin	int s;
111953541Sshin	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
112053541Sshin	struct dadq *dp;
112153541Sshin
112295023Ssuz	s = splnet();		/* XXX */
112353541Sshin
112453541Sshin	/* Sanity check */
112553541Sshin	if (ia == NULL) {
112662587Sitojun		log(LOG_ERR, "nd6_dad_timer: called with null parameter\n");
112753541Sshin		goto done;
112853541Sshin	}
112953541Sshin	dp = nd6_dad_find(ifa);
113053541Sshin	if (dp == NULL) {
113162587Sitojun		log(LOG_ERR, "nd6_dad_timer: DAD structure not found\n");
113253541Sshin		goto done;
113353541Sshin	}
113453541Sshin	if (ia->ia6_flags & IN6_IFF_DUPLICATED) {
113562587Sitojun		log(LOG_ERR, "nd6_dad_timer: called with duplicated address "
113653541Sshin			"%s(%s)\n",
113753541Sshin			ip6_sprintf(&ia->ia_addr.sin6_addr),
113853541Sshin			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
113953541Sshin		goto done;
114053541Sshin	}
114153541Sshin	if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0) {
114262587Sitojun		log(LOG_ERR, "nd6_dad_timer: called with non-tentative address "
114353541Sshin			"%s(%s)\n",
114453541Sshin			ip6_sprintf(&ia->ia_addr.sin6_addr),
114553541Sshin			ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
114653541Sshin		goto done;
114753541Sshin	}
114853541Sshin
114962587Sitojun	/* timeouted with IFF_{RUNNING,UP} check */
115062587Sitojun	if (dp->dad_ns_tcount > dad_maxtry) {
115178064Sume		nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
1152120941Sume		    if_name(ifa->ifa_ifp)));
115362587Sitojun
115462587Sitojun		TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
115562587Sitojun		free(dp, M_IP6NDP);
115662587Sitojun		dp = NULL;
115762587Sitojun		IFAFREE(ifa);
115862587Sitojun		goto done;
115962587Sitojun	}
116062587Sitojun
116153541Sshin	/* Need more checks? */
116253541Sshin	if (dp->dad_ns_ocount < dp->dad_count) {
116353541Sshin		/*
116453541Sshin		 * We have more NS to go.  Send NS packet for DAD.
116553541Sshin		 */
116662587Sitojun		nd6_dad_ns_output(dp, ifa);
1167120941Sume		nd6_dad_starttimer(dp,
1168121161Sume		    ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
116953541Sshin	} else {
117053541Sshin		/*
117153541Sshin		 * We have transmitted sufficient number of DAD packets.
117253541Sshin		 * See what we've got.
117353541Sshin		 */
117453541Sshin		int duplicate;
117553541Sshin
117653541Sshin		duplicate = 0;
117753541Sshin
117853541Sshin		if (dp->dad_na_icount) {
117953541Sshin			/*
118053541Sshin			 * the check is in nd6_dad_na_input(),
118153541Sshin			 * but just in case
118253541Sshin			 */
118353541Sshin			duplicate++;
118453541Sshin		}
118553541Sshin
118653541Sshin		if (dp->dad_ns_icount) {
118795023Ssuz#if 0 /* heuristics */
118862587Sitojun			/*
118962587Sitojun			 * if
119062587Sitojun			 * - we have sent many(?) DAD NS, and
119162587Sitojun			 * - the number of NS we sent equals to the
119262587Sitojun			 *   number of NS we've got, and
119362587Sitojun			 * - we've got no NA
119462587Sitojun			 * we may have a faulty network card/driver which
119562587Sitojun			 * loops back multicasts to myself.
119662587Sitojun			 */
119762587Sitojun			if (3 < dp->dad_count
119862587Sitojun			 && dp->dad_ns_icount == dp->dad_count
119962587Sitojun			 && dp->dad_na_icount == 0) {
120062587Sitojun				log(LOG_INFO, "DAD questionable for %s(%s): "
1201120941Sume				    "network card loops back multicast?\n",
1202120941Sume				    ip6_sprintf(&ia->ia_addr.sin6_addr),
1203120941Sume				    if_name(ifa->ifa_ifp));
120462587Sitojun				/* XXX consider it a duplicate or not? */
120562587Sitojun				/* duplicate++; */
120662587Sitojun			} else {
120762587Sitojun				/* We've seen NS, means DAD has failed. */
120862587Sitojun				duplicate++;
120962587Sitojun			}
121062587Sitojun#else
121153541Sshin			/* We've seen NS, means DAD has failed. */
121253541Sshin			duplicate++;
121362587Sitojun#endif
121453541Sshin		}
121553541Sshin
121653541Sshin		if (duplicate) {
121753541Sshin			/* (*dp) will be freed in nd6_dad_duplicated() */
121853541Sshin			dp = NULL;
121953541Sshin			nd6_dad_duplicated(ifa);
122053541Sshin		} else {
122153541Sshin			/*
122253541Sshin			 * We are done with DAD.  No NA came, no NS came.
122353541Sshin			 * duplicated address found.
122453541Sshin			 */
122553541Sshin			ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
122653541Sshin
122778064Sume			nd6log((LOG_DEBUG,
122862587Sitojun			    "%s: DAD complete for %s - no duplicates found\n",
122962587Sitojun			    if_name(ifa->ifa_ifp),
123078064Sume			    ip6_sprintf(&ia->ia_addr.sin6_addr)));
123153541Sshin
123253541Sshin			TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
123353541Sshin			free(dp, M_IP6NDP);
123453541Sshin			dp = NULL;
123562587Sitojun			IFAFREE(ifa);
123653541Sshin		}
123753541Sshin	}
123853541Sshin
123953541Sshindone:
124053541Sshin	splx(s);
124153541Sshin}
124253541Sshin
124353541Sshinvoid
124453541Sshinnd6_dad_duplicated(ifa)
124553541Sshin	struct ifaddr *ifa;
124653541Sshin{
124753541Sshin	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
124853541Sshin	struct dadq *dp;
124953541Sshin
125053541Sshin	dp = nd6_dad_find(ifa);
125153541Sshin	if (dp == NULL) {
125262587Sitojun		log(LOG_ERR, "nd6_dad_duplicated: DAD structure not found\n");
125353541Sshin		return;
125453541Sshin	}
125553541Sshin
125678064Sume	log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "
125778064Sume	    "NS in/out=%d/%d, NA in=%d\n",
125878064Sume	    if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr),
125978064Sume	    dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);
126053541Sshin
126153541Sshin	ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
126253541Sshin	ia->ia6_flags |= IN6_IFF_DUPLICATED;
126353541Sshin
126453541Sshin	/* We are done with DAD, with duplicated address found. (failure) */
126578064Sume	nd6_dad_stoptimer(dp);
126653541Sshin
126762587Sitojun	log(LOG_ERR, "%s: DAD complete for %s - duplicate found\n",
126853541Sshin	    if_name(ifa->ifa_ifp), ip6_sprintf(&ia->ia_addr.sin6_addr));
126962587Sitojun	log(LOG_ERR, "%s: manual intervention required\n",
127062587Sitojun	    if_name(ifa->ifa_ifp));
127153541Sshin
127253541Sshin	TAILQ_REMOVE(&dadq, (struct dadq *)dp, dad_list);
127353541Sshin	free(dp, M_IP6NDP);
127453541Sshin	dp = NULL;
127562587Sitojun	IFAFREE(ifa);
127653541Sshin}
127753541Sshin
127862587Sitojunstatic void
127962587Sitojunnd6_dad_ns_output(dp, ifa)
128062587Sitojun	struct dadq *dp;
128162587Sitojun	struct ifaddr *ifa;
128262587Sitojun{
128362587Sitojun	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
128462587Sitojun	struct ifnet *ifp = ifa->ifa_ifp;
128562587Sitojun
128662587Sitojun	dp->dad_ns_tcount++;
128762587Sitojun	if ((ifp->if_flags & IFF_UP) == 0) {
128862587Sitojun#if 0
128962587Sitojun		printf("%s: interface down?\n", if_name(ifp));
129062587Sitojun#endif
129162587Sitojun		return;
129262587Sitojun	}
129362587Sitojun	if ((ifp->if_flags & IFF_RUNNING) == 0) {
129462587Sitojun#if 0
129562587Sitojun		printf("%s: interface not running?\n", if_name(ifp));
129662587Sitojun#endif
129762587Sitojun		return;
129862587Sitojun	}
129962587Sitojun
130062587Sitojun	dp->dad_ns_ocount++;
130162587Sitojun	nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
130262587Sitojun}
130362587Sitojun
130462587Sitojunstatic void
130553541Sshinnd6_dad_ns_input(ifa)
130653541Sshin	struct ifaddr *ifa;
130753541Sshin{
130853541Sshin	struct in6_ifaddr *ia;
130953541Sshin	struct ifnet *ifp;
131078064Sume	const struct in6_addr *taddr6;
131153541Sshin	struct dadq *dp;
131253541Sshin	int duplicate;
131353541Sshin
131453541Sshin	if (!ifa)
131553541Sshin		panic("ifa == NULL in nd6_dad_ns_input");
131653541Sshin
131753541Sshin	ia = (struct in6_ifaddr *)ifa;
131853541Sshin	ifp = ifa->ifa_ifp;
131953541Sshin	taddr6 = &ia->ia_addr.sin6_addr;
132053541Sshin	duplicate = 0;
132153541Sshin	dp = nd6_dad_find(ifa);
132253541Sshin
132353541Sshin	/* Quickhack - completely ignore DAD NS packets */
132453541Sshin	if (dad_ignore_ns) {
132578064Sume		nd6log((LOG_INFO,
132678064Sume		    "nd6_dad_ns_input: ignoring DAD NS packet for "
132753541Sshin		    "address %s(%s)\n", ip6_sprintf(taddr6),
132878064Sume		    if_name(ifa->ifa_ifp)));
132953541Sshin		return;
133053541Sshin	}
133153541Sshin
133253541Sshin	/*
133353541Sshin	 * if I'm yet to start DAD, someone else started using this address
133453541Sshin	 * first.  I have a duplicate and you win.
133553541Sshin	 */
133653541Sshin	if (!dp || dp->dad_ns_ocount == 0)
133753541Sshin		duplicate++;
133853541Sshin
133953541Sshin	/* XXX more checks for loopback situation - see nd6_dad_timer too */
134053541Sshin
134153541Sshin	if (duplicate) {
134253541Sshin		dp = NULL;	/* will be freed in nd6_dad_duplicated() */
134353541Sshin		nd6_dad_duplicated(ifa);
134453541Sshin	} else {
134553541Sshin		/*
134653541Sshin		 * not sure if I got a duplicate.
134753541Sshin		 * increment ns count and see what happens.
134853541Sshin		 */
134953541Sshin		if (dp)
135053541Sshin			dp->dad_ns_icount++;
135153541Sshin	}
135253541Sshin}
135353541Sshin
135462587Sitojunstatic void
135553541Sshinnd6_dad_na_input(ifa)
135653541Sshin	struct ifaddr *ifa;
135753541Sshin{
135853541Sshin	struct dadq *dp;
135953541Sshin
136053541Sshin	if (!ifa)
136153541Sshin		panic("ifa == NULL in nd6_dad_na_input");
136253541Sshin
136353541Sshin	dp = nd6_dad_find(ifa);
136453541Sshin	if (dp)
136553541Sshin		dp->dad_na_icount++;
136653541Sshin
136753541Sshin	/* remove the address. */
136853541Sshin	nd6_dad_duplicated(ifa);
136953541Sshin}
1370