nd6_rtr.c revision 190964
1139826Simp/*-
253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
353541Sshin * All rights reserved.
453541Sshin *
553541Sshin * Redistribution and use in source and binary forms, with or without
653541Sshin * modification, are permitted provided that the following conditions
753541Sshin * are met:
853541Sshin * 1. Redistributions of source code must retain the above copyright
953541Sshin *    notice, this list of conditions and the following disclaimer.
1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1153541Sshin *    notice, this list of conditions and the following disclaimer in the
1253541Sshin *    documentation and/or other materials provided with the distribution.
1353541Sshin * 3. Neither the name of the project nor the names of its contributors
1453541Sshin *    may be used to endorse or promote products derived from this software
1553541Sshin *    without specific prior written permission.
1653541Sshin *
1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2053541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2753541Sshin * SUCH DAMAGE.
28174510Sobrien *
29174510Sobrien *	$KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $
3053541Sshin */
3153541Sshin
32174510Sobrien#include <sys/cdefs.h>
33174510Sobrien__FBSDID("$FreeBSD: head/sys/netinet6/nd6_rtr.c 190964 2009-04-12 13:22:33Z rwatson $");
34174510Sobrien
3562587Sitojun#include "opt_inet.h"
3662587Sitojun#include "opt_inet6.h"
37189106Sbz#include "opt_route.h"
3862587Sitojun
3953541Sshin#include <sys/param.h>
4053541Sshin#include <sys/systm.h>
4153541Sshin#include <sys/malloc.h>
4253541Sshin#include <sys/mbuf.h>
4353541Sshin#include <sys/socket.h>
4453541Sshin#include <sys/sockio.h>
4553541Sshin#include <sys/time.h>
4678064Sume#include <sys/kernel.h>
47185751Simp#include <sys/lock.h>
4853541Sshin#include <sys/errno.h>
49185747Skmacy#include <sys/rwlock.h>
5053541Sshin#include <sys/syslog.h>
5178064Sume#include <sys/queue.h>
52181803Sbz#include <sys/vimage.h>
5353541Sshin
5453541Sshin#include <net/if.h>
5553541Sshin#include <net/if_types.h>
5653541Sshin#include <net/if_dl.h>
5753541Sshin#include <net/route.h>
5853541Sshin#include <net/radix.h>
59185571Sbz#include <net/vnet.h>
6053541Sshin
6153541Sshin#include <netinet/in.h>
62186119Sqingli#include <net/if_llatbl.h>
6353541Sshin#include <netinet6/in6_var.h>
6478064Sume#include <netinet6/in6_ifattach.h>
6562587Sitojun#include <netinet/ip6.h>
6653541Sshin#include <netinet6/ip6_var.h>
6753541Sshin#include <netinet6/nd6.h>
6862587Sitojun#include <netinet/icmp6.h>
6962587Sitojun#include <netinet6/scope6_var.h>
70185571Sbz#include <netinet6/vinet6.h>
7153541Sshin
72175162Sobrienstatic int rtpref(struct nd_defrouter *);
73175162Sobrienstatic struct nd_defrouter *defrtrlist_update(struct nd_defrouter *);
74151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *,
75151539Ssuz    struct mbuf *, int));
76175162Sobrienstatic struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *,	int);
7762587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
7878064Sume	struct nd_defrouter *));
79175162Sobrienstatic void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *);
80175162Sobrienstatic void pfxrtr_del(struct nd_pfxrouter *);
8162587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router
82175162Sobrien(struct nd_prefix *);
83175162Sobrienstatic void defrouter_delreq(struct nd_defrouter *);
84175162Sobrienstatic void nd6_rtmsg(int, struct rtentry *);
8553541Sshin
86175162Sobrienstatic int in6_init_prefix_ltimes(struct nd_prefix *);
87120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *,
88120941Sume	struct in6_addrlifetime *));
8953541Sshin
90175162Sobrienstatic int rt6_deleteroute(struct radix_node *, void *);
9153541Sshin
92185348Szec#ifdef VIMAGE_GLOBALS
9362587Sitojunextern int nd6_recalc_reachtm_interval;
9453541Sshin
9578064Sumestatic struct ifnet *nd6_defifp;
9662587Sitojunint nd6_defifindex;
9762587Sitojun
98185088Szecint ip6_use_tempaddr;
9978064Sumeint ip6_desync_factor;
100185088Szecu_int32_t ip6_temp_preferred_lifetime;
101185088Szecu_int32_t ip6_temp_valid_lifetime;
102185088Szecint ip6_temp_regen_advance;
103185088Szec#endif
10478064Sume
105151539Ssuz/* RTPREF_MEDIUM has to be 0! */
106151539Ssuz#define RTPREF_HIGH	1
107151539Ssuz#define RTPREF_MEDIUM	0
108151539Ssuz#define RTPREF_LOW	(-1)
109151539Ssuz#define RTPREF_RESERVED	(-2)
110151539Ssuz#define RTPREF_INVALID	(-3)	/* internal */
111151539Ssuz
11278064Sume/*
11353541Sshin * Receive Router Solicitation Message - just for routers.
11453541Sshin * Router solicitation/advertisement is mostly managed by userland program
11553541Sshin * (rtadvd) so here we have no function like nd6_ra_output().
11653541Sshin *
11753541Sshin * Based on RFC 2461
11853541Sshin */
11953541Sshinvoid
120171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len)
12153541Sshin{
122183550Szec	INIT_VNET_INET6(curvnet);
12353541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
12453541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
12562587Sitojun	struct nd_router_solicit *nd_rs;
12653541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
12753541Sshin	char *lladdr = NULL;
12853541Sshin	int lladdrlen = 0;
12953541Sshin	union nd_opts ndopts;
130165118Sbz	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
13153541Sshin
13253541Sshin	/* If I'm not a router, ignore it. */
133181803Sbz	if (V_ip6_accept_rtadv != 0 || V_ip6_forwarding != 1)
13462587Sitojun		goto freeit;
13553541Sshin
13653541Sshin	/* Sanity checks */
13753541Sshin	if (ip6->ip6_hlim != 255) {
13878064Sume		nd6log((LOG_ERR,
13978064Sume		    "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
140165118Sbz		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
141165118Sbz		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
14278064Sume		goto bad;
14353541Sshin	}
14453541Sshin
14553541Sshin	/*
14653541Sshin	 * Don't update the neighbor cache, if src = ::.
14753541Sshin	 * This indicates that the src has no IP address assigned yet.
14853541Sshin	 */
14953541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
15062587Sitojun		goto freeit;
15162587Sitojun
15262587Sitojun#ifndef PULLDOWN_TEST
15362587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
15462587Sitojun	nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
15562587Sitojun#else
15662587Sitojun	IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
15762587Sitojun	if (nd_rs == NULL) {
158190964Srwatson		ICMP6STAT_INC(icp6s_tooshort);
15953541Sshin		return;
16062587Sitojun	}
16162587Sitojun#endif
16253541Sshin
16353541Sshin	icmp6len -= sizeof(*nd_rs);
16453541Sshin	nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
16553541Sshin	if (nd6_options(&ndopts) < 0) {
16678064Sume		nd6log((LOG_INFO,
16778064Sume		    "nd6_rs_input: invalid ND option, ignored\n"));
16878064Sume		/* nd6_options have incremented stats */
16962587Sitojun		goto freeit;
17053541Sshin	}
17153541Sshin
17253541Sshin	if (ndopts.nd_opts_src_lladdr) {
17353541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
17453541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
17553541Sshin	}
17653541Sshin
17753541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
17878064Sume		nd6log((LOG_INFO,
17953541Sshin		    "nd6_rs_input: lladdrlen mismatch for %s "
18053541Sshin		    "(if %d, RS packet %d)\n",
181165118Sbz		    ip6_sprintf(ip6bufs, &saddr6),
182120941Sume		    ifp->if_addrlen, lladdrlen - 2));
18378064Sume		goto bad;
18453541Sshin	}
18553541Sshin
18653541Sshin	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
18762587Sitojun
18862587Sitojun freeit:
18962587Sitojun	m_freem(m);
19078064Sume	return;
19178064Sume
19278064Sume bad:
193190964Srwatson	ICMP6STAT_INC(icp6s_badrs);
19478064Sume	m_freem(m);
19553541Sshin}
19653541Sshin
19753541Sshin/*
19853541Sshin * Receive Router Advertisement Message.
19953541Sshin *
20053541Sshin * Based on RFC 2461
20153541Sshin * TODO: on-link bit on prefix information
20253541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
20353541Sshin */
20453541Sshinvoid
205171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len)
20653541Sshin{
207183550Szec	INIT_VNET_INET6(curvnet);
20853541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
209121161Sume	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
21053541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
21162587Sitojun	struct nd_router_advert *nd_ra;
21253541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
213151539Ssuz	int mcast = 0;
21453541Sshin	union nd_opts ndopts;
21553541Sshin	struct nd_defrouter *dr;
216165118Sbz	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
21753541Sshin
218118498Sume	/*
219118498Sume	 * We only accept RAs only when
220118498Sume	 * the system-wide variable allows the acceptance, and
221118498Sume	 * per-interface variable allows RAs on the receiving interface.
222118498Sume	 */
223181803Sbz	if (V_ip6_accept_rtadv == 0)
22462587Sitojun		goto freeit;
225118498Sume	if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
226118498Sume		goto freeit;
22753541Sshin
22853541Sshin	if (ip6->ip6_hlim != 255) {
22978064Sume		nd6log((LOG_ERR,
23078064Sume		    "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
231165118Sbz		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
232165118Sbz		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
23378064Sume		goto bad;
23453541Sshin	}
23553541Sshin
23653541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
23778064Sume		nd6log((LOG_ERR,
23853541Sshin		    "nd6_ra_input: src %s is not link-local\n",
239165118Sbz		    ip6_sprintf(ip6bufs, &saddr6)));
24078064Sume		goto bad;
24162587Sitojun	}
24262587Sitojun
24362587Sitojun#ifndef PULLDOWN_TEST
24462587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
24562587Sitojun	nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
24662587Sitojun#else
24762587Sitojun	IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
24862587Sitojun	if (nd_ra == NULL) {
249190964Srwatson		ICMP6STAT_INC(icp6s_tooshort);
25053541Sshin		return;
25153541Sshin	}
25262587Sitojun#endif
25353541Sshin
25453541Sshin	icmp6len -= sizeof(*nd_ra);
25553541Sshin	nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
25653541Sshin	if (nd6_options(&ndopts) < 0) {
25778064Sume		nd6log((LOG_INFO,
25878064Sume		    "nd6_ra_input: invalid ND option, ignored\n"));
25978064Sume		/* nd6_options have incremented stats */
26062587Sitojun		goto freeit;
26153541Sshin	}
26253541Sshin
26353541Sshin    {
26453541Sshin	struct nd_defrouter dr0;
26553541Sshin	u_int32_t advreachable = nd_ra->nd_ra_reachable;
26653541Sshin
267151539Ssuz	/* remember if this is a multicasted advertisement */
268151539Ssuz	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
269151539Ssuz		mcast = 1;
270151539Ssuz
271151539Ssuz	bzero(&dr0, sizeof(dr0));
27253541Sshin	dr0.rtaddr = saddr6;
27353541Sshin	dr0.flags  = nd_ra->nd_ra_flags_reserved;
274156871Ssuz	dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
27553541Sshin	dr0.expire = time_second + dr0.rtlifetime;
27653541Sshin	dr0.ifp = ifp;
27753541Sshin	/* unspecified or not? (RFC 2461 6.3.4) */
27853541Sshin	if (advreachable) {
27990868Smike		advreachable = ntohl(advreachable);
28053541Sshin		if (advreachable <= MAX_REACHABLE_TIME &&
28153541Sshin		    ndi->basereachable != advreachable) {
28253541Sshin			ndi->basereachable = advreachable;
28353541Sshin			ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
284181803Sbz			ndi->recalctm = V_nd6_recalc_reachtm_interval; /* reset */
28553541Sshin		}
28653541Sshin	}
28753541Sshin	if (nd_ra->nd_ra_retransmit)
28853541Sshin		ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
28953541Sshin	if (nd_ra->nd_ra_curhoplimit)
29053541Sshin		ndi->chlim = nd_ra->nd_ra_curhoplimit;
29153541Sshin	dr = defrtrlist_update(&dr0);
29253541Sshin    }
29353541Sshin
29453541Sshin	/*
29553541Sshin	 * prefix
29653541Sshin	 */
29753541Sshin	if (ndopts.nd_opts_pi) {
29853541Sshin		struct nd_opt_hdr *pt;
29978064Sume		struct nd_opt_prefix_info *pi = NULL;
300151539Ssuz		struct nd_prefixctl pr;
30153541Sshin
30253541Sshin		for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
30353541Sshin		     pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
30453541Sshin		     pt = (struct nd_opt_hdr *)((caddr_t)pt +
30553541Sshin						(pt->nd_opt_len << 3))) {
30653541Sshin			if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
30753541Sshin				continue;
30853541Sshin			pi = (struct nd_opt_prefix_info *)pt;
30953541Sshin
31053541Sshin			if (pi->nd_opt_pi_len != 4) {
31178064Sume				nd6log((LOG_INFO,
31278064Sume				    "nd6_ra_input: invalid option "
31378064Sume				    "len %d for prefix information option, "
31478064Sume				    "ignored\n", pi->nd_opt_pi_len));
31553541Sshin				continue;
31653541Sshin			}
31753541Sshin
31853541Sshin			if (128 < pi->nd_opt_pi_prefix_len) {
31978064Sume				nd6log((LOG_INFO,
32078064Sume				    "nd6_ra_input: invalid prefix "
32178064Sume				    "len %d for prefix information option, "
32278064Sume				    "ignored\n", pi->nd_opt_pi_prefix_len));
32353541Sshin				continue;
32453541Sshin			}
32553541Sshin
32653541Sshin			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
32753541Sshin			 || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
32878064Sume				nd6log((LOG_INFO,
32978064Sume				    "nd6_ra_input: invalid prefix "
33078064Sume				    "%s, ignored\n",
331165118Sbz				    ip6_sprintf(ip6bufs,
332165118Sbz					&pi->nd_opt_pi_prefix)));
33353541Sshin				continue;
33453541Sshin			}
33553541Sshin
33653541Sshin			bzero(&pr, sizeof(pr));
33753541Sshin			pr.ndpr_prefix.sin6_family = AF_INET6;
33853541Sshin			pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
33953541Sshin			pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
34053541Sshin			pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
34153541Sshin
34253541Sshin			pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
343120941Sume			    ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
34453541Sshin			pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
345120941Sume			    ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
34653541Sshin			pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
34753541Sshin			pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
348120941Sume			pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time);
349151539Ssuz			(void)prelist_update(&pr, dr, m, mcast);
35053541Sshin		}
35153541Sshin	}
35253541Sshin
35353541Sshin	/*
35453541Sshin	 * MTU
35553541Sshin	 */
35653541Sshin	if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
357121283Sume		u_long mtu;
358121283Sume		u_long maxmtu;
35953541Sshin
360121283Sume		mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
361120941Sume
36253541Sshin		/* lower bound */
36353541Sshin		if (mtu < IPV6_MMTU) {
36478064Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option "
365121283Sume			    "mtu=%lu sent from %s, ignoring\n",
366165118Sbz			    mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src)));
36753541Sshin			goto skip;
36853541Sshin		}
36953541Sshin
37053541Sshin		/* upper bound */
371121283Sume		maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu)
372121283Sume		    ? ndi->maxmtu : ifp->if_mtu;
373121283Sume		if (mtu <= maxmtu) {
374121283Sume			int change = (ndi->linkmtu != mtu);
37553541Sshin
376121283Sume			ndi->linkmtu = mtu;
377121283Sume			if (change) /* in6_maxmtu may change */
378121283Sume				in6_setmaxmtu();
37953541Sshin		} else {
380121283Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
381121283Sume			    "mtu=%lu sent from %s; "
382121283Sume			    "exceeds maxmtu %lu, ignoring\n",
383165118Sbz			    mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu));
38453541Sshin		}
38553541Sshin	}
38653541Sshin
38753541Sshin skip:
388120941Sume
38953541Sshin	/*
39095023Ssuz	 * Source link layer address
39153541Sshin	 */
39253541Sshin    {
39353541Sshin	char *lladdr = NULL;
39453541Sshin	int lladdrlen = 0;
395120941Sume
39653541Sshin	if (ndopts.nd_opts_src_lladdr) {
39753541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
39853541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
39953541Sshin	}
40053541Sshin
40153541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
40278064Sume		nd6log((LOG_INFO,
40353541Sshin		    "nd6_ra_input: lladdrlen mismatch for %s "
404165118Sbz		    "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6),
405120941Sume		    ifp->if_addrlen, lladdrlen - 2));
40678064Sume		goto bad;
40753541Sshin	}
40853541Sshin
409120941Sume	nd6_cache_lladdr(ifp, &saddr6, lladdr,
410120941Sume	    lladdrlen, ND_ROUTER_ADVERT, 0);
41162587Sitojun
41262587Sitojun	/*
41362587Sitojun	 * Installing a link-layer address might change the state of the
41462587Sitojun	 * router's neighbor cache, which might also affect our on-link
41562587Sitojun	 * detection of adveritsed prefixes.
41662587Sitojun	 */
41762587Sitojun	pfxlist_onlink_check();
41853541Sshin    }
41962587Sitojun
42078064Sume freeit:
42162587Sitojun	m_freem(m);
42278064Sume	return;
42378064Sume
42478064Sume bad:
425190964Srwatson	ICMP6STAT_INC(icp6s_badra);
42678064Sume	m_freem(m);
42753541Sshin}
42853541Sshin
42953541Sshin/*
43053541Sshin * default router list proccessing sub routines
43153541Sshin */
43262587Sitojun
43362587Sitojun/* tell the change to user processes watching the routing socket. */
43462587Sitojunstatic void
435171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt)
43662587Sitojun{
43762587Sitojun	struct rt_addrinfo info;
43862587Sitojun
43962587Sitojun	bzero((caddr_t)&info, sizeof(info));
44062587Sitojun	info.rti_info[RTAX_DST] = rt_key(rt);
44162587Sitojun	info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
44262587Sitojun	info.rti_info[RTAX_NETMASK] = rt_mask(rt);
443151539Ssuz	if (rt->rt_ifp) {
444151539Ssuz		info.rti_info[RTAX_IFP] =
445151539Ssuz		    TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
446151539Ssuz		info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
447151539Ssuz	}
44862587Sitojun
44962587Sitojun	rt_missmsg(cmd, &info, rt->rt_flags, 0);
45062587Sitojun}
45162587Sitojun
45253541Sshinvoid
453171259Sdelphijdefrouter_addreq(struct nd_defrouter *new)
45453541Sshin{
45553541Sshin	struct sockaddr_in6 def, mask, gate;
45662587Sitojun	struct rtentry *newrt = NULL;
457151539Ssuz	int s;
458151539Ssuz	int error;
45953541Sshin
460128397Sluigi	bzero(&def, sizeof(def));
461128397Sluigi	bzero(&mask, sizeof(mask));
462128397Sluigi	bzero(&gate, sizeof(gate));
46353541Sshin
464120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
465120941Sume	    sizeof(struct sockaddr_in6);
466151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
46753541Sshin	gate.sin6_addr = new->rtaddr;
46853541Sshin
469151539Ssuz	s = splnet();
470151539Ssuz	error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
471120941Sume	    (struct sockaddr *)&gate, (struct sockaddr *)&mask,
472120941Sume	    RTF_GATEWAY, &newrt);
47362587Sitojun	if (newrt) {
47478064Sume		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
475186119Sqingli		RTFREE(newrt);
47662587Sitojun	}
477151539Ssuz	if (error == 0)
478151539Ssuz		new->installed = 1;
479151539Ssuz	splx(s);
48053541Sshin	return;
48153541Sshin}
48253541Sshin
48353541Sshinstruct nd_defrouter *
484171259Sdelphijdefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp)
48553541Sshin{
486183550Szec	INIT_VNET_INET6(ifp->if_vnet);
48753541Sshin	struct nd_defrouter *dr;
48853541Sshin
489181803Sbz	for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
49062587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
49153541Sshin		if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
492120856Sume			return (dr);
49362587Sitojun	}
49453541Sshin
495120856Sume	return (NULL);		/* search failed */
49653541Sshin}
49753541Sshin
498151539Ssuz/*
499151539Ssuz * Remove the default route for a given router.
500151539Ssuz * This is just a subroutine function for defrouter_select(), and should
501151539Ssuz * not be called from anywhere else.
502151539Ssuz */
503151539Ssuzstatic void
504171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr)
50553541Sshin{
50653541Sshin	struct sockaddr_in6 def, mask, gate;
50762587Sitojun	struct rtentry *oldrt = NULL;
50853541Sshin
509128397Sluigi	bzero(&def, sizeof(def));
510128397Sluigi	bzero(&mask, sizeof(mask));
511128397Sluigi	bzero(&gate, sizeof(gate));
51253541Sshin
513120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
514120941Sume	    sizeof(struct sockaddr_in6);
515151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
51653541Sshin	gate.sin6_addr = dr->rtaddr;
51753541Sshin
51853541Sshin	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
519120941Sume	    (struct sockaddr *)&gate,
520120941Sume	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
52162587Sitojun	if (oldrt) {
52278064Sume		nd6_rtmsg(RTM_DELETE, oldrt);
523108269Sru		RTFREE(oldrt);
52462587Sitojun	}
52553541Sshin
526151539Ssuz	dr->installed = 0;
52753541Sshin}
52853541Sshin
529151539Ssuz/*
530151539Ssuz * remove all default routes from default router list
531151539Ssuz */
53253541Sshinvoid
533171259Sdelphijdefrouter_reset(void)
534151539Ssuz{
535183550Szec	INIT_VNET_INET6(curvnet);
536151539Ssuz	struct nd_defrouter *dr;
537151539Ssuz
538181803Sbz	for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
539151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry))
540151539Ssuz		defrouter_delreq(dr);
541151539Ssuz
542151539Ssuz	/*
543151539Ssuz	 * XXX should we also nuke any default routers in the kernel, by
544151539Ssuz	 * going through them by rtalloc1()?
545151539Ssuz	 */
546151539Ssuz}
547151539Ssuz
548151539Ssuzvoid
549171259Sdelphijdefrtrlist_del(struct nd_defrouter *dr)
55053541Sshin{
551183550Szec	INIT_VNET_INET6(curvnet);
55253541Sshin	struct nd_defrouter *deldr = NULL;
55353541Sshin	struct nd_prefix *pr;
55453541Sshin
55553541Sshin	/*
55653541Sshin	 * Flush all the routing table entries that use the router
55753541Sshin	 * as a next hop.
55853541Sshin	 */
559181803Sbz	if (!V_ip6_forwarding && V_ip6_accept_rtadv) /* XXX: better condition? */
56053541Sshin		rt6_flush(&dr->rtaddr, dr->ifp);
56153541Sshin
562151539Ssuz	if (dr->installed) {
563151539Ssuz		deldr = dr;
564151539Ssuz		defrouter_delreq(dr);
565151539Ssuz	}
566181803Sbz	TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry);
56753541Sshin
56853541Sshin	/*
56953541Sshin	 * Also delete all the pointers to the router in each prefix lists.
57053541Sshin	 */
571181803Sbz	for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
57253541Sshin		struct nd_pfxrouter *pfxrtr;
57353541Sshin		if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
57453541Sshin			pfxrtr_del(pfxrtr);
57553541Sshin	}
57653541Sshin	pfxlist_onlink_check();
57753541Sshin
57853541Sshin	/*
57962587Sitojun	 * If the router is the primary one, choose a new one.
58062587Sitojun	 * Note that defrouter_select() will remove the current gateway
58162587Sitojun	 * from the routing table.
58253541Sshin	 */
58353541Sshin	if (deldr)
58462587Sitojun		defrouter_select();
58562587Sitojun
58653541Sshin	free(dr, M_IP6NDP);
58753541Sshin}
58853541Sshin
58962587Sitojun/*
590151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and
591151539Ssuz * draft-ietf-ipngwg-router-selection:
592151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred.
593151539Ssuz *    If we have more than one (probably) reachable router, prefer ones
594151539Ssuz *    with the highest router preference.
59562587Sitojun * 2) When no routers on the list are known to be reachable or
59662587Sitojun *    probably reachable, routers SHOULD be selected in a round-robin
597151539Ssuz *    fashion, regardless of router preference values.
59862587Sitojun * 3) If the Default Router List is empty, assume that all
59962587Sitojun *    destinations are on-link.
600151539Ssuz *
601151539Ssuz * We assume nd_defrouter is sorted by router preference value.
602151539Ssuz * Since the code below covers both with and without router preference cases,
603151539Ssuz * we do not need to classify the cases by ifdef.
604151539Ssuz *
605151539Ssuz * At this moment, we do not try to install more than one default router,
606151539Ssuz * even when the multipath routing is available, because we're not sure about
607151539Ssuz * the benefits for stub hosts comparing to the risk of making the code
608151539Ssuz * complicated and the possibility of introducing bugs.
60962587Sitojun */
61062587Sitojunvoid
611171259Sdelphijdefrouter_select(void)
61262587Sitojun{
613183550Szec	INIT_VNET_INET6(curvnet);
61462587Sitojun	int s = splnet();
615151539Ssuz	struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
616186119Sqingli	struct llentry *ln = NULL;
61762587Sitojun
61862587Sitojun	/*
619151539Ssuz	 * This function should be called only when acting as an autoconfigured
620151539Ssuz	 * host.  Although the remaining part of this function is not effective
621151539Ssuz	 * if the node is not an autoconfigured host, we explicitly exclude
622151539Ssuz	 * such cases here for safety.
623151539Ssuz	 */
624181803Sbz	if (V_ip6_forwarding || !V_ip6_accept_rtadv) {
625151539Ssuz		nd6log((LOG_WARNING,
626151539Ssuz		    "defrouter_select: called unexpectedly (forwarding=%d, "
627181803Sbz		    "accept_rtadv=%d)\n", V_ip6_forwarding, V_ip6_accept_rtadv));
628151539Ssuz		splx(s);
629151539Ssuz		return;
630151539Ssuz	}
631151539Ssuz
632151539Ssuz	/*
633151539Ssuz	 * Let's handle easy case (3) first:
634151539Ssuz	 * If default router list is empty, there's nothing to be done.
635151539Ssuz	 */
636181803Sbz	if (!TAILQ_FIRST(&V_nd_defrouter)) {
637151539Ssuz		splx(s);
638151539Ssuz		return;
639151539Ssuz	}
640151539Ssuz
641151539Ssuz	/*
64262587Sitojun	 * Search for a (probably) reachable router from the list.
643151539Ssuz	 * We just pick up the first reachable one (if any), assuming that
644151539Ssuz	 * the ordering rule of the list described in defrtrlist_update().
64562587Sitojun	 */
646181803Sbz	for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
64762587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
648186119Sqingli		IF_AFDATA_LOCK(dr->ifp);
649151539Ssuz		if (selected_dr == NULL &&
650186119Sqingli		    (ln = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
65162587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln)) {
652151539Ssuz			selected_dr = dr;
65362587Sitojun		}
654186119Sqingli		IF_AFDATA_UNLOCK(dr->ifp);
655188113Sbz		if (ln != NULL) {
656186148Skmacy			LLE_RUNLOCK(ln);
657188113Sbz			ln = NULL;
658188113Sbz		}
65962587Sitojun
660151539Ssuz		if (dr->installed && installed_dr == NULL)
661151539Ssuz			installed_dr = dr;
662151539Ssuz		else if (dr->installed && installed_dr) {
663151539Ssuz			/* this should not happen.  warn for diagnosis. */
664151539Ssuz			log(LOG_ERR, "defrouter_select: more than one router"
665151539Ssuz			    " is installed\n");
66662587Sitojun		}
66762587Sitojun	}
668151539Ssuz	/*
669151539Ssuz	 * If none of the default routers was found to be reachable,
670151539Ssuz	 * round-robin the list regardless of preference.
671151539Ssuz	 * Otherwise, if we have an installed router, check if the selected
672151539Ssuz	 * (reachable) router should really be preferred to the installed one.
673151539Ssuz	 * We only prefer the new router when the old one is not reachable
674151539Ssuz	 * or when the new one has a really higher preference value.
675151539Ssuz	 */
676151539Ssuz	if (selected_dr == NULL) {
677151539Ssuz		if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry))
678181803Sbz			selected_dr = TAILQ_FIRST(&V_nd_defrouter);
679151539Ssuz		else
680151539Ssuz			selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
681186119Sqingli	} else if (installed_dr) {
682186119Sqingli		IF_AFDATA_LOCK(installed_dr->ifp);
683186119Sqingli		if ((ln = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) &&
684186119Sqingli		    ND6_IS_LLINFO_PROBREACH(ln) &&
685186119Sqingli		    rtpref(selected_dr) <= rtpref(installed_dr)) {
686186119Sqingli			selected_dr = installed_dr;
687186119Sqingli		}
688186119Sqingli		IF_AFDATA_UNLOCK(installed_dr->ifp);
689186148Skmacy		if (ln != NULL)
690186148Skmacy			LLE_RUNLOCK(ln);
691151539Ssuz	}
69262587Sitojun
693151539Ssuz	/*
694151539Ssuz	 * If the selected router is different than the installed one,
695151539Ssuz	 * remove the installed router and install the selected one.
696151539Ssuz	 * Note that the selected router is never NULL here.
697151539Ssuz	 */
698151539Ssuz	if (installed_dr != selected_dr) {
699151539Ssuz		if (installed_dr)
700151539Ssuz			defrouter_delreq(installed_dr);
701151539Ssuz		defrouter_addreq(selected_dr);
702151539Ssuz	}
703151539Ssuz
70462587Sitojun	splx(s);
70562587Sitojun	return;
70662587Sitojun}
70762587Sitojun
708151539Ssuz/*
709151539Ssuz * for default router selection
710151539Ssuz * regards router-preference field as a 2-bit signed integer
711151539Ssuz */
712151539Ssuzstatic int
713151539Ssuzrtpref(struct nd_defrouter *dr)
714151539Ssuz{
715151539Ssuz	switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) {
716151539Ssuz	case ND_RA_FLAG_RTPREF_HIGH:
717151539Ssuz		return (RTPREF_HIGH);
718151539Ssuz	case ND_RA_FLAG_RTPREF_MEDIUM:
719156871Ssuz	case ND_RA_FLAG_RTPREF_RSV:
720151539Ssuz		return (RTPREF_MEDIUM);
721151539Ssuz	case ND_RA_FLAG_RTPREF_LOW:
722151539Ssuz		return (RTPREF_LOW);
723151539Ssuz	default:
724151539Ssuz		/*
725151539Ssuz		 * This case should never happen.  If it did, it would mean a
726151539Ssuz		 * serious bug of kernel internal.  We thus always bark here.
727151539Ssuz		 * Or, can we even panic?
728151539Ssuz		 */
729151539Ssuz		log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags);
730151539Ssuz		return (RTPREF_INVALID);
731151539Ssuz	}
732151539Ssuz	/* NOTREACHED */
733151539Ssuz}
734151539Ssuz
73553541Sshinstatic struct nd_defrouter *
736171259Sdelphijdefrtrlist_update(struct nd_defrouter *new)
73753541Sshin{
738183550Szec	INIT_VNET_INET6(curvnet);
73953541Sshin	struct nd_defrouter *dr, *n;
74053541Sshin	int s = splnet();
74153541Sshin
74253541Sshin	if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
74353541Sshin		/* entry exists */
74453541Sshin		if (new->rtlifetime == 0) {
74553541Sshin			defrtrlist_del(dr);
74653541Sshin			dr = NULL;
74753541Sshin		} else {
748151539Ssuz			int oldpref = rtpref(dr);
749151539Ssuz
75053541Sshin			/* override */
75153541Sshin			dr->flags = new->flags; /* xxx flag check */
75253541Sshin			dr->rtlifetime = new->rtlifetime;
75353541Sshin			dr->expire = new->expire;
754151539Ssuz
755151539Ssuz			/*
756151539Ssuz			 * If the preference does not change, there's no need
757151539Ssuz			 * to sort the entries.
758151539Ssuz			 */
759151539Ssuz			if (rtpref(new) == oldpref) {
760151539Ssuz				splx(s);
761151539Ssuz				return (dr);
762151539Ssuz			}
763151539Ssuz
764151539Ssuz			/*
765151539Ssuz			 * preferred router may be changed, so relocate
766151539Ssuz			 * this router.
767151539Ssuz			 * XXX: calling TAILQ_REMOVE directly is a bad manner.
768151539Ssuz			 * However, since defrtrlist_del() has many side
769151539Ssuz			 * effects, we intentionally do so here.
770151539Ssuz			 * defrouter_select() below will handle routing
771151539Ssuz			 * changes later.
772151539Ssuz			 */
773181803Sbz			TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry);
774151539Ssuz			n = dr;
775151539Ssuz			goto insert;
77653541Sshin		}
77753541Sshin		splx(s);
778120856Sume		return (dr);
77953541Sshin	}
78053541Sshin
78153541Sshin	/* entry does not exist */
78253541Sshin	if (new->rtlifetime == 0) {
78353541Sshin		splx(s);
784120856Sume		return (NULL);
78553541Sshin	}
78653541Sshin
78753541Sshin	n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
78853541Sshin	if (n == NULL) {
78953541Sshin		splx(s);
790120856Sume		return (NULL);
79153541Sshin	}
79253541Sshin	bzero(n, sizeof(*n));
79353541Sshin	*n = *new;
79462587Sitojun
795151539Ssuzinsert:
79662587Sitojun	/*
797151539Ssuz	 * Insert the new router in the Default Router List;
798151539Ssuz	 * The Default Router List should be in the descending order
799151539Ssuz	 * of router-preferece.  Routers with the same preference are
800151539Ssuz	 * sorted in the arriving time order.
80162587Sitojun	 */
802151539Ssuz
803151539Ssuz	/* insert at the end of the group */
804181803Sbz	for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
805151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry)) {
806151539Ssuz		if (rtpref(n) > rtpref(dr))
807151539Ssuz			break;
808151539Ssuz	}
809151539Ssuz	if (dr)
810151539Ssuz		TAILQ_INSERT_BEFORE(dr, n, dr_entry);
811151539Ssuz	else
812181803Sbz		TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry);
813151539Ssuz
814151539Ssuz	defrouter_select();
815151539Ssuz
81653541Sshin	splx(s);
817120941Sume
818120856Sume	return (n);
81953541Sshin}
82053541Sshin
82153541Sshinstatic struct nd_pfxrouter *
822171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr)
82353541Sshin{
82453541Sshin	struct nd_pfxrouter *search;
825120941Sume
82662587Sitojun	for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
82753541Sshin		if (search->router == dr)
82853541Sshin			break;
82953541Sshin	}
83053541Sshin
831120856Sume	return (search);
83253541Sshin}
83353541Sshin
83453541Sshinstatic void
835171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr)
83653541Sshin{
83753541Sshin	struct nd_pfxrouter *new;
83853541Sshin
83953541Sshin	new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
84053541Sshin	if (new == NULL)
84153541Sshin		return;
84253541Sshin	bzero(new, sizeof(*new));
84353541Sshin	new->router = dr;
84453541Sshin
84553541Sshin	LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
84653541Sshin
84753541Sshin	pfxlist_onlink_check();
84853541Sshin}
84953541Sshin
85053541Sshinstatic void
851171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr)
85253541Sshin{
85353541Sshin	LIST_REMOVE(pfr, pfr_entry);
85453541Sshin	free(pfr, M_IP6NDP);
85553541Sshin}
85653541Sshin
85778064Sumestruct nd_prefix *
858171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key)
85953541Sshin{
860183550Szec	INIT_VNET_INET6(curvnet);
86153541Sshin	struct nd_prefix *search;
86253541Sshin
863181887Sjulian	for (search = V_nd_prefix.lh_first;
864181888Sjulian	    search; search = search->ndpr_next) {
865151539Ssuz		if (key->ndpr_ifp == search->ndpr_ifp &&
866151539Ssuz		    key->ndpr_plen == search->ndpr_plen &&
867151539Ssuz		    in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr,
868151539Ssuz		    &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) {
86953541Sshin			break;
87053541Sshin		}
87153541Sshin	}
87253541Sshin
873120856Sume	return (search);
87453541Sshin}
87553541Sshin
87678064Sumeint
877171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
878171259Sdelphij    struct nd_prefix **newp)
87953541Sshin{
880183550Szec	INIT_VNET_INET6(curvnet);
88178064Sume	struct nd_prefix *new = NULL;
882151539Ssuz	int error = 0;
88353541Sshin	int i, s;
884165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
88553541Sshin
88653541Sshin	new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
88753541Sshin	if (new == NULL)
888120941Sume		return(ENOMEM);
88953541Sshin	bzero(new, sizeof(*new));
890151539Ssuz	new->ndpr_ifp = pr->ndpr_ifp;
891151539Ssuz	new->ndpr_prefix = pr->ndpr_prefix;
892151539Ssuz	new->ndpr_plen = pr->ndpr_plen;
893151539Ssuz	new->ndpr_vltime = pr->ndpr_vltime;
894151539Ssuz	new->ndpr_pltime = pr->ndpr_pltime;
895151539Ssuz	new->ndpr_flags = pr->ndpr_flags;
896151539Ssuz	if ((error = in6_init_prefix_ltimes(new)) != 0) {
897151539Ssuz		free(new, M_IP6NDP);
898151539Ssuz		return(error);
899151539Ssuz	}
900151539Ssuz	new->ndpr_lastupdate = time_second;
90178064Sume	if (newp != NULL)
90278064Sume		*newp = new;
90353541Sshin
904120941Sume	/* initialization */
90553541Sshin	LIST_INIT(&new->ndpr_advrtrs);
90653541Sshin	in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
90753541Sshin	/* make prefix in the canonical form */
90853541Sshin	for (i = 0; i < 4; i++)
90953541Sshin		new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
910120941Sume		    new->ndpr_mask.s6_addr32[i];
91153541Sshin
91253541Sshin	s = splnet();
91353541Sshin	/* link ndpr_entry to nd_prefix list */
914181803Sbz	LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry);
91553541Sshin	splx(s);
91653541Sshin
91778064Sume	/* ND_OPT_PI_FLAG_ONLINK processing */
91878064Sume	if (new->ndpr_raf_onlink) {
91978064Sume		int e;
92078064Sume
92178064Sume		if ((e = nd6_prefix_onlink(new)) != 0) {
92278064Sume			nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
92378064Sume			    "the prefix %s/%d on-link on %s (errno=%d)\n",
924165118Sbz			    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
92578064Sume			    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
92678064Sume			/* proceed anyway. XXX: is it correct? */
92778064Sume		}
92878064Sume	}
92978064Sume
930120941Sume	if (dr)
93153541Sshin		pfxrtr_add(new, dr);
93253541Sshin
93353541Sshin	return 0;
93453541Sshin}
93553541Sshin
93653541Sshinvoid
937171259Sdelphijprelist_remove(struct nd_prefix *pr)
93853541Sshin{
939183550Szec	INIT_VNET_INET6(curvnet);
94053541Sshin	struct nd_pfxrouter *pfr, *next;
94178064Sume	int e, s;
942165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
94353541Sshin
94478064Sume	/* make sure to invalidate the prefix until it is really freed. */
94578064Sume	pr->ndpr_vltime = 0;
94678064Sume	pr->ndpr_pltime = 0;
947151539Ssuz
94878064Sume	/*
94978064Sume	 * Though these flags are now meaningless, we'd rather keep the value
950151479Ssuz	 * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users
951151479Ssuz	 * when executing "ndp -p".
95278064Sume	 */
953151479Ssuz
95478064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
95578064Sume	    (e = nd6_prefix_offlink(pr)) != 0) {
95678064Sume		nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
95778064Sume		    "on %s, errno=%d\n",
958165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
95978064Sume		    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
96078064Sume		/* what should we do? */
96178064Sume	}
96278064Sume
96378064Sume	if (pr->ndpr_refcnt > 0)
96478064Sume		return;		/* notice here? */
96578064Sume
96653541Sshin	s = splnet();
96778064Sume
96853541Sshin	/* unlink ndpr_entry from nd_prefix list */
96953541Sshin	LIST_REMOVE(pr, ndpr_entry);
97053541Sshin
97153541Sshin	/* free list of routers that adversed the prefix */
97262587Sitojun	for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
97362587Sitojun		next = pfr->pfr_next;
97453541Sshin
97553541Sshin		free(pfr, M_IP6NDP);
97653541Sshin	}
97778064Sume	splx(s);
97878064Sume
97953541Sshin	free(pr, M_IP6NDP);
98053541Sshin
98153541Sshin	pfxlist_onlink_check();
98253541Sshin}
98353541Sshin
984171259Sdelphij/*
985171259Sdelphij * dr - may be NULL
986171259Sdelphij */
987171259Sdelphij
988151539Ssuzstatic int
989171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
990171259Sdelphij    struct mbuf *m, int mcast)
99153541Sshin{
992183550Szec	INIT_VNET_INET6(curvnet);
99378064Sume	struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
99478064Sume	struct ifaddr *ifa;
99578064Sume	struct ifnet *ifp = new->ndpr_ifp;
99653541Sshin	struct nd_prefix *pr;
99753541Sshin	int s = splnet();
99853541Sshin	int error = 0;
99978064Sume	int newprefix = 0;
100053541Sshin	int auth;
100178064Sume	struct in6_addrlifetime lt6_tmp;
1002165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
100353541Sshin
100453541Sshin	auth = 0;
100553541Sshin	if (m) {
100653541Sshin		/*
100753541Sshin		 * Authenticity for NA consists authentication for
100853541Sshin		 * both IP header and IP datagrams, doesn't it ?
100953541Sshin		 */
101053541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
1011120941Sume		auth = ((m->m_flags & M_AUTHIPHDR) &&
1012120941Sume		    (m->m_flags & M_AUTHIPDGM));
101353541Sshin#endif
101453541Sshin	}
101553541Sshin
101678064Sume	if ((pr = nd6_prefix_lookup(new)) != NULL) {
101778064Sume		/*
101878064Sume		 * nd6_prefix_lookup() ensures that pr and new have the same
101978064Sume		 * prefix on a same interface.
102078064Sume		 */
102153541Sshin
102253541Sshin		/*
102378064Sume		 * Update prefix information.  Note that the on-link (L) bit
102478064Sume		 * and the autonomous (A) bit should NOT be changed from 1
102578064Sume		 * to 0.
102653541Sshin		 */
102778064Sume		if (new->ndpr_raf_onlink == 1)
102878064Sume			pr->ndpr_raf_onlink = 1;
102978064Sume		if (new->ndpr_raf_auto == 1)
103078064Sume			pr->ndpr_raf_auto = 1;
103178064Sume		if (new->ndpr_raf_onlink) {
103278064Sume			pr->ndpr_vltime = new->ndpr_vltime;
103378064Sume			pr->ndpr_pltime = new->ndpr_pltime;
1034151539Ssuz			(void)in6_init_prefix_ltimes(pr); /* XXX error case? */
1035151539Ssuz			pr->ndpr_lastupdate = time_second;
103678064Sume		}
103753541Sshin
103878064Sume		if (new->ndpr_raf_onlink &&
103978064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
104078064Sume			int e;
104153541Sshin
104278064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
104378064Sume				nd6log((LOG_ERR,
104478064Sume				    "prelist_update: failed to make "
104578064Sume				    "the prefix %s/%d on-link on %s "
104678064Sume				    "(errno=%d)\n",
1047165118Sbz				    ip6_sprintf(ip6buf,
1048165118Sbz					    &pr->ndpr_prefix.sin6_addr),
104978064Sume				    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
105078064Sume				/* proceed anyway. XXX: is it correct? */
105153541Sshin			}
105278064Sume		}
105353541Sshin
105478064Sume		if (dr && pfxrtr_lookup(pr, dr) == NULL)
105578064Sume			pfxrtr_add(pr, dr);
105678064Sume	} else {
105778064Sume		struct nd_prefix *newpr = NULL;
105853541Sshin
105978064Sume		newprefix = 1;
106053541Sshin
106178064Sume		if (new->ndpr_vltime == 0)
106278064Sume			goto end;
106378064Sume		if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
106478064Sume			goto end;
106553541Sshin
106678064Sume		error = nd6_prelist_add(new, dr, &newpr);
106778064Sume		if (error != 0 || newpr == NULL) {
106878064Sume			nd6log((LOG_NOTICE, "prelist_update: "
106978064Sume			    "nd6_prelist_add failed for %s/%d on %s "
107078064Sume			    "errno=%d, returnpr=%p\n",
1071165118Sbz			    ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr),
1072120941Sume			    new->ndpr_plen, if_name(new->ndpr_ifp),
1073120941Sume			    error, newpr));
107478064Sume			goto end; /* we should just give up in this case. */
107578064Sume		}
107653541Sshin
107778064Sume		/*
107878064Sume		 * XXX: from the ND point of view, we can ignore a prefix
107978064Sume		 * with the on-link bit being zero.  However, we need a
108078064Sume		 * prefix structure for references from autoconfigured
1081120941Sume		 * addresses.  Thus, we explicitly make sure that the prefix
108278064Sume		 * itself expires now.
108378064Sume		 */
108478064Sume		if (newpr->ndpr_raf_onlink == 0) {
108578064Sume			newpr->ndpr_vltime = 0;
108678064Sume			newpr->ndpr_pltime = 0;
108778064Sume			in6_init_prefix_ltimes(newpr);
108853541Sshin		}
108953541Sshin
109078064Sume		pr = newpr;
109178064Sume	}
109253541Sshin
109378064Sume	/*
109478064Sume	 * Address autoconfiguration based on Section 5.5.3 of RFC 2462.
109578064Sume	 * Note that pr must be non NULL at this point.
109678064Sume	 */
109762587Sitojun
109878064Sume	/* 5.5.3 (a). Ignore the prefix without the A bit set. */
109978064Sume	if (!new->ndpr_raf_auto)
1100151539Ssuz		goto end;
110162587Sitojun
110278064Sume	/*
110378064Sume	 * 5.5.3 (b). the link-local prefix should have been ignored in
110478064Sume	 * nd6_ra_input.
110578064Sume	 */
110662587Sitojun
1107151539Ssuz	/* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */
1108151539Ssuz	if (new->ndpr_pltime > new->ndpr_vltime) {
1109151539Ssuz		error = EINVAL;	/* XXX: won't be used */
1110151539Ssuz		goto end;
1111151539Ssuz	}
111262587Sitojun
1113171260Sdelphij	/*
1114151539Ssuz	 * 5.5.3 (d).  If the prefix advertised is not equal to the prefix of
1115151539Ssuz	 * an address configured by stateless autoconfiguration already in the
1116151539Ssuz	 * list of addresses associated with the interface, and the Valid
1117151539Ssuz	 * Lifetime is not 0, form an address.  We first check if we have
1118151539Ssuz	 * a matching prefix.
1119151539Ssuz	 * Note: we apply a clarification in rfc2462bis-02 here.  We only
1120151539Ssuz	 * consider autoconfigured addresses while RFC2462 simply said
1121151539Ssuz	 * "address".
112278064Sume	 */
1123120941Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
112478064Sume		struct in6_ifaddr *ifa6;
1125151539Ssuz		u_int32_t remaininglifetime;
112653541Sshin
112778064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
112878064Sume			continue;
112953541Sshin
113078064Sume		ifa6 = (struct in6_ifaddr *)ifa;
113153541Sshin
113253541Sshin		/*
1133151539Ssuz		 * We only consider autoconfigured addresses as per rfc2462bis.
1134151539Ssuz		 */
1135151539Ssuz		if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF))
1136151539Ssuz			continue;
1137151539Ssuz
1138151539Ssuz		/*
113978064Sume		 * Spec is not clear here, but I believe we should concentrate
114078064Sume		 * on unicast (i.e. not anycast) addresses.
114178064Sume		 * XXX: other ia6_flags? detached or duplicated?
114253541Sshin		 */
114378064Sume		if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
114478064Sume			continue;
1145120941Sume
1146151539Ssuz		/*
1147151539Ssuz		 * Ignore the address if it is not associated with a prefix
1148151539Ssuz		 * or is associated with a prefix that is different from this
1149151539Ssuz		 * one.  (pr is never NULL here)
1150151539Ssuz		 */
1151151539Ssuz		if (ifa6->ia6_ndpr != pr)
115278064Sume			continue;
115353541Sshin
115478064Sume		if (ia6_match == NULL) /* remember the first one */
115578064Sume			ia6_match = ifa6;
115678064Sume
115778064Sume		/*
115878064Sume		 * An already autoconfigured address matched.  Now that we
115978064Sume		 * are sure there is at least one matched address, we can
116078064Sume		 * proceed to 5.5.3. (e): update the lifetimes according to the
116178064Sume		 * "two hours" rule and the privacy extension.
1162151539Ssuz		 * We apply some clarifications in rfc2462bis:
1163151539Ssuz		 * - use remaininglifetime instead of storedlifetime as a
1164151539Ssuz		 *   variable name
1165151539Ssuz		 * - remove the dead code in the "two-hour" rule
116678064Sume		 */
116778064Sume#define TWOHOUR		(120*60)
116878064Sume		lt6_tmp = ifa6->ia6_lifetime;
116978064Sume
1170112678Sume		if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME)
1171151539Ssuz			remaininglifetime = ND6_INFINITE_LIFETIME;
1172151539Ssuz		else if (time_second - ifa6->ia6_updatetime >
1173151539Ssuz			 lt6_tmp.ia6t_vltime) {
1174151539Ssuz			/*
1175151539Ssuz			 * The case of "invalid" address.  We should usually
1176151539Ssuz			 * not see this case.
1177151539Ssuz			 */
1178151539Ssuz			remaininglifetime = 0;
1179151539Ssuz		} else
1180151539Ssuz			remaininglifetime = lt6_tmp.ia6t_vltime -
1181151539Ssuz			    (time_second - ifa6->ia6_updatetime);
118278064Sume
1183112678Sume		/* when not updating, keep the current stored lifetime. */
1184151539Ssuz		lt6_tmp.ia6t_vltime = remaininglifetime;
1185112678Sume
118678064Sume		if (TWOHOUR < new->ndpr_vltime ||
1187151539Ssuz		    remaininglifetime < new->ndpr_vltime) {
118878064Sume			lt6_tmp.ia6t_vltime = new->ndpr_vltime;
1189151539Ssuz		} else if (remaininglifetime <= TWOHOUR) {
119078064Sume			if (auth) {
119178064Sume				lt6_tmp.ia6t_vltime = new->ndpr_vltime;
119278064Sume			}
119378064Sume		} else {
119478064Sume			/*
119578064Sume			 * new->ndpr_vltime <= TWOHOUR &&
1196151539Ssuz			 * TWOHOUR < remaininglifetime
119778064Sume			 */
119878064Sume			lt6_tmp.ia6t_vltime = TWOHOUR;
119953541Sshin		}
120053541Sshin
120178064Sume		/* The 2 hour rule is not imposed for preferred lifetime. */
120278064Sume		lt6_tmp.ia6t_pltime = new->ndpr_pltime;
120353541Sshin
120478064Sume		in6_init_address_ltimes(pr, &lt6_tmp);
120553541Sshin
1206171260Sdelphij		/*
1207151539Ssuz		 * We need to treat lifetimes for temporary addresses
1208151539Ssuz		 * differently, according to
1209151539Ssuz		 * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1);
1210151539Ssuz		 * we only update the lifetimes when they are in the maximum
1211151539Ssuz		 * intervals.
1212171260Sdelphij		 */
1213171260Sdelphij		if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
1214151539Ssuz			u_int32_t maxvltime, maxpltime;
1215151539Ssuz
1216181803Sbz			if (V_ip6_temp_valid_lifetime >
1217151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1218181803Sbz			    V_ip6_desync_factor)) {
1219181803Sbz				maxvltime = V_ip6_temp_valid_lifetime -
1220151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1221181803Sbz				    V_ip6_desync_factor;
1222151539Ssuz			} else
1223151539Ssuz				maxvltime = 0;
1224181803Sbz			if (V_ip6_temp_preferred_lifetime >
1225151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1226181803Sbz			    V_ip6_desync_factor)) {
1227181803Sbz				maxpltime = V_ip6_temp_preferred_lifetime -
1228151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1229181803Sbz				    V_ip6_desync_factor;
1230151539Ssuz			} else
1231151539Ssuz				maxpltime = 0;
1232151539Ssuz
1233151539Ssuz			if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME ||
1234151539Ssuz			    lt6_tmp.ia6t_vltime > maxvltime) {
1235151539Ssuz				lt6_tmp.ia6t_vltime = maxvltime;
123678064Sume			}
1237151539Ssuz			if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME ||
1238151539Ssuz			    lt6_tmp.ia6t_pltime > maxpltime) {
1239151539Ssuz				lt6_tmp.ia6t_pltime = maxpltime;
124078064Sume			}
124178064Sume		}
124278064Sume		ifa6->ia6_lifetime = lt6_tmp;
1243151539Ssuz		ifa6->ia6_updatetime = time_second;
124453541Sshin	}
124578064Sume	if (ia6_match == NULL && new->ndpr_vltime) {
1246151539Ssuz		int ifidlen;
1247151539Ssuz
124878064Sume		/*
1249151539Ssuz		 * 5.5.3 (d) (continued)
125078064Sume		 * No address matched and the valid lifetime is non-zero.
125178064Sume		 * Create a new address.
125278064Sume		 */
1253151539Ssuz
1254151539Ssuz		/*
1255151539Ssuz		 * Prefix Length check:
1256151539Ssuz		 * If the sum of the prefix length and interface identifier
1257151539Ssuz		 * length does not equal 128 bits, the Prefix Information
1258151539Ssuz		 * option MUST be ignored.  The length of the interface
1259151539Ssuz		 * identifier is defined in a separate link-type specific
1260151539Ssuz		 * document.
1261151539Ssuz		 */
1262151539Ssuz		ifidlen = in6_if2idlen(ifp);
1263151539Ssuz		if (ifidlen < 0) {
1264151539Ssuz			/* this should not happen, so we always log it. */
1265151539Ssuz			log(LOG_ERR, "prelist_update: IFID undefined (%s)\n",
1266151539Ssuz			    if_name(ifp));
1267151539Ssuz			goto end;
1268151539Ssuz		}
1269151539Ssuz		if (ifidlen + pr->ndpr_plen != 128) {
1270151539Ssuz			nd6log((LOG_INFO,
1271151539Ssuz			    "prelist_update: invalid prefixlen "
1272151539Ssuz			    "%d for %s, ignored\n",
1273151539Ssuz			    pr->ndpr_plen, if_name(ifp)));
1274151539Ssuz			goto end;
1275151539Ssuz		}
1276151539Ssuz
1277151539Ssuz		if ((ia6 = in6_ifadd(new, mcast)) != NULL) {
127878064Sume			/*
127978064Sume			 * note that we should use pr (not new) for reference.
128078064Sume			 */
128178064Sume			pr->ndpr_refcnt++;
128278064Sume			ia6->ia6_ndpr = pr;
128353541Sshin
128478064Sume			/*
128578064Sume			 * RFC 3041 3.3 (2).
128678064Sume			 * When a new public address is created as described
128778064Sume			 * in RFC2462, also create a new temporary address.
128878064Sume			 *
128978064Sume			 * RFC 3041 3.5.
129078064Sume			 * When an interface connects to a new link, a new
129178064Sume			 * randomized interface identifier should be generated
129278064Sume			 * immediately together with a new set of temporary
129378064Sume			 * addresses.  Thus, we specifiy 1 as the 2nd arg of
129478064Sume			 * in6_tmpifadd().
129578064Sume			 */
1296181803Sbz			if (V_ip6_use_tempaddr) {
129778064Sume				int e;
1298151539Ssuz				if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) {
129978064Sume					nd6log((LOG_NOTICE, "prelist_update: "
130078064Sume					    "failed to create a temporary "
130178064Sume					    "address, errno=%d\n",
130278064Sume					    e));
130378064Sume				}
130478064Sume			}
130578064Sume
130678064Sume			/*
130778064Sume			 * A newly added address might affect the status
130878064Sume			 * of other addresses, so we check and update it.
130978064Sume			 * XXX: what if address duplication happens?
131078064Sume			 */
131178064Sume			pfxlist_onlink_check();
131278064Sume		} else {
131378064Sume			/* just set an error. do not bark here. */
131478064Sume			error = EADDRNOTAVAIL; /* XXX: might be unused. */
131578064Sume		}
131678064Sume	}
131778064Sume
131853541Sshin end:
131953541Sshin	splx(s);
132053541Sshin	return error;
132153541Sshin}
132253541Sshin
132353541Sshin/*
132462587Sitojun * A supplement function used in the on-link detection below;
132562587Sitojun * detect if a given prefix has a (probably) reachable advertising router.
132662587Sitojun * XXX: lengthy function name...
132762587Sitojun */
132878064Sumestatic struct nd_pfxrouter *
1329171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr)
133062587Sitojun{
133162587Sitojun	struct nd_pfxrouter *pfxrtr;
1332186119Sqingli	struct llentry *ln;
1333186162Skmacy	int canreach;
133462587Sitojun
1335186198Skmacy	for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr != NULL;
133662587Sitojun	     pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
1337186119Sqingli		IF_AFDATA_LOCK(pfxrtr->router->ifp);
1338186162Skmacy		ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp);
1339186162Skmacy		IF_AFDATA_UNLOCK(pfxrtr->router->ifp);
1340186198Skmacy		if (ln == NULL)
1341186198Skmacy			continue;
1342186198Skmacy		canreach = ND6_IS_LLINFO_PROBREACH(ln);
1343186198Skmacy		LLE_RUNLOCK(ln);
1344186162Skmacy		if (canreach)
1345186162Skmacy			break;
134662587Sitojun	}
1347120856Sume	return (pfxrtr);
134862587Sitojun}
134962587Sitojun
135062587Sitojun/*
135153541Sshin * Check if each prefix in the prefix list has at least one available router
135278064Sume * that advertised the prefix (a router is "available" if its neighbor cache
135378064Sume * entry is reachable or probably reachable).
135462587Sitojun * If the check fails, the prefix may be off-link, because, for example,
135553541Sshin * we have moved from the network but the lifetime of the prefix has not
135678064Sume * expired yet.  So we should not use the prefix if there is another prefix
135778064Sume * that has an available router.
135878064Sume * But, if there is no prefix that has an available router, we still regards
135978064Sume * all the prefixes as on-link.  This is because we can't tell if all the
136053541Sshin * routers are simply dead or if we really moved from the network and there
136153541Sshin * is no router around us.
136253541Sshin */
136362587Sitojunvoid
136453541Sshinpfxlist_onlink_check()
136553541Sshin{
1366183550Szec	INIT_VNET_INET6(curvnet);
136753541Sshin	struct nd_prefix *pr;
136878064Sume	struct in6_ifaddr *ifa;
1369151539Ssuz	struct nd_defrouter *dr;
1370151539Ssuz	struct nd_pfxrouter *pfxrtr = NULL;
137153541Sshin
137262587Sitojun	/*
137362587Sitojun	 * Check if there is a prefix that has a reachable advertising
137462587Sitojun	 * router.
137562587Sitojun	 */
1376181803Sbz	for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
137778064Sume		if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
137853541Sshin			break;
137962587Sitojun	}
138053541Sshin
1381151539Ssuz	/*
1382151539Ssuz	 * If we have no such prefix, check whether we still have a router
1383151539Ssuz	 * that does not advertise any prefixes.
1384151539Ssuz	 */
1385151465Ssuz	if (pr == NULL) {
1386181803Sbz		for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
1387151539Ssuz		    dr = TAILQ_NEXT(dr, dr_entry)) {
1388151539Ssuz			struct nd_prefix *pr0;
1389151539Ssuz
1390181803Sbz			for (pr0 = V_nd_prefix.lh_first; pr0;
1391151539Ssuz			    pr0 = pr0->ndpr_next) {
1392151539Ssuz				if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL)
1393151539Ssuz					break;
1394151539Ssuz			}
1395151539Ssuz			if (pfxrtr != NULL)
1396151539Ssuz				break;
1397151539Ssuz		}
1398151539Ssuz	}
1399181803Sbz	if (pr != NULL || (TAILQ_FIRST(&V_nd_defrouter) && pfxrtr == NULL)) {
1400171260Sdelphij		/*
1401151539Ssuz		 * There is at least one prefix that has a reachable router,
1402151539Ssuz		 * or at least a router which probably does not advertise
1403151539Ssuz		 * any prefixes.  The latter would be the case when we move
1404151539Ssuz		 * to a new link where we have a router that does not provide
1405151539Ssuz		 * prefixes and we configure an address by hand.
1406171260Sdelphij		 * Detach prefixes which have no reachable advertising
1407171260Sdelphij		 * router, and attach other prefixes.
1408171260Sdelphij		 */
1409181803Sbz		for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
141078064Sume			/* XXX: a link-local prefix should never be detached */
141178064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
141278064Sume				continue;
141378064Sume
141478064Sume			/*
141578064Sume			 * we aren't interested in prefixes without the L bit
141678064Sume			 * set.
141778064Sume			 */
141878064Sume			if (pr->ndpr_raf_onlink == 0)
141978064Sume				continue;
142078064Sume
142178064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
142278064Sume			    find_pfxlist_reachable_router(pr) == NULL)
142378064Sume				pr->ndpr_stateflags |= NDPRF_DETACHED;
142478064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
142578064Sume			    find_pfxlist_reachable_router(pr) != 0)
142678064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
142753541Sshin		}
142878064Sume	} else {
142978064Sume		/* there is no prefix that has a reachable router */
1430181803Sbz		for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
143178064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
143278064Sume				continue;
143378064Sume
143478064Sume			if (pr->ndpr_raf_onlink == 0)
143578064Sume				continue;
143678064Sume
143778064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
143878064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
143953541Sshin		}
144062587Sitojun	}
144178064Sume
144278064Sume	/*
144378064Sume	 * Remove each interface route associated with a (just) detached
144478064Sume	 * prefix, and reinstall the interface route for a (just) attached
144578064Sume	 * prefix.  Note that all attempt of reinstallation does not
144678064Sume	 * necessarily success, when a same prefix is shared among multiple
144778064Sume	 * interfaces.  Such cases will be handled in nd6_prefix_onlink,
144878064Sume	 * so we don't have to care about them.
144978064Sume	 */
1450181803Sbz	for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
145178064Sume		int e;
1452165118Sbz		char ip6buf[INET6_ADDRSTRLEN];
145378064Sume
145478064Sume		if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
145578064Sume			continue;
145678064Sume
145778064Sume		if (pr->ndpr_raf_onlink == 0)
145878064Sume			continue;
145978064Sume
146078064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
146178064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
146278064Sume			if ((e = nd6_prefix_offlink(pr)) != 0) {
146378064Sume				nd6log((LOG_ERR,
146478064Sume				    "pfxlist_onlink_check: failed to "
1465151479Ssuz				    "make %s/%d offlink, errno=%d\n",
1466165118Sbz				    ip6_sprintf(ip6buf,
1467165118Sbz					    &pr->ndpr_prefix.sin6_addr),
1468165118Sbz					    pr->ndpr_plen, e));
146978064Sume			}
147078064Sume		}
147178064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
147278064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
147378064Sume		    pr->ndpr_raf_onlink) {
147478064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
147578064Sume				nd6log((LOG_ERR,
147678064Sume				    "pfxlist_onlink_check: failed to "
1477151479Ssuz				    "make %s/%d onlink, errno=%d\n",
1478165118Sbz				    ip6_sprintf(ip6buf,
1479165118Sbz					    &pr->ndpr_prefix.sin6_addr),
1480165118Sbz					    pr->ndpr_plen, e));
148178064Sume			}
148278064Sume		}
148378064Sume	}
148478064Sume
148578064Sume	/*
148678064Sume	 * Changes on the prefix status might affect address status as well.
148778064Sume	 * Make sure that all addresses derived from an attached prefix are
148878064Sume	 * attached, and that all addresses derived from a detached prefix are
148978064Sume	 * detached.  Note, however, that a manually configured address should
149078064Sume	 * always be attached.
149178064Sume	 * The precise detection logic is same as the one for prefixes.
149278064Sume	 */
1493181803Sbz	for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) {
1494120941Sume		if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
149578064Sume			continue;
149678064Sume
149778064Sume		if (ifa->ia6_ndpr == NULL) {
149878064Sume			/*
149978064Sume			 * This can happen when we first configure the address
150078064Sume			 * (i.e. the address exists, but the prefix does not).
150178064Sume			 * XXX: complicated relationships...
150278064Sume			 */
150378064Sume			continue;
150478064Sume		}
150578064Sume
150678064Sume		if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
150778064Sume			break;
150878064Sume	}
150978064Sume	if (ifa) {
1510181803Sbz		for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) {
151178064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
151278064Sume				continue;
151378064Sume
151478064Sume			if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
151578064Sume				continue;
151678064Sume
1517151539Ssuz			if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) {
1518151539Ssuz				if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1519151539Ssuz					ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1520151539Ssuz					ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1521151539Ssuz					nd6_dad_start((struct ifaddr *)ifa, 0);
1522151539Ssuz				}
1523151539Ssuz			} else {
152478064Sume				ifa->ia6_flags |= IN6_IFF_DETACHED;
1525151539Ssuz			}
152678064Sume		}
152778064Sume	}
152862587Sitojun	else {
1529181803Sbz		for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) {
153078064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
153178064Sume				continue;
153278064Sume
1533151539Ssuz			if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1534151539Ssuz				ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1535151539Ssuz				ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1536151539Ssuz				/* Do we need a delay in this case? */
1537151539Ssuz				nd6_dad_start((struct ifaddr *)ifa, 0);
1538151539Ssuz			}
153978064Sume		}
154053541Sshin	}
154153541Sshin}
154253541Sshin
154378064Sumeint
1544171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr)
154553541Sshin{
1546183550Szec	INIT_VNET_INET6(curvnet);
154778064Sume	struct ifaddr *ifa;
154878064Sume	struct ifnet *ifp = pr->ndpr_ifp;
154978064Sume	struct sockaddr_in6 mask6;
155078064Sume	struct nd_prefix *opr;
155178064Sume	u_long rtflags;
155278064Sume	int error = 0;
1553186119Sqingli	struct radix_node_head *rnh;
155478064Sume	struct rtentry *rt = NULL;
1555165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
1556186119Sqingli	struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
155753541Sshin
155878064Sume	/* sanity check */
155978064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
156078064Sume		nd6log((LOG_ERR,
156178064Sume		    "nd6_prefix_onlink: %s/%d is already on-link\n",
1562165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
1563165118Sbz		    pr->ndpr_plen));
1564151465Ssuz		return (EEXIST);
156578064Sume	}
156678064Sume
156753541Sshin	/*
156878064Sume	 * Add the interface route associated with the prefix.  Before
156978064Sume	 * installing the route, check if there's the same prefix on another
157078064Sume	 * interface, and the prefix has already installed the interface route.
157178064Sume	 * Although such a configuration is expected to be rare, we explicitly
157278064Sume	 * allow it.
157353541Sshin	 */
1574181803Sbz	for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
157578064Sume		if (opr == pr)
157678064Sume			continue;
157778064Sume
157878064Sume		if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
157978064Sume			continue;
158078064Sume
158178064Sume		if (opr->ndpr_plen == pr->ndpr_plen &&
158278064Sume		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1583120941Sume		    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen))
1584120856Sume			return (0);
158578064Sume	}
158678064Sume
158778064Sume	/*
1588120941Sume	 * We prefer link-local addresses as the associated interface address.
158978064Sume	 */
159078064Sume	/* search for a link-local addr */
159178064Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
1592120941Sume	    IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
159378064Sume	if (ifa == NULL) {
159478064Sume		/* XXX: freebsd does not have ifa_ifwithaf */
1595120941Sume		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
159678064Sume			if (ifa->ifa_addr->sa_family == AF_INET6)
159778064Sume				break;
159878064Sume		}
159978064Sume		/* should we care about ia6_flags? */
160078064Sume	}
160178064Sume	if (ifa == NULL) {
160278064Sume		/*
160378064Sume		 * This can still happen, when, for example, we receive an RA
160478064Sume		 * containing a prefix with the L bit set and the A bit clear,
160578064Sume		 * after removing all IPv6 addresses on the receiving
160678064Sume		 * interface.  This should, of course, be rare though.
160778064Sume		 */
160878064Sume		nd6log((LOG_NOTICE,
160978064Sume		    "nd6_prefix_onlink: failed to find any ifaddr"
161078064Sume		    " to add route for a prefix(%s/%d) on %s\n",
1611165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
161278064Sume		    pr->ndpr_plen, if_name(ifp)));
1613120856Sume		return (0);
161478064Sume	}
161578064Sume
161678064Sume	/*
161778064Sume	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
161878064Sume	 * ifa->ifa_rtrequest = nd6_rtrequest;
161978064Sume	 */
162078064Sume	bzero(&mask6, sizeof(mask6));
162178064Sume	mask6.sin6_len = sizeof(mask6);
162278064Sume	mask6.sin6_addr = pr->ndpr_mask;
1623186119Sqingli	rtflags = ifa->ifa_flags | RTF_UP;
162478064Sume	error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
1625120941Sume	    ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
162678064Sume	if (error == 0) {
1627186119Sqingli		if (rt != NULL) /* this should be non NULL, though */ {
1628186119Sqingli			rnh = V_rt_tables[rt->rt_fibnum][AF_INET6];
1629186119Sqingli			RADIX_NODE_HEAD_LOCK(rnh);
1630186119Sqingli			RT_LOCK(rt);
1631186119Sqingli			if (!rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl)) {
1632186119Sqingli				((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
1633186119Sqingli					rt->rt_ifp->if_type;
1634186119Sqingli				((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
1635186119Sqingli					rt->rt_ifp->if_index;
1636186119Sqingli			}
1637186119Sqingli			RADIX_NODE_HEAD_UNLOCK(rnh);
163878064Sume			nd6_rtmsg(RTM_ADD, rt);
1639186119Sqingli			RT_UNLOCK(rt);
1640186119Sqingli		}
164178064Sume		pr->ndpr_stateflags |= NDPRF_ONLINK;
1642120941Sume	} else {
1643165118Sbz		char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN];
164478064Sume		nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
164578064Sume		    " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
164678064Sume		    "errno = %d\n",
1647165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
164878064Sume		    pr->ndpr_plen, if_name(ifp),
1649165118Sbz		    ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
1650165118Sbz		    ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error));
165178064Sume	}
165278064Sume
1653120727Ssam	if (rt != NULL) {
1654120727Ssam		RT_LOCK(rt);
1655122334Ssam		RT_REMREF(rt);
1656120727Ssam		RT_UNLOCK(rt);
1657120727Ssam	}
165878064Sume
1659120856Sume	return (error);
166078064Sume}
166178064Sume
166278064Sumeint
1663171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr)
166478064Sume{
1665183550Szec	INIT_VNET_INET6(curvnet);
166678064Sume	int error = 0;
166778064Sume	struct ifnet *ifp = pr->ndpr_ifp;
166878064Sume	struct nd_prefix *opr;
166978064Sume	struct sockaddr_in6 sa6, mask6;
167078064Sume	struct rtentry *rt = NULL;
1671165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
167278064Sume
167378064Sume	/* sanity check */
167478064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
167578064Sume		nd6log((LOG_ERR,
167678064Sume		    "nd6_prefix_offlink: %s/%d is already off-link\n",
1677165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
1678165118Sbz		    pr->ndpr_plen));
1679120856Sume		return (EEXIST);
168078064Sume	}
168178064Sume
168253541Sshin	bzero(&sa6, sizeof(sa6));
168353541Sshin	sa6.sin6_family = AF_INET6;
168453541Sshin	sa6.sin6_len = sizeof(sa6);
168553541Sshin	bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
1686120941Sume	    sizeof(struct in6_addr));
168753541Sshin	bzero(&mask6, sizeof(mask6));
168853541Sshin	mask6.sin6_family = AF_INET6;
168953541Sshin	mask6.sin6_len = sizeof(sa6);
169053541Sshin	bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
169178064Sume	error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
1692120941Sume	    (struct sockaddr *)&mask6, 0, &rt);
169378064Sume	if (error == 0) {
169478064Sume		pr->ndpr_stateflags &= ~NDPRF_ONLINK;
169553541Sshin
169678064Sume		/* report the route deletion to the routing socket. */
169778064Sume		if (rt != NULL)
169878064Sume			nd6_rtmsg(RTM_DELETE, rt);
169953541Sshin
170078064Sume		/*
170178064Sume		 * There might be the same prefix on another interface,
170278064Sume		 * the prefix which could not be on-link just because we have
170378064Sume		 * the interface route (see comments in nd6_prefix_onlink).
170478064Sume		 * If there's one, try to make the prefix on-link on the
170578064Sume		 * interface.
170678064Sume		 */
1707181803Sbz		for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
170878064Sume			if (opr == pr)
170978064Sume				continue;
171053541Sshin
171178064Sume			if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
171278064Sume				continue;
171353541Sshin
171478064Sume			/*
171578064Sume			 * KAME specific: detached prefixes should not be
171678064Sume			 * on-link.
171778064Sume			 */
171878064Sume			if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
171978064Sume				continue;
172078064Sume
172178064Sume			if (opr->ndpr_plen == pr->ndpr_plen &&
172278064Sume			    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1723120941Sume			    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
172478064Sume				int e;
172578064Sume
172678064Sume				if ((e = nd6_prefix_onlink(opr)) != 0) {
172778064Sume					nd6log((LOG_ERR,
172878064Sume					    "nd6_prefix_offlink: failed to "
172978064Sume					    "recover a prefix %s/%d from %s "
173078064Sume					    "to %s (errno = %d)\n",
1731165118Sbz					    ip6_sprintf(ip6buf,
1732165118Sbz						&opr->ndpr_prefix.sin6_addr),
173378064Sume					    opr->ndpr_plen, if_name(ifp),
173478064Sume					    if_name(opr->ndpr_ifp), e));
173578064Sume				}
173678064Sume			}
173778064Sume		}
1738120941Sume	} else {
173978064Sume		/* XXX: can we still set the NDPRF_ONLINK flag? */
174078064Sume		nd6log((LOG_ERR,
174178064Sume		    "nd6_prefix_offlink: failed to delete route: "
174278064Sume		    "%s/%d on %s (errno = %d)\n",
1743165118Sbz		    ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen,
1744165118Sbz		    if_name(ifp), error));
174578064Sume	}
174653541Sshin
1747120941Sume	if (rt != NULL) {
1748108269Sru		RTFREE(rt);
1749120941Sume	}
175053541Sshin
1751120856Sume	return (error);
175253541Sshin}
175353541Sshin
175453541Sshinstatic struct in6_ifaddr *
1755171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast)
175653541Sshin{
1757183550Szec	INIT_VNET_INET6(curvnet);
175878064Sume	struct ifnet *ifp = pr->ndpr_ifp;
175953541Sshin	struct ifaddr *ifa;
176078064Sume	struct in6_aliasreq ifra;
176178064Sume	struct in6_ifaddr *ia, *ib;
176278064Sume	int error, plen0;
176353541Sshin	struct in6_addr mask;
176478064Sume	int prefixlen = pr->ndpr_plen;
1765151539Ssuz	int updateflags;
1766165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
176753541Sshin
1768121168Sume	in6_prefixlen2mask(&mask, prefixlen);
176953541Sshin
177078064Sume	/*
177178064Sume	 * find a link-local address (will be interface ID).
177278064Sume	 * Is it really mandatory? Theoretically, a global or a site-local
177378064Sume	 * address can be configured without a link-local address, if we
177478064Sume	 * have a unique interface identifier...
177578064Sume	 *
177678064Sume	 * it is not mandatory to have a link-local address, we can generate
177778064Sume	 * interface identifier on the fly.  we do this because:
177878064Sume	 * (1) it should be the easiest way to find interface identifier.
177978064Sume	 * (2) RFC2462 5.4 suggesting the use of the same interface identifier
178078064Sume	 * for multiple addresses on a single interface, and possible shortcut
178178064Sume	 * of DAD.  we omitted DAD for this reason in the past.
1782120941Sume	 * (3) a user can prevent autoconfiguration of global address
178378064Sume	 * by removing link-local address by hand (this is partly because we
1784108533Sschweikh	 * don't have other way to control the use of IPv6 on an interface.
178578064Sume	 * this has been our design choice - cf. NRL's "ifconfig auto").
178678064Sume	 * (4) it is easier to manage when an interface has addresses
178778064Sume	 * with the same interface identifier, than to have multiple addresses
178878064Sume	 * with different interface identifiers.
178978064Sume	 */
1790120941Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
179153541Sshin	if (ifa)
179253541Sshin		ib = (struct in6_ifaddr *)ifa;
179353541Sshin	else
179453541Sshin		return NULL;
179553541Sshin
179653541Sshin	/* prefixlen + ifidlen must be equal to 128 */
179778064Sume	plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
179878064Sume	if (prefixlen != plen0) {
179978064Sume		nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
180078064Sume		    "(prefix=%d ifid=%d)\n",
180178064Sume		    if_name(ifp), prefixlen, 128 - plen0));
180253541Sshin		return NULL;
180353541Sshin	}
180453541Sshin
180553541Sshin	/* make ifaddr */
180653541Sshin
180778064Sume	bzero(&ifra, sizeof(ifra));
180878064Sume	/*
180978064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
181078064Sume	 * for safety.
181178064Sume	 */
181278064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
181378064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
181478064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
181578064Sume	/* prefix */
1816151539Ssuz	ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr;
181778064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
181878064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
181978064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
182078064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
182153541Sshin
182253541Sshin	/* interface ID */
1823120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
1824151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
1825120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
1826151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
1827120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1828151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
1829120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1830151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
1831120941Sume
183278064Sume	/* new prefix mask. */
183378064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
183478064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
183578064Sume	bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
1836120941Sume	    sizeof(ifra.ifra_prefixmask.sin6_addr));
183753541Sshin
1838151539Ssuz	/* lifetimes. */
183978064Sume	ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
184078064Sume	ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
184153541Sshin
184278064Sume	/* XXX: scope zone ID? */
184353541Sshin
184478064Sume	ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
1845151539Ssuz
1846171260Sdelphij	/*
1847151539Ssuz	 * Make sure that we do not have this address already.  This should
1848151539Ssuz	 * usually not happen, but we can still see this case, e.g., if we
1849151539Ssuz	 * have manually configured the exact address to be configured.
185078064Sume	 */
1851151539Ssuz	if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
1852151539Ssuz		/* this should be rare enough to make an explicit log */
1853151539Ssuz		log(LOG_INFO, "in6_ifadd: %s is already configured\n",
1854165118Sbz		    ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr));
1855151539Ssuz		return (NULL);
1856151539Ssuz	}
185753541Sshin
185853541Sshin	/*
1859151539Ssuz	 * Allocate ifaddr structure, link into chain, etc.
1860151539Ssuz	 * If we are going to create a new address upon receiving a multicasted
1861151539Ssuz	 * RA, we need to impose a random delay before starting DAD.
1862151539Ssuz	 * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2]
186353541Sshin	 */
1864151539Ssuz	updateflags = 0;
1865151539Ssuz	if (mcast)
1866151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1867151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) {
186878064Sume		nd6log((LOG_ERR,
186978064Sume		    "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
1870165118Sbz		    ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr),
1871165118Sbz		    if_name(ifp), error));
1872120856Sume		return (NULL);	/* ifaddr must not have been allocated. */
187353541Sshin	}
187453541Sshin
187578064Sume	ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
187653541Sshin
1877120941Sume	return (ia);		/* this is always non-NULL */
187853541Sshin}
187953541Sshin
1880171259Sdelphij/*
1881171259Sdelphij * ia0 - corresponding public address
1882171259Sdelphij */
188353541Sshinint
1884171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay)
188553541Sshin{
1886183550Szec	INIT_VNET_INET6(curvnet);
188778064Sume	struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
1888151539Ssuz	struct in6_ifaddr *newia, *ia;
188978064Sume	struct in6_aliasreq ifra;
189078064Sume	int i, error;
189178064Sume	int trylimit = 3;	/* XXX: adhoc value */
1892151539Ssuz	int updateflags;
189378064Sume	u_int32_t randid[2];
189478064Sume	time_t vltime0, pltime0;
189553541Sshin
189678064Sume	bzero(&ifra, sizeof(ifra));
189778064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
189878064Sume	ifra.ifra_addr = ia0->ia_addr;
189978064Sume	/* copy prefix mask */
190078064Sume	ifra.ifra_prefixmask = ia0->ia_prefixmask;
190178064Sume	/* clear the old IFID */
190278064Sume	for (i = 0; i < 4; i++) {
1903120941Sume		ifra.ifra_addr.sin6_addr.s6_addr32[i] &=
1904120941Sume		    ifra.ifra_prefixmask.sin6_addr.s6_addr32[i];
190578064Sume	}
190653541Sshin
190778064Sume  again:
1908151539Ssuz	if (in6_get_tmpifid(ifp, (u_int8_t *)randid,
1909151539Ssuz	    (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) {
1910151539Ssuz		nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good "
1911151539Ssuz		    "random IFID\n"));
1912151539Ssuz		return (EINVAL);
1913151539Ssuz	}
1914120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1915120941Sume	    (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2]));
1916120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1917120941Sume	    (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3]));
191853541Sshin
1919171260Sdelphij	/*
1920151539Ssuz	 * in6_get_tmpifid() quite likely provided a unique interface ID.
1921151539Ssuz	 * However, we may still have a chance to see collision, because
1922151539Ssuz	 * there may be a time lag between generation of the ID and generation
1923151539Ssuz	 * of the address.  So, we'll do one more sanity check.
192478064Sume	 */
1925181803Sbz	for (ia = V_in6_ifaddr; ia; ia = ia->ia_next) {
1926151539Ssuz		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
1927151539Ssuz		    &ifra.ifra_addr.sin6_addr)) {
1928171260Sdelphij			if (trylimit-- == 0) {
1929151539Ssuz				/*
1930151539Ssuz				 * Give up.  Something strange should have
1931151539Ssuz				 * happened.
1932151539Ssuz				 */
1933151539Ssuz				nd6log((LOG_NOTICE, "in6_tmpifadd: failed to "
1934151539Ssuz				    "find a unique random IFID\n"));
1935151539Ssuz				return (EEXIST);
1936151539Ssuz			}
1937151539Ssuz			forcegen = 1;
1938151539Ssuz			goto again;
193978064Sume		}
194053541Sshin	}
194153541Sshin
194278064Sume	/*
194378064Sume	 * The Valid Lifetime is the lower of the Valid Lifetime of the
194478064Sume         * public address or TEMP_VALID_LIFETIME.
194578064Sume	 * The Preferred Lifetime is the lower of the Preferred Lifetime
194678064Sume         * of the public address or TEMP_PREFERRED_LIFETIME -
194778064Sume         * DESYNC_FACTOR.
194878064Sume	 */
1949151539Ssuz	if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
195078064Sume		vltime0 = IFA6_IS_INVALID(ia0) ? 0 :
1951151539Ssuz		    (ia0->ia6_lifetime.ia6t_vltime -
1952151539Ssuz		    (time_second - ia0->ia6_updatetime));
1953181803Sbz		if (vltime0 > V_ip6_temp_valid_lifetime)
1954181803Sbz			vltime0 = V_ip6_temp_valid_lifetime;
195578064Sume	} else
1956181803Sbz		vltime0 = V_ip6_temp_valid_lifetime;
1957151539Ssuz	if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
195878064Sume		pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 :
1959151539Ssuz		    (ia0->ia6_lifetime.ia6t_pltime -
1960151539Ssuz		    (time_second - ia0->ia6_updatetime));
1961181803Sbz		if (pltime0 > V_ip6_temp_preferred_lifetime - V_ip6_desync_factor){
1962181803Sbz			pltime0 = V_ip6_temp_preferred_lifetime -
1963181803Sbz			    V_ip6_desync_factor;
196478064Sume		}
196578064Sume	} else
1966181803Sbz		pltime0 = V_ip6_temp_preferred_lifetime - V_ip6_desync_factor;
196778064Sume	ifra.ifra_lifetime.ia6t_vltime = vltime0;
196878064Sume	ifra.ifra_lifetime.ia6t_pltime = pltime0;
196953541Sshin
197078064Sume	/*
197178064Sume	 * A temporary address is created only if this calculated Preferred
197278064Sume	 * Lifetime is greater than REGEN_ADVANCE time units.
197378064Sume	 */
1974181803Sbz	if (ifra.ifra_lifetime.ia6t_pltime <= V_ip6_temp_regen_advance)
1975120856Sume		return (0);
197653541Sshin
197778064Sume	/* XXX: scope zone ID? */
197878064Sume
197978064Sume	ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
198078064Sume
198178064Sume	/* allocate ifaddr structure, link into chain, etc. */
1982151539Ssuz	updateflags = 0;
1983151539Ssuz	if (delay)
1984151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1985151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0)
1986120856Sume		return (error);
198778064Sume
198878064Sume	newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
198978064Sume	if (newia == NULL) {	/* XXX: can it happen? */
199078064Sume		nd6log((LOG_ERR,
199178064Sume		    "in6_tmpifadd: ifa update succeeded, but we got "
199278064Sume		    "no ifaddr\n"));
1993120856Sume		return (EINVAL); /* XXX */
199453541Sshin	}
199578064Sume	newia->ia6_ndpr = ia0->ia6_ndpr;
199678064Sume	newia->ia6_ndpr->ndpr_refcnt++;
199753541Sshin
199878407Sume	/*
199978407Sume	 * A newly added address might affect the status of other addresses.
200078407Sume	 * XXX: when the temporary address is generated with a new public
200178407Sume	 * address, the onlink check is redundant.  However, it would be safe
200278407Sume	 * to do the check explicitly everywhere a new address is generated,
200378407Sume	 * and, in fact, we surely need the check when we create a new
200478407Sume	 * temporary address due to deprecation of an old temporary address.
200578407Sume	 */
200678407Sume	pfxlist_onlink_check();
200778407Sume
2008120856Sume	return (0);
2009120941Sume}
201053541Sshin
2011151539Ssuzstatic int
201253541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr)
201353541Sshin{
201453541Sshin	if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
201553541Sshin		ndpr->ndpr_preferred = 0;
201653541Sshin	else
201753541Sshin		ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
201853541Sshin	if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
201953541Sshin		ndpr->ndpr_expire = 0;
202053541Sshin	else
202153541Sshin		ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
202253541Sshin
202353541Sshin	return 0;
202453541Sshin}
202553541Sshin
202653541Sshinstatic void
202778064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
202853541Sshin{
202978064Sume	/* init ia6t_expire */
203078064Sume	if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
203178064Sume		lt6->ia6t_expire = 0;
203278064Sume	else {
203378064Sume		lt6->ia6t_expire = time_second;
203478064Sume		lt6->ia6t_expire += lt6->ia6t_vltime;
203553541Sshin	}
203662587Sitojun
203753541Sshin	/* init ia6t_preferred */
203853541Sshin	if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
203953541Sshin		lt6->ia6t_preferred = 0;
204053541Sshin	else {
204153541Sshin		lt6->ia6t_preferred = time_second;
204253541Sshin		lt6->ia6t_preferred += lt6->ia6t_pltime;
204353541Sshin	}
204453541Sshin}
204553541Sshin
204653541Sshin/*
204753541Sshin * Delete all the routing table entries that use the specified gateway.
204853541Sshin * XXX: this function causes search through all entries of routing table, so
204953541Sshin * it shouldn't be called when acting as a router.
205053541Sshin */
205153541Sshinvoid
2052171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
205353541Sshin{
2054183550Szec	INIT_VNET_NET(curvnet);
2055181803Sbz	struct radix_node_head *rnh = V_rt_tables[0][AF_INET6];
205653541Sshin	int s = splnet();
205753541Sshin
205853541Sshin	/* We'll care only link-local addresses */
205953541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
206053541Sshin		splx(s);
206153541Sshin		return;
206253541Sshin	}
206353541Sshin
2064108250Shsu	RADIX_NODE_HEAD_LOCK(rnh);
206553541Sshin	rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
2066108250Shsu	RADIX_NODE_HEAD_UNLOCK(rnh);
206753541Sshin	splx(s);
206853541Sshin}
206953541Sshin
207053541Sshinstatic int
2071171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg)
207253541Sshin{
207353541Sshin#define SIN6(s)	((struct sockaddr_in6 *)s)
207453541Sshin	struct rtentry *rt = (struct rtentry *)rn;
207553541Sshin	struct in6_addr *gate = (struct in6_addr *)arg;
207653541Sshin
207753541Sshin	if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
2078120856Sume		return (0);
207953541Sshin
2080120941Sume	if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) {
2081120856Sume		return (0);
2082120941Sume	}
208353541Sshin
208453541Sshin	/*
208578064Sume	 * Do not delete a static route.
208678064Sume	 * XXX: this seems to be a bit ad-hoc. Should we consider the
208778064Sume	 * 'cloned' bit instead?
208878064Sume	 */
208978064Sume	if ((rt->rt_flags & RTF_STATIC) != 0)
2090120856Sume		return (0);
209178064Sume
209278064Sume	/*
209353541Sshin	 * We delete only host route. This means, in particular, we don't
209453541Sshin	 * delete default route.
209553541Sshin	 */
209653541Sshin	if ((rt->rt_flags & RTF_HOST) == 0)
2097120856Sume		return (0);
209853541Sshin
2099120941Sume	return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
2100120941Sume	    rt_mask(rt), rt->rt_flags, 0));
210153541Sshin#undef SIN6
210253541Sshin}
210362587Sitojun
210462587Sitojunint
2105171259Sdelphijnd6_setdefaultiface(int ifindex)
210662587Sitojun{
2107183550Szec	INIT_VNET_NET(curvnet);
2108183550Szec	INIT_VNET_INET6(curvnet);
210962587Sitojun	int error = 0;
211062587Sitojun
2111181803Sbz	if (ifindex < 0 || V_if_index < ifindex)
2112120856Sume		return (EINVAL);
2113151539Ssuz	if (ifindex != 0 && !ifnet_byindex(ifindex))
2114151539Ssuz		return (EINVAL);
211562587Sitojun
2116181803Sbz	if (V_nd6_defifindex != ifindex) {
2117181803Sbz		V_nd6_defifindex = ifindex;
2118181803Sbz		if (V_nd6_defifindex > 0)
2119181803Sbz			V_nd6_defifp = ifnet_byindex(V_nd6_defifindex);
212062587Sitojun		else
2121181803Sbz			V_nd6_defifp = NULL;
212262587Sitojun
212362587Sitojun		/*
212462587Sitojun		 * Our current implementation assumes one-to-one maping between
212562587Sitojun		 * interfaces and links, so it would be natural to use the
212662587Sitojun		 * default interface as the default link.
212762587Sitojun		 */
2128181803Sbz		scope6_setdefault(V_nd6_defifp);
212962587Sitojun	}
213062587Sitojun
2131120856Sume	return (error);
213262587Sitojun}
2133