nd6_rtr.c revision 175162
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 175162 2008-01-08 19:08:58Z obrien $");
34174510Sobrien
3562587Sitojun#include "opt_inet.h"
3662587Sitojun#include "opt_inet6.h"
3762587Sitojun
3853541Sshin#include <sys/param.h>
3953541Sshin#include <sys/systm.h>
4053541Sshin#include <sys/malloc.h>
4153541Sshin#include <sys/mbuf.h>
4253541Sshin#include <sys/socket.h>
4353541Sshin#include <sys/sockio.h>
4453541Sshin#include <sys/time.h>
4578064Sume#include <sys/kernel.h>
4653541Sshin#include <sys/errno.h>
4753541Sshin#include <sys/syslog.h>
4878064Sume#include <sys/queue.h>
4953541Sshin
5053541Sshin#include <net/if.h>
5153541Sshin#include <net/if_types.h>
5253541Sshin#include <net/if_dl.h>
5353541Sshin#include <net/route.h>
5453541Sshin#include <net/radix.h>
5553541Sshin
5653541Sshin#include <netinet/in.h>
5753541Sshin#include <netinet6/in6_var.h>
5878064Sume#include <netinet6/in6_ifattach.h>
5962587Sitojun#include <netinet/ip6.h>
6053541Sshin#include <netinet6/ip6_var.h>
6153541Sshin#include <netinet6/nd6.h>
6262587Sitojun#include <netinet/icmp6.h>
6362587Sitojun#include <netinet6/scope6_var.h>
6453541Sshin
6562587Sitojun#define SDL(s)	((struct sockaddr_dl *)s)
6653541Sshin
67175162Sobrienstatic int rtpref(struct nd_defrouter *);
68175162Sobrienstatic struct nd_defrouter *defrtrlist_update(struct nd_defrouter *);
69151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *,
70151539Ssuz    struct mbuf *, int));
71175162Sobrienstatic struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *,	int);
7262587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
7378064Sume	struct nd_defrouter *));
74175162Sobrienstatic void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *);
75175162Sobrienstatic void pfxrtr_del(struct nd_pfxrouter *);
7662587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router
77175162Sobrien(struct nd_prefix *);
78175162Sobrienstatic void defrouter_delreq(struct nd_defrouter *);
79175162Sobrienstatic void nd6_rtmsg(int, struct rtentry *);
8053541Sshin
81175162Sobrienstatic int in6_init_prefix_ltimes(struct nd_prefix *);
82120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *,
83120941Sume	struct in6_addrlifetime *));
8453541Sshin
85175162Sobrienstatic int rt6_deleteroute(struct radix_node *, void *);
8653541Sshin
8762587Sitojunextern int nd6_recalc_reachtm_interval;
8853541Sshin
8978064Sumestatic struct ifnet *nd6_defifp;
9062587Sitojunint nd6_defifindex;
9162587Sitojun
9278064Sumeint ip6_use_tempaddr = 0;
9378064Sume
9478064Sumeint ip6_desync_factor;
9578064Sumeu_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME;
9678064Sumeu_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME;
9753541Sshin/*
9878064Sume * shorter lifetimes for debugging purposes.
9978064Sumeint ip6_temp_preferred_lifetime = 800;
10078064Sumestatic int ip6_temp_valid_lifetime = 1800;
10178064Sume*/
10278064Sumeint ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE;
10378064Sume
104151539Ssuz/* RTPREF_MEDIUM has to be 0! */
105151539Ssuz#define RTPREF_HIGH	1
106151539Ssuz#define RTPREF_MEDIUM	0
107151539Ssuz#define RTPREF_LOW	(-1)
108151539Ssuz#define RTPREF_RESERVED	(-2)
109151539Ssuz#define RTPREF_INVALID	(-3)	/* internal */
110151539Ssuz
11178064Sume/*
11253541Sshin * Receive Router Solicitation Message - just for routers.
11353541Sshin * Router solicitation/advertisement is mostly managed by userland program
11453541Sshin * (rtadvd) so here we have no function like nd6_ra_output().
11553541Sshin *
11653541Sshin * Based on RFC 2461
11753541Sshin */
11853541Sshinvoid
119171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len)
12053541Sshin{
12153541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
12253541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
12362587Sitojun	struct nd_router_solicit *nd_rs;
12453541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
12553541Sshin	char *lladdr = NULL;
12653541Sshin	int lladdrlen = 0;
12753541Sshin	union nd_opts ndopts;
128165118Sbz	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
12953541Sshin
13053541Sshin	/* If I'm not a router, ignore it. */
13153541Sshin	if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
13262587Sitojun		goto freeit;
13353541Sshin
13453541Sshin	/* Sanity checks */
13553541Sshin	if (ip6->ip6_hlim != 255) {
13678064Sume		nd6log((LOG_ERR,
13778064Sume		    "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
138165118Sbz		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
139165118Sbz		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
14078064Sume		goto bad;
14153541Sshin	}
14253541Sshin
14353541Sshin	/*
14453541Sshin	 * Don't update the neighbor cache, if src = ::.
14553541Sshin	 * This indicates that the src has no IP address assigned yet.
14653541Sshin	 */
14753541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
14862587Sitojun		goto freeit;
14962587Sitojun
15062587Sitojun#ifndef PULLDOWN_TEST
15162587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
15262587Sitojun	nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
15362587Sitojun#else
15462587Sitojun	IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
15562587Sitojun	if (nd_rs == NULL) {
15662587Sitojun		icmp6stat.icp6s_tooshort++;
15753541Sshin		return;
15862587Sitojun	}
15962587Sitojun#endif
16053541Sshin
16153541Sshin	icmp6len -= sizeof(*nd_rs);
16253541Sshin	nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
16353541Sshin	if (nd6_options(&ndopts) < 0) {
16478064Sume		nd6log((LOG_INFO,
16578064Sume		    "nd6_rs_input: invalid ND option, ignored\n"));
16678064Sume		/* nd6_options have incremented stats */
16762587Sitojun		goto freeit;
16853541Sshin	}
16953541Sshin
17053541Sshin	if (ndopts.nd_opts_src_lladdr) {
17153541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
17253541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
17353541Sshin	}
17453541Sshin
17553541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
17678064Sume		nd6log((LOG_INFO,
17753541Sshin		    "nd6_rs_input: lladdrlen mismatch for %s "
17853541Sshin		    "(if %d, RS packet %d)\n",
179165118Sbz		    ip6_sprintf(ip6bufs, &saddr6),
180120941Sume		    ifp->if_addrlen, lladdrlen - 2));
18178064Sume		goto bad;
18253541Sshin	}
18353541Sshin
18453541Sshin	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
18562587Sitojun
18662587Sitojun freeit:
18762587Sitojun	m_freem(m);
18878064Sume	return;
18978064Sume
19078064Sume bad:
19178064Sume	icmp6stat.icp6s_badrs++;
19278064Sume	m_freem(m);
19353541Sshin}
19453541Sshin
19553541Sshin/*
19653541Sshin * Receive Router Advertisement Message.
19753541Sshin *
19853541Sshin * Based on RFC 2461
19953541Sshin * TODO: on-link bit on prefix information
20053541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
20153541Sshin */
20253541Sshinvoid
203171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len)
20453541Sshin{
20553541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
206121161Sume	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
20753541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
20862587Sitojun	struct nd_router_advert *nd_ra;
20953541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
210151539Ssuz	int mcast = 0;
21153541Sshin	union nd_opts ndopts;
21253541Sshin	struct nd_defrouter *dr;
213165118Sbz	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
21453541Sshin
215118498Sume	/*
216118498Sume	 * We only accept RAs only when
217118498Sume	 * the system-wide variable allows the acceptance, and
218118498Sume	 * per-interface variable allows RAs on the receiving interface.
219118498Sume	 */
22053541Sshin	if (ip6_accept_rtadv == 0)
22162587Sitojun		goto freeit;
222118498Sume	if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
223118498Sume		goto freeit;
22453541Sshin
22553541Sshin	if (ip6->ip6_hlim != 255) {
22678064Sume		nd6log((LOG_ERR,
22778064Sume		    "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
228165118Sbz		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
229165118Sbz		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
23078064Sume		goto bad;
23153541Sshin	}
23253541Sshin
23353541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
23478064Sume		nd6log((LOG_ERR,
23553541Sshin		    "nd6_ra_input: src %s is not link-local\n",
236165118Sbz		    ip6_sprintf(ip6bufs, &saddr6)));
23778064Sume		goto bad;
23862587Sitojun	}
23962587Sitojun
24062587Sitojun#ifndef PULLDOWN_TEST
24162587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
24262587Sitojun	nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
24362587Sitojun#else
24462587Sitojun	IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
24562587Sitojun	if (nd_ra == NULL) {
24662587Sitojun		icmp6stat.icp6s_tooshort++;
24753541Sshin		return;
24853541Sshin	}
24962587Sitojun#endif
25053541Sshin
25153541Sshin	icmp6len -= sizeof(*nd_ra);
25253541Sshin	nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
25353541Sshin	if (nd6_options(&ndopts) < 0) {
25478064Sume		nd6log((LOG_INFO,
25578064Sume		    "nd6_ra_input: invalid ND option, ignored\n"));
25678064Sume		/* nd6_options have incremented stats */
25762587Sitojun		goto freeit;
25853541Sshin	}
25953541Sshin
26053541Sshin    {
26153541Sshin	struct nd_defrouter dr0;
26253541Sshin	u_int32_t advreachable = nd_ra->nd_ra_reachable;
26353541Sshin
264151539Ssuz	/* remember if this is a multicasted advertisement */
265151539Ssuz	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
266151539Ssuz		mcast = 1;
267151539Ssuz
268151539Ssuz	bzero(&dr0, sizeof(dr0));
26953541Sshin	dr0.rtaddr = saddr6;
27053541Sshin	dr0.flags  = nd_ra->nd_ra_flags_reserved;
271156871Ssuz	dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
27253541Sshin	dr0.expire = time_second + dr0.rtlifetime;
27353541Sshin	dr0.ifp = ifp;
27453541Sshin	/* unspecified or not? (RFC 2461 6.3.4) */
27553541Sshin	if (advreachable) {
27690868Smike		advreachable = ntohl(advreachable);
27753541Sshin		if (advreachable <= MAX_REACHABLE_TIME &&
27853541Sshin		    ndi->basereachable != advreachable) {
27953541Sshin			ndi->basereachable = advreachable;
28053541Sshin			ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
28153541Sshin			ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
28253541Sshin		}
28353541Sshin	}
28453541Sshin	if (nd_ra->nd_ra_retransmit)
28553541Sshin		ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
28653541Sshin	if (nd_ra->nd_ra_curhoplimit)
28753541Sshin		ndi->chlim = nd_ra->nd_ra_curhoplimit;
28853541Sshin	dr = defrtrlist_update(&dr0);
28953541Sshin    }
29053541Sshin
29153541Sshin	/*
29253541Sshin	 * prefix
29353541Sshin	 */
29453541Sshin	if (ndopts.nd_opts_pi) {
29553541Sshin		struct nd_opt_hdr *pt;
29678064Sume		struct nd_opt_prefix_info *pi = NULL;
297151539Ssuz		struct nd_prefixctl pr;
29853541Sshin
29953541Sshin		for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
30053541Sshin		     pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
30153541Sshin		     pt = (struct nd_opt_hdr *)((caddr_t)pt +
30253541Sshin						(pt->nd_opt_len << 3))) {
30353541Sshin			if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
30453541Sshin				continue;
30553541Sshin			pi = (struct nd_opt_prefix_info *)pt;
30653541Sshin
30753541Sshin			if (pi->nd_opt_pi_len != 4) {
30878064Sume				nd6log((LOG_INFO,
30978064Sume				    "nd6_ra_input: invalid option "
31078064Sume				    "len %d for prefix information option, "
31178064Sume				    "ignored\n", pi->nd_opt_pi_len));
31253541Sshin				continue;
31353541Sshin			}
31453541Sshin
31553541Sshin			if (128 < pi->nd_opt_pi_prefix_len) {
31678064Sume				nd6log((LOG_INFO,
31778064Sume				    "nd6_ra_input: invalid prefix "
31878064Sume				    "len %d for prefix information option, "
31978064Sume				    "ignored\n", pi->nd_opt_pi_prefix_len));
32053541Sshin				continue;
32153541Sshin			}
32253541Sshin
32353541Sshin			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
32453541Sshin			 || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
32578064Sume				nd6log((LOG_INFO,
32678064Sume				    "nd6_ra_input: invalid prefix "
32778064Sume				    "%s, ignored\n",
328165118Sbz				    ip6_sprintf(ip6bufs,
329165118Sbz					&pi->nd_opt_pi_prefix)));
33053541Sshin				continue;
33153541Sshin			}
33253541Sshin
33353541Sshin			bzero(&pr, sizeof(pr));
33453541Sshin			pr.ndpr_prefix.sin6_family = AF_INET6;
33553541Sshin			pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
33653541Sshin			pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
33753541Sshin			pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
33853541Sshin
33953541Sshin			pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
340120941Sume			    ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
34153541Sshin			pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
342120941Sume			    ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
34353541Sshin			pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
34453541Sshin			pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
345120941Sume			pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time);
346151539Ssuz			(void)prelist_update(&pr, dr, m, mcast);
34753541Sshin		}
34853541Sshin	}
34953541Sshin
35053541Sshin	/*
35153541Sshin	 * MTU
35253541Sshin	 */
35353541Sshin	if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
354121283Sume		u_long mtu;
355121283Sume		u_long maxmtu;
35653541Sshin
357121283Sume		mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
358120941Sume
35953541Sshin		/* lower bound */
36053541Sshin		if (mtu < IPV6_MMTU) {
36178064Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option "
362121283Sume			    "mtu=%lu sent from %s, ignoring\n",
363165118Sbz			    mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src)));
36453541Sshin			goto skip;
36553541Sshin		}
36653541Sshin
36753541Sshin		/* upper bound */
368121283Sume		maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu)
369121283Sume		    ? ndi->maxmtu : ifp->if_mtu;
370121283Sume		if (mtu <= maxmtu) {
371121283Sume			int change = (ndi->linkmtu != mtu);
37253541Sshin
373121283Sume			ndi->linkmtu = mtu;
374121283Sume			if (change) /* in6_maxmtu may change */
375121283Sume				in6_setmaxmtu();
37653541Sshin		} else {
377121283Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
378121283Sume			    "mtu=%lu sent from %s; "
379121283Sume			    "exceeds maxmtu %lu, ignoring\n",
380165118Sbz			    mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu));
38153541Sshin		}
38253541Sshin	}
38353541Sshin
38453541Sshin skip:
385120941Sume
38653541Sshin	/*
38795023Ssuz	 * Source link layer address
38853541Sshin	 */
38953541Sshin    {
39053541Sshin	char *lladdr = NULL;
39153541Sshin	int lladdrlen = 0;
392120941Sume
39353541Sshin	if (ndopts.nd_opts_src_lladdr) {
39453541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
39553541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
39653541Sshin	}
39753541Sshin
39853541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
39978064Sume		nd6log((LOG_INFO,
40053541Sshin		    "nd6_ra_input: lladdrlen mismatch for %s "
401165118Sbz		    "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6),
402120941Sume		    ifp->if_addrlen, lladdrlen - 2));
40378064Sume		goto bad;
40453541Sshin	}
40553541Sshin
406120941Sume	nd6_cache_lladdr(ifp, &saddr6, lladdr,
407120941Sume	    lladdrlen, ND_ROUTER_ADVERT, 0);
40862587Sitojun
40962587Sitojun	/*
41062587Sitojun	 * Installing a link-layer address might change the state of the
41162587Sitojun	 * router's neighbor cache, which might also affect our on-link
41262587Sitojun	 * detection of adveritsed prefixes.
41362587Sitojun	 */
41462587Sitojun	pfxlist_onlink_check();
41553541Sshin    }
41662587Sitojun
41778064Sume freeit:
41862587Sitojun	m_freem(m);
41978064Sume	return;
42078064Sume
42178064Sume bad:
42278064Sume	icmp6stat.icp6s_badra++;
42378064Sume	m_freem(m);
42453541Sshin}
42553541Sshin
42653541Sshin/*
42753541Sshin * default router list proccessing sub routines
42853541Sshin */
42962587Sitojun
43062587Sitojun/* tell the change to user processes watching the routing socket. */
43162587Sitojunstatic void
432171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt)
43362587Sitojun{
43462587Sitojun	struct rt_addrinfo info;
43562587Sitojun
43662587Sitojun	bzero((caddr_t)&info, sizeof(info));
43762587Sitojun	info.rti_info[RTAX_DST] = rt_key(rt);
43862587Sitojun	info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
43962587Sitojun	info.rti_info[RTAX_NETMASK] = rt_mask(rt);
440151539Ssuz	if (rt->rt_ifp) {
441151539Ssuz		info.rti_info[RTAX_IFP] =
442151539Ssuz		    TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
443151539Ssuz		info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
444151539Ssuz	}
44562587Sitojun
44662587Sitojun	rt_missmsg(cmd, &info, rt->rt_flags, 0);
44762587Sitojun}
44862587Sitojun
44953541Sshinvoid
450171259Sdelphijdefrouter_addreq(struct nd_defrouter *new)
45153541Sshin{
45253541Sshin	struct sockaddr_in6 def, mask, gate;
45362587Sitojun	struct rtentry *newrt = NULL;
454151539Ssuz	int s;
455151539Ssuz	int error;
45653541Sshin
457128397Sluigi	bzero(&def, sizeof(def));
458128397Sluigi	bzero(&mask, sizeof(mask));
459128397Sluigi	bzero(&gate, sizeof(gate));
46053541Sshin
461120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
462120941Sume	    sizeof(struct sockaddr_in6);
463151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
46453541Sshin	gate.sin6_addr = new->rtaddr;
46553541Sshin
466151539Ssuz	s = splnet();
467151539Ssuz	error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
468120941Sume	    (struct sockaddr *)&gate, (struct sockaddr *)&mask,
469120941Sume	    RTF_GATEWAY, &newrt);
47062587Sitojun	if (newrt) {
471120727Ssam		RT_LOCK(newrt);
47278064Sume		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
473122334Ssam		RT_REMREF(newrt);
474120727Ssam		RT_UNLOCK(newrt);
47562587Sitojun	}
476151539Ssuz	if (error == 0)
477151539Ssuz		new->installed = 1;
478151539Ssuz	splx(s);
47953541Sshin	return;
48053541Sshin}
48153541Sshin
48253541Sshinstruct nd_defrouter *
483171259Sdelphijdefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp)
48453541Sshin{
48553541Sshin	struct nd_defrouter *dr;
48653541Sshin
48762587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
48862587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
48953541Sshin		if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
490120856Sume			return (dr);
49162587Sitojun	}
49253541Sshin
493120856Sume	return (NULL);		/* search failed */
49453541Sshin}
49553541Sshin
496151539Ssuz/*
497151539Ssuz * Remove the default route for a given router.
498151539Ssuz * This is just a subroutine function for defrouter_select(), and should
499151539Ssuz * not be called from anywhere else.
500151539Ssuz */
501151539Ssuzstatic void
502171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr)
50353541Sshin{
50453541Sshin	struct sockaddr_in6 def, mask, gate;
50562587Sitojun	struct rtentry *oldrt = NULL;
50653541Sshin
507128397Sluigi	bzero(&def, sizeof(def));
508128397Sluigi	bzero(&mask, sizeof(mask));
509128397Sluigi	bzero(&gate, sizeof(gate));
51053541Sshin
511120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
512120941Sume	    sizeof(struct sockaddr_in6);
513151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
51453541Sshin	gate.sin6_addr = dr->rtaddr;
51553541Sshin
51653541Sshin	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
517120941Sume	    (struct sockaddr *)&gate,
518120941Sume	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
51962587Sitojun	if (oldrt) {
52078064Sume		nd6_rtmsg(RTM_DELETE, oldrt);
521108269Sru		RTFREE(oldrt);
52262587Sitojun	}
52353541Sshin
524151539Ssuz	dr->installed = 0;
52553541Sshin}
52653541Sshin
527151539Ssuz/*
528151539Ssuz * remove all default routes from default router list
529151539Ssuz */
53053541Sshinvoid
531171259Sdelphijdefrouter_reset(void)
532151539Ssuz{
533151539Ssuz	struct nd_defrouter *dr;
534151539Ssuz
535151539Ssuz	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
536151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry))
537151539Ssuz		defrouter_delreq(dr);
538151539Ssuz
539151539Ssuz	/*
540151539Ssuz	 * XXX should we also nuke any default routers in the kernel, by
541151539Ssuz	 * going through them by rtalloc1()?
542151539Ssuz	 */
543151539Ssuz}
544151539Ssuz
545151539Ssuzvoid
546171259Sdelphijdefrtrlist_del(struct nd_defrouter *dr)
54753541Sshin{
54853541Sshin	struct nd_defrouter *deldr = NULL;
54953541Sshin	struct nd_prefix *pr;
55053541Sshin
55153541Sshin	/*
55253541Sshin	 * Flush all the routing table entries that use the router
55353541Sshin	 * as a next hop.
55453541Sshin	 */
555120941Sume	if (!ip6_forwarding && ip6_accept_rtadv) /* XXX: better condition? */
55653541Sshin		rt6_flush(&dr->rtaddr, dr->ifp);
55753541Sshin
558151539Ssuz	if (dr->installed) {
559151539Ssuz		deldr = dr;
560151539Ssuz		defrouter_delreq(dr);
561151539Ssuz	}
56262587Sitojun	TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
56353541Sshin
56453541Sshin	/*
56553541Sshin	 * Also delete all the pointers to the router in each prefix lists.
56653541Sshin	 */
56762587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
56853541Sshin		struct nd_pfxrouter *pfxrtr;
56953541Sshin		if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
57053541Sshin			pfxrtr_del(pfxrtr);
57153541Sshin	}
57253541Sshin	pfxlist_onlink_check();
57353541Sshin
57453541Sshin	/*
57562587Sitojun	 * If the router is the primary one, choose a new one.
57662587Sitojun	 * Note that defrouter_select() will remove the current gateway
57762587Sitojun	 * from the routing table.
57853541Sshin	 */
57953541Sshin	if (deldr)
58062587Sitojun		defrouter_select();
58162587Sitojun
58253541Sshin	free(dr, M_IP6NDP);
58353541Sshin}
58453541Sshin
58562587Sitojun/*
586151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and
587151539Ssuz * draft-ietf-ipngwg-router-selection:
588151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred.
589151539Ssuz *    If we have more than one (probably) reachable router, prefer ones
590151539Ssuz *    with the highest router preference.
59162587Sitojun * 2) When no routers on the list are known to be reachable or
59262587Sitojun *    probably reachable, routers SHOULD be selected in a round-robin
593151539Ssuz *    fashion, regardless of router preference values.
59462587Sitojun * 3) If the Default Router List is empty, assume that all
59562587Sitojun *    destinations are on-link.
596151539Ssuz *
597151539Ssuz * We assume nd_defrouter is sorted by router preference value.
598151539Ssuz * Since the code below covers both with and without router preference cases,
599151539Ssuz * we do not need to classify the cases by ifdef.
600151539Ssuz *
601151539Ssuz * At this moment, we do not try to install more than one default router,
602151539Ssuz * even when the multipath routing is available, because we're not sure about
603151539Ssuz * the benefits for stub hosts comparing to the risk of making the code
604151539Ssuz * complicated and the possibility of introducing bugs.
60562587Sitojun */
60662587Sitojunvoid
607171259Sdelphijdefrouter_select(void)
60862587Sitojun{
60962587Sitojun	int s = splnet();
610151539Ssuz	struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
61162587Sitojun	struct rtentry *rt = NULL;
61262587Sitojun	struct llinfo_nd6 *ln = NULL;
61362587Sitojun
61462587Sitojun	/*
615151539Ssuz	 * This function should be called only when acting as an autoconfigured
616151539Ssuz	 * host.  Although the remaining part of this function is not effective
617151539Ssuz	 * if the node is not an autoconfigured host, we explicitly exclude
618151539Ssuz	 * such cases here for safety.
619151539Ssuz	 */
620151539Ssuz	if (ip6_forwarding || !ip6_accept_rtadv) {
621151539Ssuz		nd6log((LOG_WARNING,
622151539Ssuz		    "defrouter_select: called unexpectedly (forwarding=%d, "
623151539Ssuz		    "accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv));
624151539Ssuz		splx(s);
625151539Ssuz		return;
626151539Ssuz	}
627151539Ssuz
628151539Ssuz	/*
629151539Ssuz	 * Let's handle easy case (3) first:
630151539Ssuz	 * If default router list is empty, there's nothing to be done.
631151539Ssuz	 */
632151539Ssuz	if (!TAILQ_FIRST(&nd_defrouter)) {
633151539Ssuz		splx(s);
634151539Ssuz		return;
635151539Ssuz	}
636151539Ssuz
637151539Ssuz	/*
63862587Sitojun	 * Search for a (probably) reachable router from the list.
639151539Ssuz	 * We just pick up the first reachable one (if any), assuming that
640151539Ssuz	 * the ordering rule of the list described in defrtrlist_update().
64162587Sitojun	 */
64262587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
64362587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
644151539Ssuz		if (selected_dr == NULL &&
645151539Ssuz		    (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
64662587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
64762587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln)) {
648151539Ssuz			selected_dr = dr;
64962587Sitojun		}
65062587Sitojun
651151539Ssuz		if (dr->installed && installed_dr == NULL)
652151539Ssuz			installed_dr = dr;
653151539Ssuz		else if (dr->installed && installed_dr) {
654151539Ssuz			/* this should not happen.  warn for diagnosis. */
655151539Ssuz			log(LOG_ERR, "defrouter_select: more than one router"
656151539Ssuz			    " is installed\n");
65762587Sitojun		}
65862587Sitojun	}
659151539Ssuz	/*
660151539Ssuz	 * If none of the default routers was found to be reachable,
661151539Ssuz	 * round-robin the list regardless of preference.
662151539Ssuz	 * Otherwise, if we have an installed router, check if the selected
663151539Ssuz	 * (reachable) router should really be preferred to the installed one.
664151539Ssuz	 * We only prefer the new router when the old one is not reachable
665151539Ssuz	 * or when the new one has a really higher preference value.
666151539Ssuz	 */
667151539Ssuz	if (selected_dr == NULL) {
668151539Ssuz		if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry))
669151539Ssuz			selected_dr = TAILQ_FIRST(&nd_defrouter);
670151539Ssuz		else
671151539Ssuz			selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
672151539Ssuz	} else if (installed_dr &&
673151539Ssuz	    (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) &&
674151539Ssuz	    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
675151539Ssuz	    ND6_IS_LLINFO_PROBREACH(ln) &&
676151539Ssuz	    rtpref(selected_dr) <= rtpref(installed_dr)) {
677151539Ssuz		selected_dr = installed_dr;
678151539Ssuz	}
67962587Sitojun
680151539Ssuz	/*
681151539Ssuz	 * If the selected router is different than the installed one,
682151539Ssuz	 * remove the installed router and install the selected one.
683151539Ssuz	 * Note that the selected router is never NULL here.
684151539Ssuz	 */
685151539Ssuz	if (installed_dr != selected_dr) {
686151539Ssuz		if (installed_dr)
687151539Ssuz			defrouter_delreq(installed_dr);
688151539Ssuz		defrouter_addreq(selected_dr);
689151539Ssuz	}
690151539Ssuz
69162587Sitojun	splx(s);
69262587Sitojun	return;
69362587Sitojun}
69462587Sitojun
695151539Ssuz/*
696151539Ssuz * for default router selection
697151539Ssuz * regards router-preference field as a 2-bit signed integer
698151539Ssuz */
699151539Ssuzstatic int
700151539Ssuzrtpref(struct nd_defrouter *dr)
701151539Ssuz{
702151539Ssuz	switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) {
703151539Ssuz	case ND_RA_FLAG_RTPREF_HIGH:
704151539Ssuz		return (RTPREF_HIGH);
705151539Ssuz	case ND_RA_FLAG_RTPREF_MEDIUM:
706156871Ssuz	case ND_RA_FLAG_RTPREF_RSV:
707151539Ssuz		return (RTPREF_MEDIUM);
708151539Ssuz	case ND_RA_FLAG_RTPREF_LOW:
709151539Ssuz		return (RTPREF_LOW);
710151539Ssuz	default:
711151539Ssuz		/*
712151539Ssuz		 * This case should never happen.  If it did, it would mean a
713151539Ssuz		 * serious bug of kernel internal.  We thus always bark here.
714151539Ssuz		 * Or, can we even panic?
715151539Ssuz		 */
716151539Ssuz		log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags);
717151539Ssuz		return (RTPREF_INVALID);
718151539Ssuz	}
719151539Ssuz	/* NOTREACHED */
720151539Ssuz}
721151539Ssuz
72253541Sshinstatic struct nd_defrouter *
723171259Sdelphijdefrtrlist_update(struct nd_defrouter *new)
72453541Sshin{
72553541Sshin	struct nd_defrouter *dr, *n;
72653541Sshin	int s = splnet();
72753541Sshin
72853541Sshin	if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
72953541Sshin		/* entry exists */
73053541Sshin		if (new->rtlifetime == 0) {
73153541Sshin			defrtrlist_del(dr);
73253541Sshin			dr = NULL;
73353541Sshin		} else {
734151539Ssuz			int oldpref = rtpref(dr);
735151539Ssuz
73653541Sshin			/* override */
73753541Sshin			dr->flags = new->flags; /* xxx flag check */
73853541Sshin			dr->rtlifetime = new->rtlifetime;
73953541Sshin			dr->expire = new->expire;
740151539Ssuz
741151539Ssuz			/*
742151539Ssuz			 * If the preference does not change, there's no need
743151539Ssuz			 * to sort the entries.
744151539Ssuz			 */
745151539Ssuz			if (rtpref(new) == oldpref) {
746151539Ssuz				splx(s);
747151539Ssuz				return (dr);
748151539Ssuz			}
749151539Ssuz
750151539Ssuz			/*
751151539Ssuz			 * preferred router may be changed, so relocate
752151539Ssuz			 * this router.
753151539Ssuz			 * XXX: calling TAILQ_REMOVE directly is a bad manner.
754151539Ssuz			 * However, since defrtrlist_del() has many side
755151539Ssuz			 * effects, we intentionally do so here.
756151539Ssuz			 * defrouter_select() below will handle routing
757151539Ssuz			 * changes later.
758151539Ssuz			 */
759151539Ssuz			TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
760151539Ssuz			n = dr;
761151539Ssuz			goto insert;
76253541Sshin		}
76353541Sshin		splx(s);
764120856Sume		return (dr);
76553541Sshin	}
76653541Sshin
76753541Sshin	/* entry does not exist */
76853541Sshin	if (new->rtlifetime == 0) {
76953541Sshin		splx(s);
770120856Sume		return (NULL);
77153541Sshin	}
77253541Sshin
77353541Sshin	n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
77453541Sshin	if (n == NULL) {
77553541Sshin		splx(s);
776120856Sume		return (NULL);
77753541Sshin	}
77853541Sshin	bzero(n, sizeof(*n));
77953541Sshin	*n = *new;
78062587Sitojun
781151539Ssuzinsert:
78262587Sitojun	/*
783151539Ssuz	 * Insert the new router in the Default Router List;
784151539Ssuz	 * The Default Router List should be in the descending order
785151539Ssuz	 * of router-preferece.  Routers with the same preference are
786151539Ssuz	 * sorted in the arriving time order.
78762587Sitojun	 */
788151539Ssuz
789151539Ssuz	/* insert at the end of the group */
790151539Ssuz	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
791151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry)) {
792151539Ssuz		if (rtpref(n) > rtpref(dr))
793151539Ssuz			break;
794151539Ssuz	}
795151539Ssuz	if (dr)
796151539Ssuz		TAILQ_INSERT_BEFORE(dr, n, dr_entry);
797151539Ssuz	else
798151539Ssuz		TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
799151539Ssuz
800151539Ssuz	defrouter_select();
801151539Ssuz
80253541Sshin	splx(s);
803120941Sume
804120856Sume	return (n);
80553541Sshin}
80653541Sshin
80753541Sshinstatic struct nd_pfxrouter *
808171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr)
80953541Sshin{
81053541Sshin	struct nd_pfxrouter *search;
811120941Sume
81262587Sitojun	for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
81353541Sshin		if (search->router == dr)
81453541Sshin			break;
81553541Sshin	}
81653541Sshin
817120856Sume	return (search);
81853541Sshin}
81953541Sshin
82053541Sshinstatic void
821171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr)
82253541Sshin{
82353541Sshin	struct nd_pfxrouter *new;
82453541Sshin
82553541Sshin	new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
82653541Sshin	if (new == NULL)
82753541Sshin		return;
82853541Sshin	bzero(new, sizeof(*new));
82953541Sshin	new->router = dr;
83053541Sshin
83153541Sshin	LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
83253541Sshin
83353541Sshin	pfxlist_onlink_check();
83453541Sshin}
83553541Sshin
83653541Sshinstatic void
837171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr)
83853541Sshin{
83953541Sshin	LIST_REMOVE(pfr, pfr_entry);
84053541Sshin	free(pfr, M_IP6NDP);
84153541Sshin}
84253541Sshin
84378064Sumestruct nd_prefix *
844171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key)
84553541Sshin{
84653541Sshin	struct nd_prefix *search;
84753541Sshin
84862587Sitojun	for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
849151539Ssuz		if (key->ndpr_ifp == search->ndpr_ifp &&
850151539Ssuz		    key->ndpr_plen == search->ndpr_plen &&
851151539Ssuz		    in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr,
852151539Ssuz		    &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) {
85353541Sshin			break;
85453541Sshin		}
85553541Sshin	}
85653541Sshin
857120856Sume	return (search);
85853541Sshin}
85953541Sshin
86078064Sumeint
861171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
862171259Sdelphij    struct nd_prefix **newp)
86353541Sshin{
86478064Sume	struct nd_prefix *new = NULL;
865151539Ssuz	int error = 0;
86653541Sshin	int i, s;
867165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
86853541Sshin
86953541Sshin	new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
87053541Sshin	if (new == NULL)
871120941Sume		return(ENOMEM);
87253541Sshin	bzero(new, sizeof(*new));
873151539Ssuz	new->ndpr_ifp = pr->ndpr_ifp;
874151539Ssuz	new->ndpr_prefix = pr->ndpr_prefix;
875151539Ssuz	new->ndpr_plen = pr->ndpr_plen;
876151539Ssuz	new->ndpr_vltime = pr->ndpr_vltime;
877151539Ssuz	new->ndpr_pltime = pr->ndpr_pltime;
878151539Ssuz	new->ndpr_flags = pr->ndpr_flags;
879151539Ssuz	if ((error = in6_init_prefix_ltimes(new)) != 0) {
880151539Ssuz		free(new, M_IP6NDP);
881151539Ssuz		return(error);
882151539Ssuz	}
883151539Ssuz	new->ndpr_lastupdate = time_second;
88478064Sume	if (newp != NULL)
88578064Sume		*newp = new;
88653541Sshin
887120941Sume	/* initialization */
88853541Sshin	LIST_INIT(&new->ndpr_advrtrs);
88953541Sshin	in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
89053541Sshin	/* make prefix in the canonical form */
89153541Sshin	for (i = 0; i < 4; i++)
89253541Sshin		new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
893120941Sume		    new->ndpr_mask.s6_addr32[i];
89453541Sshin
89553541Sshin	s = splnet();
89653541Sshin	/* link ndpr_entry to nd_prefix list */
89753541Sshin	LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
89853541Sshin	splx(s);
89953541Sshin
90078064Sume	/* ND_OPT_PI_FLAG_ONLINK processing */
90178064Sume	if (new->ndpr_raf_onlink) {
90278064Sume		int e;
90378064Sume
90478064Sume		if ((e = nd6_prefix_onlink(new)) != 0) {
90578064Sume			nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
90678064Sume			    "the prefix %s/%d on-link on %s (errno=%d)\n",
907165118Sbz			    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
90878064Sume			    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
90978064Sume			/* proceed anyway. XXX: is it correct? */
91078064Sume		}
91178064Sume	}
91278064Sume
913120941Sume	if (dr)
91453541Sshin		pfxrtr_add(new, dr);
91553541Sshin
91653541Sshin	return 0;
91753541Sshin}
91853541Sshin
91953541Sshinvoid
920171259Sdelphijprelist_remove(struct nd_prefix *pr)
92153541Sshin{
92253541Sshin	struct nd_pfxrouter *pfr, *next;
92378064Sume	int e, s;
924165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
92553541Sshin
92678064Sume	/* make sure to invalidate the prefix until it is really freed. */
92778064Sume	pr->ndpr_vltime = 0;
92878064Sume	pr->ndpr_pltime = 0;
929151539Ssuz
93078064Sume	/*
93178064Sume	 * Though these flags are now meaningless, we'd rather keep the value
932151479Ssuz	 * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users
933151479Ssuz	 * when executing "ndp -p".
93478064Sume	 */
935151479Ssuz
93678064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
93778064Sume	    (e = nd6_prefix_offlink(pr)) != 0) {
93878064Sume		nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
93978064Sume		    "on %s, errno=%d\n",
940165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
94178064Sume		    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
94278064Sume		/* what should we do? */
94378064Sume	}
94478064Sume
94578064Sume	if (pr->ndpr_refcnt > 0)
94678064Sume		return;		/* notice here? */
94778064Sume
94853541Sshin	s = splnet();
94978064Sume
95053541Sshin	/* unlink ndpr_entry from nd_prefix list */
95153541Sshin	LIST_REMOVE(pr, ndpr_entry);
95253541Sshin
95353541Sshin	/* free list of routers that adversed the prefix */
95462587Sitojun	for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
95562587Sitojun		next = pfr->pfr_next;
95653541Sshin
95753541Sshin		free(pfr, M_IP6NDP);
95853541Sshin	}
95978064Sume	splx(s);
96078064Sume
96153541Sshin	free(pr, M_IP6NDP);
96253541Sshin
96353541Sshin	pfxlist_onlink_check();
96453541Sshin}
96553541Sshin
966171259Sdelphij/*
967171259Sdelphij * dr - may be NULL
968171259Sdelphij */
969171259Sdelphij
970151539Ssuzstatic int
971171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
972171259Sdelphij    struct mbuf *m, int mcast)
97353541Sshin{
97478064Sume	struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
97578064Sume	struct ifaddr *ifa;
97678064Sume	struct ifnet *ifp = new->ndpr_ifp;
97753541Sshin	struct nd_prefix *pr;
97853541Sshin	int s = splnet();
97953541Sshin	int error = 0;
98078064Sume	int newprefix = 0;
98153541Sshin	int auth;
98278064Sume	struct in6_addrlifetime lt6_tmp;
983165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
98453541Sshin
98553541Sshin	auth = 0;
98653541Sshin	if (m) {
98753541Sshin		/*
98853541Sshin		 * Authenticity for NA consists authentication for
98953541Sshin		 * both IP header and IP datagrams, doesn't it ?
99053541Sshin		 */
99153541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
992120941Sume		auth = ((m->m_flags & M_AUTHIPHDR) &&
993120941Sume		    (m->m_flags & M_AUTHIPDGM));
99453541Sshin#endif
99553541Sshin	}
99653541Sshin
99778064Sume	if ((pr = nd6_prefix_lookup(new)) != NULL) {
99878064Sume		/*
99978064Sume		 * nd6_prefix_lookup() ensures that pr and new have the same
100078064Sume		 * prefix on a same interface.
100178064Sume		 */
100253541Sshin
100353541Sshin		/*
100478064Sume		 * Update prefix information.  Note that the on-link (L) bit
100578064Sume		 * and the autonomous (A) bit should NOT be changed from 1
100678064Sume		 * to 0.
100753541Sshin		 */
100878064Sume		if (new->ndpr_raf_onlink == 1)
100978064Sume			pr->ndpr_raf_onlink = 1;
101078064Sume		if (new->ndpr_raf_auto == 1)
101178064Sume			pr->ndpr_raf_auto = 1;
101278064Sume		if (new->ndpr_raf_onlink) {
101378064Sume			pr->ndpr_vltime = new->ndpr_vltime;
101478064Sume			pr->ndpr_pltime = new->ndpr_pltime;
1015151539Ssuz			(void)in6_init_prefix_ltimes(pr); /* XXX error case? */
1016151539Ssuz			pr->ndpr_lastupdate = time_second;
101778064Sume		}
101853541Sshin
101978064Sume		if (new->ndpr_raf_onlink &&
102078064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
102178064Sume			int e;
102253541Sshin
102378064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
102478064Sume				nd6log((LOG_ERR,
102578064Sume				    "prelist_update: failed to make "
102678064Sume				    "the prefix %s/%d on-link on %s "
102778064Sume				    "(errno=%d)\n",
1028165118Sbz				    ip6_sprintf(ip6buf,
1029165118Sbz					    &pr->ndpr_prefix.sin6_addr),
103078064Sume				    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
103178064Sume				/* proceed anyway. XXX: is it correct? */
103253541Sshin			}
103378064Sume		}
103453541Sshin
103578064Sume		if (dr && pfxrtr_lookup(pr, dr) == NULL)
103678064Sume			pfxrtr_add(pr, dr);
103778064Sume	} else {
103878064Sume		struct nd_prefix *newpr = NULL;
103953541Sshin
104078064Sume		newprefix = 1;
104153541Sshin
104278064Sume		if (new->ndpr_vltime == 0)
104378064Sume			goto end;
104478064Sume		if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
104578064Sume			goto end;
104653541Sshin
104778064Sume		error = nd6_prelist_add(new, dr, &newpr);
104878064Sume		if (error != 0 || newpr == NULL) {
104978064Sume			nd6log((LOG_NOTICE, "prelist_update: "
105078064Sume			    "nd6_prelist_add failed for %s/%d on %s "
105178064Sume			    "errno=%d, returnpr=%p\n",
1052165118Sbz			    ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr),
1053120941Sume			    new->ndpr_plen, if_name(new->ndpr_ifp),
1054120941Sume			    error, newpr));
105578064Sume			goto end; /* we should just give up in this case. */
105678064Sume		}
105753541Sshin
105878064Sume		/*
105978064Sume		 * XXX: from the ND point of view, we can ignore a prefix
106078064Sume		 * with the on-link bit being zero.  However, we need a
106178064Sume		 * prefix structure for references from autoconfigured
1062120941Sume		 * addresses.  Thus, we explicitly make sure that the prefix
106378064Sume		 * itself expires now.
106478064Sume		 */
106578064Sume		if (newpr->ndpr_raf_onlink == 0) {
106678064Sume			newpr->ndpr_vltime = 0;
106778064Sume			newpr->ndpr_pltime = 0;
106878064Sume			in6_init_prefix_ltimes(newpr);
106953541Sshin		}
107053541Sshin
107178064Sume		pr = newpr;
107278064Sume	}
107353541Sshin
107478064Sume	/*
107578064Sume	 * Address autoconfiguration based on Section 5.5.3 of RFC 2462.
107678064Sume	 * Note that pr must be non NULL at this point.
107778064Sume	 */
107862587Sitojun
107978064Sume	/* 5.5.3 (a). Ignore the prefix without the A bit set. */
108078064Sume	if (!new->ndpr_raf_auto)
1081151539Ssuz		goto end;
108262587Sitojun
108378064Sume	/*
108478064Sume	 * 5.5.3 (b). the link-local prefix should have been ignored in
108578064Sume	 * nd6_ra_input.
108678064Sume	 */
108762587Sitojun
1088151539Ssuz	/* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */
1089151539Ssuz	if (new->ndpr_pltime > new->ndpr_vltime) {
1090151539Ssuz		error = EINVAL;	/* XXX: won't be used */
1091151539Ssuz		goto end;
1092151539Ssuz	}
109362587Sitojun
1094171260Sdelphij	/*
1095151539Ssuz	 * 5.5.3 (d).  If the prefix advertised is not equal to the prefix of
1096151539Ssuz	 * an address configured by stateless autoconfiguration already in the
1097151539Ssuz	 * list of addresses associated with the interface, and the Valid
1098151539Ssuz	 * Lifetime is not 0, form an address.  We first check if we have
1099151539Ssuz	 * a matching prefix.
1100151539Ssuz	 * Note: we apply a clarification in rfc2462bis-02 here.  We only
1101151539Ssuz	 * consider autoconfigured addresses while RFC2462 simply said
1102151539Ssuz	 * "address".
110378064Sume	 */
1104120941Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
110578064Sume		struct in6_ifaddr *ifa6;
1106151539Ssuz		u_int32_t remaininglifetime;
110753541Sshin
110878064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
110978064Sume			continue;
111053541Sshin
111178064Sume		ifa6 = (struct in6_ifaddr *)ifa;
111253541Sshin
111353541Sshin		/*
1114151539Ssuz		 * We only consider autoconfigured addresses as per rfc2462bis.
1115151539Ssuz		 */
1116151539Ssuz		if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF))
1117151539Ssuz			continue;
1118151539Ssuz
1119151539Ssuz		/*
112078064Sume		 * Spec is not clear here, but I believe we should concentrate
112178064Sume		 * on unicast (i.e. not anycast) addresses.
112278064Sume		 * XXX: other ia6_flags? detached or duplicated?
112353541Sshin		 */
112478064Sume		if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
112578064Sume			continue;
1126120941Sume
1127151539Ssuz		/*
1128151539Ssuz		 * Ignore the address if it is not associated with a prefix
1129151539Ssuz		 * or is associated with a prefix that is different from this
1130151539Ssuz		 * one.  (pr is never NULL here)
1131151539Ssuz		 */
1132151539Ssuz		if (ifa6->ia6_ndpr != pr)
113378064Sume			continue;
113453541Sshin
113578064Sume		if (ia6_match == NULL) /* remember the first one */
113678064Sume			ia6_match = ifa6;
113778064Sume
113878064Sume		/*
113978064Sume		 * An already autoconfigured address matched.  Now that we
114078064Sume		 * are sure there is at least one matched address, we can
114178064Sume		 * proceed to 5.5.3. (e): update the lifetimes according to the
114278064Sume		 * "two hours" rule and the privacy extension.
1143151539Ssuz		 * We apply some clarifications in rfc2462bis:
1144151539Ssuz		 * - use remaininglifetime instead of storedlifetime as a
1145151539Ssuz		 *   variable name
1146151539Ssuz		 * - remove the dead code in the "two-hour" rule
114778064Sume		 */
114878064Sume#define TWOHOUR		(120*60)
114978064Sume		lt6_tmp = ifa6->ia6_lifetime;
115078064Sume
1151112678Sume		if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME)
1152151539Ssuz			remaininglifetime = ND6_INFINITE_LIFETIME;
1153151539Ssuz		else if (time_second - ifa6->ia6_updatetime >
1154151539Ssuz			 lt6_tmp.ia6t_vltime) {
1155151539Ssuz			/*
1156151539Ssuz			 * The case of "invalid" address.  We should usually
1157151539Ssuz			 * not see this case.
1158151539Ssuz			 */
1159151539Ssuz			remaininglifetime = 0;
1160151539Ssuz		} else
1161151539Ssuz			remaininglifetime = lt6_tmp.ia6t_vltime -
1162151539Ssuz			    (time_second - ifa6->ia6_updatetime);
116378064Sume
1164112678Sume		/* when not updating, keep the current stored lifetime. */
1165151539Ssuz		lt6_tmp.ia6t_vltime = remaininglifetime;
1166112678Sume
116778064Sume		if (TWOHOUR < new->ndpr_vltime ||
1168151539Ssuz		    remaininglifetime < new->ndpr_vltime) {
116978064Sume			lt6_tmp.ia6t_vltime = new->ndpr_vltime;
1170151539Ssuz		} else if (remaininglifetime <= TWOHOUR) {
117178064Sume			if (auth) {
117278064Sume				lt6_tmp.ia6t_vltime = new->ndpr_vltime;
117378064Sume			}
117478064Sume		} else {
117578064Sume			/*
117678064Sume			 * new->ndpr_vltime <= TWOHOUR &&
1177151539Ssuz			 * TWOHOUR < remaininglifetime
117878064Sume			 */
117978064Sume			lt6_tmp.ia6t_vltime = TWOHOUR;
118053541Sshin		}
118153541Sshin
118278064Sume		/* The 2 hour rule is not imposed for preferred lifetime. */
118378064Sume		lt6_tmp.ia6t_pltime = new->ndpr_pltime;
118453541Sshin
118578064Sume		in6_init_address_ltimes(pr, &lt6_tmp);
118653541Sshin
1187171260Sdelphij		/*
1188151539Ssuz		 * We need to treat lifetimes for temporary addresses
1189151539Ssuz		 * differently, according to
1190151539Ssuz		 * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1);
1191151539Ssuz		 * we only update the lifetimes when they are in the maximum
1192151539Ssuz		 * intervals.
1193171260Sdelphij		 */
1194171260Sdelphij		if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
1195151539Ssuz			u_int32_t maxvltime, maxpltime;
1196151539Ssuz
1197151539Ssuz			if (ip6_temp_valid_lifetime >
1198151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1199151539Ssuz			    ip6_desync_factor)) {
1200151539Ssuz				maxvltime = ip6_temp_valid_lifetime -
1201151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1202151539Ssuz				    ip6_desync_factor;
1203151539Ssuz			} else
1204151539Ssuz				maxvltime = 0;
1205151539Ssuz			if (ip6_temp_preferred_lifetime >
1206151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1207151539Ssuz			    ip6_desync_factor)) {
1208151539Ssuz				maxpltime = ip6_temp_preferred_lifetime -
1209151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1210151539Ssuz				    ip6_desync_factor;
1211151539Ssuz			} else
1212151539Ssuz				maxpltime = 0;
1213151539Ssuz
1214151539Ssuz			if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME ||
1215151539Ssuz			    lt6_tmp.ia6t_vltime > maxvltime) {
1216151539Ssuz				lt6_tmp.ia6t_vltime = maxvltime;
121778064Sume			}
1218151539Ssuz			if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME ||
1219151539Ssuz			    lt6_tmp.ia6t_pltime > maxpltime) {
1220151539Ssuz				lt6_tmp.ia6t_pltime = maxpltime;
122178064Sume			}
122278064Sume		}
122378064Sume		ifa6->ia6_lifetime = lt6_tmp;
1224151539Ssuz		ifa6->ia6_updatetime = time_second;
122553541Sshin	}
122678064Sume	if (ia6_match == NULL && new->ndpr_vltime) {
1227151539Ssuz		int ifidlen;
1228151539Ssuz
122978064Sume		/*
1230151539Ssuz		 * 5.5.3 (d) (continued)
123178064Sume		 * No address matched and the valid lifetime is non-zero.
123278064Sume		 * Create a new address.
123378064Sume		 */
1234151539Ssuz
1235151539Ssuz		/*
1236151539Ssuz		 * Prefix Length check:
1237151539Ssuz		 * If the sum of the prefix length and interface identifier
1238151539Ssuz		 * length does not equal 128 bits, the Prefix Information
1239151539Ssuz		 * option MUST be ignored.  The length of the interface
1240151539Ssuz		 * identifier is defined in a separate link-type specific
1241151539Ssuz		 * document.
1242151539Ssuz		 */
1243151539Ssuz		ifidlen = in6_if2idlen(ifp);
1244151539Ssuz		if (ifidlen < 0) {
1245151539Ssuz			/* this should not happen, so we always log it. */
1246151539Ssuz			log(LOG_ERR, "prelist_update: IFID undefined (%s)\n",
1247151539Ssuz			    if_name(ifp));
1248151539Ssuz			goto end;
1249151539Ssuz		}
1250151539Ssuz		if (ifidlen + pr->ndpr_plen != 128) {
1251151539Ssuz			nd6log((LOG_INFO,
1252151539Ssuz			    "prelist_update: invalid prefixlen "
1253151539Ssuz			    "%d for %s, ignored\n",
1254151539Ssuz			    pr->ndpr_plen, if_name(ifp)));
1255151539Ssuz			goto end;
1256151539Ssuz		}
1257151539Ssuz
1258151539Ssuz		if ((ia6 = in6_ifadd(new, mcast)) != NULL) {
125978064Sume			/*
126078064Sume			 * note that we should use pr (not new) for reference.
126178064Sume			 */
126278064Sume			pr->ndpr_refcnt++;
126378064Sume			ia6->ia6_ndpr = pr;
126453541Sshin
126578064Sume			/*
126678064Sume			 * RFC 3041 3.3 (2).
126778064Sume			 * When a new public address is created as described
126878064Sume			 * in RFC2462, also create a new temporary address.
126978064Sume			 *
127078064Sume			 * RFC 3041 3.5.
127178064Sume			 * When an interface connects to a new link, a new
127278064Sume			 * randomized interface identifier should be generated
127378064Sume			 * immediately together with a new set of temporary
127478064Sume			 * addresses.  Thus, we specifiy 1 as the 2nd arg of
127578064Sume			 * in6_tmpifadd().
127678064Sume			 */
127778064Sume			if (ip6_use_tempaddr) {
127878064Sume				int e;
1279151539Ssuz				if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) {
128078064Sume					nd6log((LOG_NOTICE, "prelist_update: "
128178064Sume					    "failed to create a temporary "
128278064Sume					    "address, errno=%d\n",
128378064Sume					    e));
128478064Sume				}
128578064Sume			}
128678064Sume
128778064Sume			/*
128878064Sume			 * A newly added address might affect the status
128978064Sume			 * of other addresses, so we check and update it.
129078064Sume			 * XXX: what if address duplication happens?
129178064Sume			 */
129278064Sume			pfxlist_onlink_check();
129378064Sume		} else {
129478064Sume			/* just set an error. do not bark here. */
129578064Sume			error = EADDRNOTAVAIL; /* XXX: might be unused. */
129678064Sume		}
129778064Sume	}
129878064Sume
129953541Sshin end:
130053541Sshin	splx(s);
130153541Sshin	return error;
130253541Sshin}
130353541Sshin
130453541Sshin/*
130562587Sitojun * A supplement function used in the on-link detection below;
130662587Sitojun * detect if a given prefix has a (probably) reachable advertising router.
130762587Sitojun * XXX: lengthy function name...
130862587Sitojun */
130978064Sumestatic struct nd_pfxrouter *
1310171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr)
131162587Sitojun{
131262587Sitojun	struct nd_pfxrouter *pfxrtr;
131362587Sitojun	struct rtentry *rt;
131462587Sitojun	struct llinfo_nd6 *ln;
131562587Sitojun
131662587Sitojun	for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
131762587Sitojun	     pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
131862587Sitojun		if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
1319120941Sume		    pfxrtr->router->ifp)) &&
132062587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
132162587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln))
132262587Sitojun			break;	/* found */
132362587Sitojun	}
132462587Sitojun
1325120856Sume	return (pfxrtr);
132662587Sitojun}
132762587Sitojun
132862587Sitojun/*
132953541Sshin * Check if each prefix in the prefix list has at least one available router
133078064Sume * that advertised the prefix (a router is "available" if its neighbor cache
133178064Sume * entry is reachable or probably reachable).
133262587Sitojun * If the check fails, the prefix may be off-link, because, for example,
133353541Sshin * we have moved from the network but the lifetime of the prefix has not
133478064Sume * expired yet.  So we should not use the prefix if there is another prefix
133578064Sume * that has an available router.
133678064Sume * But, if there is no prefix that has an available router, we still regards
133778064Sume * all the prefixes as on-link.  This is because we can't tell if all the
133853541Sshin * routers are simply dead or if we really moved from the network and there
133953541Sshin * is no router around us.
134053541Sshin */
134162587Sitojunvoid
134253541Sshinpfxlist_onlink_check()
134353541Sshin{
134453541Sshin	struct nd_prefix *pr;
134578064Sume	struct in6_ifaddr *ifa;
1346151539Ssuz	struct nd_defrouter *dr;
1347151539Ssuz	struct nd_pfxrouter *pfxrtr = NULL;
134853541Sshin
134962587Sitojun	/*
135062587Sitojun	 * Check if there is a prefix that has a reachable advertising
135162587Sitojun	 * router.
135262587Sitojun	 */
135362587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
135478064Sume		if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
135553541Sshin			break;
135662587Sitojun	}
135753541Sshin
1358151539Ssuz	/*
1359151539Ssuz	 * If we have no such prefix, check whether we still have a router
1360151539Ssuz	 * that does not advertise any prefixes.
1361151539Ssuz	 */
1362151465Ssuz	if (pr == NULL) {
1363151539Ssuz		for (dr = TAILQ_FIRST(&nd_defrouter); dr;
1364151539Ssuz		    dr = TAILQ_NEXT(dr, dr_entry)) {
1365151539Ssuz			struct nd_prefix *pr0;
1366151539Ssuz
1367151539Ssuz			for (pr0 = nd_prefix.lh_first; pr0;
1368151539Ssuz			    pr0 = pr0->ndpr_next) {
1369151539Ssuz				if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL)
1370151539Ssuz					break;
1371151539Ssuz			}
1372151539Ssuz			if (pfxrtr != NULL)
1373151539Ssuz				break;
1374151539Ssuz		}
1375151539Ssuz	}
1376151539Ssuz	if (pr != NULL || (TAILQ_FIRST(&nd_defrouter) && pfxrtr == NULL)) {
1377171260Sdelphij		/*
1378151539Ssuz		 * There is at least one prefix that has a reachable router,
1379151539Ssuz		 * or at least a router which probably does not advertise
1380151539Ssuz		 * any prefixes.  The latter would be the case when we move
1381151539Ssuz		 * to a new link where we have a router that does not provide
1382151539Ssuz		 * prefixes and we configure an address by hand.
1383171260Sdelphij		 * Detach prefixes which have no reachable advertising
1384171260Sdelphij		 * router, and attach other prefixes.
1385171260Sdelphij		 */
138662587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
138778064Sume			/* XXX: a link-local prefix should never be detached */
138878064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
138978064Sume				continue;
139078064Sume
139178064Sume			/*
139278064Sume			 * we aren't interested in prefixes without the L bit
139378064Sume			 * set.
139478064Sume			 */
139578064Sume			if (pr->ndpr_raf_onlink == 0)
139678064Sume				continue;
139778064Sume
139878064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
139978064Sume			    find_pfxlist_reachable_router(pr) == NULL)
140078064Sume				pr->ndpr_stateflags |= NDPRF_DETACHED;
140178064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
140278064Sume			    find_pfxlist_reachable_router(pr) != 0)
140378064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
140453541Sshin		}
140578064Sume	} else {
140678064Sume		/* there is no prefix that has a reachable router */
140762587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
140878064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
140978064Sume				continue;
141078064Sume
141178064Sume			if (pr->ndpr_raf_onlink == 0)
141278064Sume				continue;
141378064Sume
141478064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
141578064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
141653541Sshin		}
141762587Sitojun	}
141878064Sume
141978064Sume	/*
142078064Sume	 * Remove each interface route associated with a (just) detached
142178064Sume	 * prefix, and reinstall the interface route for a (just) attached
142278064Sume	 * prefix.  Note that all attempt of reinstallation does not
142378064Sume	 * necessarily success, when a same prefix is shared among multiple
142478064Sume	 * interfaces.  Such cases will be handled in nd6_prefix_onlink,
142578064Sume	 * so we don't have to care about them.
142678064Sume	 */
142778064Sume	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
142878064Sume		int e;
1429165118Sbz		char ip6buf[INET6_ADDRSTRLEN];
143078064Sume
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_ONLINK) != 0) {
143978064Sume			if ((e = nd6_prefix_offlink(pr)) != 0) {
144078064Sume				nd6log((LOG_ERR,
144178064Sume				    "pfxlist_onlink_check: failed to "
1442151479Ssuz				    "make %s/%d offlink, errno=%d\n",
1443165118Sbz				    ip6_sprintf(ip6buf,
1444165118Sbz					    &pr->ndpr_prefix.sin6_addr),
1445165118Sbz					    pr->ndpr_plen, e));
144678064Sume			}
144778064Sume		}
144878064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
144978064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
145078064Sume		    pr->ndpr_raf_onlink) {
145178064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
145278064Sume				nd6log((LOG_ERR,
145378064Sume				    "pfxlist_onlink_check: failed to "
1454151479Ssuz				    "make %s/%d onlink, errno=%d\n",
1455165118Sbz				    ip6_sprintf(ip6buf,
1456165118Sbz					    &pr->ndpr_prefix.sin6_addr),
1457165118Sbz					    pr->ndpr_plen, e));
145878064Sume			}
145978064Sume		}
146078064Sume	}
146178064Sume
146278064Sume	/*
146378064Sume	 * Changes on the prefix status might affect address status as well.
146478064Sume	 * Make sure that all addresses derived from an attached prefix are
146578064Sume	 * attached, and that all addresses derived from a detached prefix are
146678064Sume	 * detached.  Note, however, that a manually configured address should
146778064Sume	 * always be attached.
146878064Sume	 * The precise detection logic is same as the one for prefixes.
146978064Sume	 */
147078064Sume	for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
1471120941Sume		if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
147278064Sume			continue;
147378064Sume
147478064Sume		if (ifa->ia6_ndpr == NULL) {
147578064Sume			/*
147678064Sume			 * This can happen when we first configure the address
147778064Sume			 * (i.e. the address exists, but the prefix does not).
147878064Sume			 * XXX: complicated relationships...
147978064Sume			 */
148078064Sume			continue;
148178064Sume		}
148278064Sume
148378064Sume		if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
148478064Sume			break;
148578064Sume	}
148678064Sume	if (ifa) {
148778064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
148878064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
148978064Sume				continue;
149078064Sume
149178064Sume			if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
149278064Sume				continue;
149378064Sume
1494151539Ssuz			if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) {
1495151539Ssuz				if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1496151539Ssuz					ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1497151539Ssuz					ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1498151539Ssuz					nd6_dad_start((struct ifaddr *)ifa, 0);
1499151539Ssuz				}
1500151539Ssuz			} else {
150178064Sume				ifa->ia6_flags |= IN6_IFF_DETACHED;
1502151539Ssuz			}
150378064Sume		}
150478064Sume	}
150562587Sitojun	else {
150678064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
150778064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
150878064Sume				continue;
150978064Sume
1510151539Ssuz			if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1511151539Ssuz				ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1512151539Ssuz				ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1513151539Ssuz				/* Do we need a delay in this case? */
1514151539Ssuz				nd6_dad_start((struct ifaddr *)ifa, 0);
1515151539Ssuz			}
151678064Sume		}
151753541Sshin	}
151853541Sshin}
151953541Sshin
152078064Sumeint
1521171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr)
152253541Sshin{
152378064Sume	struct ifaddr *ifa;
152478064Sume	struct ifnet *ifp = pr->ndpr_ifp;
152578064Sume	struct sockaddr_in6 mask6;
152678064Sume	struct nd_prefix *opr;
152778064Sume	u_long rtflags;
152878064Sume	int error = 0;
152978064Sume	struct rtentry *rt = NULL;
1530165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
153153541Sshin
153278064Sume	/* sanity check */
153378064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
153478064Sume		nd6log((LOG_ERR,
153578064Sume		    "nd6_prefix_onlink: %s/%d is already on-link\n",
1536165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
1537165118Sbz		    pr->ndpr_plen));
1538151465Ssuz		return (EEXIST);
153978064Sume	}
154078064Sume
154153541Sshin	/*
154278064Sume	 * Add the interface route associated with the prefix.  Before
154378064Sume	 * installing the route, check if there's the same prefix on another
154478064Sume	 * interface, and the prefix has already installed the interface route.
154578064Sume	 * Although such a configuration is expected to be rare, we explicitly
154678064Sume	 * allow it.
154753541Sshin	 */
154878064Sume	for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
154978064Sume		if (opr == pr)
155078064Sume			continue;
155178064Sume
155278064Sume		if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
155378064Sume			continue;
155478064Sume
155578064Sume		if (opr->ndpr_plen == pr->ndpr_plen &&
155678064Sume		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1557120941Sume		    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen))
1558120856Sume			return (0);
155978064Sume	}
156078064Sume
156178064Sume	/*
1562120941Sume	 * We prefer link-local addresses as the associated interface address.
156378064Sume	 */
156478064Sume	/* search for a link-local addr */
156578064Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
1566120941Sume	    IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
156778064Sume	if (ifa == NULL) {
156878064Sume		/* XXX: freebsd does not have ifa_ifwithaf */
1569120941Sume		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
157078064Sume			if (ifa->ifa_addr->sa_family == AF_INET6)
157178064Sume				break;
157278064Sume		}
157378064Sume		/* should we care about ia6_flags? */
157478064Sume	}
157578064Sume	if (ifa == NULL) {
157678064Sume		/*
157778064Sume		 * This can still happen, when, for example, we receive an RA
157878064Sume		 * containing a prefix with the L bit set and the A bit clear,
157978064Sume		 * after removing all IPv6 addresses on the receiving
158078064Sume		 * interface.  This should, of course, be rare though.
158178064Sume		 */
158278064Sume		nd6log((LOG_NOTICE,
158378064Sume		    "nd6_prefix_onlink: failed to find any ifaddr"
158478064Sume		    " to add route for a prefix(%s/%d) on %s\n",
1585165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
158678064Sume		    pr->ndpr_plen, if_name(ifp)));
1587120856Sume		return (0);
158878064Sume	}
158978064Sume
159078064Sume	/*
159178064Sume	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
159278064Sume	 * ifa->ifa_rtrequest = nd6_rtrequest;
159378064Sume	 */
159478064Sume	bzero(&mask6, sizeof(mask6));
159578064Sume	mask6.sin6_len = sizeof(mask6);
159678064Sume	mask6.sin6_addr = pr->ndpr_mask;
159778064Sume	rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP;
159878064Sume	if (nd6_need_cache(ifp)) {
159978064Sume		/* explicitly set in case ifa_flags does not set the flag. */
160078064Sume		rtflags |= RTF_CLONING;
160178064Sume	} else {
160278064Sume		/*
160378064Sume		 * explicitly clear the cloning bit in case ifa_flags sets it.
160478064Sume		 */
160578064Sume		rtflags &= ~RTF_CLONING;
160678064Sume	}
160778064Sume	error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
1608120941Sume	    ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
160978064Sume	if (error == 0) {
161078064Sume		if (rt != NULL) /* this should be non NULL, though */
161178064Sume			nd6_rtmsg(RTM_ADD, rt);
161278064Sume		pr->ndpr_stateflags |= NDPRF_ONLINK;
1613120941Sume	} else {
1614165118Sbz		char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN];
161578064Sume		nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
161678064Sume		    " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
161778064Sume		    "errno = %d\n",
1618165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
161978064Sume		    pr->ndpr_plen, if_name(ifp),
1620165118Sbz		    ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
1621165118Sbz		    ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error));
162278064Sume	}
162378064Sume
1624120727Ssam	if (rt != NULL) {
1625120727Ssam		RT_LOCK(rt);
1626122334Ssam		RT_REMREF(rt);
1627120727Ssam		RT_UNLOCK(rt);
1628120727Ssam	}
162978064Sume
1630120856Sume	return (error);
163178064Sume}
163278064Sume
163378064Sumeint
1634171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr)
163578064Sume{
163678064Sume	int error = 0;
163778064Sume	struct ifnet *ifp = pr->ndpr_ifp;
163878064Sume	struct nd_prefix *opr;
163978064Sume	struct sockaddr_in6 sa6, mask6;
164078064Sume	struct rtentry *rt = NULL;
1641165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
164278064Sume
164378064Sume	/* sanity check */
164478064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
164578064Sume		nd6log((LOG_ERR,
164678064Sume		    "nd6_prefix_offlink: %s/%d is already off-link\n",
1647165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
1648165118Sbz		    pr->ndpr_plen));
1649120856Sume		return (EEXIST);
165078064Sume	}
165178064Sume
165253541Sshin	bzero(&sa6, sizeof(sa6));
165353541Sshin	sa6.sin6_family = AF_INET6;
165453541Sshin	sa6.sin6_len = sizeof(sa6);
165553541Sshin	bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
1656120941Sume	    sizeof(struct in6_addr));
165753541Sshin	bzero(&mask6, sizeof(mask6));
165853541Sshin	mask6.sin6_family = AF_INET6;
165953541Sshin	mask6.sin6_len = sizeof(sa6);
166053541Sshin	bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
166178064Sume	error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
1662120941Sume	    (struct sockaddr *)&mask6, 0, &rt);
166378064Sume	if (error == 0) {
166478064Sume		pr->ndpr_stateflags &= ~NDPRF_ONLINK;
166553541Sshin
166678064Sume		/* report the route deletion to the routing socket. */
166778064Sume		if (rt != NULL)
166878064Sume			nd6_rtmsg(RTM_DELETE, rt);
166953541Sshin
167078064Sume		/*
167178064Sume		 * There might be the same prefix on another interface,
167278064Sume		 * the prefix which could not be on-link just because we have
167378064Sume		 * the interface route (see comments in nd6_prefix_onlink).
167478064Sume		 * If there's one, try to make the prefix on-link on the
167578064Sume		 * interface.
167678064Sume		 */
167778064Sume		for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
167878064Sume			if (opr == pr)
167978064Sume				continue;
168053541Sshin
168178064Sume			if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
168278064Sume				continue;
168353541Sshin
168478064Sume			/*
168578064Sume			 * KAME specific: detached prefixes should not be
168678064Sume			 * on-link.
168778064Sume			 */
168878064Sume			if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
168978064Sume				continue;
169078064Sume
169178064Sume			if (opr->ndpr_plen == pr->ndpr_plen &&
169278064Sume			    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1693120941Sume			    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
169478064Sume				int e;
169578064Sume
169678064Sume				if ((e = nd6_prefix_onlink(opr)) != 0) {
169778064Sume					nd6log((LOG_ERR,
169878064Sume					    "nd6_prefix_offlink: failed to "
169978064Sume					    "recover a prefix %s/%d from %s "
170078064Sume					    "to %s (errno = %d)\n",
1701165118Sbz					    ip6_sprintf(ip6buf,
1702165118Sbz						&opr->ndpr_prefix.sin6_addr),
170378064Sume					    opr->ndpr_plen, if_name(ifp),
170478064Sume					    if_name(opr->ndpr_ifp), e));
170578064Sume				}
170678064Sume			}
170778064Sume		}
1708120941Sume	} else {
170978064Sume		/* XXX: can we still set the NDPRF_ONLINK flag? */
171078064Sume		nd6log((LOG_ERR,
171178064Sume		    "nd6_prefix_offlink: failed to delete route: "
171278064Sume		    "%s/%d on %s (errno = %d)\n",
1713165118Sbz		    ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen,
1714165118Sbz		    if_name(ifp), error));
171578064Sume	}
171653541Sshin
1717120941Sume	if (rt != NULL) {
1718108269Sru		RTFREE(rt);
1719120941Sume	}
172053541Sshin
1721120856Sume	return (error);
172253541Sshin}
172353541Sshin
172453541Sshinstatic struct in6_ifaddr *
1725171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast)
172653541Sshin{
172778064Sume	struct ifnet *ifp = pr->ndpr_ifp;
172853541Sshin	struct ifaddr *ifa;
172978064Sume	struct in6_aliasreq ifra;
173078064Sume	struct in6_ifaddr *ia, *ib;
173178064Sume	int error, plen0;
173253541Sshin	struct in6_addr mask;
173378064Sume	int prefixlen = pr->ndpr_plen;
1734151539Ssuz	int updateflags;
1735165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
173653541Sshin
1737121168Sume	in6_prefixlen2mask(&mask, prefixlen);
173853541Sshin
173978064Sume	/*
174078064Sume	 * find a link-local address (will be interface ID).
174178064Sume	 * Is it really mandatory? Theoretically, a global or a site-local
174278064Sume	 * address can be configured without a link-local address, if we
174378064Sume	 * have a unique interface identifier...
174478064Sume	 *
174578064Sume	 * it is not mandatory to have a link-local address, we can generate
174678064Sume	 * interface identifier on the fly.  we do this because:
174778064Sume	 * (1) it should be the easiest way to find interface identifier.
174878064Sume	 * (2) RFC2462 5.4 suggesting the use of the same interface identifier
174978064Sume	 * for multiple addresses on a single interface, and possible shortcut
175078064Sume	 * of DAD.  we omitted DAD for this reason in the past.
1751120941Sume	 * (3) a user can prevent autoconfiguration of global address
175278064Sume	 * by removing link-local address by hand (this is partly because we
1753108533Sschweikh	 * don't have other way to control the use of IPv6 on an interface.
175478064Sume	 * this has been our design choice - cf. NRL's "ifconfig auto").
175578064Sume	 * (4) it is easier to manage when an interface has addresses
175678064Sume	 * with the same interface identifier, than to have multiple addresses
175778064Sume	 * with different interface identifiers.
175878064Sume	 */
1759120941Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
176053541Sshin	if (ifa)
176153541Sshin		ib = (struct in6_ifaddr *)ifa;
176253541Sshin	else
176353541Sshin		return NULL;
176453541Sshin
176553541Sshin	/* prefixlen + ifidlen must be equal to 128 */
176678064Sume	plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
176778064Sume	if (prefixlen != plen0) {
176878064Sume		nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
176978064Sume		    "(prefix=%d ifid=%d)\n",
177078064Sume		    if_name(ifp), prefixlen, 128 - plen0));
177153541Sshin		return NULL;
177253541Sshin	}
177353541Sshin
177453541Sshin	/* make ifaddr */
177553541Sshin
177678064Sume	bzero(&ifra, sizeof(ifra));
177778064Sume	/*
177878064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
177978064Sume	 * for safety.
178078064Sume	 */
178178064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
178278064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
178378064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
178478064Sume	/* prefix */
1785151539Ssuz	ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr;
178678064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
178778064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
178878064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
178978064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
179053541Sshin
179153541Sshin	/* interface ID */
1792120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
1793151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
1794120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
1795151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
1796120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1797151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
1798120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1799151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
1800120941Sume
180178064Sume	/* new prefix mask. */
180278064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
180378064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
180478064Sume	bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
1805120941Sume	    sizeof(ifra.ifra_prefixmask.sin6_addr));
180653541Sshin
1807151539Ssuz	/* lifetimes. */
180878064Sume	ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
180978064Sume	ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
181053541Sshin
181178064Sume	/* XXX: scope zone ID? */
181253541Sshin
181378064Sume	ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
1814151539Ssuz
1815171260Sdelphij	/*
1816151539Ssuz	 * Make sure that we do not have this address already.  This should
1817151539Ssuz	 * usually not happen, but we can still see this case, e.g., if we
1818151539Ssuz	 * have manually configured the exact address to be configured.
181978064Sume	 */
1820151539Ssuz	if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
1821151539Ssuz		/* this should be rare enough to make an explicit log */
1822151539Ssuz		log(LOG_INFO, "in6_ifadd: %s is already configured\n",
1823165118Sbz		    ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr));
1824151539Ssuz		return (NULL);
1825151539Ssuz	}
182653541Sshin
182753541Sshin	/*
1828151539Ssuz	 * Allocate ifaddr structure, link into chain, etc.
1829151539Ssuz	 * If we are going to create a new address upon receiving a multicasted
1830151539Ssuz	 * RA, we need to impose a random delay before starting DAD.
1831151539Ssuz	 * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2]
183253541Sshin	 */
1833151539Ssuz	updateflags = 0;
1834151539Ssuz	if (mcast)
1835151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1836151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) {
183778064Sume		nd6log((LOG_ERR,
183878064Sume		    "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
1839165118Sbz		    ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr),
1840165118Sbz		    if_name(ifp), error));
1841120856Sume		return (NULL);	/* ifaddr must not have been allocated. */
184253541Sshin	}
184353541Sshin
184478064Sume	ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
184553541Sshin
1846120941Sume	return (ia);		/* this is always non-NULL */
184753541Sshin}
184853541Sshin
1849171259Sdelphij/*
1850171259Sdelphij * ia0 - corresponding public address
1851171259Sdelphij */
185253541Sshinint
1853171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay)
185453541Sshin{
185578064Sume	struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
1856151539Ssuz	struct in6_ifaddr *newia, *ia;
185778064Sume	struct in6_aliasreq ifra;
185878064Sume	int i, error;
185978064Sume	int trylimit = 3;	/* XXX: adhoc value */
1860151539Ssuz	int updateflags;
186178064Sume	u_int32_t randid[2];
186278064Sume	time_t vltime0, pltime0;
186353541Sshin
186478064Sume	bzero(&ifra, sizeof(ifra));
186578064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
186678064Sume	ifra.ifra_addr = ia0->ia_addr;
186778064Sume	/* copy prefix mask */
186878064Sume	ifra.ifra_prefixmask = ia0->ia_prefixmask;
186978064Sume	/* clear the old IFID */
187078064Sume	for (i = 0; i < 4; i++) {
1871120941Sume		ifra.ifra_addr.sin6_addr.s6_addr32[i] &=
1872120941Sume		    ifra.ifra_prefixmask.sin6_addr.s6_addr32[i];
187378064Sume	}
187453541Sshin
187578064Sume  again:
1876151539Ssuz	if (in6_get_tmpifid(ifp, (u_int8_t *)randid,
1877151539Ssuz	    (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) {
1878151539Ssuz		nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good "
1879151539Ssuz		    "random IFID\n"));
1880151539Ssuz		return (EINVAL);
1881151539Ssuz	}
1882120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1883120941Sume	    (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2]));
1884120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1885120941Sume	    (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3]));
188653541Sshin
1887171260Sdelphij	/*
1888151539Ssuz	 * in6_get_tmpifid() quite likely provided a unique interface ID.
1889151539Ssuz	 * However, we may still have a chance to see collision, because
1890151539Ssuz	 * there may be a time lag between generation of the ID and generation
1891151539Ssuz	 * of the address.  So, we'll do one more sanity check.
189278064Sume	 */
1893151539Ssuz	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
1894151539Ssuz		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
1895151539Ssuz		    &ifra.ifra_addr.sin6_addr)) {
1896171260Sdelphij			if (trylimit-- == 0) {
1897151539Ssuz				/*
1898151539Ssuz				 * Give up.  Something strange should have
1899151539Ssuz				 * happened.
1900151539Ssuz				 */
1901151539Ssuz				nd6log((LOG_NOTICE, "in6_tmpifadd: failed to "
1902151539Ssuz				    "find a unique random IFID\n"));
1903151539Ssuz				return (EEXIST);
1904151539Ssuz			}
1905151539Ssuz			forcegen = 1;
1906151539Ssuz			goto again;
190778064Sume		}
190853541Sshin	}
190953541Sshin
191078064Sume	/*
191178064Sume	 * The Valid Lifetime is the lower of the Valid Lifetime of the
191278064Sume         * public address or TEMP_VALID_LIFETIME.
191378064Sume	 * The Preferred Lifetime is the lower of the Preferred Lifetime
191478064Sume         * of the public address or TEMP_PREFERRED_LIFETIME -
191578064Sume         * DESYNC_FACTOR.
191678064Sume	 */
1917151539Ssuz	if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
191878064Sume		vltime0 = IFA6_IS_INVALID(ia0) ? 0 :
1919151539Ssuz		    (ia0->ia6_lifetime.ia6t_vltime -
1920151539Ssuz		    (time_second - ia0->ia6_updatetime));
192178064Sume		if (vltime0 > ip6_temp_valid_lifetime)
192278064Sume			vltime0 = ip6_temp_valid_lifetime;
192378064Sume	} else
192478064Sume		vltime0 = ip6_temp_valid_lifetime;
1925151539Ssuz	if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
192678064Sume		pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 :
1927151539Ssuz		    (ia0->ia6_lifetime.ia6t_pltime -
1928151539Ssuz		    (time_second - ia0->ia6_updatetime));
192978064Sume		if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){
193078064Sume			pltime0 = ip6_temp_preferred_lifetime -
1931120941Sume			    ip6_desync_factor;
193278064Sume		}
193378064Sume	} else
193478064Sume		pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor;
193578064Sume	ifra.ifra_lifetime.ia6t_vltime = vltime0;
193678064Sume	ifra.ifra_lifetime.ia6t_pltime = pltime0;
193753541Sshin
193878064Sume	/*
193978064Sume	 * A temporary address is created only if this calculated Preferred
194078064Sume	 * Lifetime is greater than REGEN_ADVANCE time units.
194178064Sume	 */
194278064Sume	if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance)
1943120856Sume		return (0);
194453541Sshin
194578064Sume	/* XXX: scope zone ID? */
194678064Sume
194778064Sume	ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
194878064Sume
194978064Sume	/* allocate ifaddr structure, link into chain, etc. */
1950151539Ssuz	updateflags = 0;
1951151539Ssuz	if (delay)
1952151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1953151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0)
1954120856Sume		return (error);
195578064Sume
195678064Sume	newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
195778064Sume	if (newia == NULL) {	/* XXX: can it happen? */
195878064Sume		nd6log((LOG_ERR,
195978064Sume		    "in6_tmpifadd: ifa update succeeded, but we got "
196078064Sume		    "no ifaddr\n"));
1961120856Sume		return (EINVAL); /* XXX */
196253541Sshin	}
196378064Sume	newia->ia6_ndpr = ia0->ia6_ndpr;
196478064Sume	newia->ia6_ndpr->ndpr_refcnt++;
196553541Sshin
196678407Sume	/*
196778407Sume	 * A newly added address might affect the status of other addresses.
196878407Sume	 * XXX: when the temporary address is generated with a new public
196978407Sume	 * address, the onlink check is redundant.  However, it would be safe
197078407Sume	 * to do the check explicitly everywhere a new address is generated,
197178407Sume	 * and, in fact, we surely need the check when we create a new
197278407Sume	 * temporary address due to deprecation of an old temporary address.
197378407Sume	 */
197478407Sume	pfxlist_onlink_check();
197578407Sume
1976120856Sume	return (0);
1977120941Sume}
197853541Sshin
1979151539Ssuzstatic int
198053541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr)
198153541Sshin{
198253541Sshin	if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
198353541Sshin		ndpr->ndpr_preferred = 0;
198453541Sshin	else
198553541Sshin		ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
198653541Sshin	if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
198753541Sshin		ndpr->ndpr_expire = 0;
198853541Sshin	else
198953541Sshin		ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
199053541Sshin
199153541Sshin	return 0;
199253541Sshin}
199353541Sshin
199453541Sshinstatic void
199578064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
199653541Sshin{
199778064Sume	/* init ia6t_expire */
199878064Sume	if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
199978064Sume		lt6->ia6t_expire = 0;
200078064Sume	else {
200178064Sume		lt6->ia6t_expire = time_second;
200278064Sume		lt6->ia6t_expire += lt6->ia6t_vltime;
200353541Sshin	}
200462587Sitojun
200553541Sshin	/* init ia6t_preferred */
200653541Sshin	if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
200753541Sshin		lt6->ia6t_preferred = 0;
200853541Sshin	else {
200953541Sshin		lt6->ia6t_preferred = time_second;
201053541Sshin		lt6->ia6t_preferred += lt6->ia6t_pltime;
201153541Sshin	}
201253541Sshin}
201353541Sshin
201453541Sshin/*
201553541Sshin * Delete all the routing table entries that use the specified gateway.
201653541Sshin * XXX: this function causes search through all entries of routing table, so
201753541Sshin * it shouldn't be called when acting as a router.
201853541Sshin */
201953541Sshinvoid
2020171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
202153541Sshin{
202253541Sshin	struct radix_node_head *rnh = rt_tables[AF_INET6];
202353541Sshin	int s = splnet();
202453541Sshin
202553541Sshin	/* We'll care only link-local addresses */
202653541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
202753541Sshin		splx(s);
202853541Sshin		return;
202953541Sshin	}
203053541Sshin
2031108250Shsu	RADIX_NODE_HEAD_LOCK(rnh);
203253541Sshin	rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
2033108250Shsu	RADIX_NODE_HEAD_UNLOCK(rnh);
203453541Sshin	splx(s);
203553541Sshin}
203653541Sshin
203753541Sshinstatic int
2038171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg)
203953541Sshin{
204053541Sshin#define SIN6(s)	((struct sockaddr_in6 *)s)
204153541Sshin	struct rtentry *rt = (struct rtentry *)rn;
204253541Sshin	struct in6_addr *gate = (struct in6_addr *)arg;
204353541Sshin
204453541Sshin	if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
2045120856Sume		return (0);
204653541Sshin
2047120941Sume	if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) {
2048120856Sume		return (0);
2049120941Sume	}
205053541Sshin
205153541Sshin	/*
205278064Sume	 * Do not delete a static route.
205378064Sume	 * XXX: this seems to be a bit ad-hoc. Should we consider the
205478064Sume	 * 'cloned' bit instead?
205578064Sume	 */
205678064Sume	if ((rt->rt_flags & RTF_STATIC) != 0)
2057120856Sume		return (0);
205878064Sume
205978064Sume	/*
206053541Sshin	 * We delete only host route. This means, in particular, we don't
206153541Sshin	 * delete default route.
206253541Sshin	 */
206353541Sshin	if ((rt->rt_flags & RTF_HOST) == 0)
2064120856Sume		return (0);
206553541Sshin
2066120941Sume	return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
2067120941Sume	    rt_mask(rt), rt->rt_flags, 0));
206853541Sshin#undef SIN6
206953541Sshin}
207062587Sitojun
207162587Sitojunint
2072171259Sdelphijnd6_setdefaultiface(int ifindex)
207362587Sitojun{
207462587Sitojun	int error = 0;
207562587Sitojun
207662587Sitojun	if (ifindex < 0 || if_index < ifindex)
2077120856Sume		return (EINVAL);
2078151539Ssuz	if (ifindex != 0 && !ifnet_byindex(ifindex))
2079151539Ssuz		return (EINVAL);
208062587Sitojun
208162587Sitojun	if (nd6_defifindex != ifindex) {
208262587Sitojun		nd6_defifindex = ifindex;
208362587Sitojun		if (nd6_defifindex > 0)
208483130Sjlemon			nd6_defifp = ifnet_byindex(nd6_defifindex);
208562587Sitojun		else
208662587Sitojun			nd6_defifp = NULL;
208762587Sitojun
208862587Sitojun		/*
208962587Sitojun		 * Our current implementation assumes one-to-one maping between
209062587Sitojun		 * interfaces and links, so it would be natural to use the
209162587Sitojun		 * default interface as the default link.
209262587Sitojun		 */
209362587Sitojun		scope6_setdefault(nd6_defifp);
209462587Sitojun	}
209562587Sitojun
2096120856Sume	return (error);
209762587Sitojun}
2098