nd6_rtr.c revision 128397
162587Sitojun/*	$FreeBSD: head/sys/netinet6/nd6_rtr.c 128397 2004-04-18 11:45:28Z luigi $	*/
278064Sume/*	$KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $	*/
362587Sitojun
453541Sshin/*
553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
653541Sshin * All rights reserved.
753541Sshin *
853541Sshin * Redistribution and use in source and binary forms, with or without
953541Sshin * modification, are permitted provided that the following conditions
1053541Sshin * are met:
1153541Sshin * 1. Redistributions of source code must retain the above copyright
1253541Sshin *    notice, this list of conditions and the following disclaimer.
1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1453541Sshin *    notice, this list of conditions and the following disclaimer in the
1553541Sshin *    documentation and/or other materials provided with the distribution.
1653541Sshin * 3. Neither the name of the project nor the names of its contributors
1753541Sshin *    may be used to endorse or promote products derived from this software
1853541Sshin *    without specific prior written permission.
1953541Sshin *
2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2353541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3053541Sshin * SUCH DAMAGE.
3153541Sshin */
3253541Sshin
3362587Sitojun#include "opt_inet.h"
3462587Sitojun#include "opt_inet6.h"
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
6762587Sitojunstatic struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
6878064Sumestatic struct in6_ifaddr *in6_ifadd __P((struct nd_prefix *,
6978064Sume	struct in6_addr *));
7062587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
7178064Sume	struct nd_defrouter *));
7262587Sitojunstatic void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
7362587Sitojunstatic void pfxrtr_del __P((struct nd_pfxrouter *));
7462587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router
7578064Sume	__P((struct nd_prefix *));
7662587Sitojunstatic void defrouter_addifreq __P((struct ifnet *));
7778064Sumestatic void nd6_rtmsg __P((int, struct rtentry *));
7853541Sshin
79120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *,
80120941Sume	struct in6_addrlifetime *));
8153541Sshin
8262587Sitojunstatic int rt6_deleteroute __P((struct radix_node *, void *));
8353541Sshin
8462587Sitojunextern int nd6_recalc_reachtm_interval;
8553541Sshin
8678064Sumestatic struct ifnet *nd6_defifp;
8762587Sitojunint nd6_defifindex;
8862587Sitojun
8978064Sumeint ip6_use_tempaddr = 0;
9078064Sume
9178064Sumeint ip6_desync_factor;
9278064Sumeu_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME;
9378064Sumeu_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME;
9453541Sshin/*
9578064Sume * shorter lifetimes for debugging purposes.
9678064Sumeint ip6_temp_preferred_lifetime = 800;
9778064Sumestatic int ip6_temp_valid_lifetime = 1800;
9878064Sume*/
9978064Sumeint ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE;
10078064Sume
10178064Sume/*
10253541Sshin * Receive Router Solicitation Message - just for routers.
10353541Sshin * Router solicitation/advertisement is mostly managed by userland program
10453541Sshin * (rtadvd) so here we have no function like nd6_ra_output().
10553541Sshin *
10653541Sshin * Based on RFC 2461
10753541Sshin */
10853541Sshinvoid
10953541Sshinnd6_rs_input(m, off, icmp6len)
11053541Sshin	struct	mbuf *m;
11153541Sshin	int off, icmp6len;
11253541Sshin{
11353541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
11453541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
11562587Sitojun	struct nd_router_solicit *nd_rs;
11653541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
11753541Sshin	char *lladdr = NULL;
11853541Sshin	int lladdrlen = 0;
11962587Sitojun#if 0
12062587Sitojun	struct sockaddr_dl *sdl = (struct sockaddr_dl *)NULL;
12162587Sitojun	struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL;
12262587Sitojun	struct rtentry *rt = NULL;
12362587Sitojun	int is_newentry;
12462587Sitojun#endif
12553541Sshin	union nd_opts ndopts;
12653541Sshin
12753541Sshin	/* If I'm not a router, ignore it. */
12853541Sshin	if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
12962587Sitojun		goto freeit;
13053541Sshin
13153541Sshin	/* Sanity checks */
13253541Sshin	if (ip6->ip6_hlim != 255) {
13378064Sume		nd6log((LOG_ERR,
13478064Sume		    "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
13578064Sume		    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
13678064Sume		    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
13778064Sume		goto bad;
13853541Sshin	}
13953541Sshin
14053541Sshin	/*
14153541Sshin	 * Don't update the neighbor cache, if src = ::.
14253541Sshin	 * This indicates that the src has no IP address assigned yet.
14353541Sshin	 */
14453541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
14562587Sitojun		goto freeit;
14662587Sitojun
14762587Sitojun#ifndef PULLDOWN_TEST
14862587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
14962587Sitojun	nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
15062587Sitojun#else
15162587Sitojun	IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
15262587Sitojun	if (nd_rs == NULL) {
15362587Sitojun		icmp6stat.icp6s_tooshort++;
15453541Sshin		return;
15562587Sitojun	}
15662587Sitojun#endif
15753541Sshin
15853541Sshin	icmp6len -= sizeof(*nd_rs);
15953541Sshin	nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
16053541Sshin	if (nd6_options(&ndopts) < 0) {
16178064Sume		nd6log((LOG_INFO,
16278064Sume		    "nd6_rs_input: invalid ND option, ignored\n"));
16378064Sume		/* nd6_options have incremented stats */
16462587Sitojun		goto freeit;
16553541Sshin	}
16653541Sshin
16753541Sshin	if (ndopts.nd_opts_src_lladdr) {
16853541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
16953541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
17053541Sshin	}
17153541Sshin
17253541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
17378064Sume		nd6log((LOG_INFO,
17453541Sshin		    "nd6_rs_input: lladdrlen mismatch for %s "
17553541Sshin		    "(if %d, RS packet %d)\n",
176120941Sume		    ip6_sprintf(&saddr6),
177120941Sume		    ifp->if_addrlen, lladdrlen - 2));
17878064Sume		goto bad;
17953541Sshin	}
18053541Sshin
18153541Sshin	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
18262587Sitojun
18362587Sitojun freeit:
18462587Sitojun	m_freem(m);
18578064Sume	return;
18678064Sume
18778064Sume bad:
18878064Sume	icmp6stat.icp6s_badrs++;
18978064Sume	m_freem(m);
19053541Sshin}
19153541Sshin
19253541Sshin/*
19353541Sshin * Receive Router Advertisement Message.
19453541Sshin *
19553541Sshin * Based on RFC 2461
19653541Sshin * TODO: on-link bit on prefix information
19753541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
19853541Sshin */
19953541Sshinvoid
20053541Sshinnd6_ra_input(m, off, icmp6len)
20153541Sshin	struct	mbuf *m;
20253541Sshin	int off, icmp6len;
20353541Sshin{
20453541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
205121161Sume	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
20653541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
20762587Sitojun	struct nd_router_advert *nd_ra;
20853541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
20962587Sitojun#if 0
21062587Sitojun	struct in6_addr daddr6 = ip6->ip6_dst;
21162587Sitojun	int flags; /* = nd_ra->nd_ra_flags_reserved; */
21262587Sitojun	int is_managed = ((flags & ND_RA_FLAG_MANAGED) != 0);
21362587Sitojun	int is_other = ((flags & ND_RA_FLAG_OTHER) != 0);
21462587Sitojun#endif
21553541Sshin	union nd_opts ndopts;
21653541Sshin	struct nd_defrouter *dr;
21753541Sshin
218118498Sume	/*
219118498Sume	 * We only accept RAs only when
220118498Sume	 * the system-wide variable allows the acceptance, and
221118498Sume	 * per-interface variable allows RAs on the receiving interface.
222118498Sume	 */
22353541Sshin	if (ip6_accept_rtadv == 0)
22462587Sitojun		goto freeit;
225118498Sume	if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
226118498Sume		goto freeit;
22753541Sshin
22853541Sshin	if (ip6->ip6_hlim != 255) {
22978064Sume		nd6log((LOG_ERR,
23078064Sume		    "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
23178064Sume		    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
23278064Sume		    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
23378064Sume		goto bad;
23453541Sshin	}
23553541Sshin
23653541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
23778064Sume		nd6log((LOG_ERR,
23853541Sshin		    "nd6_ra_input: src %s is not link-local\n",
23978064Sume		    ip6_sprintf(&saddr6)));
24078064Sume		goto bad;
24162587Sitojun	}
24262587Sitojun
24362587Sitojun#ifndef PULLDOWN_TEST
24462587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
24562587Sitojun	nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
24662587Sitojun#else
24762587Sitojun	IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
24862587Sitojun	if (nd_ra == NULL) {
24962587Sitojun		icmp6stat.icp6s_tooshort++;
25053541Sshin		return;
25153541Sshin	}
25262587Sitojun#endif
25353541Sshin
25453541Sshin	icmp6len -= sizeof(*nd_ra);
25553541Sshin	nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
25653541Sshin	if (nd6_options(&ndopts) < 0) {
25778064Sume		nd6log((LOG_INFO,
25878064Sume		    "nd6_ra_input: invalid ND option, ignored\n"));
25978064Sume		/* nd6_options have incremented stats */
26062587Sitojun		goto freeit;
26153541Sshin	}
26253541Sshin
26353541Sshin    {
26453541Sshin	struct nd_defrouter dr0;
26553541Sshin	u_int32_t advreachable = nd_ra->nd_ra_reachable;
26653541Sshin
26753541Sshin	dr0.rtaddr = saddr6;
26853541Sshin	dr0.flags  = nd_ra->nd_ra_flags_reserved;
26953541Sshin	dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
27053541Sshin	dr0.expire = time_second + dr0.rtlifetime;
27153541Sshin	dr0.ifp = ifp;
27253541Sshin	/* unspecified or not? (RFC 2461 6.3.4) */
27353541Sshin	if (advreachable) {
27490868Smike		advreachable = ntohl(advreachable);
27553541Sshin		if (advreachable <= MAX_REACHABLE_TIME &&
27653541Sshin		    ndi->basereachable != advreachable) {
27753541Sshin			ndi->basereachable = advreachable;
27853541Sshin			ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
27953541Sshin			ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
28053541Sshin		}
28153541Sshin	}
28253541Sshin	if (nd_ra->nd_ra_retransmit)
28353541Sshin		ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
28453541Sshin	if (nd_ra->nd_ra_curhoplimit)
28553541Sshin		ndi->chlim = nd_ra->nd_ra_curhoplimit;
28653541Sshin	dr = defrtrlist_update(&dr0);
28753541Sshin    }
28853541Sshin
28953541Sshin	/*
29053541Sshin	 * prefix
29153541Sshin	 */
29253541Sshin	if (ndopts.nd_opts_pi) {
29353541Sshin		struct nd_opt_hdr *pt;
29478064Sume		struct nd_opt_prefix_info *pi = NULL;
29553541Sshin		struct nd_prefix pr;
29653541Sshin
29753541Sshin		for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
29853541Sshin		     pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
29953541Sshin		     pt = (struct nd_opt_hdr *)((caddr_t)pt +
30053541Sshin						(pt->nd_opt_len << 3))) {
30153541Sshin			if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
30253541Sshin				continue;
30353541Sshin			pi = (struct nd_opt_prefix_info *)pt;
30453541Sshin
30553541Sshin			if (pi->nd_opt_pi_len != 4) {
30678064Sume				nd6log((LOG_INFO,
30778064Sume				    "nd6_ra_input: invalid option "
30878064Sume				    "len %d for prefix information option, "
30978064Sume				    "ignored\n", pi->nd_opt_pi_len));
31053541Sshin				continue;
31153541Sshin			}
31253541Sshin
31353541Sshin			if (128 < pi->nd_opt_pi_prefix_len) {
31478064Sume				nd6log((LOG_INFO,
31578064Sume				    "nd6_ra_input: invalid prefix "
31678064Sume				    "len %d for prefix information option, "
31778064Sume				    "ignored\n", pi->nd_opt_pi_prefix_len));
31853541Sshin				continue;
31953541Sshin			}
32053541Sshin
32153541Sshin			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
32253541Sshin			 || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
32378064Sume				nd6log((LOG_INFO,
32478064Sume				    "nd6_ra_input: invalid prefix "
32578064Sume				    "%s, ignored\n",
32678064Sume				    ip6_sprintf(&pi->nd_opt_pi_prefix)));
32753541Sshin				continue;
32853541Sshin			}
32953541Sshin
33053541Sshin			/* aggregatable unicast address, rfc2374 */
33153541Sshin			if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
33253541Sshin			 && pi->nd_opt_pi_prefix_len != 64) {
33378064Sume				nd6log((LOG_INFO,
33478064Sume				    "nd6_ra_input: invalid prefixlen "
33578064Sume				    "%d for rfc2374 prefix %s, ignored\n",
33678064Sume				    pi->nd_opt_pi_prefix_len,
33778064Sume				    ip6_sprintf(&pi->nd_opt_pi_prefix)));
33853541Sshin				continue;
33953541Sshin			}
34053541Sshin
34153541Sshin			bzero(&pr, sizeof(pr));
34253541Sshin			pr.ndpr_prefix.sin6_family = AF_INET6;
34353541Sshin			pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
34453541Sshin			pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
34553541Sshin			pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
34653541Sshin
34753541Sshin			pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
348120941Sume			    ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
34953541Sshin			pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
350120941Sume			    ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
35153541Sshin			pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
35253541Sshin			pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
353120941Sume			pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time);
35453541Sshin			if (in6_init_prefix_ltimes(&pr))
35553541Sshin				continue; /* prefix lifetime init failed */
35653541Sshin			(void)prelist_update(&pr, dr, m);
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);
45278064Sume	info.rti_info[RTAX_IFP] =
45378064Sume		(struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist);
45478064Sume	info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
45562587Sitojun
45662587Sitojun	rt_missmsg(cmd, &info, rt->rt_flags, 0);
45762587Sitojun}
45862587Sitojun
45953541Sshinvoid
46053541Sshindefrouter_addreq(new)
46153541Sshin	struct nd_defrouter *new;
46253541Sshin{
46353541Sshin	struct sockaddr_in6 def, mask, gate;
46462587Sitojun	struct rtentry *newrt = NULL;
46553541Sshin
466128397Sluigi	bzero(&def, sizeof(def));
467128397Sluigi	bzero(&mask, sizeof(mask));
468128397Sluigi	bzero(&gate, sizeof(gate));
46953541Sshin
470120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
471120941Sume	    sizeof(struct sockaddr_in6);
47253541Sshin	def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
47353541Sshin	gate.sin6_addr = new->rtaddr;
47453541Sshin
47553541Sshin	(void)rtrequest(RTM_ADD, (struct sockaddr *)&def,
476120941Sume	    (struct sockaddr *)&gate, (struct sockaddr *)&mask,
477120941Sume	    RTF_GATEWAY, &newrt);
47862587Sitojun	if (newrt) {
479120727Ssam		RT_LOCK(newrt);
48078064Sume		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
481122334Ssam		RT_REMREF(newrt);
482120727Ssam		RT_UNLOCK(newrt);
48362587Sitojun	}
48453541Sshin	return;
48553541Sshin}
48653541Sshin
48762587Sitojun/* Add a route to a given interface as default */
48862587Sitojunvoid
48962587Sitojundefrouter_addifreq(ifp)
49062587Sitojun	struct ifnet *ifp;
49162587Sitojun{
49262587Sitojun	struct sockaddr_in6 def, mask;
49362587Sitojun	struct ifaddr *ifa;
49462587Sitojun	struct rtentry *newrt = NULL;
49562587Sitojun	int error, flags;
49662587Sitojun
49762587Sitojun	bzero(&def, sizeof(def));
49862587Sitojun	bzero(&mask, sizeof(mask));
49962587Sitojun
50062587Sitojun	def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);
50162587Sitojun	def.sin6_family = mask.sin6_family = AF_INET6;
50262587Sitojun
50362587Sitojun	/*
50462587Sitojun	 * Search for an ifaddr beloging to the specified interface.
50562587Sitojun	 * XXX: An IPv6 address are required to be assigned on the interface.
50662587Sitojun	 */
50762587Sitojun	if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) {
50878064Sume		nd6log((LOG_ERR,	/* better error? */
50962587Sitojun		    "defrouter_addifreq: failed to find an ifaddr "
51062587Sitojun		    "to install a route to interface %s\n",
51178064Sume		    if_name(ifp)));
51262587Sitojun		return;
51362587Sitojun	}
51462587Sitojun
51562587Sitojun	flags = ifa->ifa_flags;
51678064Sume	error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr,
517120941Sume	    (struct sockaddr *)&mask, flags, &newrt);
51878064Sume	if (error != 0) {
51978064Sume		nd6log((LOG_ERR,
52062587Sitojun		    "defrouter_addifreq: failed to install a route to "
52162587Sitojun		    "interface %s (errno = %d)\n",
52278064Sume		    if_name(ifp), error));
52362587Sitojun	} else {
52462587Sitojun		if (newrt) {
525120727Ssam			RT_LOCK(newrt);
52678064Sume			nd6_rtmsg(RTM_ADD, newrt);
527122334Ssam			RT_REMREF(newrt);
528120727Ssam			RT_UNLOCK(newrt);
52962587Sitojun		}
53062587Sitojun	}
53162587Sitojun}
53262587Sitojun
53353541Sshinstruct nd_defrouter *
53453541Sshindefrouter_lookup(addr, ifp)
53553541Sshin	struct in6_addr *addr;
53653541Sshin	struct ifnet *ifp;
53753541Sshin{
53853541Sshin	struct nd_defrouter *dr;
53953541Sshin
54062587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
54162587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
54253541Sshin		if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
543120856Sume			return (dr);
54462587Sitojun	}
54553541Sshin
546120856Sume	return (NULL);		/* search failed */
54753541Sshin}
54853541Sshin
54953541Sshinvoid
55053541Sshindefrouter_delreq(dr, dofree)
55153541Sshin	struct nd_defrouter *dr;
55253541Sshin	int dofree;
55353541Sshin{
55453541Sshin	struct sockaddr_in6 def, mask, gate;
55562587Sitojun	struct rtentry *oldrt = NULL;
55653541Sshin
557128397Sluigi	bzero(&def, sizeof(def));
558128397Sluigi	bzero(&mask, sizeof(mask));
559128397Sluigi	bzero(&gate, sizeof(gate));
56053541Sshin
561120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
562120941Sume	    sizeof(struct sockaddr_in6);
56353541Sshin	def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
56453541Sshin	gate.sin6_addr = dr->rtaddr;
56553541Sshin
56653541Sshin	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
567120941Sume	    (struct sockaddr *)&gate,
568120941Sume	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
56962587Sitojun	if (oldrt) {
57078064Sume		nd6_rtmsg(RTM_DELETE, oldrt);
571108269Sru		RTFREE(oldrt);
57262587Sitojun	}
57353541Sshin
57462587Sitojun	if (dofree)		/* XXX: necessary? */
57553541Sshin		free(dr, M_IP6NDP);
57653541Sshin}
57753541Sshin
57853541Sshinvoid
57953541Sshindefrtrlist_del(dr)
58053541Sshin	struct nd_defrouter *dr;
58153541Sshin{
58253541Sshin	struct nd_defrouter *deldr = NULL;
58353541Sshin	struct nd_prefix *pr;
58453541Sshin
58553541Sshin	/*
58653541Sshin	 * Flush all the routing table entries that use the router
58753541Sshin	 * as a next hop.
58853541Sshin	 */
589120941Sume	if (!ip6_forwarding && ip6_accept_rtadv) /* XXX: better condition? */
59053541Sshin		rt6_flush(&dr->rtaddr, dr->ifp);
59153541Sshin
59262587Sitojun	if (dr == TAILQ_FIRST(&nd_defrouter))
59353541Sshin		deldr = dr;	/* The router is primary. */
59453541Sshin
59562587Sitojun	TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
59653541Sshin
59753541Sshin	/*
59853541Sshin	 * Also delete all the pointers to the router in each prefix lists.
59953541Sshin	 */
60062587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
60153541Sshin		struct nd_pfxrouter *pfxrtr;
60253541Sshin		if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
60353541Sshin			pfxrtr_del(pfxrtr);
60453541Sshin	}
60553541Sshin	pfxlist_onlink_check();
60653541Sshin
60753541Sshin	/*
60862587Sitojun	 * If the router is the primary one, choose a new one.
60962587Sitojun	 * Note that defrouter_select() will remove the current gateway
61062587Sitojun	 * from the routing table.
61153541Sshin	 */
61253541Sshin	if (deldr)
61362587Sitojun		defrouter_select();
61462587Sitojun
61553541Sshin	free(dr, M_IP6NDP);
61653541Sshin}
61753541Sshin
61862587Sitojun/*
61962587Sitojun * Default Router Selection according to Section 6.3.6 of RFC 2461:
62062587Sitojun * 1) Routers that are reachable or probably reachable should be
62162587Sitojun *    preferred.
62262587Sitojun * 2) When no routers on the list are known to be reachable or
62362587Sitojun *    probably reachable, routers SHOULD be selected in a round-robin
62462587Sitojun *    fashion.
62562587Sitojun * 3) If the Default Router List is empty, assume that all
62662587Sitojun *    destinations are on-link.
62762587Sitojun */
62862587Sitojunvoid
62962587Sitojundefrouter_select()
63062587Sitojun{
63162587Sitojun	int s = splnet();
63262587Sitojun	struct nd_defrouter *dr, anydr;
63362587Sitojun	struct rtentry *rt = NULL;
63462587Sitojun	struct llinfo_nd6 *ln = NULL;
63562587Sitojun
63662587Sitojun	/*
63762587Sitojun	 * Search for a (probably) reachable router from the list.
63862587Sitojun	 */
63962587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
64062587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
64162587Sitojun		if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
64262587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
64362587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln)) {
64462587Sitojun			/* Got it, and move it to the head */
64562587Sitojun			TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
64662587Sitojun			TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry);
64762587Sitojun			break;
64862587Sitojun		}
64962587Sitojun	}
65062587Sitojun
65162587Sitojun	if ((dr = TAILQ_FIRST(&nd_defrouter))) {
65262587Sitojun		/*
65362587Sitojun		 * De-install the previous default gateway and install
65462587Sitojun		 * a new one.
65562587Sitojun		 * Note that if there is no reachable router in the list,
65662587Sitojun		 * the head entry will be used anyway.
65762587Sitojun		 * XXX: do we have to check the current routing table entry?
65862587Sitojun		 */
65962587Sitojun		bzero(&anydr, sizeof(anydr));
66062587Sitojun		defrouter_delreq(&anydr, 0);
66162587Sitojun		defrouter_addreq(dr);
66262587Sitojun	}
66362587Sitojun	else {
66462587Sitojun		/*
66562587Sitojun		 * The Default Router List is empty, so install the default
66662587Sitojun		 * route to an inteface.
66762587Sitojun		 * XXX: The specification does not say this mechanism should
66862587Sitojun		 * be restricted to hosts, but this would be not useful
66962587Sitojun		 * (even harmful) for routers.
67062587Sitojun		 */
67162587Sitojun		if (!ip6_forwarding) {
67262587Sitojun			/*
67362587Sitojun			 * De-install the current default route
67462587Sitojun			 * in advance.
67562587Sitojun			 */
67662587Sitojun			bzero(&anydr, sizeof(anydr));
67762587Sitojun			defrouter_delreq(&anydr, 0);
67862587Sitojun			if (nd6_defifp) {
67962587Sitojun				/*
68062587Sitojun				 * Install a route to the default interface
68162587Sitojun				 * as default route.
68278064Sume				 * XXX: we enable this for host only, because
68378064Sume				 * this may override a default route installed
68478064Sume				 * a user process (e.g. routing daemon) in a
68578064Sume				 * router case.
68662587Sitojun				 */
68762587Sitojun				defrouter_addifreq(nd6_defifp);
68878064Sume			} else {
68978064Sume				nd6log((LOG_INFO, "defrouter_select: "
69078064Sume				    "there's no default router and no default"
69178064Sume				    " interface\n"));
69262587Sitojun			}
69362587Sitojun		}
69462587Sitojun	}
69562587Sitojun
69662587Sitojun	splx(s);
69762587Sitojun	return;
69862587Sitojun}
69962587Sitojun
70053541Sshinstatic struct nd_defrouter *
70153541Sshindefrtrlist_update(new)
70253541Sshin	struct nd_defrouter *new;
70353541Sshin{
70453541Sshin	struct nd_defrouter *dr, *n;
70553541Sshin	int s = splnet();
70653541Sshin
70753541Sshin	if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
70853541Sshin		/* entry exists */
70953541Sshin		if (new->rtlifetime == 0) {
71053541Sshin			defrtrlist_del(dr);
71153541Sshin			dr = NULL;
71253541Sshin		} else {
71353541Sshin			/* override */
71453541Sshin			dr->flags = new->flags; /* xxx flag check */
71553541Sshin			dr->rtlifetime = new->rtlifetime;
71653541Sshin			dr->expire = new->expire;
71753541Sshin		}
71853541Sshin		splx(s);
719120856Sume		return (dr);
72053541Sshin	}
72153541Sshin
72253541Sshin	/* entry does not exist */
72353541Sshin	if (new->rtlifetime == 0) {
72453541Sshin		splx(s);
725120856Sume		return (NULL);
72653541Sshin	}
72753541Sshin
72853541Sshin	n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
72953541Sshin	if (n == NULL) {
73053541Sshin		splx(s);
731120856Sume		return (NULL);
73253541Sshin	}
73353541Sshin	bzero(n, sizeof(*n));
73453541Sshin	*n = *new;
73562587Sitojun
73662587Sitojun	/*
73762587Sitojun	 * Insert the new router at the end of the Default Router List.
73862587Sitojun	 * If there is no other router, install it anyway. Otherwise,
73962587Sitojun	 * just continue to use the current default router.
74062587Sitojun	 */
74162587Sitojun	TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
74262587Sitojun	if (TAILQ_FIRST(&nd_defrouter) == n)
74362587Sitojun		defrouter_select();
74453541Sshin	splx(s);
745120941Sume
746120856Sume	return (n);
74753541Sshin}
74853541Sshin
74953541Sshinstatic struct nd_pfxrouter *
75053541Sshinpfxrtr_lookup(pr, dr)
75153541Sshin	struct nd_prefix *pr;
75253541Sshin	struct nd_defrouter *dr;
75353541Sshin{
75453541Sshin	struct nd_pfxrouter *search;
755120941Sume
75662587Sitojun	for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
75753541Sshin		if (search->router == dr)
75853541Sshin			break;
75953541Sshin	}
76053541Sshin
761120856Sume	return (search);
76253541Sshin}
76353541Sshin
76453541Sshinstatic void
76553541Sshinpfxrtr_add(pr, dr)
76653541Sshin	struct nd_prefix *pr;
76753541Sshin	struct nd_defrouter *dr;
76853541Sshin{
76953541Sshin	struct nd_pfxrouter *new;
77053541Sshin
77153541Sshin	new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
77253541Sshin	if (new == NULL)
77353541Sshin		return;
77453541Sshin	bzero(new, sizeof(*new));
77553541Sshin	new->router = dr;
77653541Sshin
77753541Sshin	LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
77853541Sshin
77953541Sshin	pfxlist_onlink_check();
78053541Sshin}
78153541Sshin
78253541Sshinstatic void
78353541Sshinpfxrtr_del(pfr)
78453541Sshin	struct nd_pfxrouter *pfr;
78553541Sshin{
78653541Sshin	LIST_REMOVE(pfr, pfr_entry);
78753541Sshin	free(pfr, M_IP6NDP);
78853541Sshin}
78953541Sshin
79078064Sumestruct nd_prefix *
79178064Sumend6_prefix_lookup(pr)
79253541Sshin	struct nd_prefix *pr;
79353541Sshin{
79453541Sshin	struct nd_prefix *search;
79553541Sshin
79662587Sitojun	for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
79753541Sshin		if (pr->ndpr_ifp == search->ndpr_ifp &&
79853541Sshin		    pr->ndpr_plen == search->ndpr_plen &&
79953541Sshin		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
800120941Sume		    &search->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
80153541Sshin			break;
80253541Sshin		}
80353541Sshin	}
80453541Sshin
805120856Sume	return (search);
80653541Sshin}
80753541Sshin
80878064Sumeint
80978064Sumend6_prelist_add(pr, dr, newp)
81078064Sume	struct nd_prefix *pr, **newp;
81153541Sshin	struct nd_defrouter *dr;
81253541Sshin{
81378064Sume	struct nd_prefix *new = NULL;
81453541Sshin	int i, s;
81553541Sshin
81653541Sshin	new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
81753541Sshin	if (new == NULL)
818120941Sume		return(ENOMEM);
81953541Sshin	bzero(new, sizeof(*new));
82053541Sshin	*new = *pr;
82178064Sume	if (newp != NULL)
82278064Sume		*newp = new;
82353541Sshin
824120941Sume	/* initialization */
82553541Sshin	LIST_INIT(&new->ndpr_advrtrs);
82653541Sshin	in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
82753541Sshin	/* make prefix in the canonical form */
82853541Sshin	for (i = 0; i < 4; i++)
82953541Sshin		new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
830120941Sume		    new->ndpr_mask.s6_addr32[i];
83153541Sshin
83253541Sshin	s = splnet();
83353541Sshin	/* link ndpr_entry to nd_prefix list */
83453541Sshin	LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
83553541Sshin	splx(s);
83653541Sshin
83778064Sume	/* ND_OPT_PI_FLAG_ONLINK processing */
83878064Sume	if (new->ndpr_raf_onlink) {
83978064Sume		int e;
84078064Sume
84178064Sume		if ((e = nd6_prefix_onlink(new)) != 0) {
84278064Sume			nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
84378064Sume			    "the prefix %s/%d on-link on %s (errno=%d)\n",
84478064Sume			    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
84578064Sume			    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
84678064Sume			/* proceed anyway. XXX: is it correct? */
84778064Sume		}
84878064Sume	}
84978064Sume
850120941Sume	if (dr)
85153541Sshin		pfxrtr_add(new, dr);
85253541Sshin
85353541Sshin	return 0;
85453541Sshin}
85553541Sshin
85653541Sshinvoid
85753541Sshinprelist_remove(pr)
85853541Sshin	struct nd_prefix *pr;
85953541Sshin{
86053541Sshin	struct nd_pfxrouter *pfr, *next;
86178064Sume	int e, s;
86253541Sshin
86378064Sume	/* make sure to invalidate the prefix until it is really freed. */
86478064Sume	pr->ndpr_vltime = 0;
86578064Sume	pr->ndpr_pltime = 0;
86678064Sume#if 0
86778064Sume	/*
86878064Sume	 * Though these flags are now meaningless, we'd rather keep the value
86978064Sume	 * not to confuse users when executing "ndp -p".
87078064Sume	 */
87178064Sume	pr->ndpr_raf_onlink = 0;
87278064Sume	pr->ndpr_raf_auto = 0;
87378064Sume#endif
87478064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
87578064Sume	    (e = nd6_prefix_offlink(pr)) != 0) {
87678064Sume		nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
87778064Sume		    "on %s, errno=%d\n",
87878064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
87978064Sume		    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
88078064Sume		/* what should we do? */
88178064Sume	}
88278064Sume
88378064Sume	if (pr->ndpr_refcnt > 0)
88478064Sume		return;		/* notice here? */
88578064Sume
88653541Sshin	s = splnet();
88778064Sume
88853541Sshin	/* unlink ndpr_entry from nd_prefix list */
88953541Sshin	LIST_REMOVE(pr, ndpr_entry);
89053541Sshin
89153541Sshin	/* free list of routers that adversed the prefix */
89262587Sitojun	for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
89362587Sitojun		next = pfr->pfr_next;
89453541Sshin
89553541Sshin		free(pfr, M_IP6NDP);
89653541Sshin	}
89778064Sume	splx(s);
89878064Sume
89953541Sshin	free(pr, M_IP6NDP);
90053541Sshin
90153541Sshin	pfxlist_onlink_check();
90253541Sshin}
90353541Sshin
90453541Sshinint
90553541Sshinprelist_update(new, dr, m)
90653541Sshin	struct nd_prefix *new;
90753541Sshin	struct nd_defrouter *dr; /* may be NULL */
90853541Sshin	struct mbuf *m;
90953541Sshin{
91078064Sume	struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
91178064Sume	struct ifaddr *ifa;
91278064Sume	struct ifnet *ifp = new->ndpr_ifp;
91353541Sshin	struct nd_prefix *pr;
91453541Sshin	int s = splnet();
91553541Sshin	int error = 0;
91678064Sume	int newprefix = 0;
91753541Sshin	int auth;
91878064Sume	struct in6_addrlifetime lt6_tmp;
91953541Sshin
92053541Sshin	auth = 0;
92153541Sshin	if (m) {
92253541Sshin		/*
92353541Sshin		 * Authenticity for NA consists authentication for
92453541Sshin		 * both IP header and IP datagrams, doesn't it ?
92553541Sshin		 */
92653541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
927120941Sume		auth = ((m->m_flags & M_AUTHIPHDR) &&
928120941Sume		    (m->m_flags & M_AUTHIPDGM));
92953541Sshin#endif
93053541Sshin	}
93153541Sshin
93278064Sume	if ((pr = nd6_prefix_lookup(new)) != NULL) {
93378064Sume		/*
93478064Sume		 * nd6_prefix_lookup() ensures that pr and new have the same
93578064Sume		 * prefix on a same interface.
93678064Sume		 */
93753541Sshin
93853541Sshin		/*
93978064Sume		 * Update prefix information.  Note that the on-link (L) bit
94078064Sume		 * and the autonomous (A) bit should NOT be changed from 1
94178064Sume		 * to 0.
94253541Sshin		 */
94378064Sume		if (new->ndpr_raf_onlink == 1)
94478064Sume			pr->ndpr_raf_onlink = 1;
94578064Sume		if (new->ndpr_raf_auto == 1)
94678064Sume			pr->ndpr_raf_auto = 1;
94778064Sume		if (new->ndpr_raf_onlink) {
94878064Sume			pr->ndpr_vltime = new->ndpr_vltime;
94978064Sume			pr->ndpr_pltime = new->ndpr_pltime;
95078064Sume			pr->ndpr_preferred = new->ndpr_preferred;
95178064Sume			pr->ndpr_expire = new->ndpr_expire;
95278064Sume		}
95353541Sshin
95478064Sume		if (new->ndpr_raf_onlink &&
95578064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
95678064Sume			int e;
95753541Sshin
95878064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
95978064Sume				nd6log((LOG_ERR,
96078064Sume				    "prelist_update: failed to make "
96178064Sume				    "the prefix %s/%d on-link on %s "
96278064Sume				    "(errno=%d)\n",
96378064Sume				    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
96478064Sume				    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
96578064Sume				/* proceed anyway. XXX: is it correct? */
96653541Sshin			}
96778064Sume		}
96853541Sshin
96978064Sume		if (dr && pfxrtr_lookup(pr, dr) == NULL)
97078064Sume			pfxrtr_add(pr, dr);
97178064Sume	} else {
97278064Sume		struct nd_prefix *newpr = NULL;
97353541Sshin
97478064Sume		newprefix = 1;
97553541Sshin
97678064Sume		if (new->ndpr_vltime == 0)
97778064Sume			goto end;
97878064Sume		if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
97978064Sume			goto end;
98053541Sshin
98178064Sume		bzero(&new->ndpr_addr, sizeof(struct in6_addr));
98262587Sitojun
98378064Sume		error = nd6_prelist_add(new, dr, &newpr);
98478064Sume		if (error != 0 || newpr == NULL) {
98578064Sume			nd6log((LOG_NOTICE, "prelist_update: "
98678064Sume			    "nd6_prelist_add failed for %s/%d on %s "
98778064Sume			    "errno=%d, returnpr=%p\n",
98878064Sume			    ip6_sprintf(&new->ndpr_prefix.sin6_addr),
989120941Sume			    new->ndpr_plen, if_name(new->ndpr_ifp),
990120941Sume			    error, newpr));
99178064Sume			goto end; /* we should just give up in this case. */
99278064Sume		}
99353541Sshin
99478064Sume		/*
99578064Sume		 * XXX: from the ND point of view, we can ignore a prefix
99678064Sume		 * with the on-link bit being zero.  However, we need a
99778064Sume		 * prefix structure for references from autoconfigured
998120941Sume		 * addresses.  Thus, we explicitly make sure that the prefix
99978064Sume		 * itself expires now.
100078064Sume		 */
100178064Sume		if (newpr->ndpr_raf_onlink == 0) {
100278064Sume			newpr->ndpr_vltime = 0;
100378064Sume			newpr->ndpr_pltime = 0;
100478064Sume			in6_init_prefix_ltimes(newpr);
100553541Sshin		}
100653541Sshin
100778064Sume		pr = newpr;
100878064Sume	}
100953541Sshin
101078064Sume	/*
101178064Sume	 * Address autoconfiguration based on Section 5.5.3 of RFC 2462.
101278064Sume	 * Note that pr must be non NULL at this point.
101378064Sume	 */
101462587Sitojun
101578064Sume	/* 5.5.3 (a). Ignore the prefix without the A bit set. */
101678064Sume	if (!new->ndpr_raf_auto)
101778064Sume		goto afteraddrconf;
101862587Sitojun
101978064Sume	/*
102078064Sume	 * 5.5.3 (b). the link-local prefix should have been ignored in
102178064Sume	 * nd6_ra_input.
102278064Sume	 */
102362587Sitojun
102478064Sume	/*
102578064Sume	 * 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime.
102678064Sume	 * This should have been done in nd6_ra_input.
102778064Sume	 */
102862587Sitojun
102978064Sume 	/*
103078064Sume	 * 5.5.3 (d). If the prefix advertised does not match the prefix of an
103178064Sume	 * address already in the list, and the Valid Lifetime is not 0,
103278064Sume	 * form an address.  Note that even a manually configured address
103378064Sume	 * should reject autoconfiguration of a new address.
103478064Sume	 */
1035120941Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
103678064Sume		struct in6_ifaddr *ifa6;
103778064Sume		int ifa_plen;
103878064Sume		u_int32_t storedlifetime;
103953541Sshin
104078064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
104178064Sume			continue;
104253541Sshin
104378064Sume		ifa6 = (struct in6_ifaddr *)ifa;
104453541Sshin
104553541Sshin		/*
104678064Sume		 * Spec is not clear here, but I believe we should concentrate
104778064Sume		 * on unicast (i.e. not anycast) addresses.
104878064Sume		 * XXX: other ia6_flags? detached or duplicated?
104953541Sshin		 */
105078064Sume		if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
105178064Sume			continue;
1052120941Sume
105378064Sume		ifa_plen = in6_mask2len(&ifa6->ia_prefixmask.sin6_addr, NULL);
105478064Sume		if (ifa_plen != new->ndpr_plen ||
105578064Sume		    !in6_are_prefix_equal(&ifa6->ia_addr.sin6_addr,
1056120941Sume		    &new->ndpr_prefix.sin6_addr, ifa_plen))
105778064Sume			continue;
105853541Sshin
105978064Sume		if (ia6_match == NULL) /* remember the first one */
106078064Sume			ia6_match = ifa6;
106178064Sume
106278064Sume		if ((ifa6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
106378064Sume			continue;
106478064Sume
106578064Sume		/*
106678064Sume		 * An already autoconfigured address matched.  Now that we
106778064Sume		 * are sure there is at least one matched address, we can
106878064Sume		 * proceed to 5.5.3. (e): update the lifetimes according to the
106978064Sume		 * "two hours" rule and the privacy extension.
107078064Sume		 */
107178064Sume#define TWOHOUR		(120*60)
107278064Sume		lt6_tmp = ifa6->ia6_lifetime;
107378064Sume
1074112678Sume		if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME)
1075112678Sume			storedlifetime = ND6_INFINITE_LIFETIME;
1076112678Sume		else if (IFA6_IS_INVALID(ifa6))
1077112678Sume			storedlifetime = 0;
1078112678Sume		else
1079112678Sume			storedlifetime = lt6_tmp.ia6t_expire - time_second;
108078064Sume
1081112678Sume		/* when not updating, keep the current stored lifetime. */
1082112678Sume		lt6_tmp.ia6t_vltime = storedlifetime;
1083112678Sume
108478064Sume		if (TWOHOUR < new->ndpr_vltime ||
108578064Sume		    storedlifetime < new->ndpr_vltime) {
108678064Sume			lt6_tmp.ia6t_vltime = new->ndpr_vltime;
108778064Sume		} else if (storedlifetime <= TWOHOUR
108878064Sume#if 0
108978064Sume			   /*
109078064Sume			    * This condition is logically redundant, so we just
109178064Sume			    * omit it.
109278064Sume			    * See IPng 6712, 6717, and 6721.
109378064Sume			    */
109478064Sume			   && new->ndpr_vltime <= storedlifetime
109578064Sume#endif
109678064Sume			) {
109778064Sume			if (auth) {
109878064Sume				lt6_tmp.ia6t_vltime = new->ndpr_vltime;
109978064Sume			}
110078064Sume		} else {
110178064Sume			/*
110278064Sume			 * new->ndpr_vltime <= TWOHOUR &&
110378064Sume			 * TWOHOUR < storedlifetime
110478064Sume			 */
110578064Sume			lt6_tmp.ia6t_vltime = TWOHOUR;
110653541Sshin		}
110753541Sshin
110878064Sume		/* The 2 hour rule is not imposed for preferred lifetime. */
110978064Sume		lt6_tmp.ia6t_pltime = new->ndpr_pltime;
111053541Sshin
111178064Sume		in6_init_address_ltimes(pr, &lt6_tmp);
111253541Sshin
111378064Sume		/*
111478064Sume		 * When adjusting the lifetimes of an existing temporary
111578064Sume		 * address, only lower the lifetimes.
111678064Sume		 * RFC 3041 3.3. (1).
111778064Sume		 * XXX: how should we modify ia6t_[pv]ltime?
111878064Sume		 */
111978064Sume		if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
112078064Sume			if (lt6_tmp.ia6t_expire == 0 || /* no expire */
112178064Sume			    lt6_tmp.ia6t_expire >
112278064Sume			    ifa6->ia6_lifetime.ia6t_expire) {
112378064Sume				lt6_tmp.ia6t_expire =
1124120941Sume				    ifa6->ia6_lifetime.ia6t_expire;
112578064Sume			}
112678064Sume			if (lt6_tmp.ia6t_preferred == 0 || /* no expire */
112778064Sume			    lt6_tmp.ia6t_preferred >
112878064Sume			    ifa6->ia6_lifetime.ia6t_preferred) {
112978064Sume				lt6_tmp.ia6t_preferred =
1130120941Sume				    ifa6->ia6_lifetime.ia6t_preferred;
113178064Sume			}
113278064Sume		}
113378064Sume
113478064Sume		ifa6->ia6_lifetime = lt6_tmp;
113553541Sshin	}
113678064Sume	if (ia6_match == NULL && new->ndpr_vltime) {
113778064Sume		/*
113878064Sume		 * No address matched and the valid lifetime is non-zero.
113978064Sume		 * Create a new address.
114078064Sume		 */
114178064Sume		if ((ia6 = in6_ifadd(new, NULL)) != NULL) {
114278064Sume			/*
114378064Sume			 * note that we should use pr (not new) for reference.
114478064Sume			 */
114578064Sume			pr->ndpr_refcnt++;
114678064Sume			ia6->ia6_ndpr = pr;
114753541Sshin
114878064Sume			/*
114978064Sume			 * RFC 3041 3.3 (2).
115078064Sume			 * When a new public address is created as described
115178064Sume			 * in RFC2462, also create a new temporary address.
115278064Sume			 *
115378064Sume			 * RFC 3041 3.5.
115478064Sume			 * When an interface connects to a new link, a new
115578064Sume			 * randomized interface identifier should be generated
115678064Sume			 * immediately together with a new set of temporary
115778064Sume			 * addresses.  Thus, we specifiy 1 as the 2nd arg of
115878064Sume			 * in6_tmpifadd().
115978064Sume			 */
116078064Sume			if (ip6_use_tempaddr) {
116178064Sume				int e;
116278064Sume				if ((e = in6_tmpifadd(ia6, 1)) != 0) {
116378064Sume					nd6log((LOG_NOTICE, "prelist_update: "
116478064Sume					    "failed to create a temporary "
116578064Sume					    "address, errno=%d\n",
116678064Sume					    e));
116778064Sume				}
116878064Sume			}
116978064Sume
117078064Sume			/*
117178064Sume			 * A newly added address might affect the status
117278064Sume			 * of other addresses, so we check and update it.
117378064Sume			 * XXX: what if address duplication happens?
117478064Sume			 */
117578064Sume			pfxlist_onlink_check();
117678064Sume		} else {
117778064Sume			/* just set an error. do not bark here. */
117878064Sume			error = EADDRNOTAVAIL; /* XXX: might be unused. */
117978064Sume		}
118078064Sume	}
118178064Sume
118278064Sume  afteraddrconf:
118378064Sume
118453541Sshin end:
118553541Sshin	splx(s);
118653541Sshin	return error;
118753541Sshin}
118853541Sshin
118953541Sshin/*
119062587Sitojun * A supplement function used in the on-link detection below;
119162587Sitojun * detect if a given prefix has a (probably) reachable advertising router.
119262587Sitojun * XXX: lengthy function name...
119362587Sitojun */
119478064Sumestatic struct nd_pfxrouter *
119562587Sitojunfind_pfxlist_reachable_router(pr)
119662587Sitojun	struct nd_prefix *pr;
119762587Sitojun{
119862587Sitojun	struct nd_pfxrouter *pfxrtr;
119962587Sitojun	struct rtentry *rt;
120062587Sitojun	struct llinfo_nd6 *ln;
120162587Sitojun
120262587Sitojun	for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
120362587Sitojun	     pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
120462587Sitojun		if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
1205120941Sume		    pfxrtr->router->ifp)) &&
120662587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
120762587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln))
120862587Sitojun			break;	/* found */
120962587Sitojun	}
121062587Sitojun
1211120856Sume	return (pfxrtr);
121262587Sitojun}
121362587Sitojun
121462587Sitojun/*
121553541Sshin * Check if each prefix in the prefix list has at least one available router
121678064Sume * that advertised the prefix (a router is "available" if its neighbor cache
121778064Sume * entry is reachable or probably reachable).
121862587Sitojun * If the check fails, the prefix may be off-link, because, for example,
121953541Sshin * we have moved from the network but the lifetime of the prefix has not
122078064Sume * expired yet.  So we should not use the prefix if there is another prefix
122178064Sume * that has an available router.
122278064Sume * But, if there is no prefix that has an available router, we still regards
122378064Sume * all the prefixes as on-link.  This is because we can't tell if all the
122453541Sshin * routers are simply dead or if we really moved from the network and there
122553541Sshin * is no router around us.
122653541Sshin */
122762587Sitojunvoid
122853541Sshinpfxlist_onlink_check()
122953541Sshin{
123053541Sshin	struct nd_prefix *pr;
123178064Sume	struct in6_ifaddr *ifa;
123253541Sshin
123362587Sitojun	/*
123462587Sitojun	 * Check if there is a prefix that has a reachable advertising
123562587Sitojun	 * router.
123662587Sitojun	 */
123762587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
123878064Sume		if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
123953541Sshin			break;
124062587Sitojun	}
124153541Sshin
124253541Sshin	if (pr) {
124353541Sshin		/*
124462587Sitojun		 * There is at least one prefix that has a reachable router.
124578064Sume		 * Detach prefixes which have no reachable advertising
124678064Sume		 * router, and attach other prefixes.
124753541Sshin		 */
124862587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
124978064Sume			/* XXX: a link-local prefix should never be detached */
125078064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
125178064Sume				continue;
125278064Sume
125378064Sume			/*
125478064Sume			 * we aren't interested in prefixes without the L bit
125578064Sume			 * set.
125678064Sume			 */
125778064Sume			if (pr->ndpr_raf_onlink == 0)
125878064Sume				continue;
125978064Sume
126078064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
126178064Sume			    find_pfxlist_reachable_router(pr) == NULL)
126278064Sume				pr->ndpr_stateflags |= NDPRF_DETACHED;
126378064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
126478064Sume			    find_pfxlist_reachable_router(pr) != 0)
126578064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
126653541Sshin		}
126778064Sume	} else {
126878064Sume		/* there is no prefix that has a reachable router */
126962587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
127078064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
127178064Sume				continue;
127278064Sume
127378064Sume			if (pr->ndpr_raf_onlink == 0)
127478064Sume				continue;
127578064Sume
127678064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
127778064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
127853541Sshin		}
127962587Sitojun	}
128078064Sume
128178064Sume	/*
128278064Sume	 * Remove each interface route associated with a (just) detached
128378064Sume	 * prefix, and reinstall the interface route for a (just) attached
128478064Sume	 * prefix.  Note that all attempt of reinstallation does not
128578064Sume	 * necessarily success, when a same prefix is shared among multiple
128678064Sume	 * interfaces.  Such cases will be handled in nd6_prefix_onlink,
128778064Sume	 * so we don't have to care about them.
128878064Sume	 */
128978064Sume	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
129078064Sume		int e;
129178064Sume
129278064Sume		if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
129378064Sume			continue;
129478064Sume
129578064Sume		if (pr->ndpr_raf_onlink == 0)
129678064Sume			continue;
129778064Sume
129878064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
129978064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
130078064Sume			if ((e = nd6_prefix_offlink(pr)) != 0) {
130178064Sume				nd6log((LOG_ERR,
130278064Sume				    "pfxlist_onlink_check: failed to "
130378064Sume				    "make %s/%d offlink, errno=%d\n",
130478064Sume				    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
130578064Sume				    pr->ndpr_plen, e));
130678064Sume			}
130778064Sume		}
130878064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
130978064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
131078064Sume		    pr->ndpr_raf_onlink) {
131178064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
131278064Sume				nd6log((LOG_ERR,
131378064Sume				    "pfxlist_onlink_check: failed to "
131478064Sume				    "make %s/%d offlink, errno=%d\n",
131578064Sume				    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
131678064Sume				    pr->ndpr_plen, e));
131778064Sume			}
131878064Sume		}
131978064Sume	}
132078064Sume
132178064Sume	/*
132278064Sume	 * Changes on the prefix status might affect address status as well.
132378064Sume	 * Make sure that all addresses derived from an attached prefix are
132478064Sume	 * attached, and that all addresses derived from a detached prefix are
132578064Sume	 * detached.  Note, however, that a manually configured address should
132678064Sume	 * always be attached.
132778064Sume	 * The precise detection logic is same as the one for prefixes.
132878064Sume	 */
132978064Sume	for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
1330120941Sume		if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
133178064Sume			continue;
133278064Sume
133378064Sume		if (ifa->ia6_ndpr == NULL) {
133478064Sume			/*
133578064Sume			 * This can happen when we first configure the address
133678064Sume			 * (i.e. the address exists, but the prefix does not).
133778064Sume			 * XXX: complicated relationships...
133878064Sume			 */
133978064Sume			continue;
134078064Sume		}
134178064Sume
134278064Sume		if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
134378064Sume			break;
134478064Sume	}
134578064Sume	if (ifa) {
134678064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
134778064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
134878064Sume				continue;
134978064Sume
135078064Sume			if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
135178064Sume				continue;
135278064Sume
135378064Sume			if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
135478064Sume				ifa->ia6_flags &= ~IN6_IFF_DETACHED;
135578064Sume			else
135678064Sume				ifa->ia6_flags |= IN6_IFF_DETACHED;
135778064Sume		}
135878064Sume	}
135962587Sitojun	else {
136078064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
136178064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
136278064Sume				continue;
136378064Sume
136478064Sume			ifa->ia6_flags &= ~IN6_IFF_DETACHED;
136578064Sume		}
136653541Sshin	}
136753541Sshin}
136853541Sshin
136978064Sumeint
137078064Sumend6_prefix_onlink(pr)
137153541Sshin	struct nd_prefix *pr;
137253541Sshin{
137378064Sume	struct ifaddr *ifa;
137478064Sume	struct ifnet *ifp = pr->ndpr_ifp;
137578064Sume	struct sockaddr_in6 mask6;
137678064Sume	struct nd_prefix *opr;
137778064Sume	u_long rtflags;
137878064Sume	int error = 0;
137978064Sume	struct rtentry *rt = NULL;
138053541Sshin
138178064Sume	/* sanity check */
138278064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
138378064Sume		nd6log((LOG_ERR,
138478064Sume		    "nd6_prefix_onlink: %s/%d is already on-link\n",
138578064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen);
1386120856Sume		return (EEXIST));
138778064Sume	}
138878064Sume
138953541Sshin	/*
139078064Sume	 * Add the interface route associated with the prefix.  Before
139178064Sume	 * installing the route, check if there's the same prefix on another
139278064Sume	 * interface, and the prefix has already installed the interface route.
139378064Sume	 * Although such a configuration is expected to be rare, we explicitly
139478064Sume	 * allow it.
139553541Sshin	 */
139678064Sume	for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
139778064Sume		if (opr == pr)
139878064Sume			continue;
139978064Sume
140078064Sume		if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
140178064Sume			continue;
140278064Sume
140378064Sume		if (opr->ndpr_plen == pr->ndpr_plen &&
140478064Sume		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1405120941Sume		    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen))
1406120856Sume			return (0);
140778064Sume	}
140878064Sume
140978064Sume	/*
1410120941Sume	 * We prefer link-local addresses as the associated interface address.
141178064Sume	 */
141278064Sume	/* search for a link-local addr */
141378064Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
1414120941Sume	    IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
141578064Sume	if (ifa == NULL) {
141678064Sume		/* XXX: freebsd does not have ifa_ifwithaf */
1417120941Sume		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
141878064Sume			if (ifa->ifa_addr->sa_family == AF_INET6)
141978064Sume				break;
142078064Sume		}
142178064Sume		/* should we care about ia6_flags? */
142278064Sume	}
142378064Sume	if (ifa == NULL) {
142478064Sume		/*
142578064Sume		 * This can still happen, when, for example, we receive an RA
142678064Sume		 * containing a prefix with the L bit set and the A bit clear,
142778064Sume		 * after removing all IPv6 addresses on the receiving
142878064Sume		 * interface.  This should, of course, be rare though.
142978064Sume		 */
143078064Sume		nd6log((LOG_NOTICE,
143178064Sume		    "nd6_prefix_onlink: failed to find any ifaddr"
143278064Sume		    " to add route for a prefix(%s/%d) on %s\n",
143378064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
143478064Sume		    pr->ndpr_plen, if_name(ifp)));
1435120856Sume		return (0);
143678064Sume	}
143778064Sume
143878064Sume	/*
143978064Sume	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
144078064Sume	 * ifa->ifa_rtrequest = nd6_rtrequest;
144178064Sume	 */
144278064Sume	bzero(&mask6, sizeof(mask6));
144378064Sume	mask6.sin6_len = sizeof(mask6);
144478064Sume	mask6.sin6_addr = pr->ndpr_mask;
144578064Sume	rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP;
144678064Sume	if (nd6_need_cache(ifp)) {
144778064Sume		/* explicitly set in case ifa_flags does not set the flag. */
144878064Sume		rtflags |= RTF_CLONING;
144978064Sume	} else {
145078064Sume		/*
145178064Sume		 * explicitly clear the cloning bit in case ifa_flags sets it.
145278064Sume		 */
145378064Sume		rtflags &= ~RTF_CLONING;
145478064Sume	}
145578064Sume	error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
1456120941Sume	    ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
145778064Sume	if (error == 0) {
145878064Sume		if (rt != NULL) /* this should be non NULL, though */
145978064Sume			nd6_rtmsg(RTM_ADD, rt);
146078064Sume		pr->ndpr_stateflags |= NDPRF_ONLINK;
1461120941Sume	} else {
146278064Sume		nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
146378064Sume		    " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
146478064Sume		    "errno = %d\n",
146578064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
146678064Sume		    pr->ndpr_plen, if_name(ifp),
146778064Sume		    ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
146878064Sume		    ip6_sprintf(&mask6.sin6_addr), rtflags, error));
146978064Sume	}
147078064Sume
1471120727Ssam	if (rt != NULL) {
1472120727Ssam		RT_LOCK(rt);
1473122334Ssam		RT_REMREF(rt);
1474120727Ssam		RT_UNLOCK(rt);
1475120727Ssam	}
147678064Sume
1477120856Sume	return (error);
147878064Sume}
147978064Sume
148078064Sumeint
148178064Sumend6_prefix_offlink(pr)
148278064Sume	struct nd_prefix *pr;
148378064Sume{
148478064Sume	int error = 0;
148578064Sume	struct ifnet *ifp = pr->ndpr_ifp;
148678064Sume	struct nd_prefix *opr;
148778064Sume	struct sockaddr_in6 sa6, mask6;
148878064Sume	struct rtentry *rt = NULL;
148978064Sume
149078064Sume	/* sanity check */
149178064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
149278064Sume		nd6log((LOG_ERR,
149378064Sume		    "nd6_prefix_offlink: %s/%d is already off-link\n",
149478064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen));
1495120856Sume		return (EEXIST);
149678064Sume	}
149778064Sume
149853541Sshin	bzero(&sa6, sizeof(sa6));
149953541Sshin	sa6.sin6_family = AF_INET6;
150053541Sshin	sa6.sin6_len = sizeof(sa6);
150153541Sshin	bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
1502120941Sume	    sizeof(struct in6_addr));
150353541Sshin	bzero(&mask6, sizeof(mask6));
150453541Sshin	mask6.sin6_family = AF_INET6;
150553541Sshin	mask6.sin6_len = sizeof(sa6);
150653541Sshin	bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
150778064Sume	error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
1508120941Sume	    (struct sockaddr *)&mask6, 0, &rt);
150978064Sume	if (error == 0) {
151078064Sume		pr->ndpr_stateflags &= ~NDPRF_ONLINK;
151153541Sshin
151278064Sume		/* report the route deletion to the routing socket. */
151378064Sume		if (rt != NULL)
151478064Sume			nd6_rtmsg(RTM_DELETE, rt);
151553541Sshin
151678064Sume		/*
151778064Sume		 * There might be the same prefix on another interface,
151878064Sume		 * the prefix which could not be on-link just because we have
151978064Sume		 * the interface route (see comments in nd6_prefix_onlink).
152078064Sume		 * If there's one, try to make the prefix on-link on the
152178064Sume		 * interface.
152278064Sume		 */
152378064Sume		for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
152478064Sume			if (opr == pr)
152578064Sume				continue;
152653541Sshin
152778064Sume			if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
152878064Sume				continue;
152953541Sshin
153078064Sume			/*
153178064Sume			 * KAME specific: detached prefixes should not be
153278064Sume			 * on-link.
153378064Sume			 */
153478064Sume			if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
153578064Sume				continue;
153678064Sume
153778064Sume			if (opr->ndpr_plen == pr->ndpr_plen &&
153878064Sume			    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1539120941Sume			    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
154078064Sume				int e;
154178064Sume
154278064Sume				if ((e = nd6_prefix_onlink(opr)) != 0) {
154378064Sume					nd6log((LOG_ERR,
154478064Sume					    "nd6_prefix_offlink: failed to "
154578064Sume					    "recover a prefix %s/%d from %s "
154678064Sume					    "to %s (errno = %d)\n",
154778064Sume					    ip6_sprintf(&opr->ndpr_prefix.sin6_addr),
154878064Sume					    opr->ndpr_plen, if_name(ifp),
154978064Sume					    if_name(opr->ndpr_ifp), e));
155078064Sume				}
155178064Sume			}
155278064Sume		}
1553120941Sume	} else {
155478064Sume		/* XXX: can we still set the NDPRF_ONLINK flag? */
155578064Sume		nd6log((LOG_ERR,
155678064Sume		    "nd6_prefix_offlink: failed to delete route: "
155778064Sume		    "%s/%d on %s (errno = %d)\n",
155878064Sume		    ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp),
155978064Sume		    error));
156078064Sume	}
156153541Sshin
1562120941Sume	if (rt != NULL) {
1563108269Sru		RTFREE(rt);
1564120941Sume	}
156553541Sshin
1566120856Sume	return (error);
156753541Sshin}
156853541Sshin
156953541Sshinstatic struct in6_ifaddr *
157078064Sumein6_ifadd(pr, ifid)
157178064Sume	struct nd_prefix *pr;
157278064Sume	struct in6_addr  *ifid;   /* Mobile IPv6 addition */
157353541Sshin{
157478064Sume	struct ifnet *ifp = pr->ndpr_ifp;
157553541Sshin	struct ifaddr *ifa;
157678064Sume	struct in6_aliasreq ifra;
157778064Sume	struct in6_ifaddr *ia, *ib;
157878064Sume	int error, plen0;
157953541Sshin	struct in6_addr mask;
158078064Sume	int prefixlen = pr->ndpr_plen;
158153541Sshin
1582121168Sume	in6_prefixlen2mask(&mask, prefixlen);
158353541Sshin
158478064Sume	/*
158578064Sume	 * find a link-local address (will be interface ID).
158678064Sume	 * Is it really mandatory? Theoretically, a global or a site-local
158778064Sume	 * address can be configured without a link-local address, if we
158878064Sume	 * have a unique interface identifier...
158978064Sume	 *
159078064Sume	 * it is not mandatory to have a link-local address, we can generate
159178064Sume	 * interface identifier on the fly.  we do this because:
159278064Sume	 * (1) it should be the easiest way to find interface identifier.
159378064Sume	 * (2) RFC2462 5.4 suggesting the use of the same interface identifier
159478064Sume	 * for multiple addresses on a single interface, and possible shortcut
159578064Sume	 * of DAD.  we omitted DAD for this reason in the past.
1596120941Sume	 * (3) a user can prevent autoconfiguration of global address
159778064Sume	 * by removing link-local address by hand (this is partly because we
1598108533Sschweikh	 * don't have other way to control the use of IPv6 on an interface.
159978064Sume	 * this has been our design choice - cf. NRL's "ifconfig auto").
160078064Sume	 * (4) it is easier to manage when an interface has addresses
160178064Sume	 * with the same interface identifier, than to have multiple addresses
160278064Sume	 * with different interface identifiers.
160378064Sume	 *
160478064Sume	 * Mobile IPv6 addition: allow for caller to specify a wished interface
160578064Sume	 * ID. This is to not break connections when moving addresses between
160678064Sume	 * interfaces.
160778064Sume	 */
1608120941Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
160953541Sshin	if (ifa)
161053541Sshin		ib = (struct in6_ifaddr *)ifa;
161153541Sshin	else
161253541Sshin		return NULL;
161353541Sshin
161462587Sitojun#if 0 /* don't care link local addr state, and always do DAD */
161562587Sitojun	/* if link-local address is not eligible, do not autoconfigure. */
161662587Sitojun	if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) {
161762587Sitojun		printf("in6_ifadd: link-local address not ready\n");
161862587Sitojun		return NULL;
161962587Sitojun	}
162062587Sitojun#endif
162162587Sitojun
162253541Sshin	/* prefixlen + ifidlen must be equal to 128 */
162378064Sume	plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
162478064Sume	if (prefixlen != plen0) {
162578064Sume		nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
162678064Sume		    "(prefix=%d ifid=%d)\n",
162778064Sume		    if_name(ifp), prefixlen, 128 - plen0));
162853541Sshin		return NULL;
162953541Sshin	}
163053541Sshin
163153541Sshin	/* make ifaddr */
163253541Sshin
163378064Sume	bzero(&ifra, sizeof(ifra));
163478064Sume	/*
163578064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
163678064Sume	 * for safety.
163778064Sume	 */
163878064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
163978064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
164078064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
164178064Sume	/* prefix */
164278064Sume	bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr,
1643120941Sume	    sizeof(ifra.ifra_addr.sin6_addr));
164478064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
164578064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
164678064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
164778064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
164853541Sshin
164953541Sshin	/* interface ID */
165078064Sume	if (ifid == NULL || IN6_IS_ADDR_UNSPECIFIED(ifid))
165178064Sume		ifid = &ib->ia_addr.sin6_addr;
1652120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
1653120941Sume	    (ifid->s6_addr32[0] & ~mask.s6_addr32[0]);
1654120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
1655120941Sume	    (ifid->s6_addr32[1] & ~mask.s6_addr32[1]);
1656120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1657120941Sume	    (ifid->s6_addr32[2] & ~mask.s6_addr32[2]);
1658120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1659120941Sume	    (ifid->s6_addr32[3] & ~mask.s6_addr32[3]);
1660120941Sume
166178064Sume	/* new prefix mask. */
166278064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
166378064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
166478064Sume	bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
1665120941Sume	    sizeof(ifra.ifra_prefixmask.sin6_addr));
166653541Sshin
166778064Sume	/*
166878064Sume	 * lifetime.
166978064Sume	 * XXX: in6_init_address_ltimes would override these values later.
1670120941Sume	 * We should reconsider this logic.
167178064Sume	 */
167278064Sume	ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
167378064Sume	ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
167453541Sshin
167578064Sume	/* XXX: scope zone ID? */
167653541Sshin
167778064Sume	ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
167878064Sume	/*
167978064Sume	 * temporarily set the nopfx flag to avoid conflict.
168078064Sume	 * XXX: we should reconsider the entire mechanism about prefix
168178064Sume	 * manipulation.
168278064Sume	 */
168378064Sume	ifra.ifra_flags |= IN6_IFF_NOPFX;
168453541Sshin
168553541Sshin	/*
168678064Sume	 * keep the new address, regardless of the result of in6_update_ifa.
168778064Sume	 * XXX: this address is now meaningless.
168878064Sume	 * We should reconsider its role.
168953541Sshin	 */
169078064Sume	pr->ndpr_addr = ifra.ifra_addr.sin6_addr;
169178064Sume
169278064Sume	/* allocate ifaddr structure, link into chain, etc. */
169378064Sume	if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
169478064Sume		nd6log((LOG_ERR,
169578064Sume		    "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
169678064Sume		    ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp),
169778064Sume		    error));
1698120856Sume		return (NULL);	/* ifaddr must not have been allocated. */
169953541Sshin	}
170053541Sshin
170178064Sume	ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
170253541Sshin
1703120941Sume	return (ia);		/* this is always non-NULL */
170453541Sshin}
170553541Sshin
170653541Sshinint
170778064Sumein6_tmpifadd(ia0, forcegen)
170878064Sume	const struct in6_ifaddr *ia0; /* corresponding public address */
170978407Sume	int forcegen;
171053541Sshin{
171178064Sume	struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
171278064Sume	struct in6_ifaddr *newia;
171378064Sume	struct in6_aliasreq ifra;
171478064Sume	int i, error;
171578064Sume	int trylimit = 3;	/* XXX: adhoc value */
171678064Sume	u_int32_t randid[2];
171778064Sume	time_t vltime0, pltime0;
171853541Sshin
171978064Sume	bzero(&ifra, sizeof(ifra));
172078064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
172178064Sume	ifra.ifra_addr = ia0->ia_addr;
172278064Sume	/* copy prefix mask */
172378064Sume	ifra.ifra_prefixmask = ia0->ia_prefixmask;
172478064Sume	/* clear the old IFID */
172578064Sume	for (i = 0; i < 4; i++) {
1726120941Sume		ifra.ifra_addr.sin6_addr.s6_addr32[i] &=
1727120941Sume		    ifra.ifra_prefixmask.sin6_addr.s6_addr32[i];
172878064Sume	}
172953541Sshin
173078064Sume  again:
173178064Sume	in6_get_tmpifid(ifp, (u_int8_t *)randid,
1732120941Sume	    (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen);
1733120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1734120941Sume	    (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2]));
1735120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1736120941Sume	    (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3]));
173753541Sshin
173878064Sume	/*
173978064Sume	 * If by chance the new temporary address is the same as an address
174078064Sume	 * already assigned to the interface, generate a new randomized
174178064Sume	 * interface identifier and repeat this step.
174278064Sume	 * RFC 3041 3.3 (4).
174378064Sume	 */
174478064Sume	if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
174578064Sume		if (trylimit-- == 0) {
174678064Sume			nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find "
174778064Sume			    "a unique random IFID\n"));
1748120856Sume			return (EEXIST);
174978064Sume		}
175078064Sume		forcegen = 1;
175178064Sume		goto again;
175253541Sshin	}
175353541Sshin
175478064Sume	/*
175578064Sume	 * The Valid Lifetime is the lower of the Valid Lifetime of the
175678064Sume         * public address or TEMP_VALID_LIFETIME.
175778064Sume	 * The Preferred Lifetime is the lower of the Preferred Lifetime
175878064Sume         * of the public address or TEMP_PREFERRED_LIFETIME -
175978064Sume         * DESYNC_FACTOR.
176078064Sume	 */
176178064Sume	if (ia0->ia6_lifetime.ia6t_expire != 0) {
176278064Sume		vltime0 = IFA6_IS_INVALID(ia0) ? 0 :
1763120941Sume		    (ia0->ia6_lifetime.ia6t_expire - time_second);
176478064Sume		if (vltime0 > ip6_temp_valid_lifetime)
176578064Sume			vltime0 = ip6_temp_valid_lifetime;
176678064Sume	} else
176778064Sume		vltime0 = ip6_temp_valid_lifetime;
176878064Sume	if (ia0->ia6_lifetime.ia6t_preferred != 0) {
176978064Sume		pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 :
1770120941Sume		    (ia0->ia6_lifetime.ia6t_preferred - time_second);
177178064Sume		if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){
177278064Sume			pltime0 = ip6_temp_preferred_lifetime -
1773120941Sume			    ip6_desync_factor;
177478064Sume		}
177578064Sume	} else
177678064Sume		pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor;
177778064Sume	ifra.ifra_lifetime.ia6t_vltime = vltime0;
177878064Sume	ifra.ifra_lifetime.ia6t_pltime = pltime0;
177953541Sshin
178078064Sume	/*
178178064Sume	 * A temporary address is created only if this calculated Preferred
178278064Sume	 * Lifetime is greater than REGEN_ADVANCE time units.
178378064Sume	 */
178478064Sume	if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance)
1785120856Sume		return (0);
178653541Sshin
178778064Sume	/* XXX: scope zone ID? */
178878064Sume
178978064Sume	ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
179078064Sume
179178064Sume	/* allocate ifaddr structure, link into chain, etc. */
179278064Sume	if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0)
1793120856Sume		return (error);
179478064Sume
179578064Sume	newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
179678064Sume	if (newia == NULL) {	/* XXX: can it happen? */
179778064Sume		nd6log((LOG_ERR,
179878064Sume		    "in6_tmpifadd: ifa update succeeded, but we got "
179978064Sume		    "no ifaddr\n"));
1800120856Sume		return (EINVAL); /* XXX */
180153541Sshin	}
180278064Sume	newia->ia6_ndpr = ia0->ia6_ndpr;
180378064Sume	newia->ia6_ndpr->ndpr_refcnt++;
180453541Sshin
180578407Sume	/*
180678407Sume	 * A newly added address might affect the status of other addresses.
180778407Sume	 * XXX: when the temporary address is generated with a new public
180878407Sume	 * address, the onlink check is redundant.  However, it would be safe
180978407Sume	 * to do the check explicitly everywhere a new address is generated,
181078407Sume	 * and, in fact, we surely need the check when we create a new
181178407Sume	 * temporary address due to deprecation of an old temporary address.
181278407Sume	 */
181378407Sume	pfxlist_onlink_check();
181478407Sume
1815120856Sume	return (0);
1816120941Sume}
181753541Sshin
181853541Sshinint
181953541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr)
182053541Sshin{
182178064Sume	/* check if preferred lifetime > valid lifetime.  RFC2462 5.5.3 (c) */
182253541Sshin	if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
182378064Sume		nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
182453541Sshin		    "(%d) is greater than valid lifetime(%d)\n",
182578064Sume		    (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime));
182653541Sshin		return (EINVAL);
182753541Sshin	}
182853541Sshin	if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
182953541Sshin		ndpr->ndpr_preferred = 0;
183053541Sshin	else
183153541Sshin		ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
183253541Sshin	if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
183353541Sshin		ndpr->ndpr_expire = 0;
183453541Sshin	else
183553541Sshin		ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
183653541Sshin
183753541Sshin	return 0;
183853541Sshin}
183953541Sshin
184053541Sshinstatic void
184178064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
184253541Sshin{
184378064Sume	/* init ia6t_expire */
184478064Sume	if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
184578064Sume		lt6->ia6t_expire = 0;
184678064Sume	else {
184778064Sume		lt6->ia6t_expire = time_second;
184878064Sume		lt6->ia6t_expire += lt6->ia6t_vltime;
184953541Sshin	}
185062587Sitojun
185153541Sshin	/* init ia6t_preferred */
185253541Sshin	if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
185353541Sshin		lt6->ia6t_preferred = 0;
185453541Sshin	else {
185553541Sshin		lt6->ia6t_preferred = time_second;
185653541Sshin		lt6->ia6t_preferred += lt6->ia6t_pltime;
185753541Sshin	}
185853541Sshin}
185953541Sshin
186053541Sshin/*
186153541Sshin * Delete all the routing table entries that use the specified gateway.
186253541Sshin * XXX: this function causes search through all entries of routing table, so
186353541Sshin * it shouldn't be called when acting as a router.
186453541Sshin */
186553541Sshinvoid
186653541Sshinrt6_flush(gateway, ifp)
186778064Sume	struct in6_addr *gateway;
186878064Sume	struct ifnet *ifp;
186953541Sshin{
187053541Sshin	struct radix_node_head *rnh = rt_tables[AF_INET6];
187153541Sshin	int s = splnet();
187253541Sshin
187353541Sshin	/* We'll care only link-local addresses */
187453541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
187553541Sshin		splx(s);
187653541Sshin		return;
187753541Sshin	}
187853541Sshin	/* XXX: hack for KAME's link-local address kludge */
187953541Sshin	gateway->s6_addr16[1] = htons(ifp->if_index);
188053541Sshin
1881108250Shsu	RADIX_NODE_HEAD_LOCK(rnh);
188253541Sshin	rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
1883108250Shsu	RADIX_NODE_HEAD_UNLOCK(rnh);
188453541Sshin	splx(s);
188553541Sshin}
188653541Sshin
188753541Sshinstatic int
188853541Sshinrt6_deleteroute(rn, arg)
188953541Sshin	struct radix_node *rn;
189053541Sshin	void *arg;
189153541Sshin{
189253541Sshin#define SIN6(s)	((struct sockaddr_in6 *)s)
189353541Sshin	struct rtentry *rt = (struct rtentry *)rn;
189453541Sshin	struct in6_addr *gate = (struct in6_addr *)arg;
189553541Sshin
189653541Sshin	if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
1897120856Sume		return (0);
189853541Sshin
1899120941Sume	if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) {
1900120856Sume		return (0);
1901120941Sume	}
190253541Sshin
190353541Sshin	/*
190478064Sume	 * Do not delete a static route.
190578064Sume	 * XXX: this seems to be a bit ad-hoc. Should we consider the
190678064Sume	 * 'cloned' bit instead?
190778064Sume	 */
190878064Sume	if ((rt->rt_flags & RTF_STATIC) != 0)
1909120856Sume		return (0);
191078064Sume
191178064Sume	/*
191253541Sshin	 * We delete only host route. This means, in particular, we don't
191353541Sshin	 * delete default route.
191453541Sshin	 */
191553541Sshin	if ((rt->rt_flags & RTF_HOST) == 0)
1916120856Sume		return (0);
191753541Sshin
1918120941Sume	return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
1919120941Sume	    rt_mask(rt), rt->rt_flags, 0));
192053541Sshin#undef SIN6
192153541Sshin}
192262587Sitojun
192362587Sitojunint
192462587Sitojunnd6_setdefaultiface(ifindex)
192562587Sitojun	int ifindex;
192662587Sitojun{
192762587Sitojun	int error = 0;
192862587Sitojun
192962587Sitojun	if (ifindex < 0 || if_index < ifindex)
1930120856Sume		return (EINVAL);
193162587Sitojun
193262587Sitojun	if (nd6_defifindex != ifindex) {
193362587Sitojun		nd6_defifindex = ifindex;
193462587Sitojun		if (nd6_defifindex > 0)
193583130Sjlemon			nd6_defifp = ifnet_byindex(nd6_defifindex);
193662587Sitojun		else
193762587Sitojun			nd6_defifp = NULL;
193862587Sitojun
193962587Sitojun		/*
194062587Sitojun		 * If the Default Router List is empty, install a route
194162587Sitojun		 * to the specified interface as default or remove the default
194262587Sitojun		 * route when the default interface becomes canceled.
194362587Sitojun		 * The check for the queue is actually redundant, but
194462587Sitojun		 * we do this here to avoid re-install the default route
194562587Sitojun		 * if the list is NOT empty.
194662587Sitojun		 */
194762587Sitojun		if (TAILQ_FIRST(&nd_defrouter) == NULL)
194862587Sitojun			defrouter_select();
194962587Sitojun
195062587Sitojun		/*
195162587Sitojun		 * Our current implementation assumes one-to-one maping between
195262587Sitojun		 * interfaces and links, so it would be natural to use the
195362587Sitojun		 * default interface as the default link.
195462587Sitojun		 */
195562587Sitojun		scope6_setdefault(nd6_defifp);
195662587Sitojun	}
195762587Sitojun
1958120856Sume	return (error);
195962587Sitojun}
1960