nd6_rtr.c revision 151539
162587Sitojun/*	$FreeBSD: head/sys/netinet6/nd6_rtr.c 151539 2005-10-21 16:23:01Z suz $	*/
278064Sume/*	$KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $	*/
362587Sitojun
4139826Simp/*-
553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
653541Sshin * All rights reserved.
753541Sshin *
853541Sshin * Redistribution and use in source and binary forms, with or without
953541Sshin * modification, are permitted provided that the following conditions
1053541Sshin * are met:
1153541Sshin * 1. Redistributions of source code must retain the above copyright
1253541Sshin *    notice, this list of conditions and the following disclaimer.
1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1453541Sshin *    notice, this list of conditions and the following disclaimer in the
1553541Sshin *    documentation and/or other materials provided with the distribution.
1653541Sshin * 3. Neither the name of the project nor the names of its contributors
1753541Sshin *    may be used to endorse or promote products derived from this software
1853541Sshin *    without specific prior written permission.
1953541Sshin *
2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2353541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3053541Sshin * SUCH DAMAGE.
3153541Sshin */
3253541Sshin
3362587Sitojun#include "opt_inet.h"
3462587Sitojun#include "opt_inet6.h"
3562587Sitojun
3653541Sshin#include <sys/param.h>
3753541Sshin#include <sys/systm.h>
3853541Sshin#include <sys/malloc.h>
3953541Sshin#include <sys/mbuf.h>
4053541Sshin#include <sys/socket.h>
4153541Sshin#include <sys/sockio.h>
4253541Sshin#include <sys/time.h>
4378064Sume#include <sys/kernel.h>
4453541Sshin#include <sys/errno.h>
4553541Sshin#include <sys/syslog.h>
4678064Sume#include <sys/queue.h>
4753541Sshin
4853541Sshin#include <net/if.h>
4953541Sshin#include <net/if_types.h>
5053541Sshin#include <net/if_dl.h>
5153541Sshin#include <net/route.h>
5253541Sshin#include <net/radix.h>
5353541Sshin
5453541Sshin#include <netinet/in.h>
5553541Sshin#include <netinet6/in6_var.h>
5678064Sume#include <netinet6/in6_ifattach.h>
5762587Sitojun#include <netinet/ip6.h>
5853541Sshin#include <netinet6/ip6_var.h>
5953541Sshin#include <netinet6/nd6.h>
6062587Sitojun#include <netinet/icmp6.h>
6162587Sitojun#include <netinet6/scope6_var.h>
6253541Sshin
6353541Sshin#include <net/net_osdep.h>
6453541Sshin
6562587Sitojun#define SDL(s)	((struct sockaddr_dl *)s)
6653541Sshin
67151539Ssuzstatic int rtpref __P((struct nd_defrouter *));
6862587Sitojunstatic struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
69151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *,
70151539Ssuz    struct mbuf *, int));
71151539Ssuzstatic struct in6_ifaddr *in6_ifadd __P((struct nd_prefixctl *,	int));
7262587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
7378064Sume	struct nd_defrouter *));
7462587Sitojunstatic void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
7562587Sitojunstatic void pfxrtr_del __P((struct nd_pfxrouter *));
7662587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router
7778064Sume	__P((struct nd_prefix *));
78151539Ssuzstatic void defrouter_delreq __P((struct nd_defrouter *));
7978064Sumestatic void nd6_rtmsg __P((int, struct rtentry *));
8053541Sshin
81151539Ssuzstatic int in6_init_prefix_ltimes __P((struct nd_prefix *));
82120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *,
83120941Sume	struct in6_addrlifetime *));
8453541Sshin
8562587Sitojunstatic int rt6_deleteroute __P((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
11953541Sshinnd6_rs_input(m, off, icmp6len)
12053541Sshin	struct	mbuf *m;
12153541Sshin	int off, icmp6len;
12253541Sshin{
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;
13053541Sshin
13153541Sshin	/* If I'm not a router, ignore it. */
13253541Sshin	if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
13362587Sitojun		goto freeit;
13453541Sshin
13553541Sshin	/* Sanity checks */
13653541Sshin	if (ip6->ip6_hlim != 255) {
13778064Sume		nd6log((LOG_ERR,
13878064Sume		    "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
13978064Sume		    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
14078064Sume		    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
14178064Sume		goto bad;
14253541Sshin	}
14353541Sshin
14453541Sshin	/*
14553541Sshin	 * Don't update the neighbor cache, if src = ::.
14653541Sshin	 * This indicates that the src has no IP address assigned yet.
14753541Sshin	 */
14853541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
14962587Sitojun		goto freeit;
15062587Sitojun
15162587Sitojun#ifndef PULLDOWN_TEST
15262587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
15362587Sitojun	nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
15462587Sitojun#else
15562587Sitojun	IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
15662587Sitojun	if (nd_rs == NULL) {
15762587Sitojun		icmp6stat.icp6s_tooshort++;
15853541Sshin		return;
15962587Sitojun	}
16062587Sitojun#endif
16153541Sshin
16253541Sshin	icmp6len -= sizeof(*nd_rs);
16353541Sshin	nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
16453541Sshin	if (nd6_options(&ndopts) < 0) {
16578064Sume		nd6log((LOG_INFO,
16678064Sume		    "nd6_rs_input: invalid ND option, ignored\n"));
16778064Sume		/* nd6_options have incremented stats */
16862587Sitojun		goto freeit;
16953541Sshin	}
17053541Sshin
17153541Sshin	if (ndopts.nd_opts_src_lladdr) {
17253541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
17353541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
17453541Sshin	}
17553541Sshin
17653541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
17778064Sume		nd6log((LOG_INFO,
17853541Sshin		    "nd6_rs_input: lladdrlen mismatch for %s "
17953541Sshin		    "(if %d, RS packet %d)\n",
180120941Sume		    ip6_sprintf(&saddr6),
181120941Sume		    ifp->if_addrlen, lladdrlen - 2));
18278064Sume		goto bad;
18353541Sshin	}
18453541Sshin
18553541Sshin	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
18662587Sitojun
18762587Sitojun freeit:
18862587Sitojun	m_freem(m);
18978064Sume	return;
19078064Sume
19178064Sume bad:
19278064Sume	icmp6stat.icp6s_badrs++;
19378064Sume	m_freem(m);
19453541Sshin}
19553541Sshin
19653541Sshin/*
19753541Sshin * Receive Router Advertisement Message.
19853541Sshin *
19953541Sshin * Based on RFC 2461
20053541Sshin * TODO: on-link bit on prefix information
20153541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
20253541Sshin */
20353541Sshinvoid
20453541Sshinnd6_ra_input(m, off, icmp6len)
20553541Sshin	struct	mbuf *m;
20653541Sshin	int off, icmp6len;
20753541Sshin{
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;
21653541Sshin
217118498Sume	/*
218118498Sume	 * We only accept RAs only when
219118498Sume	 * the system-wide variable allows the acceptance, and
220118498Sume	 * per-interface variable allows RAs on the receiving interface.
221118498Sume	 */
22253541Sshin	if (ip6_accept_rtadv == 0)
22362587Sitojun		goto freeit;
224118498Sume	if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
225118498Sume		goto freeit;
22653541Sshin
22753541Sshin	if (ip6->ip6_hlim != 255) {
22878064Sume		nd6log((LOG_ERR,
22978064Sume		    "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
23078064Sume		    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
23178064Sume		    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
23278064Sume		goto bad;
23353541Sshin	}
23453541Sshin
23553541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
23678064Sume		nd6log((LOG_ERR,
23753541Sshin		    "nd6_ra_input: src %s is not link-local\n",
23878064Sume		    ip6_sprintf(&saddr6)));
23978064Sume		goto bad;
24062587Sitojun	}
24162587Sitojun
24262587Sitojun#ifndef PULLDOWN_TEST
24362587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
24462587Sitojun	nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
24562587Sitojun#else
24662587Sitojun	IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
24762587Sitojun	if (nd_ra == NULL) {
24862587Sitojun		icmp6stat.icp6s_tooshort++;
24953541Sshin		return;
25053541Sshin	}
25162587Sitojun#endif
25253541Sshin
25353541Sshin	icmp6len -= sizeof(*nd_ra);
25453541Sshin	nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
25553541Sshin	if (nd6_options(&ndopts) < 0) {
25678064Sume		nd6log((LOG_INFO,
25778064Sume		    "nd6_ra_input: invalid ND option, ignored\n"));
25878064Sume		/* nd6_options have incremented stats */
25962587Sitojun		goto freeit;
26053541Sshin	}
26153541Sshin
26253541Sshin    {
26353541Sshin	struct nd_defrouter dr0;
26453541Sshin	u_int32_t advreachable = nd_ra->nd_ra_reachable;
26553541Sshin
266151539Ssuz	/* remember if this is a multicasted advertisement */
267151539Ssuz	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
268151539Ssuz		mcast = 1;
269151539Ssuz
270151539Ssuz	bzero(&dr0, sizeof(dr0));
27153541Sshin	dr0.rtaddr = saddr6;
27253541Sshin	dr0.flags  = nd_ra->nd_ra_flags_reserved;
273151539Ssuz	if (rtpref(&dr0) == RTPREF_RESERVED) {
274151539Ssuz		/*
275151539Ssuz		 * "reserved" router preference should be treated as
276151539Ssuz		 * 0-lifetime.  Note that rtpref() covers the case that the
277151539Ssuz		 * kernel is not configured to support the preference
278151539Ssuz		 * extension.
279151539Ssuz		 */
280151539Ssuz		dr0.rtlifetime = 0;
281151539Ssuz	} else
282151539Ssuz		dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
28353541Sshin	dr0.expire = time_second + dr0.rtlifetime;
28453541Sshin	dr0.ifp = ifp;
28553541Sshin	/* unspecified or not? (RFC 2461 6.3.4) */
28653541Sshin	if (advreachable) {
28790868Smike		advreachable = ntohl(advreachable);
28853541Sshin		if (advreachable <= MAX_REACHABLE_TIME &&
28953541Sshin		    ndi->basereachable != advreachable) {
29053541Sshin			ndi->basereachable = advreachable;
29153541Sshin			ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
29253541Sshin			ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
29353541Sshin		}
29453541Sshin	}
29553541Sshin	if (nd_ra->nd_ra_retransmit)
29653541Sshin		ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
29753541Sshin	if (nd_ra->nd_ra_curhoplimit)
29853541Sshin		ndi->chlim = nd_ra->nd_ra_curhoplimit;
29953541Sshin	dr = defrtrlist_update(&dr0);
30053541Sshin    }
30153541Sshin
30253541Sshin	/*
30353541Sshin	 * prefix
30453541Sshin	 */
30553541Sshin	if (ndopts.nd_opts_pi) {
30653541Sshin		struct nd_opt_hdr *pt;
30778064Sume		struct nd_opt_prefix_info *pi = NULL;
308151539Ssuz		struct nd_prefixctl pr;
30953541Sshin
31053541Sshin		for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
31153541Sshin		     pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
31253541Sshin		     pt = (struct nd_opt_hdr *)((caddr_t)pt +
31353541Sshin						(pt->nd_opt_len << 3))) {
31453541Sshin			if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
31553541Sshin				continue;
31653541Sshin			pi = (struct nd_opt_prefix_info *)pt;
31753541Sshin
31853541Sshin			if (pi->nd_opt_pi_len != 4) {
31978064Sume				nd6log((LOG_INFO,
32078064Sume				    "nd6_ra_input: invalid option "
32178064Sume				    "len %d for prefix information option, "
32278064Sume				    "ignored\n", pi->nd_opt_pi_len));
32353541Sshin				continue;
32453541Sshin			}
32553541Sshin
32653541Sshin			if (128 < pi->nd_opt_pi_prefix_len) {
32778064Sume				nd6log((LOG_INFO,
32878064Sume				    "nd6_ra_input: invalid prefix "
32978064Sume				    "len %d for prefix information option, "
33078064Sume				    "ignored\n", pi->nd_opt_pi_prefix_len));
33153541Sshin				continue;
33253541Sshin			}
33353541Sshin
33453541Sshin			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
33553541Sshin			 || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
33678064Sume				nd6log((LOG_INFO,
33778064Sume				    "nd6_ra_input: invalid prefix "
33878064Sume				    "%s, ignored\n",
33978064Sume				    ip6_sprintf(&pi->nd_opt_pi_prefix)));
34053541Sshin				continue;
34153541Sshin			}
34253541Sshin
34353541Sshin			bzero(&pr, sizeof(pr));
34453541Sshin			pr.ndpr_prefix.sin6_family = AF_INET6;
34553541Sshin			pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
34653541Sshin			pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
34753541Sshin			pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
34853541Sshin
34953541Sshin			pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
350120941Sume			    ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
35153541Sshin			pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
352120941Sume			    ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
35353541Sshin			pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
35453541Sshin			pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
355120941Sume			pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time);
356151539Ssuz			(void)prelist_update(&pr, dr, m, mcast);
35753541Sshin		}
35853541Sshin	}
35953541Sshin
36053541Sshin	/*
36153541Sshin	 * MTU
36253541Sshin	 */
36353541Sshin	if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
364121283Sume		u_long mtu;
365121283Sume		u_long maxmtu;
36653541Sshin
367121283Sume		mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
368120941Sume
36953541Sshin		/* lower bound */
37053541Sshin		if (mtu < IPV6_MMTU) {
37178064Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option "
372121283Sume			    "mtu=%lu sent from %s, ignoring\n",
37378064Sume			    mtu, ip6_sprintf(&ip6->ip6_src)));
37453541Sshin			goto skip;
37553541Sshin		}
37653541Sshin
37753541Sshin		/* upper bound */
378121283Sume		maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu)
379121283Sume		    ? ndi->maxmtu : ifp->if_mtu;
380121283Sume		if (mtu <= maxmtu) {
381121283Sume			int change = (ndi->linkmtu != mtu);
38253541Sshin
383121283Sume			ndi->linkmtu = mtu;
384121283Sume			if (change) /* in6_maxmtu may change */
385121283Sume				in6_setmaxmtu();
38653541Sshin		} else {
387121283Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
388121283Sume			    "mtu=%lu sent from %s; "
389121283Sume			    "exceeds maxmtu %lu, ignoring\n",
390121283Sume			    mtu, ip6_sprintf(&ip6->ip6_src), maxmtu));
39153541Sshin		}
39253541Sshin	}
39353541Sshin
39453541Sshin skip:
395120941Sume
39653541Sshin	/*
39795023Ssuz	 * Source link layer address
39853541Sshin	 */
39953541Sshin    {
40053541Sshin	char *lladdr = NULL;
40153541Sshin	int lladdrlen = 0;
402120941Sume
40353541Sshin	if (ndopts.nd_opts_src_lladdr) {
40453541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
40553541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
40653541Sshin	}
40753541Sshin
40853541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
40978064Sume		nd6log((LOG_INFO,
41053541Sshin		    "nd6_ra_input: lladdrlen mismatch for %s "
411120941Sume		    "(if %d, RA packet %d)\n", ip6_sprintf(&saddr6),
412120941Sume		    ifp->if_addrlen, lladdrlen - 2));
41378064Sume		goto bad;
41453541Sshin	}
41553541Sshin
416120941Sume	nd6_cache_lladdr(ifp, &saddr6, lladdr,
417120941Sume	    lladdrlen, ND_ROUTER_ADVERT, 0);
41862587Sitojun
41962587Sitojun	/*
42062587Sitojun	 * Installing a link-layer address might change the state of the
42162587Sitojun	 * router's neighbor cache, which might also affect our on-link
42262587Sitojun	 * detection of adveritsed prefixes.
42362587Sitojun	 */
42462587Sitojun	pfxlist_onlink_check();
42553541Sshin    }
42662587Sitojun
42778064Sume freeit:
42862587Sitojun	m_freem(m);
42978064Sume	return;
43078064Sume
43178064Sume bad:
43278064Sume	icmp6stat.icp6s_badra++;
43378064Sume	m_freem(m);
43453541Sshin}
43553541Sshin
43653541Sshin/*
43753541Sshin * default router list proccessing sub routines
43853541Sshin */
43962587Sitojun
44062587Sitojun/* tell the change to user processes watching the routing socket. */
44162587Sitojunstatic void
44278064Sumend6_rtmsg(cmd, rt)
44362587Sitojun	int cmd;
44462587Sitojun	struct rtentry *rt;
44562587Sitojun{
44662587Sitojun	struct rt_addrinfo info;
44762587Sitojun
44862587Sitojun	bzero((caddr_t)&info, sizeof(info));
44962587Sitojun	info.rti_info[RTAX_DST] = rt_key(rt);
45062587Sitojun	info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
45162587Sitojun	info.rti_info[RTAX_NETMASK] = rt_mask(rt);
452151539Ssuz	if (rt->rt_ifp) {
453151539Ssuz		info.rti_info[RTAX_IFP] =
454151539Ssuz		    TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
455151539Ssuz		info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
456151539Ssuz	}
45762587Sitojun
45862587Sitojun	rt_missmsg(cmd, &info, rt->rt_flags, 0);
45962587Sitojun}
46062587Sitojun
46153541Sshinvoid
46253541Sshindefrouter_addreq(new)
46353541Sshin	struct nd_defrouter *new;
46453541Sshin{
46553541Sshin	struct sockaddr_in6 def, mask, gate;
46662587Sitojun	struct rtentry *newrt = NULL;
467151539Ssuz	int s;
468151539Ssuz	int error;
46953541Sshin
470128397Sluigi	bzero(&def, sizeof(def));
471128397Sluigi	bzero(&mask, sizeof(mask));
472128397Sluigi	bzero(&gate, sizeof(gate));
47353541Sshin
474120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
475120941Sume	    sizeof(struct sockaddr_in6);
476151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
47753541Sshin	gate.sin6_addr = new->rtaddr;
47853541Sshin
479151539Ssuz	s = splnet();
480151539Ssuz	error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
481120941Sume	    (struct sockaddr *)&gate, (struct sockaddr *)&mask,
482120941Sume	    RTF_GATEWAY, &newrt);
48362587Sitojun	if (newrt) {
484120727Ssam		RT_LOCK(newrt);
48578064Sume		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
486122334Ssam		RT_REMREF(newrt);
487120727Ssam		RT_UNLOCK(newrt);
48862587Sitojun	}
489151539Ssuz	if (error == 0)
490151539Ssuz		new->installed = 1;
491151539Ssuz	splx(s);
49253541Sshin	return;
49353541Sshin}
49453541Sshin
49553541Sshinstruct nd_defrouter *
49653541Sshindefrouter_lookup(addr, ifp)
49753541Sshin	struct in6_addr *addr;
49853541Sshin	struct ifnet *ifp;
49953541Sshin{
50053541Sshin	struct nd_defrouter *dr;
50153541Sshin
50262587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
50362587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
50453541Sshin		if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
505120856Sume			return (dr);
50662587Sitojun	}
50753541Sshin
508120856Sume	return (NULL);		/* search failed */
50953541Sshin}
51053541Sshin
511151539Ssuz/*
512151539Ssuz * Remove the default route for a given router.
513151539Ssuz * This is just a subroutine function for defrouter_select(), and should
514151539Ssuz * not be called from anywhere else.
515151539Ssuz */
516151539Ssuzstatic void
517151539Ssuzdefrouter_delreq(dr)
51853541Sshin	struct nd_defrouter *dr;
51953541Sshin{
52053541Sshin	struct sockaddr_in6 def, mask, gate;
52162587Sitojun	struct rtentry *oldrt = NULL;
52253541Sshin
523128397Sluigi	bzero(&def, sizeof(def));
524128397Sluigi	bzero(&mask, sizeof(mask));
525128397Sluigi	bzero(&gate, sizeof(gate));
52653541Sshin
527120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
528120941Sume	    sizeof(struct sockaddr_in6);
529151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
53053541Sshin	gate.sin6_addr = dr->rtaddr;
53153541Sshin
53253541Sshin	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
533120941Sume	    (struct sockaddr *)&gate,
534120941Sume	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
53562587Sitojun	if (oldrt) {
53678064Sume		nd6_rtmsg(RTM_DELETE, oldrt);
537108269Sru		RTFREE(oldrt);
53862587Sitojun	}
53953541Sshin
540151539Ssuz	dr->installed = 0;
54153541Sshin}
54253541Sshin
543151539Ssuz/*
544151539Ssuz * remove all default routes from default router list
545151539Ssuz */
54653541Sshinvoid
547151539Ssuzdefrouter_reset()
548151539Ssuz{
549151539Ssuz	struct nd_defrouter *dr;
550151539Ssuz
551151539Ssuz	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
552151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry))
553151539Ssuz		defrouter_delreq(dr);
554151539Ssuz
555151539Ssuz	/*
556151539Ssuz	 * XXX should we also nuke any default routers in the kernel, by
557151539Ssuz	 * going through them by rtalloc1()?
558151539Ssuz	 */
559151539Ssuz}
560151539Ssuz
561151539Ssuzvoid
56253541Sshindefrtrlist_del(dr)
56353541Sshin	struct nd_defrouter *dr;
56453541Sshin{
56553541Sshin	struct nd_defrouter *deldr = NULL;
56653541Sshin	struct nd_prefix *pr;
56753541Sshin
56853541Sshin	/*
56953541Sshin	 * Flush all the routing table entries that use the router
57053541Sshin	 * as a next hop.
57153541Sshin	 */
572120941Sume	if (!ip6_forwarding && ip6_accept_rtadv) /* XXX: better condition? */
57353541Sshin		rt6_flush(&dr->rtaddr, dr->ifp);
57453541Sshin
575151539Ssuz	if (dr->installed) {
576151539Ssuz		deldr = dr;
577151539Ssuz		defrouter_delreq(dr);
578151539Ssuz	}
57962587Sitojun	TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
58053541Sshin
58153541Sshin	/*
58253541Sshin	 * Also delete all the pointers to the router in each prefix lists.
58353541Sshin	 */
58462587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
58553541Sshin		struct nd_pfxrouter *pfxrtr;
58653541Sshin		if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
58753541Sshin			pfxrtr_del(pfxrtr);
58853541Sshin	}
58953541Sshin	pfxlist_onlink_check();
59053541Sshin
59153541Sshin	/*
59262587Sitojun	 * If the router is the primary one, choose a new one.
59362587Sitojun	 * Note that defrouter_select() will remove the current gateway
59462587Sitojun	 * from the routing table.
59553541Sshin	 */
59653541Sshin	if (deldr)
59762587Sitojun		defrouter_select();
59862587Sitojun
59953541Sshin	free(dr, M_IP6NDP);
60053541Sshin}
60153541Sshin
60262587Sitojun/*
603151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and
604151539Ssuz * draft-ietf-ipngwg-router-selection:
605151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred.
606151539Ssuz *    If we have more than one (probably) reachable router, prefer ones
607151539Ssuz *    with the highest router preference.
60862587Sitojun * 2) When no routers on the list are known to be reachable or
60962587Sitojun *    probably reachable, routers SHOULD be selected in a round-robin
610151539Ssuz *    fashion, regardless of router preference values.
61162587Sitojun * 3) If the Default Router List is empty, assume that all
61262587Sitojun *    destinations are on-link.
613151539Ssuz *
614151539Ssuz * We assume nd_defrouter is sorted by router preference value.
615151539Ssuz * Since the code below covers both with and without router preference cases,
616151539Ssuz * we do not need to classify the cases by ifdef.
617151539Ssuz *
618151539Ssuz * At this moment, we do not try to install more than one default router,
619151539Ssuz * even when the multipath routing is available, because we're not sure about
620151539Ssuz * the benefits for stub hosts comparing to the risk of making the code
621151539Ssuz * complicated and the possibility of introducing bugs.
62262587Sitojun */
62362587Sitojunvoid
62462587Sitojundefrouter_select()
62562587Sitojun{
62662587Sitojun	int s = splnet();
627151539Ssuz	struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
62862587Sitojun	struct rtentry *rt = NULL;
62962587Sitojun	struct llinfo_nd6 *ln = NULL;
63062587Sitojun
63162587Sitojun	/*
632151539Ssuz	 * This function should be called only when acting as an autoconfigured
633151539Ssuz	 * host.  Although the remaining part of this function is not effective
634151539Ssuz	 * if the node is not an autoconfigured host, we explicitly exclude
635151539Ssuz	 * such cases here for safety.
636151539Ssuz	 */
637151539Ssuz	if (ip6_forwarding || !ip6_accept_rtadv) {
638151539Ssuz		nd6log((LOG_WARNING,
639151539Ssuz		    "defrouter_select: called unexpectedly (forwarding=%d, "
640151539Ssuz		    "accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv));
641151539Ssuz		splx(s);
642151539Ssuz		return;
643151539Ssuz	}
644151539Ssuz
645151539Ssuz	/*
646151539Ssuz	 * Let's handle easy case (3) first:
647151539Ssuz	 * If default router list is empty, there's nothing to be done.
648151539Ssuz	 */
649151539Ssuz	if (!TAILQ_FIRST(&nd_defrouter)) {
650151539Ssuz		splx(s);
651151539Ssuz		return;
652151539Ssuz	}
653151539Ssuz
654151539Ssuz	/*
65562587Sitojun	 * Search for a (probably) reachable router from the list.
656151539Ssuz	 * We just pick up the first reachable one (if any), assuming that
657151539Ssuz	 * the ordering rule of the list described in defrtrlist_update().
65862587Sitojun	 */
65962587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
66062587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
661151539Ssuz		if (selected_dr == NULL &&
662151539Ssuz		    (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
66362587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
66462587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln)) {
665151539Ssuz			selected_dr = dr;
66662587Sitojun		}
66762587Sitojun
668151539Ssuz		if (dr->installed && installed_dr == NULL)
669151539Ssuz			installed_dr = dr;
670151539Ssuz		else if (dr->installed && installed_dr) {
671151539Ssuz			/* this should not happen.  warn for diagnosis. */
672151539Ssuz			log(LOG_ERR, "defrouter_select: more than one router"
673151539Ssuz			    " is installed\n");
67462587Sitojun		}
67562587Sitojun	}
676151539Ssuz	/*
677151539Ssuz	 * If none of the default routers was found to be reachable,
678151539Ssuz	 * round-robin the list regardless of preference.
679151539Ssuz	 * Otherwise, if we have an installed router, check if the selected
680151539Ssuz	 * (reachable) router should really be preferred to the installed one.
681151539Ssuz	 * We only prefer the new router when the old one is not reachable
682151539Ssuz	 * or when the new one has a really higher preference value.
683151539Ssuz	 */
684151539Ssuz	if (selected_dr == NULL) {
685151539Ssuz		if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry))
686151539Ssuz			selected_dr = TAILQ_FIRST(&nd_defrouter);
687151539Ssuz		else
688151539Ssuz			selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
689151539Ssuz	} else if (installed_dr &&
690151539Ssuz	    (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) &&
691151539Ssuz	    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
692151539Ssuz	    ND6_IS_LLINFO_PROBREACH(ln) &&
693151539Ssuz	    rtpref(selected_dr) <= rtpref(installed_dr)) {
694151539Ssuz		selected_dr = installed_dr;
695151539Ssuz	}
69662587Sitojun
697151539Ssuz	/*
698151539Ssuz	 * If the selected router is different than the installed one,
699151539Ssuz	 * remove the installed router and install the selected one.
700151539Ssuz	 * Note that the selected router is never NULL here.
701151539Ssuz	 */
702151539Ssuz	if (installed_dr != selected_dr) {
703151539Ssuz		if (installed_dr)
704151539Ssuz			defrouter_delreq(installed_dr);
705151539Ssuz		defrouter_addreq(selected_dr);
706151539Ssuz	}
707151539Ssuz
70862587Sitojun	splx(s);
70962587Sitojun	return;
71062587Sitojun}
71162587Sitojun
712151539Ssuz/*
713151539Ssuz * for default router selection
714151539Ssuz * regards router-preference field as a 2-bit signed integer
715151539Ssuz */
716151539Ssuzstatic int
717151539Ssuzrtpref(struct nd_defrouter *dr)
718151539Ssuz{
719151539Ssuz	switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) {
720151539Ssuz	case ND_RA_FLAG_RTPREF_HIGH:
721151539Ssuz		return (RTPREF_HIGH);
722151539Ssuz	case ND_RA_FLAG_RTPREF_MEDIUM:
723151539Ssuz		return (RTPREF_MEDIUM);
724151539Ssuz	case ND_RA_FLAG_RTPREF_RSV:
725151539Ssuz		return (RTPREF_RESERVED);
726151539Ssuz	case ND_RA_FLAG_RTPREF_LOW:
727151539Ssuz		return (RTPREF_LOW);
728151539Ssuz	default:
729151539Ssuz		/*
730151539Ssuz		 * This case should never happen.  If it did, it would mean a
731151539Ssuz		 * serious bug of kernel internal.  We thus always bark here.
732151539Ssuz		 * Or, can we even panic?
733151539Ssuz		 */
734151539Ssuz		log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags);
735151539Ssuz		return (RTPREF_INVALID);
736151539Ssuz	}
737151539Ssuz	/* NOTREACHED */
738151539Ssuz}
739151539Ssuz
74053541Sshinstatic struct nd_defrouter *
74153541Sshindefrtrlist_update(new)
74253541Sshin	struct nd_defrouter *new;
74353541Sshin{
74453541Sshin	struct nd_defrouter *dr, *n;
74553541Sshin	int s = splnet();
74653541Sshin
74753541Sshin	if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
74853541Sshin		/* entry exists */
74953541Sshin		if (new->rtlifetime == 0) {
75053541Sshin			defrtrlist_del(dr);
75153541Sshin			dr = NULL;
75253541Sshin		} else {
753151539Ssuz			int oldpref = rtpref(dr);
754151539Ssuz
75553541Sshin			/* override */
75653541Sshin			dr->flags = new->flags; /* xxx flag check */
75753541Sshin			dr->rtlifetime = new->rtlifetime;
75853541Sshin			dr->expire = new->expire;
759151539Ssuz
760151539Ssuz			/*
761151539Ssuz			 * If the preference does not change, there's no need
762151539Ssuz			 * to sort the entries.
763151539Ssuz			 */
764151539Ssuz			if (rtpref(new) == oldpref) {
765151539Ssuz				splx(s);
766151539Ssuz				return (dr);
767151539Ssuz			}
768151539Ssuz
769151539Ssuz			/*
770151539Ssuz			 * preferred router may be changed, so relocate
771151539Ssuz			 * this router.
772151539Ssuz			 * XXX: calling TAILQ_REMOVE directly is a bad manner.
773151539Ssuz			 * However, since defrtrlist_del() has many side
774151539Ssuz			 * effects, we intentionally do so here.
775151539Ssuz			 * defrouter_select() below will handle routing
776151539Ssuz			 * changes later.
777151539Ssuz			 */
778151539Ssuz			TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
779151539Ssuz			n = dr;
780151539Ssuz			goto insert;
78153541Sshin		}
78253541Sshin		splx(s);
783120856Sume		return (dr);
78453541Sshin	}
78553541Sshin
78653541Sshin	/* entry does not exist */
78753541Sshin	if (new->rtlifetime == 0) {
78853541Sshin		splx(s);
789120856Sume		return (NULL);
79053541Sshin	}
79153541Sshin
79253541Sshin	n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
79353541Sshin	if (n == NULL) {
79453541Sshin		splx(s);
795120856Sume		return (NULL);
79653541Sshin	}
79753541Sshin	bzero(n, sizeof(*n));
79853541Sshin	*n = *new;
79962587Sitojun
800151539Ssuzinsert:
80162587Sitojun	/*
802151539Ssuz	 * Insert the new router in the Default Router List;
803151539Ssuz	 * The Default Router List should be in the descending order
804151539Ssuz	 * of router-preferece.  Routers with the same preference are
805151539Ssuz	 * sorted in the arriving time order.
80662587Sitojun	 */
807151539Ssuz
808151539Ssuz	/* insert at the end of the group */
809151539Ssuz	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
810151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry)) {
811151539Ssuz		if (rtpref(n) > rtpref(dr))
812151539Ssuz			break;
813151539Ssuz	}
814151539Ssuz	if (dr)
815151539Ssuz		TAILQ_INSERT_BEFORE(dr, n, dr_entry);
816151539Ssuz	else
817151539Ssuz		TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
818151539Ssuz
819151539Ssuz	defrouter_select();
820151539Ssuz
82153541Sshin	splx(s);
822120941Sume
823120856Sume	return (n);
82453541Sshin}
82553541Sshin
82653541Sshinstatic struct nd_pfxrouter *
82753541Sshinpfxrtr_lookup(pr, dr)
82853541Sshin	struct nd_prefix *pr;
82953541Sshin	struct nd_defrouter *dr;
83053541Sshin{
83153541Sshin	struct nd_pfxrouter *search;
832120941Sume
83362587Sitojun	for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
83453541Sshin		if (search->router == dr)
83553541Sshin			break;
83653541Sshin	}
83753541Sshin
838120856Sume	return (search);
83953541Sshin}
84053541Sshin
84153541Sshinstatic void
84253541Sshinpfxrtr_add(pr, dr)
84353541Sshin	struct nd_prefix *pr;
84453541Sshin	struct nd_defrouter *dr;
84553541Sshin{
84653541Sshin	struct nd_pfxrouter *new;
84753541Sshin
84853541Sshin	new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
84953541Sshin	if (new == NULL)
85053541Sshin		return;
85153541Sshin	bzero(new, sizeof(*new));
85253541Sshin	new->router = dr;
85353541Sshin
85453541Sshin	LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
85553541Sshin
85653541Sshin	pfxlist_onlink_check();
85753541Sshin}
85853541Sshin
85953541Sshinstatic void
86053541Sshinpfxrtr_del(pfr)
86153541Sshin	struct nd_pfxrouter *pfr;
86253541Sshin{
86353541Sshin	LIST_REMOVE(pfr, pfr_entry);
86453541Sshin	free(pfr, M_IP6NDP);
86553541Sshin}
86653541Sshin
86778064Sumestruct nd_prefix *
868151539Ssuznd6_prefix_lookup(key)
869151539Ssuz	struct nd_prefixctl *key;
87053541Sshin{
87153541Sshin	struct nd_prefix *search;
87253541Sshin
87362587Sitojun	for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
874151539Ssuz		if (key->ndpr_ifp == search->ndpr_ifp &&
875151539Ssuz		    key->ndpr_plen == search->ndpr_plen &&
876151539Ssuz		    in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr,
877151539Ssuz		    &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) {
87853541Sshin			break;
87953541Sshin		}
88053541Sshin	}
88153541Sshin
882120856Sume	return (search);
88353541Sshin}
88453541Sshin
88578064Sumeint
88678064Sumend6_prelist_add(pr, dr, newp)
887151539Ssuz	struct nd_prefixctl *pr;
888151539Ssuz	struct nd_prefix **newp;
88953541Sshin	struct nd_defrouter *dr;
89053541Sshin{
89178064Sume	struct nd_prefix *new = NULL;
892151539Ssuz	int error = 0;
89353541Sshin	int i, s;
89453541Sshin
89553541Sshin	new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
89653541Sshin	if (new == NULL)
897120941Sume		return(ENOMEM);
89853541Sshin	bzero(new, sizeof(*new));
899151539Ssuz	new->ndpr_ifp = pr->ndpr_ifp;
900151539Ssuz	new->ndpr_prefix = pr->ndpr_prefix;
901151539Ssuz	new->ndpr_plen = pr->ndpr_plen;
902151539Ssuz	new->ndpr_vltime = pr->ndpr_vltime;
903151539Ssuz	new->ndpr_pltime = pr->ndpr_pltime;
904151539Ssuz	new->ndpr_flags = pr->ndpr_flags;
905151539Ssuz	if ((error = in6_init_prefix_ltimes(new)) != 0) {
906151539Ssuz		free(new, M_IP6NDP);
907151539Ssuz		return(error);
908151539Ssuz	}
909151539Ssuz	new->ndpr_lastupdate = time_second;
91078064Sume	if (newp != NULL)
91178064Sume		*newp = new;
91253541Sshin
913120941Sume	/* initialization */
91453541Sshin	LIST_INIT(&new->ndpr_advrtrs);
91553541Sshin	in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
91653541Sshin	/* make prefix in the canonical form */
91753541Sshin	for (i = 0; i < 4; i++)
91853541Sshin		new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
919120941Sume		    new->ndpr_mask.s6_addr32[i];
92053541Sshin
92153541Sshin	s = splnet();
92253541Sshin	/* link ndpr_entry to nd_prefix list */
92353541Sshin	LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
92453541Sshin	splx(s);
92553541Sshin
92678064Sume	/* ND_OPT_PI_FLAG_ONLINK processing */
92778064Sume	if (new->ndpr_raf_onlink) {
92878064Sume		int e;
92978064Sume
93078064Sume		if ((e = nd6_prefix_onlink(new)) != 0) {
93178064Sume			nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
93278064Sume			    "the prefix %s/%d on-link on %s (errno=%d)\n",
93378064Sume			    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
93478064Sume			    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
93578064Sume			/* proceed anyway. XXX: is it correct? */
93678064Sume		}
93778064Sume	}
93878064Sume
939120941Sume	if (dr)
94053541Sshin		pfxrtr_add(new, dr);
94153541Sshin
94253541Sshin	return 0;
94353541Sshin}
94453541Sshin
94553541Sshinvoid
94653541Sshinprelist_remove(pr)
94753541Sshin	struct nd_prefix *pr;
94853541Sshin{
94953541Sshin	struct nd_pfxrouter *pfr, *next;
95078064Sume	int e, s;
95153541Sshin
95278064Sume	/* make sure to invalidate the prefix until it is really freed. */
95378064Sume	pr->ndpr_vltime = 0;
95478064Sume	pr->ndpr_pltime = 0;
955151539Ssuz
95678064Sume	/*
95778064Sume	 * Though these flags are now meaningless, we'd rather keep the value
958151479Ssuz	 * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users
959151479Ssuz	 * when executing "ndp -p".
96078064Sume	 */
961151479Ssuz
96278064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
96378064Sume	    (e = nd6_prefix_offlink(pr)) != 0) {
96478064Sume		nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
96578064Sume		    "on %s, errno=%d\n",
96678064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
96778064Sume		    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
96878064Sume		/* what should we do? */
96978064Sume	}
97078064Sume
97178064Sume	if (pr->ndpr_refcnt > 0)
97278064Sume		return;		/* notice here? */
97378064Sume
97453541Sshin	s = splnet();
97578064Sume
97653541Sshin	/* unlink ndpr_entry from nd_prefix list */
97753541Sshin	LIST_REMOVE(pr, ndpr_entry);
97853541Sshin
97953541Sshin	/* free list of routers that adversed the prefix */
98062587Sitojun	for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
98162587Sitojun		next = pfr->pfr_next;
98253541Sshin
98353541Sshin		free(pfr, M_IP6NDP);
98453541Sshin	}
98578064Sume	splx(s);
98678064Sume
98753541Sshin	free(pr, M_IP6NDP);
98853541Sshin
98953541Sshin	pfxlist_onlink_check();
99053541Sshin}
99153541Sshin
992151539Ssuzstatic int
993151539Ssuzprelist_update(new, dr, m, mcast)
994151539Ssuz	struct nd_prefixctl *new;
99553541Sshin	struct nd_defrouter *dr; /* may be NULL */
99653541Sshin	struct mbuf *m;
997151539Ssuz	int mcast;
99853541Sshin{
99978064Sume	struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
100078064Sume	struct ifaddr *ifa;
100178064Sume	struct ifnet *ifp = new->ndpr_ifp;
100253541Sshin	struct nd_prefix *pr;
100353541Sshin	int s = splnet();
100453541Sshin	int error = 0;
100578064Sume	int newprefix = 0;
100653541Sshin	int auth;
100778064Sume	struct in6_addrlifetime lt6_tmp;
100853541Sshin
100953541Sshin	auth = 0;
101053541Sshin	if (m) {
101153541Sshin		/*
101253541Sshin		 * Authenticity for NA consists authentication for
101353541Sshin		 * both IP header and IP datagrams, doesn't it ?
101453541Sshin		 */
101553541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
1016120941Sume		auth = ((m->m_flags & M_AUTHIPHDR) &&
1017120941Sume		    (m->m_flags & M_AUTHIPDGM));
101853541Sshin#endif
101953541Sshin	}
102053541Sshin
102178064Sume	if ((pr = nd6_prefix_lookup(new)) != NULL) {
102278064Sume		/*
102378064Sume		 * nd6_prefix_lookup() ensures that pr and new have the same
102478064Sume		 * prefix on a same interface.
102578064Sume		 */
102653541Sshin
102753541Sshin		/*
102878064Sume		 * Update prefix information.  Note that the on-link (L) bit
102978064Sume		 * and the autonomous (A) bit should NOT be changed from 1
103078064Sume		 * to 0.
103153541Sshin		 */
103278064Sume		if (new->ndpr_raf_onlink == 1)
103378064Sume			pr->ndpr_raf_onlink = 1;
103478064Sume		if (new->ndpr_raf_auto == 1)
103578064Sume			pr->ndpr_raf_auto = 1;
103678064Sume		if (new->ndpr_raf_onlink) {
103778064Sume			pr->ndpr_vltime = new->ndpr_vltime;
103878064Sume			pr->ndpr_pltime = new->ndpr_pltime;
1039151539Ssuz			(void)in6_init_prefix_ltimes(pr); /* XXX error case? */
1040151539Ssuz			pr->ndpr_lastupdate = time_second;
104178064Sume		}
104253541Sshin
104378064Sume		if (new->ndpr_raf_onlink &&
104478064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
104578064Sume			int e;
104653541Sshin
104778064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
104878064Sume				nd6log((LOG_ERR,
104978064Sume				    "prelist_update: failed to make "
105078064Sume				    "the prefix %s/%d on-link on %s "
105178064Sume				    "(errno=%d)\n",
105278064Sume				    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
105378064Sume				    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
105478064Sume				/* proceed anyway. XXX: is it correct? */
105553541Sshin			}
105678064Sume		}
105753541Sshin
105878064Sume		if (dr && pfxrtr_lookup(pr, dr) == NULL)
105978064Sume			pfxrtr_add(pr, dr);
106078064Sume	} else {
106178064Sume		struct nd_prefix *newpr = NULL;
106253541Sshin
106378064Sume		newprefix = 1;
106453541Sshin
106578064Sume		if (new->ndpr_vltime == 0)
106678064Sume			goto end;
106778064Sume		if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
106878064Sume			goto end;
106953541Sshin
107078064Sume		error = nd6_prelist_add(new, dr, &newpr);
107178064Sume		if (error != 0 || newpr == NULL) {
107278064Sume			nd6log((LOG_NOTICE, "prelist_update: "
107378064Sume			    "nd6_prelist_add failed for %s/%d on %s "
107478064Sume			    "errno=%d, returnpr=%p\n",
107578064Sume			    ip6_sprintf(&new->ndpr_prefix.sin6_addr),
1076120941Sume			    new->ndpr_plen, if_name(new->ndpr_ifp),
1077120941Sume			    error, newpr));
107878064Sume			goto end; /* we should just give up in this case. */
107978064Sume		}
108053541Sshin
108178064Sume		/*
108278064Sume		 * XXX: from the ND point of view, we can ignore a prefix
108378064Sume		 * with the on-link bit being zero.  However, we need a
108478064Sume		 * prefix structure for references from autoconfigured
1085120941Sume		 * addresses.  Thus, we explicitly make sure that the prefix
108678064Sume		 * itself expires now.
108778064Sume		 */
108878064Sume		if (newpr->ndpr_raf_onlink == 0) {
108978064Sume			newpr->ndpr_vltime = 0;
109078064Sume			newpr->ndpr_pltime = 0;
109178064Sume			in6_init_prefix_ltimes(newpr);
109253541Sshin		}
109353541Sshin
109478064Sume		pr = newpr;
109578064Sume	}
109653541Sshin
109778064Sume	/*
109878064Sume	 * Address autoconfiguration based on Section 5.5.3 of RFC 2462.
109978064Sume	 * Note that pr must be non NULL at this point.
110078064Sume	 */
110162587Sitojun
110278064Sume	/* 5.5.3 (a). Ignore the prefix without the A bit set. */
110378064Sume	if (!new->ndpr_raf_auto)
1104151539Ssuz		goto end;
110562587Sitojun
110678064Sume	/*
110778064Sume	 * 5.5.3 (b). the link-local prefix should have been ignored in
110878064Sume	 * nd6_ra_input.
110978064Sume	 */
111062587Sitojun
1111151539Ssuz	/* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */
1112151539Ssuz	if (new->ndpr_pltime > new->ndpr_vltime) {
1113151539Ssuz		error = EINVAL;	/* XXX: won't be used */
1114151539Ssuz		goto end;
1115151539Ssuz	}
111662587Sitojun
111778064Sume 	/*
1118151539Ssuz	 * 5.5.3 (d).  If the prefix advertised is not equal to the prefix of
1119151539Ssuz	 * an address configured by stateless autoconfiguration already in the
1120151539Ssuz	 * list of addresses associated with the interface, and the Valid
1121151539Ssuz	 * Lifetime is not 0, form an address.  We first check if we have
1122151539Ssuz	 * a matching prefix.
1123151539Ssuz	 * Note: we apply a clarification in rfc2462bis-02 here.  We only
1124151539Ssuz	 * consider autoconfigured addresses while RFC2462 simply said
1125151539Ssuz	 * "address".
112678064Sume	 */
1127120941Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
112878064Sume		struct in6_ifaddr *ifa6;
1129151539Ssuz		u_int32_t remaininglifetime;
113053541Sshin
113178064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
113278064Sume			continue;
113353541Sshin
113478064Sume		ifa6 = (struct in6_ifaddr *)ifa;
113553541Sshin
113653541Sshin		/*
1137151539Ssuz		 * We only consider autoconfigured addresses as per rfc2462bis.
1138151539Ssuz		 */
1139151539Ssuz		if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF))
1140151539Ssuz			continue;
1141151539Ssuz
1142151539Ssuz		/*
114378064Sume		 * Spec is not clear here, but I believe we should concentrate
114478064Sume		 * on unicast (i.e. not anycast) addresses.
114578064Sume		 * XXX: other ia6_flags? detached or duplicated?
114653541Sshin		 */
114778064Sume		if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
114878064Sume			continue;
1149120941Sume
1150151539Ssuz		/*
1151151539Ssuz		 * Ignore the address if it is not associated with a prefix
1152151539Ssuz		 * or is associated with a prefix that is different from this
1153151539Ssuz		 * one.  (pr is never NULL here)
1154151539Ssuz		 */
1155151539Ssuz		if (ifa6->ia6_ndpr != pr)
115678064Sume			continue;
115753541Sshin
115878064Sume		if (ia6_match == NULL) /* remember the first one */
115978064Sume			ia6_match = ifa6;
116078064Sume
116178064Sume		/*
116278064Sume		 * An already autoconfigured address matched.  Now that we
116378064Sume		 * are sure there is at least one matched address, we can
116478064Sume		 * proceed to 5.5.3. (e): update the lifetimes according to the
116578064Sume		 * "two hours" rule and the privacy extension.
1166151539Ssuz		 * We apply some clarifications in rfc2462bis:
1167151539Ssuz		 * - use remaininglifetime instead of storedlifetime as a
1168151539Ssuz		 *   variable name
1169151539Ssuz		 * - remove the dead code in the "two-hour" rule
117078064Sume		 */
117178064Sume#define TWOHOUR		(120*60)
117278064Sume		lt6_tmp = ifa6->ia6_lifetime;
117378064Sume
1174112678Sume		if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME)
1175151539Ssuz			remaininglifetime = ND6_INFINITE_LIFETIME;
1176151539Ssuz		else if (time_second - ifa6->ia6_updatetime >
1177151539Ssuz			 lt6_tmp.ia6t_vltime) {
1178151539Ssuz			/*
1179151539Ssuz			 * The case of "invalid" address.  We should usually
1180151539Ssuz			 * not see this case.
1181151539Ssuz			 */
1182151539Ssuz			remaininglifetime = 0;
1183151539Ssuz		} else
1184151539Ssuz			remaininglifetime = lt6_tmp.ia6t_vltime -
1185151539Ssuz			    (time_second - ifa6->ia6_updatetime);
118678064Sume
1187112678Sume		/* when not updating, keep the current stored lifetime. */
1188151539Ssuz		lt6_tmp.ia6t_vltime = remaininglifetime;
1189112678Sume
119078064Sume		if (TWOHOUR < new->ndpr_vltime ||
1191151539Ssuz		    remaininglifetime < new->ndpr_vltime) {
119278064Sume			lt6_tmp.ia6t_vltime = new->ndpr_vltime;
1193151539Ssuz		} else if (remaininglifetime <= TWOHOUR) {
119478064Sume			if (auth) {
119578064Sume				lt6_tmp.ia6t_vltime = new->ndpr_vltime;
119678064Sume			}
119778064Sume		} else {
119878064Sume			/*
119978064Sume			 * new->ndpr_vltime <= TWOHOUR &&
1200151539Ssuz			 * TWOHOUR < remaininglifetime
120178064Sume			 */
120278064Sume			lt6_tmp.ia6t_vltime = TWOHOUR;
120353541Sshin		}
120453541Sshin
120578064Sume		/* The 2 hour rule is not imposed for preferred lifetime. */
120678064Sume		lt6_tmp.ia6t_pltime = new->ndpr_pltime;
120753541Sshin
120878064Sume		in6_init_address_ltimes(pr, &lt6_tmp);
120953541Sshin
1210151539Ssuz  		/*
1211151539Ssuz		 * We need to treat lifetimes for temporary addresses
1212151539Ssuz		 * differently, according to
1213151539Ssuz		 * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1);
1214151539Ssuz		 * we only update the lifetimes when they are in the maximum
1215151539Ssuz		 * intervals.
1216151539Ssuz  		 */
1217151539Ssuz  		if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
1218151539Ssuz			u_int32_t maxvltime, maxpltime;
1219151539Ssuz
1220151539Ssuz			if (ip6_temp_valid_lifetime >
1221151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1222151539Ssuz			    ip6_desync_factor)) {
1223151539Ssuz				maxvltime = ip6_temp_valid_lifetime -
1224151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1225151539Ssuz				    ip6_desync_factor;
1226151539Ssuz			} else
1227151539Ssuz				maxvltime = 0;
1228151539Ssuz			if (ip6_temp_preferred_lifetime >
1229151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1230151539Ssuz			    ip6_desync_factor)) {
1231151539Ssuz				maxpltime = ip6_temp_preferred_lifetime -
1232151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1233151539Ssuz				    ip6_desync_factor;
1234151539Ssuz			} else
1235151539Ssuz				maxpltime = 0;
1236151539Ssuz
1237151539Ssuz			if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME ||
1238151539Ssuz			    lt6_tmp.ia6t_vltime > maxvltime) {
1239151539Ssuz				lt6_tmp.ia6t_vltime = maxvltime;
124078064Sume			}
1241151539Ssuz			if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME ||
1242151539Ssuz			    lt6_tmp.ia6t_pltime > maxpltime) {
1243151539Ssuz				lt6_tmp.ia6t_pltime = maxpltime;
124478064Sume			}
124578064Sume		}
124678064Sume		ifa6->ia6_lifetime = lt6_tmp;
1247151539Ssuz		ifa6->ia6_updatetime = time_second;
124853541Sshin	}
124978064Sume	if (ia6_match == NULL && new->ndpr_vltime) {
1250151539Ssuz		int ifidlen;
1251151539Ssuz
125278064Sume		/*
1253151539Ssuz		 * 5.5.3 (d) (continued)
125478064Sume		 * No address matched and the valid lifetime is non-zero.
125578064Sume		 * Create a new address.
125678064Sume		 */
1257151539Ssuz
1258151539Ssuz		/*
1259151539Ssuz		 * Prefix Length check:
1260151539Ssuz		 * If the sum of the prefix length and interface identifier
1261151539Ssuz		 * length does not equal 128 bits, the Prefix Information
1262151539Ssuz		 * option MUST be ignored.  The length of the interface
1263151539Ssuz		 * identifier is defined in a separate link-type specific
1264151539Ssuz		 * document.
1265151539Ssuz		 */
1266151539Ssuz		ifidlen = in6_if2idlen(ifp);
1267151539Ssuz		if (ifidlen < 0) {
1268151539Ssuz			/* this should not happen, so we always log it. */
1269151539Ssuz			log(LOG_ERR, "prelist_update: IFID undefined (%s)\n",
1270151539Ssuz			    if_name(ifp));
1271151539Ssuz			goto end;
1272151539Ssuz		}
1273151539Ssuz		if (ifidlen + pr->ndpr_plen != 128) {
1274151539Ssuz			nd6log((LOG_INFO,
1275151539Ssuz			    "prelist_update: invalid prefixlen "
1276151539Ssuz			    "%d for %s, ignored\n",
1277151539Ssuz			    pr->ndpr_plen, if_name(ifp)));
1278151539Ssuz			goto end;
1279151539Ssuz		}
1280151539Ssuz
1281151539Ssuz		if ((ia6 = in6_ifadd(new, mcast)) != NULL) {
128278064Sume			/*
128378064Sume			 * note that we should use pr (not new) for reference.
128478064Sume			 */
128578064Sume			pr->ndpr_refcnt++;
128678064Sume			ia6->ia6_ndpr = pr;
128753541Sshin
128878064Sume			/*
128978064Sume			 * RFC 3041 3.3 (2).
129078064Sume			 * When a new public address is created as described
129178064Sume			 * in RFC2462, also create a new temporary address.
129278064Sume			 *
129378064Sume			 * RFC 3041 3.5.
129478064Sume			 * When an interface connects to a new link, a new
129578064Sume			 * randomized interface identifier should be generated
129678064Sume			 * immediately together with a new set of temporary
129778064Sume			 * addresses.  Thus, we specifiy 1 as the 2nd arg of
129878064Sume			 * in6_tmpifadd().
129978064Sume			 */
130078064Sume			if (ip6_use_tempaddr) {
130178064Sume				int e;
1302151539Ssuz				if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) {
130378064Sume					nd6log((LOG_NOTICE, "prelist_update: "
130478064Sume					    "failed to create a temporary "
130578064Sume					    "address, errno=%d\n",
130678064Sume					    e));
130778064Sume				}
130878064Sume			}
130978064Sume
131078064Sume			/*
131178064Sume			 * A newly added address might affect the status
131278064Sume			 * of other addresses, so we check and update it.
131378064Sume			 * XXX: what if address duplication happens?
131478064Sume			 */
131578064Sume			pfxlist_onlink_check();
131678064Sume		} else {
131778064Sume			/* just set an error. do not bark here. */
131878064Sume			error = EADDRNOTAVAIL; /* XXX: might be unused. */
131978064Sume		}
132078064Sume	}
132178064Sume
132253541Sshin end:
132353541Sshin	splx(s);
132453541Sshin	return error;
132553541Sshin}
132653541Sshin
132753541Sshin/*
132862587Sitojun * A supplement function used in the on-link detection below;
132962587Sitojun * detect if a given prefix has a (probably) reachable advertising router.
133062587Sitojun * XXX: lengthy function name...
133162587Sitojun */
133278064Sumestatic struct nd_pfxrouter *
133362587Sitojunfind_pfxlist_reachable_router(pr)
133462587Sitojun	struct nd_prefix *pr;
133562587Sitojun{
133662587Sitojun	struct nd_pfxrouter *pfxrtr;
133762587Sitojun	struct rtentry *rt;
133862587Sitojun	struct llinfo_nd6 *ln;
133962587Sitojun
134062587Sitojun	for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
134162587Sitojun	     pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
134262587Sitojun		if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
1343120941Sume		    pfxrtr->router->ifp)) &&
134462587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
134562587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln))
134662587Sitojun			break;	/* found */
134762587Sitojun	}
134862587Sitojun
1349120856Sume	return (pfxrtr);
135062587Sitojun}
135162587Sitojun
135262587Sitojun/*
135353541Sshin * Check if each prefix in the prefix list has at least one available router
135478064Sume * that advertised the prefix (a router is "available" if its neighbor cache
135578064Sume * entry is reachable or probably reachable).
135662587Sitojun * If the check fails, the prefix may be off-link, because, for example,
135753541Sshin * we have moved from the network but the lifetime of the prefix has not
135878064Sume * expired yet.  So we should not use the prefix if there is another prefix
135978064Sume * that has an available router.
136078064Sume * But, if there is no prefix that has an available router, we still regards
136178064Sume * all the prefixes as on-link.  This is because we can't tell if all the
136253541Sshin * routers are simply dead or if we really moved from the network and there
136353541Sshin * is no router around us.
136453541Sshin */
136562587Sitojunvoid
136653541Sshinpfxlist_onlink_check()
136753541Sshin{
136853541Sshin	struct nd_prefix *pr;
136978064Sume	struct in6_ifaddr *ifa;
1370151539Ssuz	struct nd_defrouter *dr;
1371151539Ssuz	struct nd_pfxrouter *pfxrtr = NULL;
137253541Sshin
137362587Sitojun	/*
137462587Sitojun	 * Check if there is a prefix that has a reachable advertising
137562587Sitojun	 * router.
137662587Sitojun	 */
137762587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
137878064Sume		if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
137953541Sshin			break;
138062587Sitojun	}
138153541Sshin
1382151539Ssuz	/*
1383151539Ssuz	 * If we have no such prefix, check whether we still have a router
1384151539Ssuz	 * that does not advertise any prefixes.
1385151539Ssuz	 */
1386151465Ssuz	if (pr == NULL) {
1387151539Ssuz		for (dr = TAILQ_FIRST(&nd_defrouter); dr;
1388151539Ssuz		    dr = TAILQ_NEXT(dr, dr_entry)) {
1389151539Ssuz			struct nd_prefix *pr0;
1390151539Ssuz
1391151539Ssuz			for (pr0 = nd_prefix.lh_first; pr0;
1392151539Ssuz			    pr0 = pr0->ndpr_next) {
1393151539Ssuz				if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL)
1394151539Ssuz					break;
1395151539Ssuz			}
1396151539Ssuz			if (pfxrtr != NULL)
1397151539Ssuz				break;
1398151539Ssuz		}
1399151539Ssuz	}
1400151539Ssuz	if (pr != NULL || (TAILQ_FIRST(&nd_defrouter) && pfxrtr == NULL)) {
1401151539Ssuz  		/*
1402151539Ssuz		 * There is at least one prefix that has a reachable router,
1403151539Ssuz		 * or at least a router which probably does not advertise
1404151539Ssuz		 * any prefixes.  The latter would be the case when we move
1405151539Ssuz		 * to a new link where we have a router that does not provide
1406151539Ssuz		 * prefixes and we configure an address by hand.
1407151539Ssuz  		 * Detach prefixes which have no reachable advertising
1408151539Ssuz  		 * router, and attach other prefixes.
1409151539Ssuz  		 */
141062587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
141178064Sume			/* XXX: a link-local prefix should never be detached */
141278064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
141378064Sume				continue;
141478064Sume
141578064Sume			/*
141678064Sume			 * we aren't interested in prefixes without the L bit
141778064Sume			 * set.
141878064Sume			 */
141978064Sume			if (pr->ndpr_raf_onlink == 0)
142078064Sume				continue;
142178064Sume
142278064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
142378064Sume			    find_pfxlist_reachable_router(pr) == NULL)
142478064Sume				pr->ndpr_stateflags |= NDPRF_DETACHED;
142578064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
142678064Sume			    find_pfxlist_reachable_router(pr) != 0)
142778064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
142853541Sshin		}
142978064Sume	} else {
143078064Sume		/* there is no prefix that has a reachable router */
143162587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
143278064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
143378064Sume				continue;
143478064Sume
143578064Sume			if (pr->ndpr_raf_onlink == 0)
143678064Sume				continue;
143778064Sume
143878064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
143978064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
144053541Sshin		}
144162587Sitojun	}
144278064Sume
144378064Sume	/*
144478064Sume	 * Remove each interface route associated with a (just) detached
144578064Sume	 * prefix, and reinstall the interface route for a (just) attached
144678064Sume	 * prefix.  Note that all attempt of reinstallation does not
144778064Sume	 * necessarily success, when a same prefix is shared among multiple
144878064Sume	 * interfaces.  Such cases will be handled in nd6_prefix_onlink,
144978064Sume	 * so we don't have to care about them.
145078064Sume	 */
145178064Sume	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
145278064Sume		int e;
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",
146678064Sume				    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
146778064Sume				    pr->ndpr_plen, e));
146878064Sume			}
146978064Sume		}
147078064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
147178064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
147278064Sume		    pr->ndpr_raf_onlink) {
147378064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
147478064Sume				nd6log((LOG_ERR,
147578064Sume				    "pfxlist_onlink_check: failed to "
1476151479Ssuz				    "make %s/%d onlink, errno=%d\n",
147778064Sume				    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
147878064Sume				    pr->ndpr_plen, e));
147978064Sume			}
148078064Sume		}
148178064Sume	}
148278064Sume
148378064Sume	/*
148478064Sume	 * Changes on the prefix status might affect address status as well.
148578064Sume	 * Make sure that all addresses derived from an attached prefix are
148678064Sume	 * attached, and that all addresses derived from a detached prefix are
148778064Sume	 * detached.  Note, however, that a manually configured address should
148878064Sume	 * always be attached.
148978064Sume	 * The precise detection logic is same as the one for prefixes.
149078064Sume	 */
149178064Sume	for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
1492120941Sume		if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
149378064Sume			continue;
149478064Sume
149578064Sume		if (ifa->ia6_ndpr == NULL) {
149678064Sume			/*
149778064Sume			 * This can happen when we first configure the address
149878064Sume			 * (i.e. the address exists, but the prefix does not).
149978064Sume			 * XXX: complicated relationships...
150078064Sume			 */
150178064Sume			continue;
150278064Sume		}
150378064Sume
150478064Sume		if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
150578064Sume			break;
150678064Sume	}
150778064Sume	if (ifa) {
150878064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
150978064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
151078064Sume				continue;
151178064Sume
151278064Sume			if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
151378064Sume				continue;
151478064Sume
1515151539Ssuz			if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) {
1516151539Ssuz				if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1517151539Ssuz					ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1518151539Ssuz					ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1519151539Ssuz					nd6_dad_start((struct ifaddr *)ifa, 0);
1520151539Ssuz				}
1521151539Ssuz			} else {
152278064Sume				ifa->ia6_flags |= IN6_IFF_DETACHED;
1523151539Ssuz			}
152478064Sume		}
152578064Sume	}
152662587Sitojun	else {
152778064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
152878064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
152978064Sume				continue;
153078064Sume
1531151539Ssuz			if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1532151539Ssuz				ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1533151539Ssuz				ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1534151539Ssuz				/* Do we need a delay in this case? */
1535151539Ssuz				nd6_dad_start((struct ifaddr *)ifa, 0);
1536151539Ssuz			}
153778064Sume		}
153853541Sshin	}
153953541Sshin}
154053541Sshin
154178064Sumeint
154278064Sumend6_prefix_onlink(pr)
154353541Sshin	struct nd_prefix *pr;
154453541Sshin{
154578064Sume	struct ifaddr *ifa;
154678064Sume	struct ifnet *ifp = pr->ndpr_ifp;
154778064Sume	struct sockaddr_in6 mask6;
154878064Sume	struct nd_prefix *opr;
154978064Sume	u_long rtflags;
155078064Sume	int error = 0;
155178064Sume	struct rtentry *rt = NULL;
155253541Sshin
155378064Sume	/* sanity check */
155478064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
155578064Sume		nd6log((LOG_ERR,
155678064Sume		    "nd6_prefix_onlink: %s/%d is already on-link\n",
1557151465Ssuz		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen));
1558151465Ssuz		return (EEXIST);
155978064Sume	}
156078064Sume
156153541Sshin	/*
156278064Sume	 * Add the interface route associated with the prefix.  Before
156378064Sume	 * installing the route, check if there's the same prefix on another
156478064Sume	 * interface, and the prefix has already installed the interface route.
156578064Sume	 * Although such a configuration is expected to be rare, we explicitly
156678064Sume	 * allow it.
156753541Sshin	 */
156878064Sume	for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
156978064Sume		if (opr == pr)
157078064Sume			continue;
157178064Sume
157278064Sume		if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
157378064Sume			continue;
157478064Sume
157578064Sume		if (opr->ndpr_plen == pr->ndpr_plen &&
157678064Sume		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1577120941Sume		    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen))
1578120856Sume			return (0);
157978064Sume	}
158078064Sume
158178064Sume	/*
1582120941Sume	 * We prefer link-local addresses as the associated interface address.
158378064Sume	 */
158478064Sume	/* search for a link-local addr */
158578064Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
1586120941Sume	    IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
158778064Sume	if (ifa == NULL) {
158878064Sume		/* XXX: freebsd does not have ifa_ifwithaf */
1589120941Sume		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
159078064Sume			if (ifa->ifa_addr->sa_family == AF_INET6)
159178064Sume				break;
159278064Sume		}
159378064Sume		/* should we care about ia6_flags? */
159478064Sume	}
159578064Sume	if (ifa == NULL) {
159678064Sume		/*
159778064Sume		 * This can still happen, when, for example, we receive an RA
159878064Sume		 * containing a prefix with the L bit set and the A bit clear,
159978064Sume		 * after removing all IPv6 addresses on the receiving
160078064Sume		 * interface.  This should, of course, be rare though.
160178064Sume		 */
160278064Sume		nd6log((LOG_NOTICE,
160378064Sume		    "nd6_prefix_onlink: failed to find any ifaddr"
160478064Sume		    " to add route for a prefix(%s/%d) on %s\n",
160578064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
160678064Sume		    pr->ndpr_plen, if_name(ifp)));
1607120856Sume		return (0);
160878064Sume	}
160978064Sume
161078064Sume	/*
161178064Sume	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
161278064Sume	 * ifa->ifa_rtrequest = nd6_rtrequest;
161378064Sume	 */
161478064Sume	bzero(&mask6, sizeof(mask6));
161578064Sume	mask6.sin6_len = sizeof(mask6);
161678064Sume	mask6.sin6_addr = pr->ndpr_mask;
161778064Sume	rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP;
161878064Sume	if (nd6_need_cache(ifp)) {
161978064Sume		/* explicitly set in case ifa_flags does not set the flag. */
162078064Sume		rtflags |= RTF_CLONING;
162178064Sume	} else {
162278064Sume		/*
162378064Sume		 * explicitly clear the cloning bit in case ifa_flags sets it.
162478064Sume		 */
162578064Sume		rtflags &= ~RTF_CLONING;
162678064Sume	}
162778064Sume	error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
1628120941Sume	    ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
162978064Sume	if (error == 0) {
163078064Sume		if (rt != NULL) /* this should be non NULL, though */
163178064Sume			nd6_rtmsg(RTM_ADD, rt);
163278064Sume		pr->ndpr_stateflags |= NDPRF_ONLINK;
1633120941Sume	} else {
163478064Sume		nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
163578064Sume		    " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
163678064Sume		    "errno = %d\n",
163778064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
163878064Sume		    pr->ndpr_plen, if_name(ifp),
163978064Sume		    ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
164078064Sume		    ip6_sprintf(&mask6.sin6_addr), rtflags, error));
164178064Sume	}
164278064Sume
1643120727Ssam	if (rt != NULL) {
1644120727Ssam		RT_LOCK(rt);
1645122334Ssam		RT_REMREF(rt);
1646120727Ssam		RT_UNLOCK(rt);
1647120727Ssam	}
164878064Sume
1649120856Sume	return (error);
165078064Sume}
165178064Sume
165278064Sumeint
165378064Sumend6_prefix_offlink(pr)
165478064Sume	struct nd_prefix *pr;
165578064Sume{
165678064Sume	int error = 0;
165778064Sume	struct ifnet *ifp = pr->ndpr_ifp;
165878064Sume	struct nd_prefix *opr;
165978064Sume	struct sockaddr_in6 sa6, mask6;
166078064Sume	struct rtentry *rt = NULL;
166178064Sume
166278064Sume	/* sanity check */
166378064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
166478064Sume		nd6log((LOG_ERR,
166578064Sume		    "nd6_prefix_offlink: %s/%d is already off-link\n",
166678064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen));
1667120856Sume		return (EEXIST);
166878064Sume	}
166978064Sume
167053541Sshin	bzero(&sa6, sizeof(sa6));
167153541Sshin	sa6.sin6_family = AF_INET6;
167253541Sshin	sa6.sin6_len = sizeof(sa6);
167353541Sshin	bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
1674120941Sume	    sizeof(struct in6_addr));
167553541Sshin	bzero(&mask6, sizeof(mask6));
167653541Sshin	mask6.sin6_family = AF_INET6;
167753541Sshin	mask6.sin6_len = sizeof(sa6);
167853541Sshin	bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
167978064Sume	error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
1680120941Sume	    (struct sockaddr *)&mask6, 0, &rt);
168178064Sume	if (error == 0) {
168278064Sume		pr->ndpr_stateflags &= ~NDPRF_ONLINK;
168353541Sshin
168478064Sume		/* report the route deletion to the routing socket. */
168578064Sume		if (rt != NULL)
168678064Sume			nd6_rtmsg(RTM_DELETE, rt);
168753541Sshin
168878064Sume		/*
168978064Sume		 * There might be the same prefix on another interface,
169078064Sume		 * the prefix which could not be on-link just because we have
169178064Sume		 * the interface route (see comments in nd6_prefix_onlink).
169278064Sume		 * If there's one, try to make the prefix on-link on the
169378064Sume		 * interface.
169478064Sume		 */
169578064Sume		for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
169678064Sume			if (opr == pr)
169778064Sume				continue;
169853541Sshin
169978064Sume			if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
170078064Sume				continue;
170153541Sshin
170278064Sume			/*
170378064Sume			 * KAME specific: detached prefixes should not be
170478064Sume			 * on-link.
170578064Sume			 */
170678064Sume			if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
170778064Sume				continue;
170878064Sume
170978064Sume			if (opr->ndpr_plen == pr->ndpr_plen &&
171078064Sume			    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1711120941Sume			    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
171278064Sume				int e;
171378064Sume
171478064Sume				if ((e = nd6_prefix_onlink(opr)) != 0) {
171578064Sume					nd6log((LOG_ERR,
171678064Sume					    "nd6_prefix_offlink: failed to "
171778064Sume					    "recover a prefix %s/%d from %s "
171878064Sume					    "to %s (errno = %d)\n",
171978064Sume					    ip6_sprintf(&opr->ndpr_prefix.sin6_addr),
172078064Sume					    opr->ndpr_plen, if_name(ifp),
172178064Sume					    if_name(opr->ndpr_ifp), e));
172278064Sume				}
172378064Sume			}
172478064Sume		}
1725120941Sume	} else {
172678064Sume		/* XXX: can we still set the NDPRF_ONLINK flag? */
172778064Sume		nd6log((LOG_ERR,
172878064Sume		    "nd6_prefix_offlink: failed to delete route: "
172978064Sume		    "%s/%d on %s (errno = %d)\n",
173078064Sume		    ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp),
173178064Sume		    error));
173278064Sume	}
173353541Sshin
1734120941Sume	if (rt != NULL) {
1735108269Sru		RTFREE(rt);
1736120941Sume	}
173753541Sshin
1738120856Sume	return (error);
173953541Sshin}
174053541Sshin
174153541Sshinstatic struct in6_ifaddr *
1742151539Ssuzin6_ifadd(pr, mcast)
1743151539Ssuz	struct nd_prefixctl *pr;
1744151539Ssuz	int mcast;
174553541Sshin{
174678064Sume	struct ifnet *ifp = pr->ndpr_ifp;
174753541Sshin	struct ifaddr *ifa;
174878064Sume	struct in6_aliasreq ifra;
174978064Sume	struct in6_ifaddr *ia, *ib;
175078064Sume	int error, plen0;
175153541Sshin	struct in6_addr mask;
175278064Sume	int prefixlen = pr->ndpr_plen;
1753151539Ssuz	int updateflags;
175453541Sshin
1755121168Sume	in6_prefixlen2mask(&mask, prefixlen);
175653541Sshin
175778064Sume	/*
175878064Sume	 * find a link-local address (will be interface ID).
175978064Sume	 * Is it really mandatory? Theoretically, a global or a site-local
176078064Sume	 * address can be configured without a link-local address, if we
176178064Sume	 * have a unique interface identifier...
176278064Sume	 *
176378064Sume	 * it is not mandatory to have a link-local address, we can generate
176478064Sume	 * interface identifier on the fly.  we do this because:
176578064Sume	 * (1) it should be the easiest way to find interface identifier.
176678064Sume	 * (2) RFC2462 5.4 suggesting the use of the same interface identifier
176778064Sume	 * for multiple addresses on a single interface, and possible shortcut
176878064Sume	 * of DAD.  we omitted DAD for this reason in the past.
1769120941Sume	 * (3) a user can prevent autoconfiguration of global address
177078064Sume	 * by removing link-local address by hand (this is partly because we
1771108533Sschweikh	 * don't have other way to control the use of IPv6 on an interface.
177278064Sume	 * this has been our design choice - cf. NRL's "ifconfig auto").
177378064Sume	 * (4) it is easier to manage when an interface has addresses
177478064Sume	 * with the same interface identifier, than to have multiple addresses
177578064Sume	 * with different interface identifiers.
177678064Sume	 */
1777120941Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
177853541Sshin	if (ifa)
177953541Sshin		ib = (struct in6_ifaddr *)ifa;
178053541Sshin	else
178153541Sshin		return NULL;
178253541Sshin
178353541Sshin	/* prefixlen + ifidlen must be equal to 128 */
178478064Sume	plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
178578064Sume	if (prefixlen != plen0) {
178678064Sume		nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
178778064Sume		    "(prefix=%d ifid=%d)\n",
178878064Sume		    if_name(ifp), prefixlen, 128 - plen0));
178953541Sshin		return NULL;
179053541Sshin	}
179153541Sshin
179253541Sshin	/* make ifaddr */
179353541Sshin
179478064Sume	bzero(&ifra, sizeof(ifra));
179578064Sume	/*
179678064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
179778064Sume	 * for safety.
179878064Sume	 */
179978064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
180078064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
180178064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
180278064Sume	/* prefix */
1803151539Ssuz	ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr;
180478064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
180578064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
180678064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
180778064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
180853541Sshin
180953541Sshin	/* interface ID */
1810120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
1811151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
1812120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
1813151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
1814120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1815151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
1816120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1817151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
1818120941Sume
181978064Sume	/* new prefix mask. */
182078064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
182178064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
182278064Sume	bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
1823120941Sume	    sizeof(ifra.ifra_prefixmask.sin6_addr));
182453541Sshin
1825151539Ssuz	/* lifetimes. */
182678064Sume	ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
182778064Sume	ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
182853541Sshin
182978064Sume	/* XXX: scope zone ID? */
183053541Sshin
183178064Sume	ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
1832151539Ssuz
1833151539Ssuz  	/*
1834151539Ssuz	 * Make sure that we do not have this address already.  This should
1835151539Ssuz	 * usually not happen, but we can still see this case, e.g., if we
1836151539Ssuz	 * have manually configured the exact address to be configured.
183778064Sume	 */
1838151539Ssuz	if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
1839151539Ssuz		/* this should be rare enough to make an explicit log */
1840151539Ssuz		log(LOG_INFO, "in6_ifadd: %s is already configured\n",
1841151539Ssuz		    ip6_sprintf(&ifra.ifra_addr.sin6_addr));
1842151539Ssuz		return (NULL);
1843151539Ssuz	}
184453541Sshin
184553541Sshin	/*
1846151539Ssuz	 * Allocate ifaddr structure, link into chain, etc.
1847151539Ssuz	 * If we are going to create a new address upon receiving a multicasted
1848151539Ssuz	 * RA, we need to impose a random delay before starting DAD.
1849151539Ssuz	 * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2]
185053541Sshin	 */
1851151539Ssuz	updateflags = 0;
1852151539Ssuz	if (mcast)
1853151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1854151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) {
185578064Sume		nd6log((LOG_ERR,
185678064Sume		    "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
185778064Sume		    ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp),
185878064Sume		    error));
1859120856Sume		return (NULL);	/* ifaddr must not have been allocated. */
186053541Sshin	}
186153541Sshin
186278064Sume	ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
186353541Sshin
1864120941Sume	return (ia);		/* this is always non-NULL */
186553541Sshin}
186653541Sshin
186753541Sshinint
1868151539Ssuzin6_tmpifadd(ia0, forcegen, delay)
186978064Sume	const struct in6_ifaddr *ia0; /* corresponding public address */
1870151539Ssuz	int forcegen, delay;
187153541Sshin{
187278064Sume	struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
1873151539Ssuz	struct in6_ifaddr *newia, *ia;
187478064Sume	struct in6_aliasreq ifra;
187578064Sume	int i, error;
187678064Sume	int trylimit = 3;	/* XXX: adhoc value */
1877151539Ssuz	int updateflags;
187878064Sume	u_int32_t randid[2];
187978064Sume	time_t vltime0, pltime0;
188053541Sshin
188178064Sume	bzero(&ifra, sizeof(ifra));
188278064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
188378064Sume	ifra.ifra_addr = ia0->ia_addr;
188478064Sume	/* copy prefix mask */
188578064Sume	ifra.ifra_prefixmask = ia0->ia_prefixmask;
188678064Sume	/* clear the old IFID */
188778064Sume	for (i = 0; i < 4; i++) {
1888120941Sume		ifra.ifra_addr.sin6_addr.s6_addr32[i] &=
1889120941Sume		    ifra.ifra_prefixmask.sin6_addr.s6_addr32[i];
189078064Sume	}
189153541Sshin
189278064Sume  again:
1893151539Ssuz	if (in6_get_tmpifid(ifp, (u_int8_t *)randid,
1894151539Ssuz	    (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) {
1895151539Ssuz		nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good "
1896151539Ssuz		    "random IFID\n"));
1897151539Ssuz		return (EINVAL);
1898151539Ssuz	}
1899120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1900120941Sume	    (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2]));
1901120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1902120941Sume	    (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3]));
190353541Sshin
1904151539Ssuz  	/*
1905151539Ssuz	 * in6_get_tmpifid() quite likely provided a unique interface ID.
1906151539Ssuz	 * However, we may still have a chance to see collision, because
1907151539Ssuz	 * there may be a time lag between generation of the ID and generation
1908151539Ssuz	 * of the address.  So, we'll do one more sanity check.
190978064Sume	 */
1910151539Ssuz	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
1911151539Ssuz		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
1912151539Ssuz		    &ifra.ifra_addr.sin6_addr)) {
1913151539Ssuz  			if (trylimit-- == 0) {
1914151539Ssuz				/*
1915151539Ssuz				 * Give up.  Something strange should have
1916151539Ssuz				 * happened.
1917151539Ssuz				 */
1918151539Ssuz				nd6log((LOG_NOTICE, "in6_tmpifadd: failed to "
1919151539Ssuz				    "find a unique random IFID\n"));
1920151539Ssuz				return (EEXIST);
1921151539Ssuz			}
1922151539Ssuz			forcegen = 1;
1923151539Ssuz			goto again;
192478064Sume		}
192553541Sshin	}
192653541Sshin
192778064Sume	/*
192878064Sume	 * The Valid Lifetime is the lower of the Valid Lifetime of the
192978064Sume         * public address or TEMP_VALID_LIFETIME.
193078064Sume	 * The Preferred Lifetime is the lower of the Preferred Lifetime
193178064Sume         * of the public address or TEMP_PREFERRED_LIFETIME -
193278064Sume         * DESYNC_FACTOR.
193378064Sume	 */
1934151539Ssuz	if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
193578064Sume		vltime0 = IFA6_IS_INVALID(ia0) ? 0 :
1936151539Ssuz		    (ia0->ia6_lifetime.ia6t_vltime -
1937151539Ssuz		    (time_second - ia0->ia6_updatetime));
193878064Sume		if (vltime0 > ip6_temp_valid_lifetime)
193978064Sume			vltime0 = ip6_temp_valid_lifetime;
194078064Sume	} else
194178064Sume		vltime0 = ip6_temp_valid_lifetime;
1942151539Ssuz	if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
194378064Sume		pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 :
1944151539Ssuz		    (ia0->ia6_lifetime.ia6t_pltime -
1945151539Ssuz		    (time_second - ia0->ia6_updatetime));
194678064Sume		if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){
194778064Sume			pltime0 = ip6_temp_preferred_lifetime -
1948120941Sume			    ip6_desync_factor;
194978064Sume		}
195078064Sume	} else
195178064Sume		pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor;
195278064Sume	ifra.ifra_lifetime.ia6t_vltime = vltime0;
195378064Sume	ifra.ifra_lifetime.ia6t_pltime = pltime0;
195453541Sshin
195578064Sume	/*
195678064Sume	 * A temporary address is created only if this calculated Preferred
195778064Sume	 * Lifetime is greater than REGEN_ADVANCE time units.
195878064Sume	 */
195978064Sume	if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance)
1960120856Sume		return (0);
196153541Sshin
196278064Sume	/* XXX: scope zone ID? */
196378064Sume
196478064Sume	ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
196578064Sume
196678064Sume	/* allocate ifaddr structure, link into chain, etc. */
1967151539Ssuz	updateflags = 0;
1968151539Ssuz	if (delay)
1969151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1970151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0)
1971120856Sume		return (error);
197278064Sume
197378064Sume	newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
197478064Sume	if (newia == NULL) {	/* XXX: can it happen? */
197578064Sume		nd6log((LOG_ERR,
197678064Sume		    "in6_tmpifadd: ifa update succeeded, but we got "
197778064Sume		    "no ifaddr\n"));
1978120856Sume		return (EINVAL); /* XXX */
197953541Sshin	}
198078064Sume	newia->ia6_ndpr = ia0->ia6_ndpr;
198178064Sume	newia->ia6_ndpr->ndpr_refcnt++;
198253541Sshin
198378407Sume	/*
198478407Sume	 * A newly added address might affect the status of other addresses.
198578407Sume	 * XXX: when the temporary address is generated with a new public
198678407Sume	 * address, the onlink check is redundant.  However, it would be safe
198778407Sume	 * to do the check explicitly everywhere a new address is generated,
198878407Sume	 * and, in fact, we surely need the check when we create a new
198978407Sume	 * temporary address due to deprecation of an old temporary address.
199078407Sume	 */
199178407Sume	pfxlist_onlink_check();
199278407Sume
1993120856Sume	return (0);
1994120941Sume}
199553541Sshin
1996151539Ssuzstatic int
199753541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr)
199853541Sshin{
199953541Sshin	if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
200053541Sshin		ndpr->ndpr_preferred = 0;
200153541Sshin	else
200253541Sshin		ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
200353541Sshin	if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
200453541Sshin		ndpr->ndpr_expire = 0;
200553541Sshin	else
200653541Sshin		ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
200753541Sshin
200853541Sshin	return 0;
200953541Sshin}
201053541Sshin
201153541Sshinstatic void
201278064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
201353541Sshin{
201478064Sume	/* init ia6t_expire */
201578064Sume	if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
201678064Sume		lt6->ia6t_expire = 0;
201778064Sume	else {
201878064Sume		lt6->ia6t_expire = time_second;
201978064Sume		lt6->ia6t_expire += lt6->ia6t_vltime;
202053541Sshin	}
202162587Sitojun
202253541Sshin	/* init ia6t_preferred */
202353541Sshin	if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
202453541Sshin		lt6->ia6t_preferred = 0;
202553541Sshin	else {
202653541Sshin		lt6->ia6t_preferred = time_second;
202753541Sshin		lt6->ia6t_preferred += lt6->ia6t_pltime;
202853541Sshin	}
202953541Sshin}
203053541Sshin
203153541Sshin/*
203253541Sshin * Delete all the routing table entries that use the specified gateway.
203353541Sshin * XXX: this function causes search through all entries of routing table, so
203453541Sshin * it shouldn't be called when acting as a router.
203553541Sshin */
203653541Sshinvoid
203753541Sshinrt6_flush(gateway, ifp)
203878064Sume	struct in6_addr *gateway;
203978064Sume	struct ifnet *ifp;
204053541Sshin{
204153541Sshin	struct radix_node_head *rnh = rt_tables[AF_INET6];
204253541Sshin	int s = splnet();
204353541Sshin
204453541Sshin	/* We'll care only link-local addresses */
204553541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
204653541Sshin		splx(s);
204753541Sshin		return;
204853541Sshin	}
204953541Sshin
2050108250Shsu	RADIX_NODE_HEAD_LOCK(rnh);
205153541Sshin	rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
2052108250Shsu	RADIX_NODE_HEAD_UNLOCK(rnh);
205353541Sshin	splx(s);
205453541Sshin}
205553541Sshin
205653541Sshinstatic int
205753541Sshinrt6_deleteroute(rn, arg)
205853541Sshin	struct radix_node *rn;
205953541Sshin	void *arg;
206053541Sshin{
206153541Sshin#define SIN6(s)	((struct sockaddr_in6 *)s)
206253541Sshin	struct rtentry *rt = (struct rtentry *)rn;
206353541Sshin	struct in6_addr *gate = (struct in6_addr *)arg;
206453541Sshin
206553541Sshin	if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
2066120856Sume		return (0);
206753541Sshin
2068120941Sume	if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) {
2069120856Sume		return (0);
2070120941Sume	}
207153541Sshin
207253541Sshin	/*
207378064Sume	 * Do not delete a static route.
207478064Sume	 * XXX: this seems to be a bit ad-hoc. Should we consider the
207578064Sume	 * 'cloned' bit instead?
207678064Sume	 */
207778064Sume	if ((rt->rt_flags & RTF_STATIC) != 0)
2078120856Sume		return (0);
207978064Sume
208078064Sume	/*
208153541Sshin	 * We delete only host route. This means, in particular, we don't
208253541Sshin	 * delete default route.
208353541Sshin	 */
208453541Sshin	if ((rt->rt_flags & RTF_HOST) == 0)
2085120856Sume		return (0);
208653541Sshin
2087120941Sume	return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
2088120941Sume	    rt_mask(rt), rt->rt_flags, 0));
208953541Sshin#undef SIN6
209053541Sshin}
209162587Sitojun
209262587Sitojunint
209362587Sitojunnd6_setdefaultiface(ifindex)
209462587Sitojun	int ifindex;
209562587Sitojun{
209662587Sitojun	int error = 0;
209762587Sitojun
209862587Sitojun	if (ifindex < 0 || if_index < ifindex)
2099120856Sume		return (EINVAL);
2100151539Ssuz	if (ifindex != 0 && !ifnet_byindex(ifindex))
2101151539Ssuz		return (EINVAL);
210262587Sitojun
210362587Sitojun	if (nd6_defifindex != ifindex) {
210462587Sitojun		nd6_defifindex = ifindex;
210562587Sitojun		if (nd6_defifindex > 0)
210683130Sjlemon			nd6_defifp = ifnet_byindex(nd6_defifindex);
210762587Sitojun		else
210862587Sitojun			nd6_defifp = NULL;
210962587Sitojun
211062587Sitojun		/*
211162587Sitojun		 * Our current implementation assumes one-to-one maping between
211262587Sitojun		 * interfaces and links, so it would be natural to use the
211362587Sitojun		 * default interface as the default link.
211462587Sitojun		 */
211562587Sitojun		scope6_setdefault(nd6_defifp);
211662587Sitojun	}
211762587Sitojun
2118120856Sume	return (error);
211962587Sitojun}
2120