nd6_rtr.c revision 171259
162587Sitojun/*	$FreeBSD: head/sys/netinet6/nd6_rtr.c 171259 2007-07-05 16:23:49Z delphij $	*/
278064Sume/*	$KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $	*/
362587Sitojun
4139826Simp/*-
553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
653541Sshin * All rights reserved.
753541Sshin *
853541Sshin * Redistribution and use in source and binary forms, with or without
953541Sshin * modification, are permitted provided that the following conditions
1053541Sshin * are met:
1153541Sshin * 1. Redistributions of source code must retain the above copyright
1253541Sshin *    notice, this list of conditions and the following disclaimer.
1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1453541Sshin *    notice, this list of conditions and the following disclaimer in the
1553541Sshin *    documentation and/or other materials provided with the distribution.
1653541Sshin * 3. Neither the name of the project nor the names of its contributors
1753541Sshin *    may be used to endorse or promote products derived from this software
1853541Sshin *    without specific prior written permission.
1953541Sshin *
2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2353541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3053541Sshin * SUCH DAMAGE.
3153541Sshin */
3253541Sshin
3362587Sitojun#include "opt_inet.h"
3462587Sitojun#include "opt_inet6.h"
3562587Sitojun
3653541Sshin#include <sys/param.h>
3753541Sshin#include <sys/systm.h>
3853541Sshin#include <sys/malloc.h>
3953541Sshin#include <sys/mbuf.h>
4053541Sshin#include <sys/socket.h>
4153541Sshin#include <sys/sockio.h>
4253541Sshin#include <sys/time.h>
4378064Sume#include <sys/kernel.h>
4453541Sshin#include <sys/errno.h>
4553541Sshin#include <sys/syslog.h>
4678064Sume#include <sys/queue.h>
4753541Sshin
4853541Sshin#include <net/if.h>
4953541Sshin#include <net/if_types.h>
5053541Sshin#include <net/if_dl.h>
5153541Sshin#include <net/route.h>
5253541Sshin#include <net/radix.h>
5353541Sshin
5453541Sshin#include <netinet/in.h>
5553541Sshin#include <netinet6/in6_var.h>
5678064Sume#include <netinet6/in6_ifattach.h>
5762587Sitojun#include <netinet/ip6.h>
5853541Sshin#include <netinet6/ip6_var.h>
5953541Sshin#include <netinet6/nd6.h>
6062587Sitojun#include <netinet/icmp6.h>
6162587Sitojun#include <netinet6/scope6_var.h>
6253541Sshin
6362587Sitojun#define SDL(s)	((struct sockaddr_dl *)s)
6453541Sshin
65151539Ssuzstatic int rtpref __P((struct nd_defrouter *));
6662587Sitojunstatic struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
67151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *,
68151539Ssuz    struct mbuf *, int));
69151539Ssuzstatic struct in6_ifaddr *in6_ifadd __P((struct nd_prefixctl *,	int));
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 *));
76151539Ssuzstatic void defrouter_delreq __P((struct nd_defrouter *));
7778064Sumestatic void nd6_rtmsg __P((int, struct rtentry *));
7853541Sshin
79151539Ssuzstatic int in6_init_prefix_ltimes __P((struct nd_prefix *));
80120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *,
81120941Sume	struct in6_addrlifetime *));
8253541Sshin
8362587Sitojunstatic int rt6_deleteroute __P((struct radix_node *, void *));
8453541Sshin
8562587Sitojunextern int nd6_recalc_reachtm_interval;
8653541Sshin
8778064Sumestatic struct ifnet *nd6_defifp;
8862587Sitojunint nd6_defifindex;
8962587Sitojun
9078064Sumeint ip6_use_tempaddr = 0;
9178064Sume
9278064Sumeint ip6_desync_factor;
9378064Sumeu_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME;
9478064Sumeu_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME;
9553541Sshin/*
9678064Sume * shorter lifetimes for debugging purposes.
9778064Sumeint ip6_temp_preferred_lifetime = 800;
9878064Sumestatic int ip6_temp_valid_lifetime = 1800;
9978064Sume*/
10078064Sumeint ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE;
10178064Sume
102151539Ssuz/* RTPREF_MEDIUM has to be 0! */
103151539Ssuz#define RTPREF_HIGH	1
104151539Ssuz#define RTPREF_MEDIUM	0
105151539Ssuz#define RTPREF_LOW	(-1)
106151539Ssuz#define RTPREF_RESERVED	(-2)
107151539Ssuz#define RTPREF_INVALID	(-3)	/* internal */
108151539Ssuz
10978064Sume/*
11053541Sshin * Receive Router Solicitation Message - just for routers.
11153541Sshin * Router solicitation/advertisement is mostly managed by userland program
11253541Sshin * (rtadvd) so here we have no function like nd6_ra_output().
11353541Sshin *
11453541Sshin * Based on RFC 2461
11553541Sshin */
11653541Sshinvoid
117171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len)
11853541Sshin{
11953541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
12053541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
12162587Sitojun	struct nd_router_solicit *nd_rs;
12253541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
12353541Sshin	char *lladdr = NULL;
12453541Sshin	int lladdrlen = 0;
12553541Sshin	union nd_opts ndopts;
126165118Sbz	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
12753541Sshin
12853541Sshin	/* If I'm not a router, ignore it. */
12953541Sshin	if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
13062587Sitojun		goto freeit;
13153541Sshin
13253541Sshin	/* Sanity checks */
13353541Sshin	if (ip6->ip6_hlim != 255) {
13478064Sume		nd6log((LOG_ERR,
13578064Sume		    "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
136165118Sbz		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
137165118Sbz		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
13878064Sume		goto bad;
13953541Sshin	}
14053541Sshin
14153541Sshin	/*
14253541Sshin	 * Don't update the neighbor cache, if src = ::.
14353541Sshin	 * This indicates that the src has no IP address assigned yet.
14453541Sshin	 */
14553541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
14662587Sitojun		goto freeit;
14762587Sitojun
14862587Sitojun#ifndef PULLDOWN_TEST
14962587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
15062587Sitojun	nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
15162587Sitojun#else
15262587Sitojun	IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
15362587Sitojun	if (nd_rs == NULL) {
15462587Sitojun		icmp6stat.icp6s_tooshort++;
15553541Sshin		return;
15662587Sitojun	}
15762587Sitojun#endif
15853541Sshin
15953541Sshin	icmp6len -= sizeof(*nd_rs);
16053541Sshin	nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
16153541Sshin	if (nd6_options(&ndopts) < 0) {
16278064Sume		nd6log((LOG_INFO,
16378064Sume		    "nd6_rs_input: invalid ND option, ignored\n"));
16478064Sume		/* nd6_options have incremented stats */
16562587Sitojun		goto freeit;
16653541Sshin	}
16753541Sshin
16853541Sshin	if (ndopts.nd_opts_src_lladdr) {
16953541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
17053541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
17153541Sshin	}
17253541Sshin
17353541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
17478064Sume		nd6log((LOG_INFO,
17553541Sshin		    "nd6_rs_input: lladdrlen mismatch for %s "
17653541Sshin		    "(if %d, RS packet %d)\n",
177165118Sbz		    ip6_sprintf(ip6bufs, &saddr6),
178120941Sume		    ifp->if_addrlen, lladdrlen - 2));
17978064Sume		goto bad;
18053541Sshin	}
18153541Sshin
18253541Sshin	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
18362587Sitojun
18462587Sitojun freeit:
18562587Sitojun	m_freem(m);
18678064Sume	return;
18778064Sume
18878064Sume bad:
18978064Sume	icmp6stat.icp6s_badrs++;
19078064Sume	m_freem(m);
19153541Sshin}
19253541Sshin
19353541Sshin/*
19453541Sshin * Receive Router Advertisement Message.
19553541Sshin *
19653541Sshin * Based on RFC 2461
19753541Sshin * TODO: on-link bit on prefix information
19853541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
19953541Sshin */
20053541Sshinvoid
201171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len)
20253541Sshin{
20353541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
204121161Sume	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
20553541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
20662587Sitojun	struct nd_router_advert *nd_ra;
20753541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
208151539Ssuz	int mcast = 0;
20953541Sshin	union nd_opts ndopts;
21053541Sshin	struct nd_defrouter *dr;
211165118Sbz	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
21253541Sshin
213118498Sume	/*
214118498Sume	 * We only accept RAs only when
215118498Sume	 * the system-wide variable allows the acceptance, and
216118498Sume	 * per-interface variable allows RAs on the receiving interface.
217118498Sume	 */
21853541Sshin	if (ip6_accept_rtadv == 0)
21962587Sitojun		goto freeit;
220118498Sume	if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
221118498Sume		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",
226165118Sbz		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
227165118Sbz		    ip6_sprintf(ip6bufd, &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",
234165118Sbz		    ip6_sprintf(ip6bufs, &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
262151539Ssuz	/* remember if this is a multicasted advertisement */
263151539Ssuz	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
264151539Ssuz		mcast = 1;
265151539Ssuz
266151539Ssuz	bzero(&dr0, sizeof(dr0));
26753541Sshin	dr0.rtaddr = saddr6;
26853541Sshin	dr0.flags  = nd_ra->nd_ra_flags_reserved;
269156871Ssuz	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;
295151539Ssuz		struct nd_prefixctl 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",
326165118Sbz				    ip6_sprintf(ip6bufs,
327165118Sbz					&pi->nd_opt_pi_prefix)));
32853541Sshin				continue;
32953541Sshin			}
33053541Sshin
33153541Sshin			bzero(&pr, sizeof(pr));
33253541Sshin			pr.ndpr_prefix.sin6_family = AF_INET6;
33353541Sshin			pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
33453541Sshin			pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
33553541Sshin			pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
33653541Sshin
33753541Sshin			pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
338120941Sume			    ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
33953541Sshin			pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
340120941Sume			    ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
34153541Sshin			pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
34253541Sshin			pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
343120941Sume			pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time);
344151539Ssuz			(void)prelist_update(&pr, dr, m, mcast);
34553541Sshin		}
34653541Sshin	}
34753541Sshin
34853541Sshin	/*
34953541Sshin	 * MTU
35053541Sshin	 */
35153541Sshin	if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
352121283Sume		u_long mtu;
353121283Sume		u_long maxmtu;
35453541Sshin
355121283Sume		mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
356120941Sume
35753541Sshin		/* lower bound */
35853541Sshin		if (mtu < IPV6_MMTU) {
35978064Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option "
360121283Sume			    "mtu=%lu sent from %s, ignoring\n",
361165118Sbz			    mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src)));
36253541Sshin			goto skip;
36353541Sshin		}
36453541Sshin
36553541Sshin		/* upper bound */
366121283Sume		maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu)
367121283Sume		    ? ndi->maxmtu : ifp->if_mtu;
368121283Sume		if (mtu <= maxmtu) {
369121283Sume			int change = (ndi->linkmtu != mtu);
37053541Sshin
371121283Sume			ndi->linkmtu = mtu;
372121283Sume			if (change) /* in6_maxmtu may change */
373121283Sume				in6_setmaxmtu();
37453541Sshin		} else {
375121283Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
376121283Sume			    "mtu=%lu sent from %s; "
377121283Sume			    "exceeds maxmtu %lu, ignoring\n",
378165118Sbz			    mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu));
37953541Sshin		}
38053541Sshin	}
38153541Sshin
38253541Sshin skip:
383120941Sume
38453541Sshin	/*
38595023Ssuz	 * Source link layer address
38653541Sshin	 */
38753541Sshin    {
38853541Sshin	char *lladdr = NULL;
38953541Sshin	int lladdrlen = 0;
390120941Sume
39153541Sshin	if (ndopts.nd_opts_src_lladdr) {
39253541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
39353541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
39453541Sshin	}
39553541Sshin
39653541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
39778064Sume		nd6log((LOG_INFO,
39853541Sshin		    "nd6_ra_input: lladdrlen mismatch for %s "
399165118Sbz		    "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6),
400120941Sume		    ifp->if_addrlen, lladdrlen - 2));
40178064Sume		goto bad;
40253541Sshin	}
40353541Sshin
404120941Sume	nd6_cache_lladdr(ifp, &saddr6, lladdr,
405120941Sume	    lladdrlen, ND_ROUTER_ADVERT, 0);
40662587Sitojun
40762587Sitojun	/*
40862587Sitojun	 * Installing a link-layer address might change the state of the
40962587Sitojun	 * router's neighbor cache, which might also affect our on-link
41062587Sitojun	 * detection of adveritsed prefixes.
41162587Sitojun	 */
41262587Sitojun	pfxlist_onlink_check();
41353541Sshin    }
41462587Sitojun
41578064Sume freeit:
41662587Sitojun	m_freem(m);
41778064Sume	return;
41878064Sume
41978064Sume bad:
42078064Sume	icmp6stat.icp6s_badra++;
42178064Sume	m_freem(m);
42253541Sshin}
42353541Sshin
42453541Sshin/*
42553541Sshin * default router list proccessing sub routines
42653541Sshin */
42762587Sitojun
42862587Sitojun/* tell the change to user processes watching the routing socket. */
42962587Sitojunstatic void
430171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt)
43162587Sitojun{
43262587Sitojun	struct rt_addrinfo info;
43362587Sitojun
43462587Sitojun	bzero((caddr_t)&info, sizeof(info));
43562587Sitojun	info.rti_info[RTAX_DST] = rt_key(rt);
43662587Sitojun	info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
43762587Sitojun	info.rti_info[RTAX_NETMASK] = rt_mask(rt);
438151539Ssuz	if (rt->rt_ifp) {
439151539Ssuz		info.rti_info[RTAX_IFP] =
440151539Ssuz		    TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
441151539Ssuz		info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
442151539Ssuz	}
44362587Sitojun
44462587Sitojun	rt_missmsg(cmd, &info, rt->rt_flags, 0);
44562587Sitojun}
44662587Sitojun
44753541Sshinvoid
448171259Sdelphijdefrouter_addreq(struct nd_defrouter *new)
44953541Sshin{
45053541Sshin	struct sockaddr_in6 def, mask, gate;
45162587Sitojun	struct rtentry *newrt = NULL;
452151539Ssuz	int s;
453151539Ssuz	int error;
45453541Sshin
455128397Sluigi	bzero(&def, sizeof(def));
456128397Sluigi	bzero(&mask, sizeof(mask));
457128397Sluigi	bzero(&gate, sizeof(gate));
45853541Sshin
459120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
460120941Sume	    sizeof(struct sockaddr_in6);
461151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
46253541Sshin	gate.sin6_addr = new->rtaddr;
46353541Sshin
464151539Ssuz	s = splnet();
465151539Ssuz	error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
466120941Sume	    (struct sockaddr *)&gate, (struct sockaddr *)&mask,
467120941Sume	    RTF_GATEWAY, &newrt);
46862587Sitojun	if (newrt) {
469120727Ssam		RT_LOCK(newrt);
47078064Sume		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
471122334Ssam		RT_REMREF(newrt);
472120727Ssam		RT_UNLOCK(newrt);
47362587Sitojun	}
474151539Ssuz	if (error == 0)
475151539Ssuz		new->installed = 1;
476151539Ssuz	splx(s);
47753541Sshin	return;
47853541Sshin}
47953541Sshin
48053541Sshinstruct nd_defrouter *
481171259Sdelphijdefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp)
48253541Sshin{
48353541Sshin	struct nd_defrouter *dr;
48453541Sshin
48562587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
48662587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
48753541Sshin		if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
488120856Sume			return (dr);
48962587Sitojun	}
49053541Sshin
491120856Sume	return (NULL);		/* search failed */
49253541Sshin}
49353541Sshin
494151539Ssuz/*
495151539Ssuz * Remove the default route for a given router.
496151539Ssuz * This is just a subroutine function for defrouter_select(), and should
497151539Ssuz * not be called from anywhere else.
498151539Ssuz */
499151539Ssuzstatic void
500171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr)
50153541Sshin{
50253541Sshin	struct sockaddr_in6 def, mask, gate;
50362587Sitojun	struct rtentry *oldrt = NULL;
50453541Sshin
505128397Sluigi	bzero(&def, sizeof(def));
506128397Sluigi	bzero(&mask, sizeof(mask));
507128397Sluigi	bzero(&gate, sizeof(gate));
50853541Sshin
509120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
510120941Sume	    sizeof(struct sockaddr_in6);
511151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
51253541Sshin	gate.sin6_addr = dr->rtaddr;
51353541Sshin
51453541Sshin	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
515120941Sume	    (struct sockaddr *)&gate,
516120941Sume	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
51762587Sitojun	if (oldrt) {
51878064Sume		nd6_rtmsg(RTM_DELETE, oldrt);
519108269Sru		RTFREE(oldrt);
52062587Sitojun	}
52153541Sshin
522151539Ssuz	dr->installed = 0;
52353541Sshin}
52453541Sshin
525151539Ssuz/*
526151539Ssuz * remove all default routes from default router list
527151539Ssuz */
52853541Sshinvoid
529171259Sdelphijdefrouter_reset(void)
530151539Ssuz{
531151539Ssuz	struct nd_defrouter *dr;
532151539Ssuz
533151539Ssuz	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
534151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry))
535151539Ssuz		defrouter_delreq(dr);
536151539Ssuz
537151539Ssuz	/*
538151539Ssuz	 * XXX should we also nuke any default routers in the kernel, by
539151539Ssuz	 * going through them by rtalloc1()?
540151539Ssuz	 */
541151539Ssuz}
542151539Ssuz
543151539Ssuzvoid
544171259Sdelphijdefrtrlist_del(struct nd_defrouter *dr)
54553541Sshin{
54653541Sshin	struct nd_defrouter *deldr = NULL;
54753541Sshin	struct nd_prefix *pr;
54853541Sshin
54953541Sshin	/*
55053541Sshin	 * Flush all the routing table entries that use the router
55153541Sshin	 * as a next hop.
55253541Sshin	 */
553120941Sume	if (!ip6_forwarding && ip6_accept_rtadv) /* XXX: better condition? */
55453541Sshin		rt6_flush(&dr->rtaddr, dr->ifp);
55553541Sshin
556151539Ssuz	if (dr->installed) {
557151539Ssuz		deldr = dr;
558151539Ssuz		defrouter_delreq(dr);
559151539Ssuz	}
56062587Sitojun	TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
56153541Sshin
56253541Sshin	/*
56353541Sshin	 * Also delete all the pointers to the router in each prefix lists.
56453541Sshin	 */
56562587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
56653541Sshin		struct nd_pfxrouter *pfxrtr;
56753541Sshin		if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
56853541Sshin			pfxrtr_del(pfxrtr);
56953541Sshin	}
57053541Sshin	pfxlist_onlink_check();
57153541Sshin
57253541Sshin	/*
57362587Sitojun	 * If the router is the primary one, choose a new one.
57462587Sitojun	 * Note that defrouter_select() will remove the current gateway
57562587Sitojun	 * from the routing table.
57653541Sshin	 */
57753541Sshin	if (deldr)
57862587Sitojun		defrouter_select();
57962587Sitojun
58053541Sshin	free(dr, M_IP6NDP);
58153541Sshin}
58253541Sshin
58362587Sitojun/*
584151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and
585151539Ssuz * draft-ietf-ipngwg-router-selection:
586151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred.
587151539Ssuz *    If we have more than one (probably) reachable router, prefer ones
588151539Ssuz *    with the highest router preference.
58962587Sitojun * 2) When no routers on the list are known to be reachable or
59062587Sitojun *    probably reachable, routers SHOULD be selected in a round-robin
591151539Ssuz *    fashion, regardless of router preference values.
59262587Sitojun * 3) If the Default Router List is empty, assume that all
59362587Sitojun *    destinations are on-link.
594151539Ssuz *
595151539Ssuz * We assume nd_defrouter is sorted by router preference value.
596151539Ssuz * Since the code below covers both with and without router preference cases,
597151539Ssuz * we do not need to classify the cases by ifdef.
598151539Ssuz *
599151539Ssuz * At this moment, we do not try to install more than one default router,
600151539Ssuz * even when the multipath routing is available, because we're not sure about
601151539Ssuz * the benefits for stub hosts comparing to the risk of making the code
602151539Ssuz * complicated and the possibility of introducing bugs.
60362587Sitojun */
60462587Sitojunvoid
605171259Sdelphijdefrouter_select(void)
60662587Sitojun{
60762587Sitojun	int s = splnet();
608151539Ssuz	struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
60962587Sitojun	struct rtentry *rt = NULL;
61062587Sitojun	struct llinfo_nd6 *ln = NULL;
61162587Sitojun
61262587Sitojun	/*
613151539Ssuz	 * This function should be called only when acting as an autoconfigured
614151539Ssuz	 * host.  Although the remaining part of this function is not effective
615151539Ssuz	 * if the node is not an autoconfigured host, we explicitly exclude
616151539Ssuz	 * such cases here for safety.
617151539Ssuz	 */
618151539Ssuz	if (ip6_forwarding || !ip6_accept_rtadv) {
619151539Ssuz		nd6log((LOG_WARNING,
620151539Ssuz		    "defrouter_select: called unexpectedly (forwarding=%d, "
621151539Ssuz		    "accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv));
622151539Ssuz		splx(s);
623151539Ssuz		return;
624151539Ssuz	}
625151539Ssuz
626151539Ssuz	/*
627151539Ssuz	 * Let's handle easy case (3) first:
628151539Ssuz	 * If default router list is empty, there's nothing to be done.
629151539Ssuz	 */
630151539Ssuz	if (!TAILQ_FIRST(&nd_defrouter)) {
631151539Ssuz		splx(s);
632151539Ssuz		return;
633151539Ssuz	}
634151539Ssuz
635151539Ssuz	/*
63662587Sitojun	 * Search for a (probably) reachable router from the list.
637151539Ssuz	 * We just pick up the first reachable one (if any), assuming that
638151539Ssuz	 * the ordering rule of the list described in defrtrlist_update().
63962587Sitojun	 */
64062587Sitojun	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
64162587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
642151539Ssuz		if (selected_dr == NULL &&
643151539Ssuz		    (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
64462587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
64562587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln)) {
646151539Ssuz			selected_dr = dr;
64762587Sitojun		}
64862587Sitojun
649151539Ssuz		if (dr->installed && installed_dr == NULL)
650151539Ssuz			installed_dr = dr;
651151539Ssuz		else if (dr->installed && installed_dr) {
652151539Ssuz			/* this should not happen.  warn for diagnosis. */
653151539Ssuz			log(LOG_ERR, "defrouter_select: more than one router"
654151539Ssuz			    " is installed\n");
65562587Sitojun		}
65662587Sitojun	}
657151539Ssuz	/*
658151539Ssuz	 * If none of the default routers was found to be reachable,
659151539Ssuz	 * round-robin the list regardless of preference.
660151539Ssuz	 * Otherwise, if we have an installed router, check if the selected
661151539Ssuz	 * (reachable) router should really be preferred to the installed one.
662151539Ssuz	 * We only prefer the new router when the old one is not reachable
663151539Ssuz	 * or when the new one has a really higher preference value.
664151539Ssuz	 */
665151539Ssuz	if (selected_dr == NULL) {
666151539Ssuz		if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry))
667151539Ssuz			selected_dr = TAILQ_FIRST(&nd_defrouter);
668151539Ssuz		else
669151539Ssuz			selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
670151539Ssuz	} else if (installed_dr &&
671151539Ssuz	    (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) &&
672151539Ssuz	    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
673151539Ssuz	    ND6_IS_LLINFO_PROBREACH(ln) &&
674151539Ssuz	    rtpref(selected_dr) <= rtpref(installed_dr)) {
675151539Ssuz		selected_dr = installed_dr;
676151539Ssuz	}
67762587Sitojun
678151539Ssuz	/*
679151539Ssuz	 * If the selected router is different than the installed one,
680151539Ssuz	 * remove the installed router and install the selected one.
681151539Ssuz	 * Note that the selected router is never NULL here.
682151539Ssuz	 */
683151539Ssuz	if (installed_dr != selected_dr) {
684151539Ssuz		if (installed_dr)
685151539Ssuz			defrouter_delreq(installed_dr);
686151539Ssuz		defrouter_addreq(selected_dr);
687151539Ssuz	}
688151539Ssuz
68962587Sitojun	splx(s);
69062587Sitojun	return;
69162587Sitojun}
69262587Sitojun
693151539Ssuz/*
694151539Ssuz * for default router selection
695151539Ssuz * regards router-preference field as a 2-bit signed integer
696151539Ssuz */
697151539Ssuzstatic int
698151539Ssuzrtpref(struct nd_defrouter *dr)
699151539Ssuz{
700151539Ssuz	switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) {
701151539Ssuz	case ND_RA_FLAG_RTPREF_HIGH:
702151539Ssuz		return (RTPREF_HIGH);
703151539Ssuz	case ND_RA_FLAG_RTPREF_MEDIUM:
704156871Ssuz	case ND_RA_FLAG_RTPREF_RSV:
705151539Ssuz		return (RTPREF_MEDIUM);
706151539Ssuz	case ND_RA_FLAG_RTPREF_LOW:
707151539Ssuz		return (RTPREF_LOW);
708151539Ssuz	default:
709151539Ssuz		/*
710151539Ssuz		 * This case should never happen.  If it did, it would mean a
711151539Ssuz		 * serious bug of kernel internal.  We thus always bark here.
712151539Ssuz		 * Or, can we even panic?
713151539Ssuz		 */
714151539Ssuz		log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags);
715151539Ssuz		return (RTPREF_INVALID);
716151539Ssuz	}
717151539Ssuz	/* NOTREACHED */
718151539Ssuz}
719151539Ssuz
72053541Sshinstatic struct nd_defrouter *
721171259Sdelphijdefrtrlist_update(struct nd_defrouter *new)
72253541Sshin{
72353541Sshin	struct nd_defrouter *dr, *n;
72453541Sshin	int s = splnet();
72553541Sshin
72653541Sshin	if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
72753541Sshin		/* entry exists */
72853541Sshin		if (new->rtlifetime == 0) {
72953541Sshin			defrtrlist_del(dr);
73053541Sshin			dr = NULL;
73153541Sshin		} else {
732151539Ssuz			int oldpref = rtpref(dr);
733151539Ssuz
73453541Sshin			/* override */
73553541Sshin			dr->flags = new->flags; /* xxx flag check */
73653541Sshin			dr->rtlifetime = new->rtlifetime;
73753541Sshin			dr->expire = new->expire;
738151539Ssuz
739151539Ssuz			/*
740151539Ssuz			 * If the preference does not change, there's no need
741151539Ssuz			 * to sort the entries.
742151539Ssuz			 */
743151539Ssuz			if (rtpref(new) == oldpref) {
744151539Ssuz				splx(s);
745151539Ssuz				return (dr);
746151539Ssuz			}
747151539Ssuz
748151539Ssuz			/*
749151539Ssuz			 * preferred router may be changed, so relocate
750151539Ssuz			 * this router.
751151539Ssuz			 * XXX: calling TAILQ_REMOVE directly is a bad manner.
752151539Ssuz			 * However, since defrtrlist_del() has many side
753151539Ssuz			 * effects, we intentionally do so here.
754151539Ssuz			 * defrouter_select() below will handle routing
755151539Ssuz			 * changes later.
756151539Ssuz			 */
757151539Ssuz			TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
758151539Ssuz			n = dr;
759151539Ssuz			goto insert;
76053541Sshin		}
76153541Sshin		splx(s);
762120856Sume		return (dr);
76353541Sshin	}
76453541Sshin
76553541Sshin	/* entry does not exist */
76653541Sshin	if (new->rtlifetime == 0) {
76753541Sshin		splx(s);
768120856Sume		return (NULL);
76953541Sshin	}
77053541Sshin
77153541Sshin	n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
77253541Sshin	if (n == NULL) {
77353541Sshin		splx(s);
774120856Sume		return (NULL);
77553541Sshin	}
77653541Sshin	bzero(n, sizeof(*n));
77753541Sshin	*n = *new;
77862587Sitojun
779151539Ssuzinsert:
78062587Sitojun	/*
781151539Ssuz	 * Insert the new router in the Default Router List;
782151539Ssuz	 * The Default Router List should be in the descending order
783151539Ssuz	 * of router-preferece.  Routers with the same preference are
784151539Ssuz	 * sorted in the arriving time order.
78562587Sitojun	 */
786151539Ssuz
787151539Ssuz	/* insert at the end of the group */
788151539Ssuz	for (dr = TAILQ_FIRST(&nd_defrouter); dr;
789151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry)) {
790151539Ssuz		if (rtpref(n) > rtpref(dr))
791151539Ssuz			break;
792151539Ssuz	}
793151539Ssuz	if (dr)
794151539Ssuz		TAILQ_INSERT_BEFORE(dr, n, dr_entry);
795151539Ssuz	else
796151539Ssuz		TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
797151539Ssuz
798151539Ssuz	defrouter_select();
799151539Ssuz
80053541Sshin	splx(s);
801120941Sume
802120856Sume	return (n);
80353541Sshin}
80453541Sshin
80553541Sshinstatic struct nd_pfxrouter *
806171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr)
80753541Sshin{
80853541Sshin	struct nd_pfxrouter *search;
809120941Sume
81062587Sitojun	for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
81153541Sshin		if (search->router == dr)
81253541Sshin			break;
81353541Sshin	}
81453541Sshin
815120856Sume	return (search);
81653541Sshin}
81753541Sshin
81853541Sshinstatic void
819171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr)
82053541Sshin{
82153541Sshin	struct nd_pfxrouter *new;
82253541Sshin
82353541Sshin	new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
82453541Sshin	if (new == NULL)
82553541Sshin		return;
82653541Sshin	bzero(new, sizeof(*new));
82753541Sshin	new->router = dr;
82853541Sshin
82953541Sshin	LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
83053541Sshin
83153541Sshin	pfxlist_onlink_check();
83253541Sshin}
83353541Sshin
83453541Sshinstatic void
835171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr)
83653541Sshin{
83753541Sshin	LIST_REMOVE(pfr, pfr_entry);
83853541Sshin	free(pfr, M_IP6NDP);
83953541Sshin}
84053541Sshin
84178064Sumestruct nd_prefix *
842171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key)
84353541Sshin{
84453541Sshin	struct nd_prefix *search;
84553541Sshin
84662587Sitojun	for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
847151539Ssuz		if (key->ndpr_ifp == search->ndpr_ifp &&
848151539Ssuz		    key->ndpr_plen == search->ndpr_plen &&
849151539Ssuz		    in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr,
850151539Ssuz		    &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) {
85153541Sshin			break;
85253541Sshin		}
85353541Sshin	}
85453541Sshin
855120856Sume	return (search);
85653541Sshin}
85753541Sshin
85878064Sumeint
859171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
860171259Sdelphij    struct nd_prefix **newp)
86153541Sshin{
86278064Sume	struct nd_prefix *new = NULL;
863151539Ssuz	int error = 0;
86453541Sshin	int i, s;
865165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
86653541Sshin
86753541Sshin	new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
86853541Sshin	if (new == NULL)
869120941Sume		return(ENOMEM);
87053541Sshin	bzero(new, sizeof(*new));
871151539Ssuz	new->ndpr_ifp = pr->ndpr_ifp;
872151539Ssuz	new->ndpr_prefix = pr->ndpr_prefix;
873151539Ssuz	new->ndpr_plen = pr->ndpr_plen;
874151539Ssuz	new->ndpr_vltime = pr->ndpr_vltime;
875151539Ssuz	new->ndpr_pltime = pr->ndpr_pltime;
876151539Ssuz	new->ndpr_flags = pr->ndpr_flags;
877151539Ssuz	if ((error = in6_init_prefix_ltimes(new)) != 0) {
878151539Ssuz		free(new, M_IP6NDP);
879151539Ssuz		return(error);
880151539Ssuz	}
881151539Ssuz	new->ndpr_lastupdate = time_second;
88278064Sume	if (newp != NULL)
88378064Sume		*newp = new;
88453541Sshin
885120941Sume	/* initialization */
88653541Sshin	LIST_INIT(&new->ndpr_advrtrs);
88753541Sshin	in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
88853541Sshin	/* make prefix in the canonical form */
88953541Sshin	for (i = 0; i < 4; i++)
89053541Sshin		new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
891120941Sume		    new->ndpr_mask.s6_addr32[i];
89253541Sshin
89353541Sshin	s = splnet();
89453541Sshin	/* link ndpr_entry to nd_prefix list */
89553541Sshin	LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
89653541Sshin	splx(s);
89753541Sshin
89878064Sume	/* ND_OPT_PI_FLAG_ONLINK processing */
89978064Sume	if (new->ndpr_raf_onlink) {
90078064Sume		int e;
90178064Sume
90278064Sume		if ((e = nd6_prefix_onlink(new)) != 0) {
90378064Sume			nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
90478064Sume			    "the prefix %s/%d on-link on %s (errno=%d)\n",
905165118Sbz			    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
90678064Sume			    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
90778064Sume			/* proceed anyway. XXX: is it correct? */
90878064Sume		}
90978064Sume	}
91078064Sume
911120941Sume	if (dr)
91253541Sshin		pfxrtr_add(new, dr);
91353541Sshin
91453541Sshin	return 0;
91553541Sshin}
91653541Sshin
91753541Sshinvoid
918171259Sdelphijprelist_remove(struct nd_prefix *pr)
91953541Sshin{
92053541Sshin	struct nd_pfxrouter *pfr, *next;
92178064Sume	int e, s;
922165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
92353541Sshin
92478064Sume	/* make sure to invalidate the prefix until it is really freed. */
92578064Sume	pr->ndpr_vltime = 0;
92678064Sume	pr->ndpr_pltime = 0;
927151539Ssuz
92878064Sume	/*
92978064Sume	 * Though these flags are now meaningless, we'd rather keep the value
930151479Ssuz	 * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users
931151479Ssuz	 * when executing "ndp -p".
93278064Sume	 */
933151479Ssuz
93478064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
93578064Sume	    (e = nd6_prefix_offlink(pr)) != 0) {
93678064Sume		nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
93778064Sume		    "on %s, errno=%d\n",
938165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
93978064Sume		    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
94078064Sume		/* what should we do? */
94178064Sume	}
94278064Sume
94378064Sume	if (pr->ndpr_refcnt > 0)
94478064Sume		return;		/* notice here? */
94578064Sume
94653541Sshin	s = splnet();
94778064Sume
94853541Sshin	/* unlink ndpr_entry from nd_prefix list */
94953541Sshin	LIST_REMOVE(pr, ndpr_entry);
95053541Sshin
95153541Sshin	/* free list of routers that adversed the prefix */
95262587Sitojun	for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
95362587Sitojun		next = pfr->pfr_next;
95453541Sshin
95553541Sshin		free(pfr, M_IP6NDP);
95653541Sshin	}
95778064Sume	splx(s);
95878064Sume
95953541Sshin	free(pr, M_IP6NDP);
96053541Sshin
96153541Sshin	pfxlist_onlink_check();
96253541Sshin}
96353541Sshin
964171259Sdelphij/*
965171259Sdelphij * dr - may be NULL
966171259Sdelphij */
967171259Sdelphij
968151539Ssuzstatic int
969171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
970171259Sdelphij    struct mbuf *m, int mcast)
97153541Sshin{
97278064Sume	struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
97378064Sume	struct ifaddr *ifa;
97478064Sume	struct ifnet *ifp = new->ndpr_ifp;
97553541Sshin	struct nd_prefix *pr;
97653541Sshin	int s = splnet();
97753541Sshin	int error = 0;
97878064Sume	int newprefix = 0;
97953541Sshin	int auth;
98078064Sume	struct in6_addrlifetime lt6_tmp;
981165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
98253541Sshin
98353541Sshin	auth = 0;
98453541Sshin	if (m) {
98553541Sshin		/*
98653541Sshin		 * Authenticity for NA consists authentication for
98753541Sshin		 * both IP header and IP datagrams, doesn't it ?
98853541Sshin		 */
98953541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
990120941Sume		auth = ((m->m_flags & M_AUTHIPHDR) &&
991120941Sume		    (m->m_flags & M_AUTHIPDGM));
99253541Sshin#endif
99353541Sshin	}
99453541Sshin
99578064Sume	if ((pr = nd6_prefix_lookup(new)) != NULL) {
99678064Sume		/*
99778064Sume		 * nd6_prefix_lookup() ensures that pr and new have the same
99878064Sume		 * prefix on a same interface.
99978064Sume		 */
100053541Sshin
100153541Sshin		/*
100278064Sume		 * Update prefix information.  Note that the on-link (L) bit
100378064Sume		 * and the autonomous (A) bit should NOT be changed from 1
100478064Sume		 * to 0.
100553541Sshin		 */
100678064Sume		if (new->ndpr_raf_onlink == 1)
100778064Sume			pr->ndpr_raf_onlink = 1;
100878064Sume		if (new->ndpr_raf_auto == 1)
100978064Sume			pr->ndpr_raf_auto = 1;
101078064Sume		if (new->ndpr_raf_onlink) {
101178064Sume			pr->ndpr_vltime = new->ndpr_vltime;
101278064Sume			pr->ndpr_pltime = new->ndpr_pltime;
1013151539Ssuz			(void)in6_init_prefix_ltimes(pr); /* XXX error case? */
1014151539Ssuz			pr->ndpr_lastupdate = time_second;
101578064Sume		}
101653541Sshin
101778064Sume		if (new->ndpr_raf_onlink &&
101878064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
101978064Sume			int e;
102053541Sshin
102178064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
102278064Sume				nd6log((LOG_ERR,
102378064Sume				    "prelist_update: failed to make "
102478064Sume				    "the prefix %s/%d on-link on %s "
102578064Sume				    "(errno=%d)\n",
1026165118Sbz				    ip6_sprintf(ip6buf,
1027165118Sbz					    &pr->ndpr_prefix.sin6_addr),
102878064Sume				    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
102978064Sume				/* proceed anyway. XXX: is it correct? */
103053541Sshin			}
103178064Sume		}
103253541Sshin
103378064Sume		if (dr && pfxrtr_lookup(pr, dr) == NULL)
103478064Sume			pfxrtr_add(pr, dr);
103578064Sume	} else {
103678064Sume		struct nd_prefix *newpr = NULL;
103753541Sshin
103878064Sume		newprefix = 1;
103953541Sshin
104078064Sume		if (new->ndpr_vltime == 0)
104178064Sume			goto end;
104278064Sume		if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
104378064Sume			goto end;
104453541Sshin
104578064Sume		error = nd6_prelist_add(new, dr, &newpr);
104678064Sume		if (error != 0 || newpr == NULL) {
104778064Sume			nd6log((LOG_NOTICE, "prelist_update: "
104878064Sume			    "nd6_prelist_add failed for %s/%d on %s "
104978064Sume			    "errno=%d, returnpr=%p\n",
1050165118Sbz			    ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr),
1051120941Sume			    new->ndpr_plen, if_name(new->ndpr_ifp),
1052120941Sume			    error, newpr));
105378064Sume			goto end; /* we should just give up in this case. */
105478064Sume		}
105553541Sshin
105678064Sume		/*
105778064Sume		 * XXX: from the ND point of view, we can ignore a prefix
105878064Sume		 * with the on-link bit being zero.  However, we need a
105978064Sume		 * prefix structure for references from autoconfigured
1060120941Sume		 * addresses.  Thus, we explicitly make sure that the prefix
106178064Sume		 * itself expires now.
106278064Sume		 */
106378064Sume		if (newpr->ndpr_raf_onlink == 0) {
106478064Sume			newpr->ndpr_vltime = 0;
106578064Sume			newpr->ndpr_pltime = 0;
106678064Sume			in6_init_prefix_ltimes(newpr);
106753541Sshin		}
106853541Sshin
106978064Sume		pr = newpr;
107078064Sume	}
107153541Sshin
107278064Sume	/*
107378064Sume	 * Address autoconfiguration based on Section 5.5.3 of RFC 2462.
107478064Sume	 * Note that pr must be non NULL at this point.
107578064Sume	 */
107662587Sitojun
107778064Sume	/* 5.5.3 (a). Ignore the prefix without the A bit set. */
107878064Sume	if (!new->ndpr_raf_auto)
1079151539Ssuz		goto end;
108062587Sitojun
108178064Sume	/*
108278064Sume	 * 5.5.3 (b). the link-local prefix should have been ignored in
108378064Sume	 * nd6_ra_input.
108478064Sume	 */
108562587Sitojun
1086151539Ssuz	/* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */
1087151539Ssuz	if (new->ndpr_pltime > new->ndpr_vltime) {
1088151539Ssuz		error = EINVAL;	/* XXX: won't be used */
1089151539Ssuz		goto end;
1090151539Ssuz	}
109162587Sitojun
109278064Sume 	/*
1093151539Ssuz	 * 5.5.3 (d).  If the prefix advertised is not equal to the prefix of
1094151539Ssuz	 * an address configured by stateless autoconfiguration already in the
1095151539Ssuz	 * list of addresses associated with the interface, and the Valid
1096151539Ssuz	 * Lifetime is not 0, form an address.  We first check if we have
1097151539Ssuz	 * a matching prefix.
1098151539Ssuz	 * Note: we apply a clarification in rfc2462bis-02 here.  We only
1099151539Ssuz	 * consider autoconfigured addresses while RFC2462 simply said
1100151539Ssuz	 * "address".
110178064Sume	 */
1102120941Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
110378064Sume		struct in6_ifaddr *ifa6;
1104151539Ssuz		u_int32_t remaininglifetime;
110553541Sshin
110678064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
110778064Sume			continue;
110853541Sshin
110978064Sume		ifa6 = (struct in6_ifaddr *)ifa;
111053541Sshin
111153541Sshin		/*
1112151539Ssuz		 * We only consider autoconfigured addresses as per rfc2462bis.
1113151539Ssuz		 */
1114151539Ssuz		if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF))
1115151539Ssuz			continue;
1116151539Ssuz
1117151539Ssuz		/*
111878064Sume		 * Spec is not clear here, but I believe we should concentrate
111978064Sume		 * on unicast (i.e. not anycast) addresses.
112078064Sume		 * XXX: other ia6_flags? detached or duplicated?
112153541Sshin		 */
112278064Sume		if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
112378064Sume			continue;
1124120941Sume
1125151539Ssuz		/*
1126151539Ssuz		 * Ignore the address if it is not associated with a prefix
1127151539Ssuz		 * or is associated with a prefix that is different from this
1128151539Ssuz		 * one.  (pr is never NULL here)
1129151539Ssuz		 */
1130151539Ssuz		if (ifa6->ia6_ndpr != pr)
113178064Sume			continue;
113253541Sshin
113378064Sume		if (ia6_match == NULL) /* remember the first one */
113478064Sume			ia6_match = ifa6;
113578064Sume
113678064Sume		/*
113778064Sume		 * An already autoconfigured address matched.  Now that we
113878064Sume		 * are sure there is at least one matched address, we can
113978064Sume		 * proceed to 5.5.3. (e): update the lifetimes according to the
114078064Sume		 * "two hours" rule and the privacy extension.
1141151539Ssuz		 * We apply some clarifications in rfc2462bis:
1142151539Ssuz		 * - use remaininglifetime instead of storedlifetime as a
1143151539Ssuz		 *   variable name
1144151539Ssuz		 * - remove the dead code in the "two-hour" rule
114578064Sume		 */
114678064Sume#define TWOHOUR		(120*60)
114778064Sume		lt6_tmp = ifa6->ia6_lifetime;
114878064Sume
1149112678Sume		if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME)
1150151539Ssuz			remaininglifetime = ND6_INFINITE_LIFETIME;
1151151539Ssuz		else if (time_second - ifa6->ia6_updatetime >
1152151539Ssuz			 lt6_tmp.ia6t_vltime) {
1153151539Ssuz			/*
1154151539Ssuz			 * The case of "invalid" address.  We should usually
1155151539Ssuz			 * not see this case.
1156151539Ssuz			 */
1157151539Ssuz			remaininglifetime = 0;
1158151539Ssuz		} else
1159151539Ssuz			remaininglifetime = lt6_tmp.ia6t_vltime -
1160151539Ssuz			    (time_second - ifa6->ia6_updatetime);
116178064Sume
1162112678Sume		/* when not updating, keep the current stored lifetime. */
1163151539Ssuz		lt6_tmp.ia6t_vltime = remaininglifetime;
1164112678Sume
116578064Sume		if (TWOHOUR < new->ndpr_vltime ||
1166151539Ssuz		    remaininglifetime < new->ndpr_vltime) {
116778064Sume			lt6_tmp.ia6t_vltime = new->ndpr_vltime;
1168151539Ssuz		} else if (remaininglifetime <= TWOHOUR) {
116978064Sume			if (auth) {
117078064Sume				lt6_tmp.ia6t_vltime = new->ndpr_vltime;
117178064Sume			}
117278064Sume		} else {
117378064Sume			/*
117478064Sume			 * new->ndpr_vltime <= TWOHOUR &&
1175151539Ssuz			 * TWOHOUR < remaininglifetime
117678064Sume			 */
117778064Sume			lt6_tmp.ia6t_vltime = TWOHOUR;
117853541Sshin		}
117953541Sshin
118078064Sume		/* The 2 hour rule is not imposed for preferred lifetime. */
118178064Sume		lt6_tmp.ia6t_pltime = new->ndpr_pltime;
118253541Sshin
118378064Sume		in6_init_address_ltimes(pr, &lt6_tmp);
118453541Sshin
1185151539Ssuz  		/*
1186151539Ssuz		 * We need to treat lifetimes for temporary addresses
1187151539Ssuz		 * differently, according to
1188151539Ssuz		 * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1);
1189151539Ssuz		 * we only update the lifetimes when they are in the maximum
1190151539Ssuz		 * intervals.
1191151539Ssuz  		 */
1192151539Ssuz  		if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
1193151539Ssuz			u_int32_t maxvltime, maxpltime;
1194151539Ssuz
1195151539Ssuz			if (ip6_temp_valid_lifetime >
1196151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1197151539Ssuz			    ip6_desync_factor)) {
1198151539Ssuz				maxvltime = ip6_temp_valid_lifetime -
1199151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1200151539Ssuz				    ip6_desync_factor;
1201151539Ssuz			} else
1202151539Ssuz				maxvltime = 0;
1203151539Ssuz			if (ip6_temp_preferred_lifetime >
1204151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1205151539Ssuz			    ip6_desync_factor)) {
1206151539Ssuz				maxpltime = ip6_temp_preferred_lifetime -
1207151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1208151539Ssuz				    ip6_desync_factor;
1209151539Ssuz			} else
1210151539Ssuz				maxpltime = 0;
1211151539Ssuz
1212151539Ssuz			if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME ||
1213151539Ssuz			    lt6_tmp.ia6t_vltime > maxvltime) {
1214151539Ssuz				lt6_tmp.ia6t_vltime = maxvltime;
121578064Sume			}
1216151539Ssuz			if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME ||
1217151539Ssuz			    lt6_tmp.ia6t_pltime > maxpltime) {
1218151539Ssuz				lt6_tmp.ia6t_pltime = maxpltime;
121978064Sume			}
122078064Sume		}
122178064Sume		ifa6->ia6_lifetime = lt6_tmp;
1222151539Ssuz		ifa6->ia6_updatetime = time_second;
122353541Sshin	}
122478064Sume	if (ia6_match == NULL && new->ndpr_vltime) {
1225151539Ssuz		int ifidlen;
1226151539Ssuz
122778064Sume		/*
1228151539Ssuz		 * 5.5.3 (d) (continued)
122978064Sume		 * No address matched and the valid lifetime is non-zero.
123078064Sume		 * Create a new address.
123178064Sume		 */
1232151539Ssuz
1233151539Ssuz		/*
1234151539Ssuz		 * Prefix Length check:
1235151539Ssuz		 * If the sum of the prefix length and interface identifier
1236151539Ssuz		 * length does not equal 128 bits, the Prefix Information
1237151539Ssuz		 * option MUST be ignored.  The length of the interface
1238151539Ssuz		 * identifier is defined in a separate link-type specific
1239151539Ssuz		 * document.
1240151539Ssuz		 */
1241151539Ssuz		ifidlen = in6_if2idlen(ifp);
1242151539Ssuz		if (ifidlen < 0) {
1243151539Ssuz			/* this should not happen, so we always log it. */
1244151539Ssuz			log(LOG_ERR, "prelist_update: IFID undefined (%s)\n",
1245151539Ssuz			    if_name(ifp));
1246151539Ssuz			goto end;
1247151539Ssuz		}
1248151539Ssuz		if (ifidlen + pr->ndpr_plen != 128) {
1249151539Ssuz			nd6log((LOG_INFO,
1250151539Ssuz			    "prelist_update: invalid prefixlen "
1251151539Ssuz			    "%d for %s, ignored\n",
1252151539Ssuz			    pr->ndpr_plen, if_name(ifp)));
1253151539Ssuz			goto end;
1254151539Ssuz		}
1255151539Ssuz
1256151539Ssuz		if ((ia6 = in6_ifadd(new, mcast)) != NULL) {
125778064Sume			/*
125878064Sume			 * note that we should use pr (not new) for reference.
125978064Sume			 */
126078064Sume			pr->ndpr_refcnt++;
126178064Sume			ia6->ia6_ndpr = pr;
126253541Sshin
126378064Sume			/*
126478064Sume			 * RFC 3041 3.3 (2).
126578064Sume			 * When a new public address is created as described
126678064Sume			 * in RFC2462, also create a new temporary address.
126778064Sume			 *
126878064Sume			 * RFC 3041 3.5.
126978064Sume			 * When an interface connects to a new link, a new
127078064Sume			 * randomized interface identifier should be generated
127178064Sume			 * immediately together with a new set of temporary
127278064Sume			 * addresses.  Thus, we specifiy 1 as the 2nd arg of
127378064Sume			 * in6_tmpifadd().
127478064Sume			 */
127578064Sume			if (ip6_use_tempaddr) {
127678064Sume				int e;
1277151539Ssuz				if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) {
127878064Sume					nd6log((LOG_NOTICE, "prelist_update: "
127978064Sume					    "failed to create a temporary "
128078064Sume					    "address, errno=%d\n",
128178064Sume					    e));
128278064Sume				}
128378064Sume			}
128478064Sume
128578064Sume			/*
128678064Sume			 * A newly added address might affect the status
128778064Sume			 * of other addresses, so we check and update it.
128878064Sume			 * XXX: what if address duplication happens?
128978064Sume			 */
129078064Sume			pfxlist_onlink_check();
129178064Sume		} else {
129278064Sume			/* just set an error. do not bark here. */
129378064Sume			error = EADDRNOTAVAIL; /* XXX: might be unused. */
129478064Sume		}
129578064Sume	}
129678064Sume
129753541Sshin end:
129853541Sshin	splx(s);
129953541Sshin	return error;
130053541Sshin}
130153541Sshin
130253541Sshin/*
130362587Sitojun * A supplement function used in the on-link detection below;
130462587Sitojun * detect if a given prefix has a (probably) reachable advertising router.
130562587Sitojun * XXX: lengthy function name...
130662587Sitojun */
130778064Sumestatic struct nd_pfxrouter *
1308171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr)
130962587Sitojun{
131062587Sitojun	struct nd_pfxrouter *pfxrtr;
131162587Sitojun	struct rtentry *rt;
131262587Sitojun	struct llinfo_nd6 *ln;
131362587Sitojun
131462587Sitojun	for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
131562587Sitojun	     pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
131662587Sitojun		if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
1317120941Sume		    pfxrtr->router->ifp)) &&
131862587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
131962587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln))
132062587Sitojun			break;	/* found */
132162587Sitojun	}
132262587Sitojun
1323120856Sume	return (pfxrtr);
132462587Sitojun}
132562587Sitojun
132662587Sitojun/*
132753541Sshin * Check if each prefix in the prefix list has at least one available router
132878064Sume * that advertised the prefix (a router is "available" if its neighbor cache
132978064Sume * entry is reachable or probably reachable).
133062587Sitojun * If the check fails, the prefix may be off-link, because, for example,
133153541Sshin * we have moved from the network but the lifetime of the prefix has not
133278064Sume * expired yet.  So we should not use the prefix if there is another prefix
133378064Sume * that has an available router.
133478064Sume * But, if there is no prefix that has an available router, we still regards
133578064Sume * all the prefixes as on-link.  This is because we can't tell if all the
133653541Sshin * routers are simply dead or if we really moved from the network and there
133753541Sshin * is no router around us.
133853541Sshin */
133962587Sitojunvoid
134053541Sshinpfxlist_onlink_check()
134153541Sshin{
134253541Sshin	struct nd_prefix *pr;
134378064Sume	struct in6_ifaddr *ifa;
1344151539Ssuz	struct nd_defrouter *dr;
1345151539Ssuz	struct nd_pfxrouter *pfxrtr = NULL;
134653541Sshin
134762587Sitojun	/*
134862587Sitojun	 * Check if there is a prefix that has a reachable advertising
134962587Sitojun	 * router.
135062587Sitojun	 */
135162587Sitojun	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
135278064Sume		if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
135353541Sshin			break;
135462587Sitojun	}
135553541Sshin
1356151539Ssuz	/*
1357151539Ssuz	 * If we have no such prefix, check whether we still have a router
1358151539Ssuz	 * that does not advertise any prefixes.
1359151539Ssuz	 */
1360151465Ssuz	if (pr == NULL) {
1361151539Ssuz		for (dr = TAILQ_FIRST(&nd_defrouter); dr;
1362151539Ssuz		    dr = TAILQ_NEXT(dr, dr_entry)) {
1363151539Ssuz			struct nd_prefix *pr0;
1364151539Ssuz
1365151539Ssuz			for (pr0 = nd_prefix.lh_first; pr0;
1366151539Ssuz			    pr0 = pr0->ndpr_next) {
1367151539Ssuz				if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL)
1368151539Ssuz					break;
1369151539Ssuz			}
1370151539Ssuz			if (pfxrtr != NULL)
1371151539Ssuz				break;
1372151539Ssuz		}
1373151539Ssuz	}
1374151539Ssuz	if (pr != NULL || (TAILQ_FIRST(&nd_defrouter) && pfxrtr == NULL)) {
1375151539Ssuz  		/*
1376151539Ssuz		 * There is at least one prefix that has a reachable router,
1377151539Ssuz		 * or at least a router which probably does not advertise
1378151539Ssuz		 * any prefixes.  The latter would be the case when we move
1379151539Ssuz		 * to a new link where we have a router that does not provide
1380151539Ssuz		 * prefixes and we configure an address by hand.
1381151539Ssuz  		 * Detach prefixes which have no reachable advertising
1382151539Ssuz  		 * router, and attach other prefixes.
1383151539Ssuz  		 */
138462587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
138578064Sume			/* XXX: a link-local prefix should never be detached */
138678064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
138778064Sume				continue;
138878064Sume
138978064Sume			/*
139078064Sume			 * we aren't interested in prefixes without the L bit
139178064Sume			 * set.
139278064Sume			 */
139378064Sume			if (pr->ndpr_raf_onlink == 0)
139478064Sume				continue;
139578064Sume
139678064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
139778064Sume			    find_pfxlist_reachable_router(pr) == NULL)
139878064Sume				pr->ndpr_stateflags |= NDPRF_DETACHED;
139978064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
140078064Sume			    find_pfxlist_reachable_router(pr) != 0)
140178064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
140253541Sshin		}
140378064Sume	} else {
140478064Sume		/* there is no prefix that has a reachable router */
140562587Sitojun		for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
140678064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
140778064Sume				continue;
140878064Sume
140978064Sume			if (pr->ndpr_raf_onlink == 0)
141078064Sume				continue;
141178064Sume
141278064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
141378064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
141453541Sshin		}
141562587Sitojun	}
141678064Sume
141778064Sume	/*
141878064Sume	 * Remove each interface route associated with a (just) detached
141978064Sume	 * prefix, and reinstall the interface route for a (just) attached
142078064Sume	 * prefix.  Note that all attempt of reinstallation does not
142178064Sume	 * necessarily success, when a same prefix is shared among multiple
142278064Sume	 * interfaces.  Such cases will be handled in nd6_prefix_onlink,
142378064Sume	 * so we don't have to care about them.
142478064Sume	 */
142578064Sume	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
142678064Sume		int e;
1427165118Sbz		char ip6buf[INET6_ADDRSTRLEN];
142878064Sume
142978064Sume		if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
143078064Sume			continue;
143178064Sume
143278064Sume		if (pr->ndpr_raf_onlink == 0)
143378064Sume			continue;
143478064Sume
143578064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
143678064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
143778064Sume			if ((e = nd6_prefix_offlink(pr)) != 0) {
143878064Sume				nd6log((LOG_ERR,
143978064Sume				    "pfxlist_onlink_check: failed to "
1440151479Ssuz				    "make %s/%d offlink, errno=%d\n",
1441165118Sbz				    ip6_sprintf(ip6buf,
1442165118Sbz					    &pr->ndpr_prefix.sin6_addr),
1443165118Sbz					    pr->ndpr_plen, e));
144478064Sume			}
144578064Sume		}
144678064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
144778064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
144878064Sume		    pr->ndpr_raf_onlink) {
144978064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
145078064Sume				nd6log((LOG_ERR,
145178064Sume				    "pfxlist_onlink_check: failed to "
1452151479Ssuz				    "make %s/%d onlink, errno=%d\n",
1453165118Sbz				    ip6_sprintf(ip6buf,
1454165118Sbz					    &pr->ndpr_prefix.sin6_addr),
1455165118Sbz					    pr->ndpr_plen, e));
145678064Sume			}
145778064Sume		}
145878064Sume	}
145978064Sume
146078064Sume	/*
146178064Sume	 * Changes on the prefix status might affect address status as well.
146278064Sume	 * Make sure that all addresses derived from an attached prefix are
146378064Sume	 * attached, and that all addresses derived from a detached prefix are
146478064Sume	 * detached.  Note, however, that a manually configured address should
146578064Sume	 * always be attached.
146678064Sume	 * The precise detection logic is same as the one for prefixes.
146778064Sume	 */
146878064Sume	for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
1469120941Sume		if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
147078064Sume			continue;
147178064Sume
147278064Sume		if (ifa->ia6_ndpr == NULL) {
147378064Sume			/*
147478064Sume			 * This can happen when we first configure the address
147578064Sume			 * (i.e. the address exists, but the prefix does not).
147678064Sume			 * XXX: complicated relationships...
147778064Sume			 */
147878064Sume			continue;
147978064Sume		}
148078064Sume
148178064Sume		if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
148278064Sume			break;
148378064Sume	}
148478064Sume	if (ifa) {
148578064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
148678064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
148778064Sume				continue;
148878064Sume
148978064Sume			if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
149078064Sume				continue;
149178064Sume
1492151539Ssuz			if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) {
1493151539Ssuz				if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1494151539Ssuz					ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1495151539Ssuz					ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1496151539Ssuz					nd6_dad_start((struct ifaddr *)ifa, 0);
1497151539Ssuz				}
1498151539Ssuz			} else {
149978064Sume				ifa->ia6_flags |= IN6_IFF_DETACHED;
1500151539Ssuz			}
150178064Sume		}
150278064Sume	}
150362587Sitojun	else {
150478064Sume		for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
150578064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
150678064Sume				continue;
150778064Sume
1508151539Ssuz			if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1509151539Ssuz				ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1510151539Ssuz				ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1511151539Ssuz				/* Do we need a delay in this case? */
1512151539Ssuz				nd6_dad_start((struct ifaddr *)ifa, 0);
1513151539Ssuz			}
151478064Sume		}
151553541Sshin	}
151653541Sshin}
151753541Sshin
151878064Sumeint
1519171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr)
152053541Sshin{
152178064Sume	struct ifaddr *ifa;
152278064Sume	struct ifnet *ifp = pr->ndpr_ifp;
152378064Sume	struct sockaddr_in6 mask6;
152478064Sume	struct nd_prefix *opr;
152578064Sume	u_long rtflags;
152678064Sume	int error = 0;
152778064Sume	struct rtentry *rt = NULL;
1528165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
152953541Sshin
153078064Sume	/* sanity check */
153178064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
153278064Sume		nd6log((LOG_ERR,
153378064Sume		    "nd6_prefix_onlink: %s/%d is already on-link\n",
1534165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
1535165118Sbz		    pr->ndpr_plen));
1536151465Ssuz		return (EEXIST);
153778064Sume	}
153878064Sume
153953541Sshin	/*
154078064Sume	 * Add the interface route associated with the prefix.  Before
154178064Sume	 * installing the route, check if there's the same prefix on another
154278064Sume	 * interface, and the prefix has already installed the interface route.
154378064Sume	 * Although such a configuration is expected to be rare, we explicitly
154478064Sume	 * allow it.
154553541Sshin	 */
154678064Sume	for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
154778064Sume		if (opr == pr)
154878064Sume			continue;
154978064Sume
155078064Sume		if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
155178064Sume			continue;
155278064Sume
155378064Sume		if (opr->ndpr_plen == pr->ndpr_plen &&
155478064Sume		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1555120941Sume		    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen))
1556120856Sume			return (0);
155778064Sume	}
155878064Sume
155978064Sume	/*
1560120941Sume	 * We prefer link-local addresses as the associated interface address.
156178064Sume	 */
156278064Sume	/* search for a link-local addr */
156378064Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
1564120941Sume	    IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
156578064Sume	if (ifa == NULL) {
156678064Sume		/* XXX: freebsd does not have ifa_ifwithaf */
1567120941Sume		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
156878064Sume			if (ifa->ifa_addr->sa_family == AF_INET6)
156978064Sume				break;
157078064Sume		}
157178064Sume		/* should we care about ia6_flags? */
157278064Sume	}
157378064Sume	if (ifa == NULL) {
157478064Sume		/*
157578064Sume		 * This can still happen, when, for example, we receive an RA
157678064Sume		 * containing a prefix with the L bit set and the A bit clear,
157778064Sume		 * after removing all IPv6 addresses on the receiving
157878064Sume		 * interface.  This should, of course, be rare though.
157978064Sume		 */
158078064Sume		nd6log((LOG_NOTICE,
158178064Sume		    "nd6_prefix_onlink: failed to find any ifaddr"
158278064Sume		    " to add route for a prefix(%s/%d) on %s\n",
1583165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
158478064Sume		    pr->ndpr_plen, if_name(ifp)));
1585120856Sume		return (0);
158678064Sume	}
158778064Sume
158878064Sume	/*
158978064Sume	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
159078064Sume	 * ifa->ifa_rtrequest = nd6_rtrequest;
159178064Sume	 */
159278064Sume	bzero(&mask6, sizeof(mask6));
159378064Sume	mask6.sin6_len = sizeof(mask6);
159478064Sume	mask6.sin6_addr = pr->ndpr_mask;
159578064Sume	rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP;
159678064Sume	if (nd6_need_cache(ifp)) {
159778064Sume		/* explicitly set in case ifa_flags does not set the flag. */
159878064Sume		rtflags |= RTF_CLONING;
159978064Sume	} else {
160078064Sume		/*
160178064Sume		 * explicitly clear the cloning bit in case ifa_flags sets it.
160278064Sume		 */
160378064Sume		rtflags &= ~RTF_CLONING;
160478064Sume	}
160578064Sume	error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
1606120941Sume	    ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
160778064Sume	if (error == 0) {
160878064Sume		if (rt != NULL) /* this should be non NULL, though */
160978064Sume			nd6_rtmsg(RTM_ADD, rt);
161078064Sume		pr->ndpr_stateflags |= NDPRF_ONLINK;
1611120941Sume	} else {
1612165118Sbz		char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN];
161378064Sume		nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
161478064Sume		    " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
161578064Sume		    "errno = %d\n",
1616165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
161778064Sume		    pr->ndpr_plen, if_name(ifp),
1618165118Sbz		    ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
1619165118Sbz		    ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error));
162078064Sume	}
162178064Sume
1622120727Ssam	if (rt != NULL) {
1623120727Ssam		RT_LOCK(rt);
1624122334Ssam		RT_REMREF(rt);
1625120727Ssam		RT_UNLOCK(rt);
1626120727Ssam	}
162778064Sume
1628120856Sume	return (error);
162978064Sume}
163078064Sume
163178064Sumeint
1632171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr)
163378064Sume{
163478064Sume	int error = 0;
163578064Sume	struct ifnet *ifp = pr->ndpr_ifp;
163678064Sume	struct nd_prefix *opr;
163778064Sume	struct sockaddr_in6 sa6, mask6;
163878064Sume	struct rtentry *rt = NULL;
1639165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
164078064Sume
164178064Sume	/* sanity check */
164278064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
164378064Sume		nd6log((LOG_ERR,
164478064Sume		    "nd6_prefix_offlink: %s/%d is already off-link\n",
1645165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
1646165118Sbz		    pr->ndpr_plen));
1647120856Sume		return (EEXIST);
164878064Sume	}
164978064Sume
165053541Sshin	bzero(&sa6, sizeof(sa6));
165153541Sshin	sa6.sin6_family = AF_INET6;
165253541Sshin	sa6.sin6_len = sizeof(sa6);
165353541Sshin	bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
1654120941Sume	    sizeof(struct in6_addr));
165553541Sshin	bzero(&mask6, sizeof(mask6));
165653541Sshin	mask6.sin6_family = AF_INET6;
165753541Sshin	mask6.sin6_len = sizeof(sa6);
165853541Sshin	bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
165978064Sume	error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
1660120941Sume	    (struct sockaddr *)&mask6, 0, &rt);
166178064Sume	if (error == 0) {
166278064Sume		pr->ndpr_stateflags &= ~NDPRF_ONLINK;
166353541Sshin
166478064Sume		/* report the route deletion to the routing socket. */
166578064Sume		if (rt != NULL)
166678064Sume			nd6_rtmsg(RTM_DELETE, rt);
166753541Sshin
166878064Sume		/*
166978064Sume		 * There might be the same prefix on another interface,
167078064Sume		 * the prefix which could not be on-link just because we have
167178064Sume		 * the interface route (see comments in nd6_prefix_onlink).
167278064Sume		 * If there's one, try to make the prefix on-link on the
167378064Sume		 * interface.
167478064Sume		 */
167578064Sume		for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
167678064Sume			if (opr == pr)
167778064Sume				continue;
167853541Sshin
167978064Sume			if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
168078064Sume				continue;
168153541Sshin
168278064Sume			/*
168378064Sume			 * KAME specific: detached prefixes should not be
168478064Sume			 * on-link.
168578064Sume			 */
168678064Sume			if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
168778064Sume				continue;
168878064Sume
168978064Sume			if (opr->ndpr_plen == pr->ndpr_plen &&
169078064Sume			    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1691120941Sume			    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
169278064Sume				int e;
169378064Sume
169478064Sume				if ((e = nd6_prefix_onlink(opr)) != 0) {
169578064Sume					nd6log((LOG_ERR,
169678064Sume					    "nd6_prefix_offlink: failed to "
169778064Sume					    "recover a prefix %s/%d from %s "
169878064Sume					    "to %s (errno = %d)\n",
1699165118Sbz					    ip6_sprintf(ip6buf,
1700165118Sbz						&opr->ndpr_prefix.sin6_addr),
170178064Sume					    opr->ndpr_plen, if_name(ifp),
170278064Sume					    if_name(opr->ndpr_ifp), e));
170378064Sume				}
170478064Sume			}
170578064Sume		}
1706120941Sume	} else {
170778064Sume		/* XXX: can we still set the NDPRF_ONLINK flag? */
170878064Sume		nd6log((LOG_ERR,
170978064Sume		    "nd6_prefix_offlink: failed to delete route: "
171078064Sume		    "%s/%d on %s (errno = %d)\n",
1711165118Sbz		    ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen,
1712165118Sbz		    if_name(ifp), error));
171378064Sume	}
171453541Sshin
1715120941Sume	if (rt != NULL) {
1716108269Sru		RTFREE(rt);
1717120941Sume	}
171853541Sshin
1719120856Sume	return (error);
172053541Sshin}
172153541Sshin
172253541Sshinstatic struct in6_ifaddr *
1723171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast)
172453541Sshin{
172578064Sume	struct ifnet *ifp = pr->ndpr_ifp;
172653541Sshin	struct ifaddr *ifa;
172778064Sume	struct in6_aliasreq ifra;
172878064Sume	struct in6_ifaddr *ia, *ib;
172978064Sume	int error, plen0;
173053541Sshin	struct in6_addr mask;
173178064Sume	int prefixlen = pr->ndpr_plen;
1732151539Ssuz	int updateflags;
1733165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
173453541Sshin
1735121168Sume	in6_prefixlen2mask(&mask, prefixlen);
173653541Sshin
173778064Sume	/*
173878064Sume	 * find a link-local address (will be interface ID).
173978064Sume	 * Is it really mandatory? Theoretically, a global or a site-local
174078064Sume	 * address can be configured without a link-local address, if we
174178064Sume	 * have a unique interface identifier...
174278064Sume	 *
174378064Sume	 * it is not mandatory to have a link-local address, we can generate
174478064Sume	 * interface identifier on the fly.  we do this because:
174578064Sume	 * (1) it should be the easiest way to find interface identifier.
174678064Sume	 * (2) RFC2462 5.4 suggesting the use of the same interface identifier
174778064Sume	 * for multiple addresses on a single interface, and possible shortcut
174878064Sume	 * of DAD.  we omitted DAD for this reason in the past.
1749120941Sume	 * (3) a user can prevent autoconfiguration of global address
175078064Sume	 * by removing link-local address by hand (this is partly because we
1751108533Sschweikh	 * don't have other way to control the use of IPv6 on an interface.
175278064Sume	 * this has been our design choice - cf. NRL's "ifconfig auto").
175378064Sume	 * (4) it is easier to manage when an interface has addresses
175478064Sume	 * with the same interface identifier, than to have multiple addresses
175578064Sume	 * with different interface identifiers.
175678064Sume	 */
1757120941Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
175853541Sshin	if (ifa)
175953541Sshin		ib = (struct in6_ifaddr *)ifa;
176053541Sshin	else
176153541Sshin		return NULL;
176253541Sshin
176353541Sshin	/* prefixlen + ifidlen must be equal to 128 */
176478064Sume	plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
176578064Sume	if (prefixlen != plen0) {
176678064Sume		nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
176778064Sume		    "(prefix=%d ifid=%d)\n",
176878064Sume		    if_name(ifp), prefixlen, 128 - plen0));
176953541Sshin		return NULL;
177053541Sshin	}
177153541Sshin
177253541Sshin	/* make ifaddr */
177353541Sshin
177478064Sume	bzero(&ifra, sizeof(ifra));
177578064Sume	/*
177678064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
177778064Sume	 * for safety.
177878064Sume	 */
177978064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
178078064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
178178064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
178278064Sume	/* prefix */
1783151539Ssuz	ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr;
178478064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
178578064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
178678064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
178778064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
178853541Sshin
178953541Sshin	/* interface ID */
1790120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
1791151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
1792120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
1793151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
1794120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1795151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
1796120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1797151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
1798120941Sume
179978064Sume	/* new prefix mask. */
180078064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
180178064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
180278064Sume	bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
1803120941Sume	    sizeof(ifra.ifra_prefixmask.sin6_addr));
180453541Sshin
1805151539Ssuz	/* lifetimes. */
180678064Sume	ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
180778064Sume	ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
180853541Sshin
180978064Sume	/* XXX: scope zone ID? */
181053541Sshin
181178064Sume	ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
1812151539Ssuz
1813151539Ssuz  	/*
1814151539Ssuz	 * Make sure that we do not have this address already.  This should
1815151539Ssuz	 * usually not happen, but we can still see this case, e.g., if we
1816151539Ssuz	 * have manually configured the exact address to be configured.
181778064Sume	 */
1818151539Ssuz	if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
1819151539Ssuz		/* this should be rare enough to make an explicit log */
1820151539Ssuz		log(LOG_INFO, "in6_ifadd: %s is already configured\n",
1821165118Sbz		    ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr));
1822151539Ssuz		return (NULL);
1823151539Ssuz	}
182453541Sshin
182553541Sshin	/*
1826151539Ssuz	 * Allocate ifaddr structure, link into chain, etc.
1827151539Ssuz	 * If we are going to create a new address upon receiving a multicasted
1828151539Ssuz	 * RA, we need to impose a random delay before starting DAD.
1829151539Ssuz	 * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2]
183053541Sshin	 */
1831151539Ssuz	updateflags = 0;
1832151539Ssuz	if (mcast)
1833151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1834151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) {
183578064Sume		nd6log((LOG_ERR,
183678064Sume		    "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
1837165118Sbz		    ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr),
1838165118Sbz		    if_name(ifp), error));
1839120856Sume		return (NULL);	/* ifaddr must not have been allocated. */
184053541Sshin	}
184153541Sshin
184278064Sume	ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
184353541Sshin
1844120941Sume	return (ia);		/* this is always non-NULL */
184553541Sshin}
184653541Sshin
1847171259Sdelphij/*
1848171259Sdelphij * ia0 - corresponding public address
1849171259Sdelphij */
185053541Sshinint
1851171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay)
185253541Sshin{
185378064Sume	struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
1854151539Ssuz	struct in6_ifaddr *newia, *ia;
185578064Sume	struct in6_aliasreq ifra;
185678064Sume	int i, error;
185778064Sume	int trylimit = 3;	/* XXX: adhoc value */
1858151539Ssuz	int updateflags;
185978064Sume	u_int32_t randid[2];
186078064Sume	time_t vltime0, pltime0;
186153541Sshin
186278064Sume	bzero(&ifra, sizeof(ifra));
186378064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
186478064Sume	ifra.ifra_addr = ia0->ia_addr;
186578064Sume	/* copy prefix mask */
186678064Sume	ifra.ifra_prefixmask = ia0->ia_prefixmask;
186778064Sume	/* clear the old IFID */
186878064Sume	for (i = 0; i < 4; i++) {
1869120941Sume		ifra.ifra_addr.sin6_addr.s6_addr32[i] &=
1870120941Sume		    ifra.ifra_prefixmask.sin6_addr.s6_addr32[i];
187178064Sume	}
187253541Sshin
187378064Sume  again:
1874151539Ssuz	if (in6_get_tmpifid(ifp, (u_int8_t *)randid,
1875151539Ssuz	    (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) {
1876151539Ssuz		nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good "
1877151539Ssuz		    "random IFID\n"));
1878151539Ssuz		return (EINVAL);
1879151539Ssuz	}
1880120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1881120941Sume	    (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2]));
1882120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1883120941Sume	    (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3]));
188453541Sshin
1885151539Ssuz  	/*
1886151539Ssuz	 * in6_get_tmpifid() quite likely provided a unique interface ID.
1887151539Ssuz	 * However, we may still have a chance to see collision, because
1888151539Ssuz	 * there may be a time lag between generation of the ID and generation
1889151539Ssuz	 * of the address.  So, we'll do one more sanity check.
189078064Sume	 */
1891151539Ssuz	for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
1892151539Ssuz		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
1893151539Ssuz		    &ifra.ifra_addr.sin6_addr)) {
1894151539Ssuz  			if (trylimit-- == 0) {
1895151539Ssuz				/*
1896151539Ssuz				 * Give up.  Something strange should have
1897151539Ssuz				 * happened.
1898151539Ssuz				 */
1899151539Ssuz				nd6log((LOG_NOTICE, "in6_tmpifadd: failed to "
1900151539Ssuz				    "find a unique random IFID\n"));
1901151539Ssuz				return (EEXIST);
1902151539Ssuz			}
1903151539Ssuz			forcegen = 1;
1904151539Ssuz			goto again;
190578064Sume		}
190653541Sshin	}
190753541Sshin
190878064Sume	/*
190978064Sume	 * The Valid Lifetime is the lower of the Valid Lifetime of the
191078064Sume         * public address or TEMP_VALID_LIFETIME.
191178064Sume	 * The Preferred Lifetime is the lower of the Preferred Lifetime
191278064Sume         * of the public address or TEMP_PREFERRED_LIFETIME -
191378064Sume         * DESYNC_FACTOR.
191478064Sume	 */
1915151539Ssuz	if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
191678064Sume		vltime0 = IFA6_IS_INVALID(ia0) ? 0 :
1917151539Ssuz		    (ia0->ia6_lifetime.ia6t_vltime -
1918151539Ssuz		    (time_second - ia0->ia6_updatetime));
191978064Sume		if (vltime0 > ip6_temp_valid_lifetime)
192078064Sume			vltime0 = ip6_temp_valid_lifetime;
192178064Sume	} else
192278064Sume		vltime0 = ip6_temp_valid_lifetime;
1923151539Ssuz	if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
192478064Sume		pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 :
1925151539Ssuz		    (ia0->ia6_lifetime.ia6t_pltime -
1926151539Ssuz		    (time_second - ia0->ia6_updatetime));
192778064Sume		if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){
192878064Sume			pltime0 = ip6_temp_preferred_lifetime -
1929120941Sume			    ip6_desync_factor;
193078064Sume		}
193178064Sume	} else
193278064Sume		pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor;
193378064Sume	ifra.ifra_lifetime.ia6t_vltime = vltime0;
193478064Sume	ifra.ifra_lifetime.ia6t_pltime = pltime0;
193553541Sshin
193678064Sume	/*
193778064Sume	 * A temporary address is created only if this calculated Preferred
193878064Sume	 * Lifetime is greater than REGEN_ADVANCE time units.
193978064Sume	 */
194078064Sume	if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance)
1941120856Sume		return (0);
194253541Sshin
194378064Sume	/* XXX: scope zone ID? */
194478064Sume
194578064Sume	ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
194678064Sume
194778064Sume	/* allocate ifaddr structure, link into chain, etc. */
1948151539Ssuz	updateflags = 0;
1949151539Ssuz	if (delay)
1950151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1951151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0)
1952120856Sume		return (error);
195378064Sume
195478064Sume	newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
195578064Sume	if (newia == NULL) {	/* XXX: can it happen? */
195678064Sume		nd6log((LOG_ERR,
195778064Sume		    "in6_tmpifadd: ifa update succeeded, but we got "
195878064Sume		    "no ifaddr\n"));
1959120856Sume		return (EINVAL); /* XXX */
196053541Sshin	}
196178064Sume	newia->ia6_ndpr = ia0->ia6_ndpr;
196278064Sume	newia->ia6_ndpr->ndpr_refcnt++;
196353541Sshin
196478407Sume	/*
196578407Sume	 * A newly added address might affect the status of other addresses.
196678407Sume	 * XXX: when the temporary address is generated with a new public
196778407Sume	 * address, the onlink check is redundant.  However, it would be safe
196878407Sume	 * to do the check explicitly everywhere a new address is generated,
196978407Sume	 * and, in fact, we surely need the check when we create a new
197078407Sume	 * temporary address due to deprecation of an old temporary address.
197178407Sume	 */
197278407Sume	pfxlist_onlink_check();
197378407Sume
1974120856Sume	return (0);
1975120941Sume}
197653541Sshin
1977151539Ssuzstatic int
197853541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr)
197953541Sshin{
198053541Sshin	if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
198153541Sshin		ndpr->ndpr_preferred = 0;
198253541Sshin	else
198353541Sshin		ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
198453541Sshin	if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
198553541Sshin		ndpr->ndpr_expire = 0;
198653541Sshin	else
198753541Sshin		ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
198853541Sshin
198953541Sshin	return 0;
199053541Sshin}
199153541Sshin
199253541Sshinstatic void
199378064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
199453541Sshin{
199578064Sume	/* init ia6t_expire */
199678064Sume	if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
199778064Sume		lt6->ia6t_expire = 0;
199878064Sume	else {
199978064Sume		lt6->ia6t_expire = time_second;
200078064Sume		lt6->ia6t_expire += lt6->ia6t_vltime;
200153541Sshin	}
200262587Sitojun
200353541Sshin	/* init ia6t_preferred */
200453541Sshin	if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
200553541Sshin		lt6->ia6t_preferred = 0;
200653541Sshin	else {
200753541Sshin		lt6->ia6t_preferred = time_second;
200853541Sshin		lt6->ia6t_preferred += lt6->ia6t_pltime;
200953541Sshin	}
201053541Sshin}
201153541Sshin
201253541Sshin/*
201353541Sshin * Delete all the routing table entries that use the specified gateway.
201453541Sshin * XXX: this function causes search through all entries of routing table, so
201553541Sshin * it shouldn't be called when acting as a router.
201653541Sshin */
201753541Sshinvoid
2018171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
201953541Sshin{
202053541Sshin	struct radix_node_head *rnh = rt_tables[AF_INET6];
202153541Sshin	int s = splnet();
202253541Sshin
202353541Sshin	/* We'll care only link-local addresses */
202453541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
202553541Sshin		splx(s);
202653541Sshin		return;
202753541Sshin	}
202853541Sshin
2029108250Shsu	RADIX_NODE_HEAD_LOCK(rnh);
203053541Sshin	rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
2031108250Shsu	RADIX_NODE_HEAD_UNLOCK(rnh);
203253541Sshin	splx(s);
203353541Sshin}
203453541Sshin
203553541Sshinstatic int
2036171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg)
203753541Sshin{
203853541Sshin#define SIN6(s)	((struct sockaddr_in6 *)s)
203953541Sshin	struct rtentry *rt = (struct rtentry *)rn;
204053541Sshin	struct in6_addr *gate = (struct in6_addr *)arg;
204153541Sshin
204253541Sshin	if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
2043120856Sume		return (0);
204453541Sshin
2045120941Sume	if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) {
2046120856Sume		return (0);
2047120941Sume	}
204853541Sshin
204953541Sshin	/*
205078064Sume	 * Do not delete a static route.
205178064Sume	 * XXX: this seems to be a bit ad-hoc. Should we consider the
205278064Sume	 * 'cloned' bit instead?
205378064Sume	 */
205478064Sume	if ((rt->rt_flags & RTF_STATIC) != 0)
2055120856Sume		return (0);
205678064Sume
205778064Sume	/*
205853541Sshin	 * We delete only host route. This means, in particular, we don't
205953541Sshin	 * delete default route.
206053541Sshin	 */
206153541Sshin	if ((rt->rt_flags & RTF_HOST) == 0)
2062120856Sume		return (0);
206353541Sshin
2064120941Sume	return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
2065120941Sume	    rt_mask(rt), rt->rt_flags, 0));
206653541Sshin#undef SIN6
206753541Sshin}
206862587Sitojun
206962587Sitojunint
2070171259Sdelphijnd6_setdefaultiface(int ifindex)
207162587Sitojun{
207262587Sitojun	int error = 0;
207362587Sitojun
207462587Sitojun	if (ifindex < 0 || if_index < ifindex)
2075120856Sume		return (EINVAL);
2076151539Ssuz	if (ifindex != 0 && !ifnet_byindex(ifindex))
2077151539Ssuz		return (EINVAL);
207862587Sitojun
207962587Sitojun	if (nd6_defifindex != ifindex) {
208062587Sitojun		nd6_defifindex = ifindex;
208162587Sitojun		if (nd6_defifindex > 0)
208283130Sjlemon			nd6_defifp = ifnet_byindex(nd6_defifindex);
208362587Sitojun		else
208462587Sitojun			nd6_defifp = NULL;
208562587Sitojun
208662587Sitojun		/*
208762587Sitojun		 * Our current implementation assumes one-to-one maping between
208862587Sitojun		 * interfaces and links, so it would be natural to use the
208962587Sitojun		 * default interface as the default link.
209062587Sitojun		 */
209162587Sitojun		scope6_setdefault(nd6_defifp);
209262587Sitojun	}
209362587Sitojun
2094120856Sume	return (error);
209562587Sitojun}
2096