nd6_rtr.c revision 78407
162587Sitojun/*	$FreeBSD: head/sys/netinet6/nd6_rtr.c 78407 2001-06-18 11:37:06Z ume $	*/
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
7962587Sitojunstatic void in6_init_address_ltimes __P((struct nd_prefix *ndpr,
8078064Sume					 struct in6_addrlifetime *lt6));
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;
11762587Sitojun#if 0
11862587Sitojun	struct in6_addr daddr6 = ip6->ip6_dst;
11962587Sitojun#endif
12053541Sshin	char *lladdr = NULL;
12153541Sshin	int lladdrlen = 0;
12262587Sitojun#if 0
12362587Sitojun	struct sockaddr_dl *sdl = (struct sockaddr_dl *)NULL;
12462587Sitojun	struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL;
12562587Sitojun	struct rtentry *rt = NULL;
12662587Sitojun	int is_newentry;
12762587Sitojun#endif
12853541Sshin	union nd_opts ndopts;
12953541Sshin
13053541Sshin	/* If I'm not a router, ignore it. */
13153541Sshin	if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
13262587Sitojun		goto freeit;
13353541Sshin
13453541Sshin	/* Sanity checks */
13553541Sshin	if (ip6->ip6_hlim != 255) {
13678064Sume		nd6log((LOG_ERR,
13778064Sume		    "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
13878064Sume		    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
13978064Sume		    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
14078064Sume		goto bad;
14153541Sshin	}
14253541Sshin
14353541Sshin	/*
14453541Sshin	 * Don't update the neighbor cache, if src = ::.
14553541Sshin	 * This indicates that the src has no IP address assigned yet.
14653541Sshin	 */
14753541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
14862587Sitojun		goto freeit;
14962587Sitojun
15062587Sitojun#ifndef PULLDOWN_TEST
15162587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
15262587Sitojun	nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
15362587Sitojun#else
15462587Sitojun	IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
15562587Sitojun	if (nd_rs == NULL) {
15662587Sitojun		icmp6stat.icp6s_tooshort++;
15753541Sshin		return;
15862587Sitojun	}
15962587Sitojun#endif
16053541Sshin
16153541Sshin	icmp6len -= sizeof(*nd_rs);
16253541Sshin	nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
16353541Sshin	if (nd6_options(&ndopts) < 0) {
16478064Sume		nd6log((LOG_INFO,
16578064Sume		    "nd6_rs_input: invalid ND option, ignored\n"));
16678064Sume		/* nd6_options have incremented stats */
16762587Sitojun		goto freeit;
16853541Sshin	}
16953541Sshin
17053541Sshin	if (ndopts.nd_opts_src_lladdr) {
17153541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
17253541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
17353541Sshin	}
17453541Sshin
17553541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
17678064Sume		nd6log((LOG_INFO,
17753541Sshin		    "nd6_rs_input: lladdrlen mismatch for %s "
17853541Sshin		    "(if %d, RS packet %d)\n",
17978064Sume			ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2));
18078064Sume		goto bad;
18153541Sshin	}
18253541Sshin
18353541Sshin	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
18462587Sitojun
18562587Sitojun freeit:
18662587Sitojun	m_freem(m);
18778064Sume	return;
18878064Sume
18978064Sume bad:
19078064Sume	icmp6stat.icp6s_badrs++;
19178064Sume	m_freem(m);
19253541Sshin}
19353541Sshin
19453541Sshin/*
19553541Sshin * Receive Router Advertisement Message.
19653541Sshin *
19753541Sshin * Based on RFC 2461
19853541Sshin * TODO: on-link bit on prefix information
19953541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
20053541Sshin */
20153541Sshinvoid
20253541Sshinnd6_ra_input(m, off, icmp6len)
20353541Sshin	struct	mbuf *m;
20453541Sshin	int off, icmp6len;
20553541Sshin{
20653541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
20753541Sshin	struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
20853541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
20962587Sitojun	struct nd_router_advert *nd_ra;
21053541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
21162587Sitojun#if 0
21262587Sitojun	struct in6_addr daddr6 = ip6->ip6_dst;
21362587Sitojun	int flags; /* = nd_ra->nd_ra_flags_reserved; */
21462587Sitojun	int is_managed = ((flags & ND_RA_FLAG_MANAGED) != 0);
21562587Sitojun	int is_other = ((flags & ND_RA_FLAG_OTHER) != 0);
21662587Sitojun#endif
21753541Sshin	union nd_opts ndopts;
21853541Sshin	struct nd_defrouter *dr;
21953541Sshin
22053541Sshin	if (ip6_accept_rtadv == 0)
22162587Sitojun		goto freeit;
22253541Sshin
22353541Sshin	if (ip6->ip6_hlim != 255) {
22478064Sume		nd6log((LOG_ERR,
22578064Sume		    "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
22678064Sume		    ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
22778064Sume		    ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
22878064Sume		goto bad;
22953541Sshin	}
23053541Sshin
23153541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
23278064Sume		nd6log((LOG_ERR,
23353541Sshin		    "nd6_ra_input: src %s is not link-local\n",
23478064Sume		    ip6_sprintf(&saddr6)));
23578064Sume		goto bad;
23662587Sitojun	}
23762587Sitojun
23862587Sitojun#ifndef PULLDOWN_TEST
23962587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
24062587Sitojun	nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
24162587Sitojun#else
24262587Sitojun	IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
24362587Sitojun	if (nd_ra == NULL) {
24462587Sitojun		icmp6stat.icp6s_tooshort++;
24553541Sshin		return;
24653541Sshin	}
24762587Sitojun#endif
24853541Sshin
24953541Sshin	icmp6len -= sizeof(*nd_ra);
25053541Sshin	nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
25153541Sshin	if (nd6_options(&ndopts) < 0) {
25278064Sume		nd6log((LOG_INFO,
25378064Sume		    "nd6_ra_input: invalid ND option, ignored\n"));
25478064Sume		/* nd6_options have incremented stats */
25562587Sitojun		goto freeit;
25653541Sshin	}
25753541Sshin
25853541Sshin    {
25953541Sshin	struct nd_defrouter dr0;
26053541Sshin	u_int32_t advreachable = nd_ra->nd_ra_reachable;
26153541Sshin
26253541Sshin	dr0.rtaddr = saddr6;
26353541Sshin	dr0.flags  = nd_ra->nd_ra_flags_reserved;
26453541Sshin	dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
26553541Sshin	dr0.expire = time_second + dr0.rtlifetime;
26653541Sshin	dr0.ifp = ifp;
26762587Sitojun	dr0.advint = 0;		/* Mobile IPv6 */
26862587Sitojun	dr0.advint_expire = 0;	/* Mobile IPv6 */
26962587Sitojun	dr0.advints_lost = 0;	/* Mobile IPv6 */
27053541Sshin	/* unspecified or not? (RFC 2461 6.3.4) */
27153541Sshin	if (advreachable) {
27253541Sshin		NTOHL(advreachable);
27353541Sshin		if (advreachable <= MAX_REACHABLE_TIME &&
27453541Sshin		    ndi->basereachable != advreachable) {
27553541Sshin			ndi->basereachable = advreachable;
27653541Sshin			ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
27753541Sshin			ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
27853541Sshin		}
27953541Sshin	}
28053541Sshin	if (nd_ra->nd_ra_retransmit)
28153541Sshin		ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
28253541Sshin	if (nd_ra->nd_ra_curhoplimit)
28353541Sshin		ndi->chlim = nd_ra->nd_ra_curhoplimit;
28453541Sshin	dr = defrtrlist_update(&dr0);
28553541Sshin    }
28653541Sshin
28753541Sshin	/*
28853541Sshin	 * prefix
28953541Sshin	 */
29053541Sshin	if (ndopts.nd_opts_pi) {
29153541Sshin		struct nd_opt_hdr *pt;
29278064Sume		struct nd_opt_prefix_info *pi = NULL;
29353541Sshin		struct nd_prefix pr;
29453541Sshin
29553541Sshin		for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
29653541Sshin		     pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
29753541Sshin		     pt = (struct nd_opt_hdr *)((caddr_t)pt +
29853541Sshin						(pt->nd_opt_len << 3))) {
29953541Sshin			if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
30053541Sshin				continue;
30153541Sshin			pi = (struct nd_opt_prefix_info *)pt;
30253541Sshin
30353541Sshin			if (pi->nd_opt_pi_len != 4) {
30478064Sume				nd6log((LOG_INFO,
30578064Sume				    "nd6_ra_input: invalid option "
30678064Sume				    "len %d for prefix information option, "
30778064Sume				    "ignored\n", pi->nd_opt_pi_len));
30853541Sshin				continue;
30953541Sshin			}
31053541Sshin
31153541Sshin			if (128 < pi->nd_opt_pi_prefix_len) {
31278064Sume				nd6log((LOG_INFO,
31378064Sume				    "nd6_ra_input: invalid prefix "
31478064Sume				    "len %d for prefix information option, "
31578064Sume				    "ignored\n", pi->nd_opt_pi_prefix_len));
31653541Sshin				continue;
31753541Sshin			}
31853541Sshin
31953541Sshin			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
32053541Sshin			 || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
32178064Sume				nd6log((LOG_INFO,
32278064Sume				    "nd6_ra_input: invalid prefix "
32378064Sume				    "%s, ignored\n",
32478064Sume				    ip6_sprintf(&pi->nd_opt_pi_prefix)));
32553541Sshin				continue;
32653541Sshin			}
32753541Sshin
32853541Sshin			/* aggregatable unicast address, rfc2374 */
32953541Sshin			if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
33053541Sshin			 && pi->nd_opt_pi_prefix_len != 64) {
33178064Sume				nd6log((LOG_INFO,
33278064Sume				    "nd6_ra_input: invalid prefixlen "
33378064Sume				    "%d for rfc2374 prefix %s, ignored\n",
33478064Sume				    pi->nd_opt_pi_prefix_len,
33578064Sume				    ip6_sprintf(&pi->nd_opt_pi_prefix)));
33653541Sshin				continue;
33753541Sshin			}
33853541Sshin
33953541Sshin			bzero(&pr, sizeof(pr));
34053541Sshin			pr.ndpr_prefix.sin6_family = AF_INET6;
34153541Sshin			pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
34253541Sshin			pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
34353541Sshin			pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
34453541Sshin
34553541Sshin			pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
34653541Sshin					      ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
34753541Sshin			pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
34853541Sshin					    ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
34953541Sshin			pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
35053541Sshin			pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
35153541Sshin			pr.ndpr_pltime =
35253541Sshin				ntohl(pi->nd_opt_pi_preferred_time);
35353541Sshin
35453541Sshin			if (in6_init_prefix_ltimes(&pr))
35553541Sshin				continue; /* prefix lifetime init failed */
35653541Sshin
35753541Sshin			(void)prelist_update(&pr, dr, m);
35853541Sshin		}
35953541Sshin	}
36053541Sshin
36153541Sshin	/*
36253541Sshin	 * MTU
36353541Sshin	 */
36453541Sshin	if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
36553541Sshin		u_int32_t mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
36653541Sshin
36753541Sshin		/* lower bound */
36853541Sshin		if (mtu < IPV6_MMTU) {
36978064Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option "
37053541Sshin			    "mtu=%d sent from %s, ignoring\n",
37178064Sume			    mtu, ip6_sprintf(&ip6->ip6_src)));
37253541Sshin			goto skip;
37353541Sshin		}
37453541Sshin
37553541Sshin		/* upper bound */
37653541Sshin		if (ndi->maxmtu) {
37753541Sshin			if (mtu <= ndi->maxmtu) {
37853541Sshin				int change = (ndi->linkmtu != mtu);
37953541Sshin
38053541Sshin				ndi->linkmtu = mtu;
38153541Sshin				if (change) /* in6_maxmtu may change */
38253541Sshin					in6_setmaxmtu();
38353541Sshin			} else {
38478064Sume				nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
38553541Sshin				    "mtu=%d sent from %s; "
38653541Sshin				    "exceeds maxmtu %d, ignoring\n",
38753541Sshin				    mtu, ip6_sprintf(&ip6->ip6_src),
38878064Sume				    ndi->maxmtu));
38953541Sshin			}
39053541Sshin		} else {
39178064Sume			nd6log((LOG_INFO, "nd6_ra_input: mtu option "
39253541Sshin			    "mtu=%d sent from %s; maxmtu unknown, "
39353541Sshin			    "ignoring\n",
39478064Sume			    mtu, ip6_sprintf(&ip6->ip6_src)));
39553541Sshin		}
39653541Sshin	}
39753541Sshin
39853541Sshin skip:
39953541Sshin
40053541Sshin	/*
40153541Sshin	 * Src linkaddress
40253541Sshin	 */
40353541Sshin    {
40453541Sshin	char *lladdr = NULL;
40553541Sshin	int lladdrlen = 0;
40653541Sshin
40753541Sshin	if (ndopts.nd_opts_src_lladdr) {
40853541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
40953541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
41053541Sshin	}
41153541Sshin
41253541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
41378064Sume		nd6log((LOG_INFO,
41453541Sshin		    "nd6_ra_input: lladdrlen mismatch for %s "
41553541Sshin		    "(if %d, RA packet %d)\n",
41678064Sume			ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2));
41778064Sume		goto bad;
41853541Sshin	}
41953541Sshin
42053541Sshin	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
42162587Sitojun
42262587Sitojun	/*
42362587Sitojun	 * Installing a link-layer address might change the state of the
42462587Sitojun	 * router's neighbor cache, which might also affect our on-link
42562587Sitojun	 * detection of adveritsed prefixes.
42662587Sitojun	 */
42762587Sitojun	pfxlist_onlink_check();
42853541Sshin    }
42962587Sitojun
43078064Sume freeit:
43162587Sitojun	m_freem(m);
43278064Sume	return;
43378064Sume
43478064Sume bad:
43578064Sume	icmp6stat.icp6s_badra++;
43678064Sume	m_freem(m);
43753541Sshin}
43853541Sshin
43953541Sshin/*
44053541Sshin * default router list proccessing sub routines
44153541Sshin */
44262587Sitojun
44362587Sitojun/* tell the change to user processes watching the routing socket. */
44462587Sitojunstatic void
44578064Sumend6_rtmsg(cmd, rt)
44662587Sitojun	int cmd;
44762587Sitojun	struct rtentry *rt;
44862587Sitojun{
44962587Sitojun	struct rt_addrinfo info;
45062587Sitojun
45162587Sitojun	bzero((caddr_t)&info, sizeof(info));
45262587Sitojun	info.rti_info[RTAX_DST] = rt_key(rt);
45362587Sitojun	info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
45462587Sitojun	info.rti_info[RTAX_NETMASK] = rt_mask(rt);
45578064Sume	info.rti_info[RTAX_IFP] =
45678064Sume		(struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist);
45778064Sume	info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
45862587Sitojun
45962587Sitojun	rt_missmsg(cmd, &info, rt->rt_flags, 0);
46062587Sitojun}
46162587Sitojun
46253541Sshinvoid
46353541Sshindefrouter_addreq(new)
46453541Sshin	struct nd_defrouter *new;
46553541Sshin{
46653541Sshin	struct sockaddr_in6 def, mask, gate;
46762587Sitojun	struct rtentry *newrt = NULL;
46853541Sshin	int s;
46953541Sshin
47053541Sshin	Bzero(&def, sizeof(def));
47153541Sshin	Bzero(&mask, sizeof(mask));
47253541Sshin	Bzero(&gate, sizeof(gate));
47353541Sshin
47453541Sshin	def.sin6_len = mask.sin6_len = gate.sin6_len
47553541Sshin		= sizeof(struct sockaddr_in6);
47653541Sshin	def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
47753541Sshin	gate.sin6_addr = new->rtaddr;
47853541Sshin
47953541Sshin	s = splnet();
48053541Sshin	(void)rtrequest(RTM_ADD, (struct sockaddr *)&def,
48153541Sshin		(struct sockaddr *)&gate, (struct sockaddr *)&mask,
48262587Sitojun		RTF_GATEWAY, &newrt);
48362587Sitojun	if (newrt) {
48478064Sume		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
48562587Sitojun		newrt->rt_refcnt--;
48662587Sitojun	}
48753541Sshin	splx(s);
48853541Sshin	return;
48953541Sshin}
49053541Sshin
49162587Sitojun/* Add a route to a given interface as default */
49262587Sitojunvoid
49362587Sitojundefrouter_addifreq(ifp)
49462587Sitojun	struct ifnet *ifp;
49562587Sitojun{
49662587Sitojun	struct sockaddr_in6 def, mask;
49762587Sitojun	struct ifaddr *ifa;
49862587Sitojun	struct rtentry *newrt = NULL;
49962587Sitojun	int error, flags;
50062587Sitojun
50162587Sitojun	bzero(&def, sizeof(def));
50262587Sitojun	bzero(&mask, sizeof(mask));
50362587Sitojun
50462587Sitojun	def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);
50562587Sitojun	def.sin6_family = mask.sin6_family = AF_INET6;
50662587Sitojun
50762587Sitojun	/*
50862587Sitojun	 * Search for an ifaddr beloging to the specified interface.
50962587Sitojun	 * XXX: An IPv6 address are required to be assigned on the interface.
51062587Sitojun	 */
51162587Sitojun	if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) {
51278064Sume		nd6log((LOG_ERR,	/* better error? */
51362587Sitojun		    "defrouter_addifreq: failed to find an ifaddr "
51462587Sitojun		    "to install a route to interface %s\n",
51578064Sume		    if_name(ifp)));
51662587Sitojun		return;
51762587Sitojun	}
51862587Sitojun
51962587Sitojun	flags = ifa->ifa_flags;
52078064Sume	error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr,
52178064Sume			  (struct sockaddr *)&mask, flags, &newrt);
52278064Sume	if (error != 0) {
52378064Sume		nd6log((LOG_ERR,
52462587Sitojun		    "defrouter_addifreq: failed to install a route to "
52562587Sitojun		    "interface %s (errno = %d)\n",
52678064Sume		    if_name(ifp), error));
52762587Sitojun
52862587Sitojun		if (newrt)	/* maybe unnecessary, but do it for safety */
52962587Sitojun			newrt->rt_refcnt--;
53062587Sitojun	} else {
53162587Sitojun		if (newrt) {
53278064Sume			nd6_rtmsg(RTM_ADD, newrt);
53362587Sitojun			newrt->rt_refcnt--;
53462587Sitojun		}
53562587Sitojun	}
53662587Sitojun}
53762587Sitojun
53853541Sshinstruct nd_defrouter *
53953541Sshindefrouter_lookup(addr, ifp)
54053541Sshin	struct in6_addr *addr;
54153541Sshin	struct ifnet *ifp;
54253541Sshin{
54353541Sshin	struct nd_defrouter *dr;
54453541Sshin
54562587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
54662587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
54753541Sshin		if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
54853541Sshin			return(dr);
54962587Sitojun	}
55053541Sshin
55153541Sshin	return(NULL);		/* search failed */
55253541Sshin}
55353541Sshin
55453541Sshinvoid
55553541Sshindefrouter_delreq(dr, dofree)
55653541Sshin	struct nd_defrouter *dr;
55753541Sshin	int dofree;
55853541Sshin{
55953541Sshin	struct sockaddr_in6 def, mask, gate;
56062587Sitojun	struct rtentry *oldrt = NULL;
56153541Sshin
56253541Sshin	Bzero(&def, sizeof(def));
56353541Sshin	Bzero(&mask, sizeof(mask));
56453541Sshin	Bzero(&gate, sizeof(gate));
56553541Sshin
56653541Sshin	def.sin6_len = mask.sin6_len = gate.sin6_len
56753541Sshin		= sizeof(struct sockaddr_in6);
56853541Sshin	def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
56953541Sshin	gate.sin6_addr = dr->rtaddr;
57053541Sshin
57153541Sshin	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
57253541Sshin		  (struct sockaddr *)&gate,
57353541Sshin		  (struct sockaddr *)&mask,
57462587Sitojun		  RTF_GATEWAY, &oldrt);
57562587Sitojun	if (oldrt) {
57678064Sume		nd6_rtmsg(RTM_DELETE, oldrt);
57764540Sitojun		if (oldrt->rt_refcnt <= 0) {
57864540Sitojun			/*
57964540Sitojun			 * XXX: borrowed from the RTM_DELETE case of
58064540Sitojun			 * rtrequest().
58164540Sitojun			 */
58264540Sitojun			oldrt->rt_refcnt++;
58364540Sitojun			rtfree(oldrt);
58464540Sitojun		}
58562587Sitojun	}
58653541Sshin
58762587Sitojun	if (dofree)		/* XXX: necessary? */
58853541Sshin		free(dr, M_IP6NDP);
58953541Sshin}
59053541Sshin
59153541Sshinvoid
59253541Sshindefrtrlist_del(dr)
59353541Sshin	struct nd_defrouter *dr;
59453541Sshin{
59553541Sshin	struct nd_defrouter *deldr = NULL;
59653541Sshin	struct nd_prefix *pr;
59753541Sshin
59853541Sshin	/*
59953541Sshin	 * Flush all the routing table entries that use the router
60053541Sshin	 * as a next hop.
60153541Sshin	 */
60253541Sshin	if (!ip6_forwarding && ip6_accept_rtadv) {
60353541Sshin		/* above is a good condition? */
60453541Sshin		rt6_flush(&dr->rtaddr, dr->ifp);
60553541Sshin	}
60653541Sshin
60762587Sitojun	if (dr == TAILQ_FIRST(&nd_defrouter))
60853541Sshin		deldr = dr;	/* The router is primary. */
60953541Sshin
61062587Sitojun	TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
61153541Sshin
61253541Sshin	/*
61353541Sshin	 * Also delete all the pointers to the router in each prefix lists.
61453541Sshin	 */
61562587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
61653541Sshin		struct nd_pfxrouter *pfxrtr;
61753541Sshin		if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
61853541Sshin			pfxrtr_del(pfxrtr);
61953541Sshin	}
62053541Sshin	pfxlist_onlink_check();
62153541Sshin
62253541Sshin	/*
62362587Sitojun	 * If the router is the primary one, choose a new one.
62462587Sitojun	 * Note that defrouter_select() will remove the current gateway
62562587Sitojun	 * from the routing table.
62653541Sshin	 */
62753541Sshin	if (deldr)
62862587Sitojun		defrouter_select();
62962587Sitojun
63053541Sshin	free(dr, M_IP6NDP);
63153541Sshin}
63253541Sshin
63362587Sitojun/*
63462587Sitojun * Default Router Selection according to Section 6.3.6 of RFC 2461:
63562587Sitojun * 1) Routers that are reachable or probably reachable should be
63662587Sitojun *    preferred.
63762587Sitojun * 2) When no routers on the list are known to be reachable or
63862587Sitojun *    probably reachable, routers SHOULD be selected in a round-robin
63962587Sitojun *    fashion.
64062587Sitojun * 3) If the Default Router List is empty, assume that all
64162587Sitojun *    destinations are on-link.
64262587Sitojun */
64362587Sitojunvoid
64462587Sitojundefrouter_select()
64562587Sitojun{
64662587Sitojun	int s = splnet();
64762587Sitojun	struct nd_defrouter *dr, anydr;
64862587Sitojun	struct rtentry *rt = NULL;
64962587Sitojun	struct llinfo_nd6 *ln = NULL;
65062587Sitojun
65162587Sitojun	/*
65262587Sitojun	 * Search for a (probably) reachable router from the list.
65362587Sitojun	 */
65462587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
65562587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
65662587Sitojun		if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
65762587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
65862587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln)) {
65962587Sitojun			/* Got it, and move it to the head */
66062587Sitojun			TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
66162587Sitojun			TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry);
66262587Sitojun			break;
66362587Sitojun		}
66462587Sitojun	}
66562587Sitojun
66662587Sitojun	if ((dr = TAILQ_FIRST(&nd_defrouter))) {
66762587Sitojun		/*
66862587Sitojun		 * De-install the previous default gateway and install
66962587Sitojun		 * a new one.
67062587Sitojun		 * Note that if there is no reachable router in the list,
67162587Sitojun		 * the head entry will be used anyway.
67262587Sitojun		 * XXX: do we have to check the current routing table entry?
67362587Sitojun		 */
67462587Sitojun		bzero(&anydr, sizeof(anydr));
67562587Sitojun		defrouter_delreq(&anydr, 0);
67662587Sitojun		defrouter_addreq(dr);
67762587Sitojun	}
67862587Sitojun	else {
67962587Sitojun		/*
68062587Sitojun		 * The Default Router List is empty, so install the default
68162587Sitojun		 * route to an inteface.
68262587Sitojun		 * XXX: The specification does not say this mechanism should
68362587Sitojun		 * be restricted to hosts, but this would be not useful
68462587Sitojun		 * (even harmful) for routers.
68562587Sitojun		 */
68662587Sitojun		if (!ip6_forwarding) {
68762587Sitojun			/*
68862587Sitojun			 * De-install the current default route
68962587Sitojun			 * in advance.
69062587Sitojun			 */
69162587Sitojun			bzero(&anydr, sizeof(anydr));
69262587Sitojun			defrouter_delreq(&anydr, 0);
69362587Sitojun			if (nd6_defifp) {
69462587Sitojun				/*
69562587Sitojun				 * Install a route to the default interface
69662587Sitojun				 * as default route.
69778064Sume				 * XXX: we enable this for host only, because
69878064Sume				 * this may override a default route installed
69978064Sume				 * a user process (e.g. routing daemon) in a
70078064Sume				 * router case.
70162587Sitojun				 */
70262587Sitojun				defrouter_addifreq(nd6_defifp);
70378064Sume			} else {
70478064Sume				nd6log((LOG_INFO, "defrouter_select: "
70578064Sume				    "there's no default router and no default"
70678064Sume				    " interface\n"));
70762587Sitojun			}
70862587Sitojun		}
70962587Sitojun	}
71062587Sitojun
71162587Sitojun	splx(s);
71262587Sitojun	return;
71362587Sitojun}
71462587Sitojun
71553541Sshinstatic struct nd_defrouter *
71653541Sshindefrtrlist_update(new)
71753541Sshin	struct nd_defrouter *new;
71853541Sshin{
71953541Sshin	struct nd_defrouter *dr, *n;
72053541Sshin	int s = splnet();
72153541Sshin
72253541Sshin	if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
72353541Sshin		/* entry exists */
72453541Sshin		if (new->rtlifetime == 0) {
72553541Sshin			defrtrlist_del(dr);
72653541Sshin			dr = NULL;
72753541Sshin		} else {
72853541Sshin			/* override */
72953541Sshin			dr->flags = new->flags; /* xxx flag check */
73053541Sshin			dr->rtlifetime = new->rtlifetime;
73153541Sshin			dr->expire = new->expire;
73253541Sshin		}
73353541Sshin		splx(s);
73453541Sshin		return(dr);
73553541Sshin	}
73653541Sshin
73753541Sshin	/* entry does not exist */
73853541Sshin	if (new->rtlifetime == 0) {
73953541Sshin		splx(s);
74053541Sshin		return(NULL);
74153541Sshin	}
74253541Sshin
74353541Sshin	n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
74453541Sshin	if (n == NULL) {
74553541Sshin		splx(s);
74653541Sshin		return(NULL);
74753541Sshin	}
74853541Sshin	bzero(n, sizeof(*n));
74953541Sshin	*n = *new;
75062587Sitojun
75162587Sitojun	/*
75262587Sitojun	 * Insert the new router at the end of the Default Router List.
75362587Sitojun	 * If there is no other router, install it anyway. Otherwise,
75462587Sitojun	 * just continue to use the current default router.
75562587Sitojun	 */
75662587Sitojun	TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
75762587Sitojun	if (TAILQ_FIRST(&nd_defrouter) == n)
75862587Sitojun		defrouter_select();
75953541Sshin	splx(s);
76053541Sshin
76153541Sshin	return(n);
76253541Sshin}
76353541Sshin
76453541Sshinstatic struct nd_pfxrouter *
76553541Sshinpfxrtr_lookup(pr, dr)
76653541Sshin	struct nd_prefix *pr;
76753541Sshin	struct nd_defrouter *dr;
76853541Sshin{
76953541Sshin	struct nd_pfxrouter *search;
77062587Sitojun
77162587Sitojun	for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
77253541Sshin		if (search->router == dr)
77353541Sshin			break;
77453541Sshin	}
77553541Sshin
77653541Sshin	return(search);
77753541Sshin}
77853541Sshin
77953541Sshinstatic void
78053541Sshinpfxrtr_add(pr, dr)
78153541Sshin	struct nd_prefix *pr;
78253541Sshin	struct nd_defrouter *dr;
78353541Sshin{
78453541Sshin	struct nd_pfxrouter *new;
78553541Sshin
78653541Sshin	new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
78753541Sshin	if (new == NULL)
78853541Sshin		return;
78953541Sshin	bzero(new, sizeof(*new));
79053541Sshin	new->router = dr;
79153541Sshin
79253541Sshin	LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
79353541Sshin
79453541Sshin	pfxlist_onlink_check();
79553541Sshin}
79653541Sshin
79753541Sshinstatic void
79853541Sshinpfxrtr_del(pfr)
79953541Sshin	struct nd_pfxrouter *pfr;
80053541Sshin{
80153541Sshin	LIST_REMOVE(pfr, pfr_entry);
80253541Sshin	free(pfr, M_IP6NDP);
80353541Sshin}
80453541Sshin
80578064Sumestruct nd_prefix *
80678064Sumend6_prefix_lookup(pr)
80753541Sshin	struct nd_prefix *pr;
80853541Sshin{
80953541Sshin	struct nd_prefix *search;
81053541Sshin
81162587Sitojun	for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
81253541Sshin		if (pr->ndpr_ifp == search->ndpr_ifp &&
81353541Sshin		    pr->ndpr_plen == search->ndpr_plen &&
81453541Sshin		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
81553541Sshin					 &search->ndpr_prefix.sin6_addr,
81653541Sshin					 pr->ndpr_plen)
81753541Sshin		    ) {
81853541Sshin			break;
81953541Sshin		}
82053541Sshin	}
82153541Sshin
82253541Sshin	return(search);
82353541Sshin}
82453541Sshin
82578064Sumeint
82678064Sumend6_prelist_add(pr, dr, newp)
82778064Sume	struct nd_prefix *pr, **newp;
82853541Sshin	struct nd_defrouter *dr;
82953541Sshin{
83078064Sume	struct nd_prefix *new = NULL;
83153541Sshin	int i, s;
83253541Sshin
83353541Sshin	new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
83453541Sshin	if (new == NULL)
83553541Sshin		return ENOMEM;
83653541Sshin	bzero(new, sizeof(*new));
83753541Sshin	*new = *pr;
83878064Sume	if (newp != NULL)
83978064Sume		*newp = new;
84053541Sshin
84153541Sshin	/* initilization */
84253541Sshin	LIST_INIT(&new->ndpr_advrtrs);
84353541Sshin	in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
84453541Sshin	/* make prefix in the canonical form */
84553541Sshin	for (i = 0; i < 4; i++)
84653541Sshin		new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
84753541Sshin			new->ndpr_mask.s6_addr32[i];
84853541Sshin
84953541Sshin	s = splnet();
85053541Sshin	/* link ndpr_entry to nd_prefix list */
85153541Sshin	LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
85253541Sshin	splx(s);
85353541Sshin
85478064Sume	/* ND_OPT_PI_FLAG_ONLINK processing */
85578064Sume	if (new->ndpr_raf_onlink) {
85678064Sume		int e;
85778064Sume
85878064Sume		if ((e = nd6_prefix_onlink(new)) != 0) {
85978064Sume			nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
86078064Sume			    "the prefix %s/%d on-link on %s (errno=%d)\n",
86178064Sume			    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
86278064Sume			    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
86378064Sume			/* proceed anyway. XXX: is it correct? */
86478064Sume		}
86578064Sume	}
86678064Sume
86762587Sitojun	if (dr) {
86853541Sshin		pfxrtr_add(new, dr);
86962587Sitojun	}
87053541Sshin
87153541Sshin	return 0;
87253541Sshin}
87353541Sshin
87453541Sshinvoid
87553541Sshinprelist_remove(pr)
87653541Sshin	struct nd_prefix *pr;
87753541Sshin{
87853541Sshin	struct nd_pfxrouter *pfr, *next;
87978064Sume	int e, s;
88053541Sshin
88178064Sume	/* make sure to invalidate the prefix until it is really freed. */
88278064Sume	pr->ndpr_vltime = 0;
88378064Sume	pr->ndpr_pltime = 0;
88478064Sume#if 0
88578064Sume	/*
88678064Sume	 * Though these flags are now meaningless, we'd rather keep the value
88778064Sume	 * not to confuse users when executing "ndp -p".
88878064Sume	 */
88978064Sume	pr->ndpr_raf_onlink = 0;
89078064Sume	pr->ndpr_raf_auto = 0;
89178064Sume#endif
89278064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
89378064Sume	    (e = nd6_prefix_offlink(pr)) != 0) {
89478064Sume		nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
89578064Sume		    "on %s, errno=%d\n",
89678064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
89778064Sume		    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
89878064Sume		/* what should we do? */
89978064Sume	}
90078064Sume
90178064Sume	if (pr->ndpr_refcnt > 0)
90278064Sume		return;		/* notice here? */
90378064Sume
90453541Sshin	s = splnet();
90578064Sume
90653541Sshin	/* unlink ndpr_entry from nd_prefix list */
90753541Sshin	LIST_REMOVE(pr, ndpr_entry);
90853541Sshin
90953541Sshin	/* free list of routers that adversed the prefix */
91062587Sitojun	for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
91162587Sitojun		next = pfr->pfr_next;
91253541Sshin
91353541Sshin		free(pfr, M_IP6NDP);
91453541Sshin	}
91578064Sume	splx(s);
91678064Sume
91753541Sshin	free(pr, M_IP6NDP);
91853541Sshin
91953541Sshin	pfxlist_onlink_check();
92053541Sshin}
92153541Sshin
92253541Sshinint
92353541Sshinprelist_update(new, dr, m)
92453541Sshin	struct nd_prefix *new;
92553541Sshin	struct nd_defrouter *dr; /* may be NULL */
92653541Sshin	struct mbuf *m;
92753541Sshin{
92878064Sume	struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
92978064Sume	struct ifaddr *ifa;
93078064Sume	struct ifnet *ifp = new->ndpr_ifp;
93153541Sshin	struct nd_prefix *pr;
93253541Sshin	int s = splnet();
93353541Sshin	int error = 0;
93478064Sume	int newprefix = 0;
93553541Sshin	int auth;
93678064Sume	struct in6_addrlifetime lt6_tmp;
93753541Sshin
93853541Sshin	auth = 0;
93953541Sshin	if (m) {
94053541Sshin		/*
94153541Sshin		 * Authenticity for NA consists authentication for
94253541Sshin		 * both IP header and IP datagrams, doesn't it ?
94353541Sshin		 */
94453541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
94553541Sshin		auth = (m->m_flags & M_AUTHIPHDR
94653541Sshin		     && m->m_flags & M_AUTHIPDGM) ? 1 : 0;
94753541Sshin#endif
94853541Sshin	}
94953541Sshin
95062587Sitojun
95178064Sume	if ((pr = nd6_prefix_lookup(new)) != NULL) {
95278064Sume		/*
95378064Sume		 * nd6_prefix_lookup() ensures that pr and new have the same
95478064Sume		 * prefix on a same interface.
95578064Sume		 */
95653541Sshin
95753541Sshin		/*
95878064Sume		 * Update prefix information.  Note that the on-link (L) bit
95978064Sume		 * and the autonomous (A) bit should NOT be changed from 1
96078064Sume		 * to 0.
96153541Sshin		 */
96278064Sume		if (new->ndpr_raf_onlink == 1)
96378064Sume			pr->ndpr_raf_onlink = 1;
96478064Sume		if (new->ndpr_raf_auto == 1)
96578064Sume			pr->ndpr_raf_auto = 1;
96678064Sume		if (new->ndpr_raf_onlink) {
96778064Sume			pr->ndpr_vltime = new->ndpr_vltime;
96878064Sume			pr->ndpr_pltime = new->ndpr_pltime;
96978064Sume			pr->ndpr_preferred = new->ndpr_preferred;
97078064Sume			pr->ndpr_expire = new->ndpr_expire;
97178064Sume		}
97253541Sshin
97378064Sume		if (new->ndpr_raf_onlink &&
97478064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
97578064Sume			int e;
97653541Sshin
97778064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
97878064Sume				nd6log((LOG_ERR,
97978064Sume				    "prelist_update: failed to make "
98078064Sume				    "the prefix %s/%d on-link on %s "
98178064Sume				    "(errno=%d)\n",
98278064Sume				    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
98378064Sume				    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
98478064Sume				/* proceed anyway. XXX: is it correct? */
98553541Sshin			}
98678064Sume		}
98753541Sshin
98878064Sume		if (dr && pfxrtr_lookup(pr, dr) == NULL)
98978064Sume			pfxrtr_add(pr, dr);
99078064Sume	} else {
99178064Sume		struct nd_prefix *newpr = NULL;
99253541Sshin
99378064Sume		newprefix = 1;
99453541Sshin
99578064Sume		if (new->ndpr_vltime == 0)
99678064Sume			goto end;
99778064Sume		if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
99878064Sume			goto end;
99953541Sshin
100078064Sume		bzero(&new->ndpr_addr, sizeof(struct in6_addr));
100162587Sitojun
100278064Sume		error = nd6_prelist_add(new, dr, &newpr);
100378064Sume		if (error != 0 || newpr == NULL) {
100478064Sume			nd6log((LOG_NOTICE, "prelist_update: "
100578064Sume			    "nd6_prelist_add failed for %s/%d on %s "
100678064Sume			    "errno=%d, returnpr=%p\n",
100778064Sume			    ip6_sprintf(&new->ndpr_prefix.sin6_addr),
100878064Sume					new->ndpr_plen, if_name(new->ndpr_ifp),
100978064Sume					error, newpr));
101078064Sume			goto end; /* we should just give up in this case. */
101178064Sume		}
101253541Sshin
101378064Sume		/*
101478064Sume		 * XXX: from the ND point of view, we can ignore a prefix
101578064Sume		 * with the on-link bit being zero.  However, we need a
101678064Sume		 * prefix structure for references from autoconfigured
101778064Sume		 * addresses.  Thus, we explicitly make suret that the prefix
101878064Sume		 * itself expires now.
101978064Sume		 */
102078064Sume		if (newpr->ndpr_raf_onlink == 0) {
102178064Sume			newpr->ndpr_vltime = 0;
102278064Sume			newpr->ndpr_pltime = 0;
102378064Sume			in6_init_prefix_ltimes(newpr);
102453541Sshin		}
102553541Sshin
102678064Sume		pr = newpr;
102778064Sume	}
102853541Sshin
102978064Sume	/*
103078064Sume	 * Address autoconfiguration based on Section 5.5.3 of RFC 2462.
103178064Sume	 * Note that pr must be non NULL at this point.
103278064Sume	 */
103362587Sitojun
103478064Sume	/* 5.5.3 (a). Ignore the prefix without the A bit set. */
103578064Sume	if (!new->ndpr_raf_auto)
103678064Sume		goto afteraddrconf;
103762587Sitojun
103878064Sume	/*
103978064Sume	 * 5.5.3 (b). the link-local prefix should have been ignored in
104078064Sume	 * nd6_ra_input.
104178064Sume	 */
104262587Sitojun
104378064Sume	/*
104478064Sume	 * 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime.
104578064Sume	 * This should have been done in nd6_ra_input.
104678064Sume	 */
104762587Sitojun
104878064Sume 	/*
104978064Sume	 * 5.5.3 (d). If the prefix advertised does not match the prefix of an
105078064Sume	 * address already in the list, and the Valid Lifetime is not 0,
105178064Sume	 * form an address.  Note that even a manually configured address
105278064Sume	 * should reject autoconfiguration of a new address.
105378064Sume	 */
105478064Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
105578064Sume	{
105678064Sume		struct in6_ifaddr *ifa6;
105778064Sume		int ifa_plen;
105878064Sume		u_int32_t storedlifetime;
105953541Sshin
106078064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
106178064Sume			continue;
106253541Sshin
106378064Sume		ifa6 = (struct in6_ifaddr *)ifa;
106453541Sshin
106553541Sshin		/*
106678064Sume		 * Spec is not clear here, but I believe we should concentrate
106778064Sume		 * on unicast (i.e. not anycast) addresses.
106878064Sume		 * XXX: other ia6_flags? detached or duplicated?
106953541Sshin		 */
107078064Sume		if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
107178064Sume			continue;
107278064Sume
107378064Sume		ifa_plen = in6_mask2len(&ifa6->ia_prefixmask.sin6_addr, NULL);
107478064Sume		if (ifa_plen != new->ndpr_plen ||
107578064Sume		    !in6_are_prefix_equal(&ifa6->ia_addr.sin6_addr,
107678064Sume					  &new->ndpr_prefix.sin6_addr,
107778064Sume					  ifa_plen))
107878064Sume			continue;
107953541Sshin
108078064Sume		if (ia6_match == NULL) /* remember the first one */
108178064Sume			ia6_match = ifa6;
108278064Sume
108378064Sume		if ((ifa6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
108478064Sume			continue;
108578064Sume
108678064Sume		/*
108778064Sume		 * An already autoconfigured address matched.  Now that we
108878064Sume		 * are sure there is at least one matched address, we can
108978064Sume		 * proceed to 5.5.3. (e): update the lifetimes according to the
109078064Sume		 * "two hours" rule and the privacy extension.
109178064Sume		 */
109278064Sume#define TWOHOUR		(120*60)
109378064Sume		lt6_tmp = ifa6->ia6_lifetime;
109478064Sume
109578064Sume		storedlifetime = IFA6_IS_INVALID(ifa6) ? 0 :
109678064Sume			(lt6_tmp.ia6t_expire - time_second);
109778064Sume
109878064Sume		if (TWOHOUR < new->ndpr_vltime ||
109978064Sume		    storedlifetime < new->ndpr_vltime) {
110078064Sume			lt6_tmp.ia6t_vltime = new->ndpr_vltime;
110178064Sume		} else if (storedlifetime <= TWOHOUR
110278064Sume#if 0
110378064Sume			   /*
110478064Sume			    * This condition is logically redundant, so we just
110578064Sume			    * omit it.
110678064Sume			    * See IPng 6712, 6717, and 6721.
110778064Sume			    */
110878064Sume			   && new->ndpr_vltime <= storedlifetime
110978064Sume#endif
111078064Sume			) {
111178064Sume			if (auth) {
111278064Sume				lt6_tmp.ia6t_vltime = new->ndpr_vltime;
111378064Sume			}
111478064Sume		} else {
111578064Sume			/*
111678064Sume			 * new->ndpr_vltime <= TWOHOUR &&
111778064Sume			 * TWOHOUR < storedlifetime
111878064Sume			 */
111978064Sume			lt6_tmp.ia6t_vltime = TWOHOUR;
112053541Sshin		}
112153541Sshin
112278064Sume		/* The 2 hour rule is not imposed for preferred lifetime. */
112378064Sume		lt6_tmp.ia6t_pltime = new->ndpr_pltime;
112453541Sshin
112578064Sume		in6_init_address_ltimes(pr, &lt6_tmp);
112653541Sshin
112778064Sume		/*
112878064Sume		 * When adjusting the lifetimes of an existing temporary
112978064Sume		 * address, only lower the lifetimes.
113078064Sume		 * RFC 3041 3.3. (1).
113178064Sume		 * XXX: how should we modify ia6t_[pv]ltime?
113278064Sume		 */
113378064Sume		if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
113478064Sume			if (lt6_tmp.ia6t_expire == 0 || /* no expire */
113578064Sume			    lt6_tmp.ia6t_expire >
113678064Sume			    ifa6->ia6_lifetime.ia6t_expire) {
113778064Sume				lt6_tmp.ia6t_expire =
113878064Sume					ifa6->ia6_lifetime.ia6t_expire;
113978064Sume			}
114078064Sume			if (lt6_tmp.ia6t_preferred == 0 || /* no expire */
114178064Sume			    lt6_tmp.ia6t_preferred >
114278064Sume			    ifa6->ia6_lifetime.ia6t_preferred) {
114378064Sume				lt6_tmp.ia6t_preferred =
114478064Sume					ifa6->ia6_lifetime.ia6t_preferred;
114578064Sume			}
114678064Sume		}
114778064Sume
114878064Sume		ifa6->ia6_lifetime = lt6_tmp;
114953541Sshin	}
115078064Sume	if (ia6_match == NULL && new->ndpr_vltime) {
115178064Sume		/*
115278064Sume		 * No address matched and the valid lifetime is non-zero.
115378064Sume		 * Create a new address.
115478064Sume		 */
115578064Sume		if ((ia6 = in6_ifadd(new, NULL)) != NULL) {
115678064Sume			/*
115778064Sume			 * note that we should use pr (not new) for reference.
115878064Sume			 */
115978064Sume			pr->ndpr_refcnt++;
116078064Sume			ia6->ia6_ndpr = pr;
116153541Sshin
116278064Sume#if 0
116378064Sume			/* XXXYYY Don't do this, according to Jinmei. */
116478064Sume			pr->ndpr_addr = new->ndpr_addr;
116578064Sume#endif
116678064Sume
116778064Sume			/*
116878064Sume			 * RFC 3041 3.3 (2).
116978064Sume			 * When a new public address is created as described
117078064Sume			 * in RFC2462, also create a new temporary address.
117178064Sume			 *
117278064Sume			 * RFC 3041 3.5.
117378064Sume			 * When an interface connects to a new link, a new
117478064Sume			 * randomized interface identifier should be generated
117578064Sume			 * immediately together with a new set of temporary
117678064Sume			 * addresses.  Thus, we specifiy 1 as the 2nd arg of
117778064Sume			 * in6_tmpifadd().
117878064Sume			 */
117978064Sume			if (ip6_use_tempaddr) {
118078064Sume				int e;
118178064Sume				if ((e = in6_tmpifadd(ia6, 1)) != 0) {
118278064Sume					nd6log((LOG_NOTICE, "prelist_update: "
118378064Sume					    "failed to create a temporary "
118478064Sume					    "address, errno=%d\n",
118578064Sume					    e));
118678064Sume				}
118778064Sume			}
118878064Sume
118978064Sume			/*
119078064Sume			 * A newly added address might affect the status
119178064Sume			 * of other addresses, so we check and update it.
119278064Sume			 * XXX: what if address duplication happens?
119378064Sume			 */
119478064Sume			pfxlist_onlink_check();
119578064Sume		} else {
119678064Sume			/* just set an error. do not bark here. */
119778064Sume			error = EADDRNOTAVAIL; /* XXX: might be unused. */
119878064Sume		}
119978064Sume	}
120078064Sume
120178064Sume  afteraddrconf:
120278064Sume
120353541Sshin end:
120453541Sshin	splx(s);
120553541Sshin	return error;
120653541Sshin}
120753541Sshin
120853541Sshin/*
120962587Sitojun * A supplement function used in the on-link detection below;
121062587Sitojun * detect if a given prefix has a (probably) reachable advertising router.
121162587Sitojun * XXX: lengthy function name...
121262587Sitojun */
121378064Sumestatic struct nd_pfxrouter *
121462587Sitojunfind_pfxlist_reachable_router(pr)
121562587Sitojun	struct nd_prefix *pr;
121662587Sitojun{
121762587Sitojun	struct nd_pfxrouter *pfxrtr;
121862587Sitojun	struct rtentry *rt;
121962587Sitojun	struct llinfo_nd6 *ln;
122062587Sitojun
122162587Sitojun	for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
122262587Sitojun	     pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
122362587Sitojun		if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
122462587Sitojun				     pfxrtr->router->ifp)) &&
122562587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
122662587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln))
122762587Sitojun			break;	/* found */
122862587Sitojun	}
122962587Sitojun
123062587Sitojun	return(pfxrtr);
123162587Sitojun
123262587Sitojun}
123362587Sitojun
123462587Sitojun/*
123553541Sshin * Check if each prefix in the prefix list has at least one available router
123678064Sume * that advertised the prefix (a router is "available" if its neighbor cache
123778064Sume * entry is reachable or probably reachable).
123862587Sitojun * If the check fails, the prefix may be off-link, because, for example,
123953541Sshin * we have moved from the network but the lifetime of the prefix has not
124078064Sume * expired yet.  So we should not use the prefix if there is another prefix
124178064Sume * that has an available router.
124278064Sume * But, if there is no prefix that has an available router, we still regards
124378064Sume * all the prefixes as on-link.  This is because we can't tell if all the
124453541Sshin * routers are simply dead or if we really moved from the network and there
124553541Sshin * is no router around us.
124653541Sshin */
124762587Sitojunvoid
124853541Sshinpfxlist_onlink_check()
124953541Sshin{
125053541Sshin	struct nd_prefix *pr;
125178064Sume	struct in6_ifaddr *ifa;
125253541Sshin
125362587Sitojun	/*
125462587Sitojun	 * Check if there is a prefix that has a reachable advertising
125562587Sitojun	 * router.
125662587Sitojun	 */
125762587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
125878064Sume		if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
125953541Sshin			break;
126062587Sitojun	}
126153541Sshin
126253541Sshin	if (pr) {
126353541Sshin		/*
126462587Sitojun		 * There is at least one prefix that has a reachable router.
126578064Sume		 * Detach prefixes which have no reachable advertising
126678064Sume		 * router, and attach other prefixes.
126753541Sshin		 */
126862587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
126978064Sume			/* XXX: a link-local prefix should never be detached */
127078064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
127178064Sume				continue;
127278064Sume
127378064Sume			/*
127478064Sume			 * we aren't interested in prefixes without the L bit
127578064Sume			 * set.
127678064Sume			 */
127778064Sume			if (pr->ndpr_raf_onlink == 0)
127878064Sume				continue;
127978064Sume
128078064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
128178064Sume			    find_pfxlist_reachable_router(pr) == NULL)
128278064Sume				pr->ndpr_stateflags |= NDPRF_DETACHED;
128378064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
128478064Sume			    find_pfxlist_reachable_router(pr) != 0)
128578064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
128653541Sshin		}
128778064Sume	} else {
128878064Sume		/* there is no prefix that has a reachable router */
128962587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
129078064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
129178064Sume				continue;
129278064Sume
129378064Sume			if (pr->ndpr_raf_onlink == 0)
129478064Sume				continue;
129578064Sume
129678064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
129778064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
129853541Sshin		}
129962587Sitojun	}
130078064Sume
130178064Sume	/*
130278064Sume	 * Remove each interface route associated with a (just) detached
130378064Sume	 * prefix, and reinstall the interface route for a (just) attached
130478064Sume	 * prefix.  Note that all attempt of reinstallation does not
130578064Sume	 * necessarily success, when a same prefix is shared among multiple
130678064Sume	 * interfaces.  Such cases will be handled in nd6_prefix_onlink,
130778064Sume	 * so we don't have to care about them.
130878064Sume	 */
130978064Sume	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
131078064Sume		int e;
131178064Sume
131278064Sume		if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
131378064Sume			continue;
131478064Sume
131578064Sume		if (pr->ndpr_raf_onlink == 0)
131678064Sume			continue;
131778064Sume
131878064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
131978064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
132078064Sume			if ((e = nd6_prefix_offlink(pr)) != 0) {
132178064Sume				nd6log((LOG_ERR,
132278064Sume				    "pfxlist_onlink_check: failed to "
132378064Sume				    "make %s/%d offlink, errno=%d\n",
132478064Sume				    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
132578064Sume				    pr->ndpr_plen, e));
132678064Sume			}
132778064Sume		}
132878064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
132978064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
133078064Sume		    pr->ndpr_raf_onlink) {
133178064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
133278064Sume				nd6log((LOG_ERR,
133378064Sume				    "pfxlist_onlink_check: failed to "
133478064Sume				    "make %s/%d offlink, errno=%d\n",
133578064Sume				    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
133678064Sume				    pr->ndpr_plen, e));
133778064Sume			}
133878064Sume		}
133978064Sume	}
134078064Sume
134178064Sume	/*
134278064Sume	 * Changes on the prefix status might affect address status as well.
134378064Sume	 * Make sure that all addresses derived from an attached prefix are
134478064Sume	 * attached, and that all addresses derived from a detached prefix are
134578064Sume	 * detached.  Note, however, that a manually configured address should
134678064Sume	 * always be attached.
134778064Sume	 * The precise detection logic is same as the one for prefixes.
134878064Sume	 */
134978064Sume	for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
135078064Sume		if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
135178064Sume			continue;
135278064Sume
135378064Sume		if (ifa->ia6_ndpr == NULL) {
135478064Sume			/*
135578064Sume			 * This can happen when we first configure the address
135678064Sume			 * (i.e. the address exists, but the prefix does not).
135778064Sume			 * XXX: complicated relationships...
135878064Sume			 */
135978064Sume			continue;
136078064Sume		}
136178064Sume
136278064Sume		if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
136378064Sume			break;
136478064Sume	}
136578064Sume	if (ifa) {
136678064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
136778064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
136878064Sume				continue;
136978064Sume
137078064Sume			if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
137178064Sume				continue;
137278064Sume
137378064Sume			if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
137478064Sume				ifa->ia6_flags &= ~IN6_IFF_DETACHED;
137578064Sume			else
137678064Sume				ifa->ia6_flags |= IN6_IFF_DETACHED;
137778064Sume		}
137878064Sume	}
137962587Sitojun	else {
138078064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
138178064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
138278064Sume				continue;
138378064Sume
138478064Sume			ifa->ia6_flags &= ~IN6_IFF_DETACHED;
138578064Sume		}
138653541Sshin	}
138753541Sshin}
138853541Sshin
138978064Sumeint
139078064Sumend6_prefix_onlink(pr)
139153541Sshin	struct nd_prefix *pr;
139253541Sshin{
139378064Sume	struct ifaddr *ifa;
139478064Sume	struct ifnet *ifp = pr->ndpr_ifp;
139578064Sume	struct sockaddr_in6 mask6;
139678064Sume	struct nd_prefix *opr;
139778064Sume	u_long rtflags;
139878064Sume	int error = 0;
139978064Sume	struct rtentry *rt = NULL;
140053541Sshin
140178064Sume	/* sanity check */
140278064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
140378064Sume		nd6log((LOG_ERR,
140478064Sume		    "nd6_prefix_onlink: %s/%d is already on-link\n",
140578064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen);
140678064Sume		return(EEXIST));
140778064Sume	}
140878064Sume
140953541Sshin	/*
141078064Sume	 * Add the interface route associated with the prefix.  Before
141178064Sume	 * installing the route, check if there's the same prefix on another
141278064Sume	 * interface, and the prefix has already installed the interface route.
141378064Sume	 * Although such a configuration is expected to be rare, we explicitly
141478064Sume	 * allow it.
141553541Sshin	 */
141678064Sume	for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
141778064Sume		if (opr == pr)
141878064Sume			continue;
141978064Sume
142078064Sume		if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
142178064Sume			continue;
142278064Sume
142378064Sume		if (opr->ndpr_plen == pr->ndpr_plen &&
142478064Sume		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
142578064Sume					 &opr->ndpr_prefix.sin6_addr,
142678064Sume					 pr->ndpr_plen))
142778064Sume			return(0);
142878064Sume	}
142978064Sume
143078064Sume	/*
143178064Sume	 * We prefer link-local addresses as the associated interface address.
143278064Sume	 */
143378064Sume	/* search for a link-local addr */
143478064Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
143578064Sume						      IN6_IFF_NOTREADY|
143678064Sume						      IN6_IFF_ANYCAST);
143778064Sume	if (ifa == NULL) {
143878064Sume		/* XXX: freebsd does not have ifa_ifwithaf */
143978064Sume		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
144078064Sume		{
144178064Sume			if (ifa->ifa_addr->sa_family == AF_INET6)
144278064Sume				break;
144378064Sume		}
144478064Sume		/* should we care about ia6_flags? */
144578064Sume	}
144678064Sume	if (ifa == NULL) {
144778064Sume		/*
144878064Sume		 * This can still happen, when, for example, we receive an RA
144978064Sume		 * containing a prefix with the L bit set and the A bit clear,
145078064Sume		 * after removing all IPv6 addresses on the receiving
145178064Sume		 * interface.  This should, of course, be rare though.
145278064Sume		 */
145378064Sume		nd6log((LOG_NOTICE,
145478064Sume		    "nd6_prefix_onlink: failed to find any ifaddr"
145578064Sume		    " to add route for a prefix(%s/%d) on %s\n",
145678064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
145778064Sume		    pr->ndpr_plen, if_name(ifp)));
145878064Sume		return(0);
145978064Sume	}
146078064Sume
146178064Sume	/*
146278064Sume	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
146378064Sume	 * ifa->ifa_rtrequest = nd6_rtrequest;
146478064Sume	 */
146578064Sume	bzero(&mask6, sizeof(mask6));
146678064Sume	mask6.sin6_len = sizeof(mask6);
146778064Sume	mask6.sin6_addr = pr->ndpr_mask;
146878064Sume	rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP;
146978064Sume	if (nd6_need_cache(ifp)) {
147078064Sume		/* explicitly set in case ifa_flags does not set the flag. */
147178064Sume		rtflags |= RTF_CLONING;
147278064Sume	} else {
147378064Sume		/*
147478064Sume		 * explicitly clear the cloning bit in case ifa_flags sets it.
147578064Sume		 */
147678064Sume		rtflags &= ~RTF_CLONING;
147778064Sume	}
147878064Sume	error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
147978064Sume			  ifa->ifa_addr, (struct sockaddr *)&mask6,
148078064Sume			  rtflags, &rt);
148178064Sume	if (error == 0) {
148278064Sume		if (rt != NULL) /* this should be non NULL, though */
148378064Sume			nd6_rtmsg(RTM_ADD, rt);
148478064Sume		pr->ndpr_stateflags |= NDPRF_ONLINK;
148578064Sume	}
148678064Sume	else {
148778064Sume		nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
148878064Sume		    " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
148978064Sume		    "errno = %d\n",
149078064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
149178064Sume		    pr->ndpr_plen, if_name(ifp),
149278064Sume		    ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
149378064Sume		    ip6_sprintf(&mask6.sin6_addr), rtflags, error));
149478064Sume	}
149578064Sume
149678064Sume	if (rt != NULL)
149778064Sume		rt->rt_refcnt--;
149878064Sume
149978064Sume	return(error);
150078064Sume}
150178064Sume
150278064Sumeint
150378064Sumend6_prefix_offlink(pr)
150478064Sume	struct nd_prefix *pr;
150578064Sume{
150678064Sume	int error = 0;
150778064Sume	struct ifnet *ifp = pr->ndpr_ifp;
150878064Sume	struct nd_prefix *opr;
150978064Sume	struct sockaddr_in6 sa6, mask6;
151078064Sume	struct rtentry *rt = NULL;
151178064Sume
151278064Sume	/* sanity check */
151378064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
151478064Sume		nd6log((LOG_ERR,
151578064Sume		    "nd6_prefix_offlink: %s/%d is already off-link\n",
151678064Sume		    ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen));
151778064Sume		return(EEXIST);
151878064Sume	}
151978064Sume
152053541Sshin	bzero(&sa6, sizeof(sa6));
152153541Sshin	sa6.sin6_family = AF_INET6;
152253541Sshin	sa6.sin6_len = sizeof(sa6);
152353541Sshin	bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
152453541Sshin	      sizeof(struct in6_addr));
152553541Sshin	bzero(&mask6, sizeof(mask6));
152653541Sshin	mask6.sin6_family = AF_INET6;
152753541Sshin	mask6.sin6_len = sizeof(sa6);
152853541Sshin	bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
152978064Sume	error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
153078064Sume			  (struct sockaddr *)&mask6, 0, &rt);
153178064Sume	if (error == 0) {
153278064Sume		pr->ndpr_stateflags &= ~NDPRF_ONLINK;
153353541Sshin
153478064Sume		/* report the route deletion to the routing socket. */
153578064Sume		if (rt != NULL)
153678064Sume			nd6_rtmsg(RTM_DELETE, rt);
153753541Sshin
153878064Sume		/*
153978064Sume		 * There might be the same prefix on another interface,
154078064Sume		 * the prefix which could not be on-link just because we have
154178064Sume		 * the interface route (see comments in nd6_prefix_onlink).
154278064Sume		 * If there's one, try to make the prefix on-link on the
154378064Sume		 * interface.
154478064Sume		 */
154578064Sume		for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
154678064Sume			if (opr == pr)
154778064Sume				continue;
154853541Sshin
154978064Sume			if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
155078064Sume				continue;
155153541Sshin
155278064Sume			/*
155378064Sume			 * KAME specific: detached prefixes should not be
155478064Sume			 * on-link.
155578064Sume			 */
155678064Sume			if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
155778064Sume				continue;
155878064Sume
155978064Sume			if (opr->ndpr_plen == pr->ndpr_plen &&
156078064Sume			    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
156178064Sume						 &opr->ndpr_prefix.sin6_addr,
156278064Sume						 pr->ndpr_plen)) {
156378064Sume				int e;
156478064Sume
156578064Sume				if ((e = nd6_prefix_onlink(opr)) != 0) {
156678064Sume					nd6log((LOG_ERR,
156778064Sume					    "nd6_prefix_offlink: failed to "
156878064Sume					    "recover a prefix %s/%d from %s "
156978064Sume					    "to %s (errno = %d)\n",
157078064Sume					    ip6_sprintf(&opr->ndpr_prefix.sin6_addr),
157178064Sume					    opr->ndpr_plen, if_name(ifp),
157278064Sume					    if_name(opr->ndpr_ifp), e));
157378064Sume				}
157478064Sume			}
157578064Sume		}
157662587Sitojun	}
157762587Sitojun	else {
157878064Sume		/* XXX: can we still set the NDPRF_ONLINK flag? */
157978064Sume		nd6log((LOG_ERR,
158078064Sume		    "nd6_prefix_offlink: failed to delete route: "
158178064Sume		    "%s/%d on %s (errno = %d)\n",
158278064Sume		    ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp),
158378064Sume		    error));
158478064Sume	}
158553541Sshin
158678064Sume	if (rt != NULL) {
158778064Sume		if (rt->rt_refcnt <= 0) {
158878064Sume			/* XXX: we should free the entry ourselves. */
158978064Sume			rt->rt_refcnt++;
159078064Sume			rtfree(rt);
159153541Sshin		}
159253541Sshin	}
159353541Sshin
159478064Sume	return(error);
159553541Sshin}
159653541Sshin
159753541Sshinstatic struct in6_ifaddr *
159878064Sumein6_ifadd(pr, ifid)
159978064Sume	struct nd_prefix *pr;
160078064Sume	struct in6_addr  *ifid;   /* Mobile IPv6 addition */
160153541Sshin{
160278064Sume	struct ifnet *ifp = pr->ndpr_ifp;
160353541Sshin	struct ifaddr *ifa;
160478064Sume	struct in6_aliasreq ifra;
160578064Sume	struct in6_ifaddr *ia, *ib;
160678064Sume	int error, plen0;
160753541Sshin	struct in6_addr mask;
160878064Sume	int prefixlen = pr->ndpr_plen;
160953541Sshin
161053541Sshin	in6_len2mask(&mask, prefixlen);
161153541Sshin
161278064Sume	/*
161378064Sume	 * find a link-local address (will be interface ID).
161478064Sume	 * Is it really mandatory? Theoretically, a global or a site-local
161578064Sume	 * address can be configured without a link-local address, if we
161678064Sume	 * have a unique interface identifier...
161778064Sume	 *
161878064Sume	 * it is not mandatory to have a link-local address, we can generate
161978064Sume	 * interface identifier on the fly.  we do this because:
162078064Sume	 * (1) it should be the easiest way to find interface identifier.
162178064Sume	 * (2) RFC2462 5.4 suggesting the use of the same interface identifier
162278064Sume	 * for multiple addresses on a single interface, and possible shortcut
162378064Sume	 * of DAD.  we omitted DAD for this reason in the past.
162478064Sume	 * (3) a user can prevent autoconfiguration of global address
162578064Sume	 * by removing link-local address by hand (this is partly because we
162678064Sume	 * don't have other way to control the use of IPv6 on a interface.
162778064Sume	 * this has been our design choice - cf. NRL's "ifconfig auto").
162878064Sume	 * (4) it is easier to manage when an interface has addresses
162978064Sume	 * with the same interface identifier, than to have multiple addresses
163078064Sume	 * with different interface identifiers.
163178064Sume	 *
163278064Sume	 * Mobile IPv6 addition: allow for caller to specify a wished interface
163378064Sume	 * ID. This is to not break connections when moving addresses between
163478064Sume	 * interfaces.
163578064Sume	 */
163662587Sitojun	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);/* 0 is OK? */
163753541Sshin	if (ifa)
163853541Sshin		ib = (struct in6_ifaddr *)ifa;
163953541Sshin	else
164053541Sshin		return NULL;
164153541Sshin
164262587Sitojun#if 0 /* don't care link local addr state, and always do DAD */
164362587Sitojun	/* if link-local address is not eligible, do not autoconfigure. */
164462587Sitojun	if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) {
164562587Sitojun		printf("in6_ifadd: link-local address not ready\n");
164662587Sitojun		return NULL;
164762587Sitojun	}
164862587Sitojun#endif
164962587Sitojun
165053541Sshin	/* prefixlen + ifidlen must be equal to 128 */
165178064Sume	plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
165278064Sume	if (prefixlen != plen0) {
165378064Sume		nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
165478064Sume		    "(prefix=%d ifid=%d)\n",
165578064Sume		    if_name(ifp), prefixlen, 128 - plen0));
165653541Sshin		return NULL;
165753541Sshin	}
165853541Sshin
165953541Sshin	/* make ifaddr */
166053541Sshin
166178064Sume	bzero(&ifra, sizeof(ifra));
166278064Sume	/*
166378064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
166478064Sume	 * for safety.
166578064Sume	 */
166678064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
166778064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
166878064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
166978064Sume	/* prefix */
167078064Sume	bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr,
167178064Sume	      sizeof(ifra.ifra_addr.sin6_addr));
167278064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
167378064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
167478064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
167578064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
167653541Sshin
167753541Sshin	/* interface ID */
167878064Sume	if (ifid == NULL || IN6_IS_ADDR_UNSPECIFIED(ifid))
167978064Sume		ifid = &ib->ia_addr.sin6_addr;
168078064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0]
168178064Sume		|= (ifid->s6_addr32[0] & ~mask.s6_addr32[0]);
168278064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1]
168378064Sume		|= (ifid->s6_addr32[1] & ~mask.s6_addr32[1]);
168478064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2]
168578064Sume		|= (ifid->s6_addr32[2] & ~mask.s6_addr32[2]);
168678064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3]
168778064Sume		|= (ifid->s6_addr32[3] & ~mask.s6_addr32[3]);
168878064Sume
168978064Sume	/* new prefix mask. */
169078064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
169178064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
169278064Sume	bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
169378064Sume	      sizeof(ifra.ifra_prefixmask.sin6_addr));
169453541Sshin
169578064Sume	/*
169678064Sume	 * lifetime.
169778064Sume	 * XXX: in6_init_address_ltimes would override these values later.
169878064Sume	 * We should reconsider this logic.
169978064Sume	 */
170078064Sume	ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
170178064Sume	ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
170253541Sshin
170378064Sume	/* XXX: scope zone ID? */
170453541Sshin
170578064Sume	ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
170678064Sume	/*
170778064Sume	 * temporarily set the nopfx flag to avoid conflict.
170878064Sume	 * XXX: we should reconsider the entire mechanism about prefix
170978064Sume	 * manipulation.
171078064Sume	 */
171178064Sume	ifra.ifra_flags |= IN6_IFF_NOPFX;
171253541Sshin
171353541Sshin	/*
171478064Sume	 * keep the new address, regardless of the result of in6_update_ifa.
171578064Sume	 * XXX: this address is now meaningless.
171678064Sume	 * We should reconsider its role.
171753541Sshin	 */
171878064Sume	pr->ndpr_addr = ifra.ifra_addr.sin6_addr;
171978064Sume
172078064Sume	/* allocate ifaddr structure, link into chain, etc. */
172178064Sume	if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
172278064Sume		nd6log((LOG_ERR,
172378064Sume		    "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
172478064Sume		    ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp),
172578064Sume		    error));
172678064Sume		return(NULL);	/* ifaddr must not have been allocated. */
172753541Sshin	}
172853541Sshin
172978064Sume	ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
173053541Sshin
173178064Sume	return(ia);		/* this must NOT be NULL. */
173253541Sshin}
173353541Sshin
173453541Sshinint
173578064Sumein6_tmpifadd(ia0, forcegen)
173678064Sume	const struct in6_ifaddr *ia0; /* corresponding public address */
173778407Sume	int forcegen;
173853541Sshin{
173978064Sume	struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
174078064Sume	struct in6_ifaddr *newia;
174178064Sume	struct in6_aliasreq ifra;
174278064Sume	int i, error;
174378064Sume	int trylimit = 3;	/* XXX: adhoc value */
174478064Sume	u_int32_t randid[2];
174578064Sume	time_t vltime0, pltime0;
174653541Sshin
174778064Sume	bzero(&ifra, sizeof(ifra));
174878064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
174978064Sume	ifra.ifra_addr = ia0->ia_addr;
175078064Sume	/* copy prefix mask */
175178064Sume	ifra.ifra_prefixmask = ia0->ia_prefixmask;
175278064Sume	/* clear the old IFID */
175378064Sume	for (i = 0; i < 4; i++) {
175478064Sume		ifra.ifra_addr.sin6_addr.s6_addr32[i]
175578064Sume			&= ifra.ifra_prefixmask.sin6_addr.s6_addr32[i];
175678064Sume	}
175753541Sshin
175878064Sume  again:
175978064Sume	in6_get_tmpifid(ifp, (u_int8_t *)randid,
176078064Sume			(const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8],
176178064Sume			forcegen);
176278064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2]
176378064Sume		|= (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2]));
176478064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3]
176578064Sume		|= (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3]));
176653541Sshin
176778064Sume	/*
176878064Sume	 * If by chance the new temporary address is the same as an address
176978064Sume	 * already assigned to the interface, generate a new randomized
177078064Sume	 * interface identifier and repeat this step.
177178064Sume	 * RFC 3041 3.3 (4).
177278064Sume	 */
177378064Sume	if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
177478064Sume		if (trylimit-- == 0) {
177578064Sume			nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find "
177678064Sume			    "a unique random IFID\n"));
177778064Sume			return(EEXIST);
177878064Sume		}
177978064Sume		forcegen = 1;
178078064Sume		goto again;
178153541Sshin	}
178253541Sshin
178378064Sume	/*
178478064Sume	 * The Valid Lifetime is the lower of the Valid Lifetime of the
178578064Sume         * public address or TEMP_VALID_LIFETIME.
178678064Sume	 * The Preferred Lifetime is the lower of the Preferred Lifetime
178778064Sume         * of the public address or TEMP_PREFERRED_LIFETIME -
178878064Sume         * DESYNC_FACTOR.
178978064Sume	 */
179078064Sume	if (ia0->ia6_lifetime.ia6t_expire != 0) {
179178064Sume		vltime0 = IFA6_IS_INVALID(ia0) ? 0 :
179278064Sume			(ia0->ia6_lifetime.ia6t_expire - time_second);
179378064Sume		if (vltime0 > ip6_temp_valid_lifetime)
179478064Sume			vltime0 = ip6_temp_valid_lifetime;
179578064Sume	} else
179678064Sume		vltime0 = ip6_temp_valid_lifetime;
179778064Sume	if (ia0->ia6_lifetime.ia6t_preferred != 0) {
179878064Sume		pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 :
179978064Sume			(ia0->ia6_lifetime.ia6t_preferred - time_second);
180078064Sume		if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){
180178064Sume			pltime0 = ip6_temp_preferred_lifetime -
180278064Sume				ip6_desync_factor;
180378064Sume		}
180478064Sume	} else
180578064Sume		pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor;
180678064Sume	ifra.ifra_lifetime.ia6t_vltime = vltime0;
180778064Sume	ifra.ifra_lifetime.ia6t_pltime = pltime0;
180853541Sshin
180978064Sume	/*
181078064Sume	 * A temporary address is created only if this calculated Preferred
181178064Sume	 * Lifetime is greater than REGEN_ADVANCE time units.
181278064Sume	 */
181378064Sume	if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance)
181478064Sume		return(0);
181553541Sshin
181678064Sume	/* XXX: scope zone ID? */
181778064Sume
181878064Sume	ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
181978064Sume
182078064Sume	/* allocate ifaddr structure, link into chain, etc. */
182178064Sume	if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0)
182278064Sume		return(error);
182378064Sume
182478064Sume	newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
182578064Sume	if (newia == NULL) {	/* XXX: can it happen? */
182678064Sume		nd6log((LOG_ERR,
182778064Sume		    "in6_tmpifadd: ifa update succeeded, but we got "
182878064Sume		    "no ifaddr\n"));
182978064Sume		return(EINVAL); /* XXX */
183053541Sshin	}
183178064Sume	newia->ia6_ndpr = ia0->ia6_ndpr;
183278064Sume	newia->ia6_ndpr->ndpr_refcnt++;
183353541Sshin
183478407Sume	/*
183578407Sume	 * A newly added address might affect the status of other addresses.
183678407Sume	 * XXX: when the temporary address is generated with a new public
183778407Sume	 * address, the onlink check is redundant.  However, it would be safe
183878407Sume	 * to do the check explicitly everywhere a new address is generated,
183978407Sume	 * and, in fact, we surely need the check when we create a new
184078407Sume	 * temporary address due to deprecation of an old temporary address.
184178407Sume	 */
184278407Sume	pfxlist_onlink_check();
184378407Sume
184478064Sume	return(0);
184578064Sume}
184653541Sshin
184753541Sshinint
184853541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr)
184953541Sshin{
185078064Sume	/* check if preferred lifetime > valid lifetime.  RFC2462 5.5.3 (c) */
185153541Sshin	if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
185278064Sume		nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
185353541Sshin		    "(%d) is greater than valid lifetime(%d)\n",
185478064Sume		    (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime));
185553541Sshin		return (EINVAL);
185653541Sshin	}
185753541Sshin	if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
185853541Sshin		ndpr->ndpr_preferred = 0;
185953541Sshin	else
186053541Sshin		ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
186153541Sshin	if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
186253541Sshin		ndpr->ndpr_expire = 0;
186353541Sshin	else
186453541Sshin		ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
186553541Sshin
186653541Sshin	return 0;
186753541Sshin}
186853541Sshin
186953541Sshinstatic void
187078064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
187153541Sshin{
187262587Sitojun	/* Valid lifetime must not be updated unless explicitly specified. */
187378064Sume	/* init ia6t_expire */
187478064Sume	if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
187578064Sume		lt6->ia6t_expire = 0;
187678064Sume	else {
187778064Sume		lt6->ia6t_expire = time_second;
187878064Sume		lt6->ia6t_expire += lt6->ia6t_vltime;
187953541Sshin	}
188062587Sitojun
188153541Sshin	/* init ia6t_preferred */
188253541Sshin	if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
188353541Sshin		lt6->ia6t_preferred = 0;
188453541Sshin	else {
188553541Sshin		lt6->ia6t_preferred = time_second;
188653541Sshin		lt6->ia6t_preferred += lt6->ia6t_pltime;
188753541Sshin	}
188853541Sshin}
188953541Sshin
189053541Sshin/*
189153541Sshin * Delete all the routing table entries that use the specified gateway.
189253541Sshin * XXX: this function causes search through all entries of routing table, so
189353541Sshin * it shouldn't be called when acting as a router.
189453541Sshin */
189553541Sshinvoid
189653541Sshinrt6_flush(gateway, ifp)
189778064Sume	struct in6_addr *gateway;
189878064Sume	struct ifnet *ifp;
189953541Sshin{
190053541Sshin	struct radix_node_head *rnh = rt_tables[AF_INET6];
190153541Sshin	int s = splnet();
190253541Sshin
190353541Sshin	/* We'll care only link-local addresses */
190453541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
190553541Sshin		splx(s);
190653541Sshin		return;
190753541Sshin	}
190853541Sshin	/* XXX: hack for KAME's link-local address kludge */
190953541Sshin	gateway->s6_addr16[1] = htons(ifp->if_index);
191053541Sshin
191153541Sshin	rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
191253541Sshin	splx(s);
191353541Sshin}
191453541Sshin
191553541Sshinstatic int
191653541Sshinrt6_deleteroute(rn, arg)
191753541Sshin	struct radix_node *rn;
191853541Sshin	void *arg;
191953541Sshin{
192053541Sshin#define SIN6(s)	((struct sockaddr_in6 *)s)
192153541Sshin	struct rtentry *rt = (struct rtentry *)rn;
192253541Sshin	struct in6_addr *gate = (struct in6_addr *)arg;
192353541Sshin
192453541Sshin	if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
192553541Sshin		return(0);
192653541Sshin
192753541Sshin	if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr))
192853541Sshin		return(0);
192953541Sshin
193053541Sshin	/*
193178064Sume	 * Do not delete a static route.
193278064Sume	 * XXX: this seems to be a bit ad-hoc. Should we consider the
193378064Sume	 * 'cloned' bit instead?
193478064Sume	 */
193578064Sume	if ((rt->rt_flags & RTF_STATIC) != 0)
193678064Sume		return(0);
193778064Sume
193878064Sume	/*
193953541Sshin	 * We delete only host route. This means, in particular, we don't
194053541Sshin	 * delete default route.
194153541Sshin	 */
194253541Sshin	if ((rt->rt_flags & RTF_HOST) == 0)
194353541Sshin		return(0);
194453541Sshin
194553541Sshin	return(rtrequest(RTM_DELETE, rt_key(rt),
194653541Sshin			 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0));
194753541Sshin#undef SIN6
194853541Sshin}
194962587Sitojun
195062587Sitojunint
195162587Sitojunnd6_setdefaultiface(ifindex)
195262587Sitojun	int ifindex;
195362587Sitojun{
195462587Sitojun	int error = 0;
195562587Sitojun
195662587Sitojun	if (ifindex < 0 || if_index < ifindex)
195762587Sitojun		return(EINVAL);
195862587Sitojun
195962587Sitojun	if (nd6_defifindex != ifindex) {
196062587Sitojun		nd6_defifindex = ifindex;
196162587Sitojun		if (nd6_defifindex > 0)
196262587Sitojun			nd6_defifp = ifindex2ifnet[nd6_defifindex];
196362587Sitojun		else
196462587Sitojun			nd6_defifp = NULL;
196562587Sitojun
196662587Sitojun		/*
196762587Sitojun		 * If the Default Router List is empty, install a route
196862587Sitojun		 * to the specified interface as default or remove the default
196962587Sitojun		 * route when the default interface becomes canceled.
197062587Sitojun		 * The check for the queue is actually redundant, but
197162587Sitojun		 * we do this here to avoid re-install the default route
197262587Sitojun		 * if the list is NOT empty.
197362587Sitojun		 */
197462587Sitojun		if (TAILQ_FIRST(&nd_defrouter) == NULL)
197562587Sitojun			defrouter_select();
197662587Sitojun
197762587Sitojun		/*
197862587Sitojun		 * Our current implementation assumes one-to-one maping between
197962587Sitojun		 * interfaces and links, so it would be natural to use the
198062587Sitojun		 * default interface as the default link.
198162587Sitojun		 */
198262587Sitojun		scope6_setdefault(nd6_defifp);
198362587Sitojun	}
198462587Sitojun
198562587Sitojun	return(error);
198662587Sitojun}
1987