nd6_rtr.c revision 181803
1139826Simp/*-
253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
353541Sshin * All rights reserved.
453541Sshin *
553541Sshin * Redistribution and use in source and binary forms, with or without
653541Sshin * modification, are permitted provided that the following conditions
753541Sshin * are met:
853541Sshin * 1. Redistributions of source code must retain the above copyright
953541Sshin *    notice, this list of conditions and the following disclaimer.
1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright
1153541Sshin *    notice, this list of conditions and the following disclaimer in the
1253541Sshin *    documentation and/or other materials provided with the distribution.
1353541Sshin * 3. Neither the name of the project nor the names of its contributors
1453541Sshin *    may be used to endorse or promote products derived from this software
1553541Sshin *    without specific prior written permission.
1653541Sshin *
1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2053541Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2753541Sshin * SUCH DAMAGE.
28174510Sobrien *
29174510Sobrien *	$KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $
3053541Sshin */
3153541Sshin
32174510Sobrien#include <sys/cdefs.h>
33174510Sobrien__FBSDID("$FreeBSD: head/sys/netinet6/nd6_rtr.c 181803 2008-08-17 23:27:27Z bz $");
34174510Sobrien
3562587Sitojun#include "opt_inet.h"
3662587Sitojun#include "opt_inet6.h"
3762587Sitojun
3853541Sshin#include <sys/param.h>
3953541Sshin#include <sys/systm.h>
4053541Sshin#include <sys/malloc.h>
4153541Sshin#include <sys/mbuf.h>
4253541Sshin#include <sys/socket.h>
4353541Sshin#include <sys/sockio.h>
4453541Sshin#include <sys/time.h>
4578064Sume#include <sys/kernel.h>
4653541Sshin#include <sys/errno.h>
4753541Sshin#include <sys/syslog.h>
4878064Sume#include <sys/queue.h>
49181803Sbz#include <sys/vimage.h>
5053541Sshin
5153541Sshin#include <net/if.h>
5253541Sshin#include <net/if_types.h>
5353541Sshin#include <net/if_dl.h>
5453541Sshin#include <net/route.h>
5553541Sshin#include <net/radix.h>
5653541Sshin
5753541Sshin#include <netinet/in.h>
5853541Sshin#include <netinet6/in6_var.h>
5978064Sume#include <netinet6/in6_ifattach.h>
6062587Sitojun#include <netinet/ip6.h>
6153541Sshin#include <netinet6/ip6_var.h>
6253541Sshin#include <netinet6/nd6.h>
6362587Sitojun#include <netinet/icmp6.h>
6462587Sitojun#include <netinet6/scope6_var.h>
6553541Sshin
6662587Sitojun#define SDL(s)	((struct sockaddr_dl *)s)
6753541Sshin
68175162Sobrienstatic int rtpref(struct nd_defrouter *);
69175162Sobrienstatic struct nd_defrouter *defrtrlist_update(struct nd_defrouter *);
70151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *,
71151539Ssuz    struct mbuf *, int));
72175162Sobrienstatic struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *,	int);
7362587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
7478064Sume	struct nd_defrouter *));
75175162Sobrienstatic void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *);
76175162Sobrienstatic void pfxrtr_del(struct nd_pfxrouter *);
7762587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router
78175162Sobrien(struct nd_prefix *);
79175162Sobrienstatic void defrouter_delreq(struct nd_defrouter *);
80175162Sobrienstatic void nd6_rtmsg(int, struct rtentry *);
8153541Sshin
82175162Sobrienstatic int in6_init_prefix_ltimes(struct nd_prefix *);
83120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *,
84120941Sume	struct in6_addrlifetime *));
8553541Sshin
86175162Sobrienstatic int rt6_deleteroute(struct radix_node *, void *);
8753541Sshin
8862587Sitojunextern int nd6_recalc_reachtm_interval;
8953541Sshin
9078064Sumestatic struct ifnet *nd6_defifp;
9162587Sitojunint nd6_defifindex;
9262587Sitojun
9378064Sumeint ip6_use_tempaddr = 0;
9478064Sume
9578064Sumeint ip6_desync_factor;
9678064Sumeu_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME;
9778064Sumeu_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME;
9853541Sshin/*
9978064Sume * shorter lifetimes for debugging purposes.
10078064Sumeint ip6_temp_preferred_lifetime = 800;
10178064Sumestatic int ip6_temp_valid_lifetime = 1800;
10278064Sume*/
10378064Sumeint ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE;
10478064Sume
105151539Ssuz/* RTPREF_MEDIUM has to be 0! */
106151539Ssuz#define RTPREF_HIGH	1
107151539Ssuz#define RTPREF_MEDIUM	0
108151539Ssuz#define RTPREF_LOW	(-1)
109151539Ssuz#define RTPREF_RESERVED	(-2)
110151539Ssuz#define RTPREF_INVALID	(-3)	/* internal */
111151539Ssuz
11278064Sume/*
11353541Sshin * Receive Router Solicitation Message - just for routers.
11453541Sshin * Router solicitation/advertisement is mostly managed by userland program
11553541Sshin * (rtadvd) so here we have no function like nd6_ra_output().
11653541Sshin *
11753541Sshin * Based on RFC 2461
11853541Sshin */
11953541Sshinvoid
120171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len)
12153541Sshin{
12253541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
12353541Sshin	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
12462587Sitojun	struct nd_router_solicit *nd_rs;
12553541Sshin	struct in6_addr saddr6 = ip6->ip6_src;
12653541Sshin	char *lladdr = NULL;
12753541Sshin	int lladdrlen = 0;
12853541Sshin	union nd_opts ndopts;
129165118Sbz	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
13053541Sshin
13153541Sshin	/* If I'm not a router, ignore it. */
132181803Sbz	if (V_ip6_accept_rtadv != 0 || V_ip6_forwarding != 1)
13362587Sitojun		goto freeit;
13453541Sshin
13553541Sshin	/* Sanity checks */
13653541Sshin	if (ip6->ip6_hlim != 255) {
13778064Sume		nd6log((LOG_ERR,
13878064Sume		    "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
139165118Sbz		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
140165118Sbz		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
14178064Sume		goto bad;
14253541Sshin	}
14353541Sshin
14453541Sshin	/*
14553541Sshin	 * Don't update the neighbor cache, if src = ::.
14653541Sshin	 * This indicates that the src has no IP address assigned yet.
14753541Sshin	 */
14853541Sshin	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
14962587Sitojun		goto freeit;
15062587Sitojun
15162587Sitojun#ifndef PULLDOWN_TEST
15262587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
15362587Sitojun	nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);
15462587Sitojun#else
15562587Sitojun	IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
15662587Sitojun	if (nd_rs == NULL) {
157181803Sbz		V_icmp6stat.icp6s_tooshort++;
15853541Sshin		return;
15962587Sitojun	}
16062587Sitojun#endif
16153541Sshin
16253541Sshin	icmp6len -= sizeof(*nd_rs);
16353541Sshin	nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
16453541Sshin	if (nd6_options(&ndopts) < 0) {
16578064Sume		nd6log((LOG_INFO,
16678064Sume		    "nd6_rs_input: invalid ND option, ignored\n"));
16778064Sume		/* nd6_options have incremented stats */
16862587Sitojun		goto freeit;
16953541Sshin	}
17053541Sshin
17153541Sshin	if (ndopts.nd_opts_src_lladdr) {
17253541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
17353541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
17453541Sshin	}
17553541Sshin
17653541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
17778064Sume		nd6log((LOG_INFO,
17853541Sshin		    "nd6_rs_input: lladdrlen mismatch for %s "
17953541Sshin		    "(if %d, RS packet %d)\n",
180165118Sbz		    ip6_sprintf(ip6bufs, &saddr6),
181120941Sume		    ifp->if_addrlen, lladdrlen - 2));
18278064Sume		goto bad;
18353541Sshin	}
18453541Sshin
18553541Sshin	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
18662587Sitojun
18762587Sitojun freeit:
18862587Sitojun	m_freem(m);
18978064Sume	return;
19078064Sume
19178064Sume bad:
192181803Sbz	V_icmp6stat.icp6s_badrs++;
19378064Sume	m_freem(m);
19453541Sshin}
19553541Sshin
19653541Sshin/*
19753541Sshin * Receive Router Advertisement Message.
19853541Sshin *
19953541Sshin * Based on RFC 2461
20053541Sshin * TODO: on-link bit on prefix information
20153541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
20253541Sshin */
20353541Sshinvoid
204171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len)
20553541Sshin{
20653541Sshin	struct ifnet *ifp = m->m_pkthdr.rcvif;
207121161Sume	struct nd_ifinfo *ndi = ND_IFINFO(ifp);
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;
211151539Ssuz	int mcast = 0;
21253541Sshin	union nd_opts ndopts;
21353541Sshin	struct nd_defrouter *dr;
214165118Sbz	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
21553541Sshin
216118498Sume	/*
217118498Sume	 * We only accept RAs only when
218118498Sume	 * the system-wide variable allows the acceptance, and
219118498Sume	 * per-interface variable allows RAs on the receiving interface.
220118498Sume	 */
221181803Sbz	if (V_ip6_accept_rtadv == 0)
22262587Sitojun		goto freeit;
223118498Sume	if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
224118498Sume		goto freeit;
22553541Sshin
22653541Sshin	if (ip6->ip6_hlim != 255) {
22778064Sume		nd6log((LOG_ERR,
22878064Sume		    "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
229165118Sbz		    ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src),
230165118Sbz		    ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp)));
23178064Sume		goto bad;
23253541Sshin	}
23353541Sshin
23453541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
23578064Sume		nd6log((LOG_ERR,
23653541Sshin		    "nd6_ra_input: src %s is not link-local\n",
237165118Sbz		    ip6_sprintf(ip6bufs, &saddr6)));
23878064Sume		goto bad;
23962587Sitojun	}
24062587Sitojun
24162587Sitojun#ifndef PULLDOWN_TEST
24262587Sitojun	IP6_EXTHDR_CHECK(m, off, icmp6len,);
24362587Sitojun	nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);
24462587Sitojun#else
24562587Sitojun	IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
24662587Sitojun	if (nd_ra == NULL) {
247181803Sbz		V_icmp6stat.icp6s_tooshort++;
24853541Sshin		return;
24953541Sshin	}
25062587Sitojun#endif
25153541Sshin
25253541Sshin	icmp6len -= sizeof(*nd_ra);
25353541Sshin	nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
25453541Sshin	if (nd6_options(&ndopts) < 0) {
25578064Sume		nd6log((LOG_INFO,
25678064Sume		    "nd6_ra_input: invalid ND option, ignored\n"));
25778064Sume		/* nd6_options have incremented stats */
25862587Sitojun		goto freeit;
25953541Sshin	}
26053541Sshin
26153541Sshin    {
26253541Sshin	struct nd_defrouter dr0;
26353541Sshin	u_int32_t advreachable = nd_ra->nd_ra_reachable;
26453541Sshin
265151539Ssuz	/* remember if this is a multicasted advertisement */
266151539Ssuz	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
267151539Ssuz		mcast = 1;
268151539Ssuz
269151539Ssuz	bzero(&dr0, sizeof(dr0));
27053541Sshin	dr0.rtaddr = saddr6;
27153541Sshin	dr0.flags  = nd_ra->nd_ra_flags_reserved;
272156871Ssuz	dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
27353541Sshin	dr0.expire = time_second + dr0.rtlifetime;
27453541Sshin	dr0.ifp = ifp;
27553541Sshin	/* unspecified or not? (RFC 2461 6.3.4) */
27653541Sshin	if (advreachable) {
27790868Smike		advreachable = ntohl(advreachable);
27853541Sshin		if (advreachable <= MAX_REACHABLE_TIME &&
27953541Sshin		    ndi->basereachable != advreachable) {
28053541Sshin			ndi->basereachable = advreachable;
28153541Sshin			ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
282181803Sbz			ndi->recalctm = V_nd6_recalc_reachtm_interval; /* reset */
28353541Sshin		}
28453541Sshin	}
28553541Sshin	if (nd_ra->nd_ra_retransmit)
28653541Sshin		ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
28753541Sshin	if (nd_ra->nd_ra_curhoplimit)
28853541Sshin		ndi->chlim = nd_ra->nd_ra_curhoplimit;
28953541Sshin	dr = defrtrlist_update(&dr0);
29053541Sshin    }
29153541Sshin
29253541Sshin	/*
29353541Sshin	 * prefix
29453541Sshin	 */
29553541Sshin	if (ndopts.nd_opts_pi) {
29653541Sshin		struct nd_opt_hdr *pt;
29778064Sume		struct nd_opt_prefix_info *pi = NULL;
298151539Ssuz		struct nd_prefixctl pr;
29953541Sshin
30053541Sshin		for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
30153541Sshin		     pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
30253541Sshin		     pt = (struct nd_opt_hdr *)((caddr_t)pt +
30353541Sshin						(pt->nd_opt_len << 3))) {
30453541Sshin			if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
30553541Sshin				continue;
30653541Sshin			pi = (struct nd_opt_prefix_info *)pt;
30753541Sshin
30853541Sshin			if (pi->nd_opt_pi_len != 4) {
30978064Sume				nd6log((LOG_INFO,
31078064Sume				    "nd6_ra_input: invalid option "
31178064Sume				    "len %d for prefix information option, "
31278064Sume				    "ignored\n", pi->nd_opt_pi_len));
31353541Sshin				continue;
31453541Sshin			}
31553541Sshin
31653541Sshin			if (128 < pi->nd_opt_pi_prefix_len) {
31778064Sume				nd6log((LOG_INFO,
31878064Sume				    "nd6_ra_input: invalid prefix "
31978064Sume				    "len %d for prefix information option, "
32078064Sume				    "ignored\n", pi->nd_opt_pi_prefix_len));
32153541Sshin				continue;
32253541Sshin			}
32353541Sshin
32453541Sshin			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
32553541Sshin			 || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
32678064Sume				nd6log((LOG_INFO,
32778064Sume				    "nd6_ra_input: invalid prefix "
32878064Sume				    "%s, ignored\n",
329165118Sbz				    ip6_sprintf(ip6bufs,
330165118Sbz					&pi->nd_opt_pi_prefix)));
33153541Sshin				continue;
33253541Sshin			}
33353541Sshin
33453541Sshin			bzero(&pr, sizeof(pr));
33553541Sshin			pr.ndpr_prefix.sin6_family = AF_INET6;
33653541Sshin			pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
33753541Sshin			pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
33853541Sshin			pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
33953541Sshin
34053541Sshin			pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
341120941Sume			    ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
34253541Sshin			pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
343120941Sume			    ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
34453541Sshin			pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
34553541Sshin			pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
346120941Sume			pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time);
347151539Ssuz			(void)prelist_update(&pr, dr, m, mcast);
34853541Sshin		}
34953541Sshin	}
35053541Sshin
35153541Sshin	/*
35253541Sshin	 * MTU
35353541Sshin	 */
35453541Sshin	if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
355121283Sume		u_long mtu;
356121283Sume		u_long maxmtu;
35753541Sshin
358121283Sume		mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
359120941Sume
36053541Sshin		/* lower bound */
36153541Sshin		if (mtu < IPV6_MMTU) {
36278064Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option "
363121283Sume			    "mtu=%lu sent from %s, ignoring\n",
364165118Sbz			    mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src)));
36553541Sshin			goto skip;
36653541Sshin		}
36753541Sshin
36853541Sshin		/* upper bound */
369121283Sume		maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu)
370121283Sume		    ? ndi->maxmtu : ifp->if_mtu;
371121283Sume		if (mtu <= maxmtu) {
372121283Sume			int change = (ndi->linkmtu != mtu);
37353541Sshin
374121283Sume			ndi->linkmtu = mtu;
375121283Sume			if (change) /* in6_maxmtu may change */
376121283Sume				in6_setmaxmtu();
37753541Sshin		} else {
378121283Sume			nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
379121283Sume			    "mtu=%lu sent from %s; "
380121283Sume			    "exceeds maxmtu %lu, ignoring\n",
381165118Sbz			    mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu));
38253541Sshin		}
38353541Sshin	}
38453541Sshin
38553541Sshin skip:
386120941Sume
38753541Sshin	/*
38895023Ssuz	 * Source link layer address
38953541Sshin	 */
39053541Sshin    {
39153541Sshin	char *lladdr = NULL;
39253541Sshin	int lladdrlen = 0;
393120941Sume
39453541Sshin	if (ndopts.nd_opts_src_lladdr) {
39553541Sshin		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
39653541Sshin		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
39753541Sshin	}
39853541Sshin
39953541Sshin	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
40078064Sume		nd6log((LOG_INFO,
40153541Sshin		    "nd6_ra_input: lladdrlen mismatch for %s "
402165118Sbz		    "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6),
403120941Sume		    ifp->if_addrlen, lladdrlen - 2));
40478064Sume		goto bad;
40553541Sshin	}
40653541Sshin
407120941Sume	nd6_cache_lladdr(ifp, &saddr6, lladdr,
408120941Sume	    lladdrlen, ND_ROUTER_ADVERT, 0);
40962587Sitojun
41062587Sitojun	/*
41162587Sitojun	 * Installing a link-layer address might change the state of the
41262587Sitojun	 * router's neighbor cache, which might also affect our on-link
41362587Sitojun	 * detection of adveritsed prefixes.
41462587Sitojun	 */
41562587Sitojun	pfxlist_onlink_check();
41653541Sshin    }
41762587Sitojun
41878064Sume freeit:
41962587Sitojun	m_freem(m);
42078064Sume	return;
42178064Sume
42278064Sume bad:
423181803Sbz	V_icmp6stat.icp6s_badra++;
42478064Sume	m_freem(m);
42553541Sshin}
42653541Sshin
42753541Sshin/*
42853541Sshin * default router list proccessing sub routines
42953541Sshin */
43062587Sitojun
43162587Sitojun/* tell the change to user processes watching the routing socket. */
43262587Sitojunstatic void
433171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt)
43462587Sitojun{
43562587Sitojun	struct rt_addrinfo info;
43662587Sitojun
43762587Sitojun	bzero((caddr_t)&info, sizeof(info));
43862587Sitojun	info.rti_info[RTAX_DST] = rt_key(rt);
43962587Sitojun	info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
44062587Sitojun	info.rti_info[RTAX_NETMASK] = rt_mask(rt);
441151539Ssuz	if (rt->rt_ifp) {
442151539Ssuz		info.rti_info[RTAX_IFP] =
443151539Ssuz		    TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
444151539Ssuz		info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
445151539Ssuz	}
44662587Sitojun
44762587Sitojun	rt_missmsg(cmd, &info, rt->rt_flags, 0);
44862587Sitojun}
44962587Sitojun
45053541Sshinvoid
451171259Sdelphijdefrouter_addreq(struct nd_defrouter *new)
45253541Sshin{
45353541Sshin	struct sockaddr_in6 def, mask, gate;
45462587Sitojun	struct rtentry *newrt = NULL;
455151539Ssuz	int s;
456151539Ssuz	int error;
45753541Sshin
458128397Sluigi	bzero(&def, sizeof(def));
459128397Sluigi	bzero(&mask, sizeof(mask));
460128397Sluigi	bzero(&gate, sizeof(gate));
46153541Sshin
462120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
463120941Sume	    sizeof(struct sockaddr_in6);
464151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
46553541Sshin	gate.sin6_addr = new->rtaddr;
46653541Sshin
467151539Ssuz	s = splnet();
468151539Ssuz	error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
469120941Sume	    (struct sockaddr *)&gate, (struct sockaddr *)&mask,
470120941Sume	    RTF_GATEWAY, &newrt);
47162587Sitojun	if (newrt) {
472120727Ssam		RT_LOCK(newrt);
47378064Sume		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
474122334Ssam		RT_REMREF(newrt);
475120727Ssam		RT_UNLOCK(newrt);
47662587Sitojun	}
477151539Ssuz	if (error == 0)
478151539Ssuz		new->installed = 1;
479151539Ssuz	splx(s);
48053541Sshin	return;
48153541Sshin}
48253541Sshin
48353541Sshinstruct nd_defrouter *
484171259Sdelphijdefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp)
48553541Sshin{
48653541Sshin	struct nd_defrouter *dr;
48753541Sshin
488181803Sbz	for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
48962587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
49053541Sshin		if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
491120856Sume			return (dr);
49262587Sitojun	}
49353541Sshin
494120856Sume	return (NULL);		/* search failed */
49553541Sshin}
49653541Sshin
497151539Ssuz/*
498151539Ssuz * Remove the default route for a given router.
499151539Ssuz * This is just a subroutine function for defrouter_select(), and should
500151539Ssuz * not be called from anywhere else.
501151539Ssuz */
502151539Ssuzstatic void
503171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr)
50453541Sshin{
50553541Sshin	struct sockaddr_in6 def, mask, gate;
50662587Sitojun	struct rtentry *oldrt = NULL;
50753541Sshin
508128397Sluigi	bzero(&def, sizeof(def));
509128397Sluigi	bzero(&mask, sizeof(mask));
510128397Sluigi	bzero(&gate, sizeof(gate));
51153541Sshin
512120941Sume	def.sin6_len = mask.sin6_len = gate.sin6_len =
513120941Sume	    sizeof(struct sockaddr_in6);
514151539Ssuz	def.sin6_family = gate.sin6_family = AF_INET6;
51553541Sshin	gate.sin6_addr = dr->rtaddr;
51653541Sshin
51753541Sshin	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
518120941Sume	    (struct sockaddr *)&gate,
519120941Sume	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
52062587Sitojun	if (oldrt) {
52178064Sume		nd6_rtmsg(RTM_DELETE, oldrt);
522108269Sru		RTFREE(oldrt);
52362587Sitojun	}
52453541Sshin
525151539Ssuz	dr->installed = 0;
52653541Sshin}
52753541Sshin
528151539Ssuz/*
529151539Ssuz * remove all default routes from default router list
530151539Ssuz */
53153541Sshinvoid
532171259Sdelphijdefrouter_reset(void)
533151539Ssuz{
534151539Ssuz	struct nd_defrouter *dr;
535151539Ssuz
536181803Sbz	for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
537151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry))
538151539Ssuz		defrouter_delreq(dr);
539151539Ssuz
540151539Ssuz	/*
541151539Ssuz	 * XXX should we also nuke any default routers in the kernel, by
542151539Ssuz	 * going through them by rtalloc1()?
543151539Ssuz	 */
544151539Ssuz}
545151539Ssuz
546151539Ssuzvoid
547171259Sdelphijdefrtrlist_del(struct nd_defrouter *dr)
54853541Sshin{
54953541Sshin	struct nd_defrouter *deldr = NULL;
55053541Sshin	struct nd_prefix *pr;
55153541Sshin
55253541Sshin	/*
55353541Sshin	 * Flush all the routing table entries that use the router
55453541Sshin	 * as a next hop.
55553541Sshin	 */
556181803Sbz	if (!V_ip6_forwarding && V_ip6_accept_rtadv) /* XXX: better condition? */
55753541Sshin		rt6_flush(&dr->rtaddr, dr->ifp);
55853541Sshin
559151539Ssuz	if (dr->installed) {
560151539Ssuz		deldr = dr;
561151539Ssuz		defrouter_delreq(dr);
562151539Ssuz	}
563181803Sbz	TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry);
56453541Sshin
56553541Sshin	/*
56653541Sshin	 * Also delete all the pointers to the router in each prefix lists.
56753541Sshin	 */
568181803Sbz	for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
56953541Sshin		struct nd_pfxrouter *pfxrtr;
57053541Sshin		if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
57153541Sshin			pfxrtr_del(pfxrtr);
57253541Sshin	}
57353541Sshin	pfxlist_onlink_check();
57453541Sshin
57553541Sshin	/*
57662587Sitojun	 * If the router is the primary one, choose a new one.
57762587Sitojun	 * Note that defrouter_select() will remove the current gateway
57862587Sitojun	 * from the routing table.
57953541Sshin	 */
58053541Sshin	if (deldr)
58162587Sitojun		defrouter_select();
58262587Sitojun
58353541Sshin	free(dr, M_IP6NDP);
58453541Sshin}
58553541Sshin
58662587Sitojun/*
587151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and
588151539Ssuz * draft-ietf-ipngwg-router-selection:
589151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred.
590151539Ssuz *    If we have more than one (probably) reachable router, prefer ones
591151539Ssuz *    with the highest router preference.
59262587Sitojun * 2) When no routers on the list are known to be reachable or
59362587Sitojun *    probably reachable, routers SHOULD be selected in a round-robin
594151539Ssuz *    fashion, regardless of router preference values.
59562587Sitojun * 3) If the Default Router List is empty, assume that all
59662587Sitojun *    destinations are on-link.
597151539Ssuz *
598151539Ssuz * We assume nd_defrouter is sorted by router preference value.
599151539Ssuz * Since the code below covers both with and without router preference cases,
600151539Ssuz * we do not need to classify the cases by ifdef.
601151539Ssuz *
602151539Ssuz * At this moment, we do not try to install more than one default router,
603151539Ssuz * even when the multipath routing is available, because we're not sure about
604151539Ssuz * the benefits for stub hosts comparing to the risk of making the code
605151539Ssuz * complicated and the possibility of introducing bugs.
60662587Sitojun */
60762587Sitojunvoid
608171259Sdelphijdefrouter_select(void)
60962587Sitojun{
61062587Sitojun	int s = splnet();
611151539Ssuz	struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
61262587Sitojun	struct rtentry *rt = NULL;
61362587Sitojun	struct llinfo_nd6 *ln = NULL;
61462587Sitojun
61562587Sitojun	/*
616151539Ssuz	 * This function should be called only when acting as an autoconfigured
617151539Ssuz	 * host.  Although the remaining part of this function is not effective
618151539Ssuz	 * if the node is not an autoconfigured host, we explicitly exclude
619151539Ssuz	 * such cases here for safety.
620151539Ssuz	 */
621181803Sbz	if (V_ip6_forwarding || !V_ip6_accept_rtadv) {
622151539Ssuz		nd6log((LOG_WARNING,
623151539Ssuz		    "defrouter_select: called unexpectedly (forwarding=%d, "
624181803Sbz		    "accept_rtadv=%d)\n", V_ip6_forwarding, V_ip6_accept_rtadv));
625151539Ssuz		splx(s);
626151539Ssuz		return;
627151539Ssuz	}
628151539Ssuz
629151539Ssuz	/*
630151539Ssuz	 * Let's handle easy case (3) first:
631151539Ssuz	 * If default router list is empty, there's nothing to be done.
632151539Ssuz	 */
633181803Sbz	if (!TAILQ_FIRST(&V_nd_defrouter)) {
634151539Ssuz		splx(s);
635151539Ssuz		return;
636151539Ssuz	}
637151539Ssuz
638151539Ssuz	/*
63962587Sitojun	 * Search for a (probably) reachable router from the list.
640151539Ssuz	 * We just pick up the first reachable one (if any), assuming that
641151539Ssuz	 * the ordering rule of the list described in defrtrlist_update().
64262587Sitojun	 */
643181803Sbz	for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
64462587Sitojun	     dr = TAILQ_NEXT(dr, dr_entry)) {
645151539Ssuz		if (selected_dr == NULL &&
646151539Ssuz		    (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
64762587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
64862587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln)) {
649151539Ssuz			selected_dr = dr;
65062587Sitojun		}
65162587Sitojun
652151539Ssuz		if (dr->installed && installed_dr == NULL)
653151539Ssuz			installed_dr = dr;
654151539Ssuz		else if (dr->installed && installed_dr) {
655151539Ssuz			/* this should not happen.  warn for diagnosis. */
656151539Ssuz			log(LOG_ERR, "defrouter_select: more than one router"
657151539Ssuz			    " is installed\n");
65862587Sitojun		}
65962587Sitojun	}
660151539Ssuz	/*
661151539Ssuz	 * If none of the default routers was found to be reachable,
662151539Ssuz	 * round-robin the list regardless of preference.
663151539Ssuz	 * Otherwise, if we have an installed router, check if the selected
664151539Ssuz	 * (reachable) router should really be preferred to the installed one.
665151539Ssuz	 * We only prefer the new router when the old one is not reachable
666151539Ssuz	 * or when the new one has a really higher preference value.
667151539Ssuz	 */
668151539Ssuz	if (selected_dr == NULL) {
669151539Ssuz		if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry))
670181803Sbz			selected_dr = TAILQ_FIRST(&V_nd_defrouter);
671151539Ssuz		else
672151539Ssuz			selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
673151539Ssuz	} else if (installed_dr &&
674151539Ssuz	    (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) &&
675151539Ssuz	    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
676151539Ssuz	    ND6_IS_LLINFO_PROBREACH(ln) &&
677151539Ssuz	    rtpref(selected_dr) <= rtpref(installed_dr)) {
678151539Ssuz		selected_dr = installed_dr;
679151539Ssuz	}
68062587Sitojun
681151539Ssuz	/*
682151539Ssuz	 * If the selected router is different than the installed one,
683151539Ssuz	 * remove the installed router and install the selected one.
684151539Ssuz	 * Note that the selected router is never NULL here.
685151539Ssuz	 */
686151539Ssuz	if (installed_dr != selected_dr) {
687151539Ssuz		if (installed_dr)
688151539Ssuz			defrouter_delreq(installed_dr);
689151539Ssuz		defrouter_addreq(selected_dr);
690151539Ssuz	}
691151539Ssuz
69262587Sitojun	splx(s);
69362587Sitojun	return;
69462587Sitojun}
69562587Sitojun
696151539Ssuz/*
697151539Ssuz * for default router selection
698151539Ssuz * regards router-preference field as a 2-bit signed integer
699151539Ssuz */
700151539Ssuzstatic int
701151539Ssuzrtpref(struct nd_defrouter *dr)
702151539Ssuz{
703151539Ssuz	switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) {
704151539Ssuz	case ND_RA_FLAG_RTPREF_HIGH:
705151539Ssuz		return (RTPREF_HIGH);
706151539Ssuz	case ND_RA_FLAG_RTPREF_MEDIUM:
707156871Ssuz	case ND_RA_FLAG_RTPREF_RSV:
708151539Ssuz		return (RTPREF_MEDIUM);
709151539Ssuz	case ND_RA_FLAG_RTPREF_LOW:
710151539Ssuz		return (RTPREF_LOW);
711151539Ssuz	default:
712151539Ssuz		/*
713151539Ssuz		 * This case should never happen.  If it did, it would mean a
714151539Ssuz		 * serious bug of kernel internal.  We thus always bark here.
715151539Ssuz		 * Or, can we even panic?
716151539Ssuz		 */
717151539Ssuz		log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags);
718151539Ssuz		return (RTPREF_INVALID);
719151539Ssuz	}
720151539Ssuz	/* NOTREACHED */
721151539Ssuz}
722151539Ssuz
72353541Sshinstatic struct nd_defrouter *
724171259Sdelphijdefrtrlist_update(struct nd_defrouter *new)
72553541Sshin{
72653541Sshin	struct nd_defrouter *dr, *n;
72753541Sshin	int s = splnet();
72853541Sshin
72953541Sshin	if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
73053541Sshin		/* entry exists */
73153541Sshin		if (new->rtlifetime == 0) {
73253541Sshin			defrtrlist_del(dr);
73353541Sshin			dr = NULL;
73453541Sshin		} else {
735151539Ssuz			int oldpref = rtpref(dr);
736151539Ssuz
73753541Sshin			/* override */
73853541Sshin			dr->flags = new->flags; /* xxx flag check */
73953541Sshin			dr->rtlifetime = new->rtlifetime;
74053541Sshin			dr->expire = new->expire;
741151539Ssuz
742151539Ssuz			/*
743151539Ssuz			 * If the preference does not change, there's no need
744151539Ssuz			 * to sort the entries.
745151539Ssuz			 */
746151539Ssuz			if (rtpref(new) == oldpref) {
747151539Ssuz				splx(s);
748151539Ssuz				return (dr);
749151539Ssuz			}
750151539Ssuz
751151539Ssuz			/*
752151539Ssuz			 * preferred router may be changed, so relocate
753151539Ssuz			 * this router.
754151539Ssuz			 * XXX: calling TAILQ_REMOVE directly is a bad manner.
755151539Ssuz			 * However, since defrtrlist_del() has many side
756151539Ssuz			 * effects, we intentionally do so here.
757151539Ssuz			 * defrouter_select() below will handle routing
758151539Ssuz			 * changes later.
759151539Ssuz			 */
760181803Sbz			TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry);
761151539Ssuz			n = dr;
762151539Ssuz			goto insert;
76353541Sshin		}
76453541Sshin		splx(s);
765120856Sume		return (dr);
76653541Sshin	}
76753541Sshin
76853541Sshin	/* entry does not exist */
76953541Sshin	if (new->rtlifetime == 0) {
77053541Sshin		splx(s);
771120856Sume		return (NULL);
77253541Sshin	}
77353541Sshin
77453541Sshin	n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
77553541Sshin	if (n == NULL) {
77653541Sshin		splx(s);
777120856Sume		return (NULL);
77853541Sshin	}
77953541Sshin	bzero(n, sizeof(*n));
78053541Sshin	*n = *new;
78162587Sitojun
782151539Ssuzinsert:
78362587Sitojun	/*
784151539Ssuz	 * Insert the new router in the Default Router List;
785151539Ssuz	 * The Default Router List should be in the descending order
786151539Ssuz	 * of router-preferece.  Routers with the same preference are
787151539Ssuz	 * sorted in the arriving time order.
78862587Sitojun	 */
789151539Ssuz
790151539Ssuz	/* insert at the end of the group */
791181803Sbz	for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
792151539Ssuz	     dr = TAILQ_NEXT(dr, dr_entry)) {
793151539Ssuz		if (rtpref(n) > rtpref(dr))
794151539Ssuz			break;
795151539Ssuz	}
796151539Ssuz	if (dr)
797151539Ssuz		TAILQ_INSERT_BEFORE(dr, n, dr_entry);
798151539Ssuz	else
799181803Sbz		TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry);
800151539Ssuz
801151539Ssuz	defrouter_select();
802151539Ssuz
80353541Sshin	splx(s);
804120941Sume
805120856Sume	return (n);
80653541Sshin}
80753541Sshin
80853541Sshinstatic struct nd_pfxrouter *
809171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr)
81053541Sshin{
81153541Sshin	struct nd_pfxrouter *search;
812120941Sume
81362587Sitojun	for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
81453541Sshin		if (search->router == dr)
81553541Sshin			break;
81653541Sshin	}
81753541Sshin
818120856Sume	return (search);
81953541Sshin}
82053541Sshin
82153541Sshinstatic void
822171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr)
82353541Sshin{
82453541Sshin	struct nd_pfxrouter *new;
82553541Sshin
82653541Sshin	new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
82753541Sshin	if (new == NULL)
82853541Sshin		return;
82953541Sshin	bzero(new, sizeof(*new));
83053541Sshin	new->router = dr;
83153541Sshin
83253541Sshin	LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
83353541Sshin
83453541Sshin	pfxlist_onlink_check();
83553541Sshin}
83653541Sshin
83753541Sshinstatic void
838171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr)
83953541Sshin{
84053541Sshin	LIST_REMOVE(pfr, pfr_entry);
84153541Sshin	free(pfr, M_IP6NDP);
84253541Sshin}
84353541Sshin
84478064Sumestruct nd_prefix *
845171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key)
84653541Sshin{
84753541Sshin	struct nd_prefix *search;
84853541Sshin
849181803Sbz	for (search = V_nd_prefix.lh_first; search; search = search->ndpr_next) {
850151539Ssuz		if (key->ndpr_ifp == search->ndpr_ifp &&
851151539Ssuz		    key->ndpr_plen == search->ndpr_plen &&
852151539Ssuz		    in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr,
853151539Ssuz		    &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) {
85453541Sshin			break;
85553541Sshin		}
85653541Sshin	}
85753541Sshin
858120856Sume	return (search);
85953541Sshin}
86053541Sshin
86178064Sumeint
862171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
863171259Sdelphij    struct nd_prefix **newp)
86453541Sshin{
86578064Sume	struct nd_prefix *new = NULL;
866151539Ssuz	int error = 0;
86753541Sshin	int i, s;
868165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
86953541Sshin
87053541Sshin	new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
87153541Sshin	if (new == NULL)
872120941Sume		return(ENOMEM);
87353541Sshin	bzero(new, sizeof(*new));
874151539Ssuz	new->ndpr_ifp = pr->ndpr_ifp;
875151539Ssuz	new->ndpr_prefix = pr->ndpr_prefix;
876151539Ssuz	new->ndpr_plen = pr->ndpr_plen;
877151539Ssuz	new->ndpr_vltime = pr->ndpr_vltime;
878151539Ssuz	new->ndpr_pltime = pr->ndpr_pltime;
879151539Ssuz	new->ndpr_flags = pr->ndpr_flags;
880151539Ssuz	if ((error = in6_init_prefix_ltimes(new)) != 0) {
881151539Ssuz		free(new, M_IP6NDP);
882151539Ssuz		return(error);
883151539Ssuz	}
884151539Ssuz	new->ndpr_lastupdate = time_second;
88578064Sume	if (newp != NULL)
88678064Sume		*newp = new;
88753541Sshin
888120941Sume	/* initialization */
88953541Sshin	LIST_INIT(&new->ndpr_advrtrs);
89053541Sshin	in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
89153541Sshin	/* make prefix in the canonical form */
89253541Sshin	for (i = 0; i < 4; i++)
89353541Sshin		new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
894120941Sume		    new->ndpr_mask.s6_addr32[i];
89553541Sshin
89653541Sshin	s = splnet();
89753541Sshin	/* link ndpr_entry to nd_prefix list */
898181803Sbz	LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry);
89953541Sshin	splx(s);
90053541Sshin
90178064Sume	/* ND_OPT_PI_FLAG_ONLINK processing */
90278064Sume	if (new->ndpr_raf_onlink) {
90378064Sume		int e;
90478064Sume
90578064Sume		if ((e = nd6_prefix_onlink(new)) != 0) {
90678064Sume			nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
90778064Sume			    "the prefix %s/%d on-link on %s (errno=%d)\n",
908165118Sbz			    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
90978064Sume			    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
91078064Sume			/* proceed anyway. XXX: is it correct? */
91178064Sume		}
91278064Sume	}
91378064Sume
914120941Sume	if (dr)
91553541Sshin		pfxrtr_add(new, dr);
91653541Sshin
91753541Sshin	return 0;
91853541Sshin}
91953541Sshin
92053541Sshinvoid
921171259Sdelphijprelist_remove(struct nd_prefix *pr)
92253541Sshin{
92353541Sshin	struct nd_pfxrouter *pfr, *next;
92478064Sume	int e, s;
925165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
92653541Sshin
92778064Sume	/* make sure to invalidate the prefix until it is really freed. */
92878064Sume	pr->ndpr_vltime = 0;
92978064Sume	pr->ndpr_pltime = 0;
930151539Ssuz
93178064Sume	/*
93278064Sume	 * Though these flags are now meaningless, we'd rather keep the value
933151479Ssuz	 * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users
934151479Ssuz	 * when executing "ndp -p".
93578064Sume	 */
936151479Ssuz
93778064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
93878064Sume	    (e = nd6_prefix_offlink(pr)) != 0) {
93978064Sume		nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
94078064Sume		    "on %s, errno=%d\n",
941165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
94278064Sume		    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
94378064Sume		/* what should we do? */
94478064Sume	}
94578064Sume
94678064Sume	if (pr->ndpr_refcnt > 0)
94778064Sume		return;		/* notice here? */
94878064Sume
94953541Sshin	s = splnet();
95078064Sume
95153541Sshin	/* unlink ndpr_entry from nd_prefix list */
95253541Sshin	LIST_REMOVE(pr, ndpr_entry);
95353541Sshin
95453541Sshin	/* free list of routers that adversed the prefix */
95562587Sitojun	for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
95662587Sitojun		next = pfr->pfr_next;
95753541Sshin
95853541Sshin		free(pfr, M_IP6NDP);
95953541Sshin	}
96078064Sume	splx(s);
96178064Sume
96253541Sshin	free(pr, M_IP6NDP);
96353541Sshin
96453541Sshin	pfxlist_onlink_check();
96553541Sshin}
96653541Sshin
967171259Sdelphij/*
968171259Sdelphij * dr - may be NULL
969171259Sdelphij */
970171259Sdelphij
971151539Ssuzstatic int
972171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
973171259Sdelphij    struct mbuf *m, int mcast)
97453541Sshin{
97578064Sume	struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
97678064Sume	struct ifaddr *ifa;
97778064Sume	struct ifnet *ifp = new->ndpr_ifp;
97853541Sshin	struct nd_prefix *pr;
97953541Sshin	int s = splnet();
98053541Sshin	int error = 0;
98178064Sume	int newprefix = 0;
98253541Sshin	int auth;
98378064Sume	struct in6_addrlifetime lt6_tmp;
984165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
98553541Sshin
98653541Sshin	auth = 0;
98753541Sshin	if (m) {
98853541Sshin		/*
98953541Sshin		 * Authenticity for NA consists authentication for
99053541Sshin		 * both IP header and IP datagrams, doesn't it ?
99153541Sshin		 */
99253541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
993120941Sume		auth = ((m->m_flags & M_AUTHIPHDR) &&
994120941Sume		    (m->m_flags & M_AUTHIPDGM));
99553541Sshin#endif
99653541Sshin	}
99753541Sshin
99878064Sume	if ((pr = nd6_prefix_lookup(new)) != NULL) {
99978064Sume		/*
100078064Sume		 * nd6_prefix_lookup() ensures that pr and new have the same
100178064Sume		 * prefix on a same interface.
100278064Sume		 */
100353541Sshin
100453541Sshin		/*
100578064Sume		 * Update prefix information.  Note that the on-link (L) bit
100678064Sume		 * and the autonomous (A) bit should NOT be changed from 1
100778064Sume		 * to 0.
100853541Sshin		 */
100978064Sume		if (new->ndpr_raf_onlink == 1)
101078064Sume			pr->ndpr_raf_onlink = 1;
101178064Sume		if (new->ndpr_raf_auto == 1)
101278064Sume			pr->ndpr_raf_auto = 1;
101378064Sume		if (new->ndpr_raf_onlink) {
101478064Sume			pr->ndpr_vltime = new->ndpr_vltime;
101578064Sume			pr->ndpr_pltime = new->ndpr_pltime;
1016151539Ssuz			(void)in6_init_prefix_ltimes(pr); /* XXX error case? */
1017151539Ssuz			pr->ndpr_lastupdate = time_second;
101878064Sume		}
101953541Sshin
102078064Sume		if (new->ndpr_raf_onlink &&
102178064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
102278064Sume			int e;
102353541Sshin
102478064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
102578064Sume				nd6log((LOG_ERR,
102678064Sume				    "prelist_update: failed to make "
102778064Sume				    "the prefix %s/%d on-link on %s "
102878064Sume				    "(errno=%d)\n",
1029165118Sbz				    ip6_sprintf(ip6buf,
1030165118Sbz					    &pr->ndpr_prefix.sin6_addr),
103178064Sume				    pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
103278064Sume				/* proceed anyway. XXX: is it correct? */
103353541Sshin			}
103478064Sume		}
103553541Sshin
103678064Sume		if (dr && pfxrtr_lookup(pr, dr) == NULL)
103778064Sume			pfxrtr_add(pr, dr);
103878064Sume	} else {
103978064Sume		struct nd_prefix *newpr = NULL;
104053541Sshin
104178064Sume		newprefix = 1;
104253541Sshin
104378064Sume		if (new->ndpr_vltime == 0)
104478064Sume			goto end;
104578064Sume		if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
104678064Sume			goto end;
104753541Sshin
104878064Sume		error = nd6_prelist_add(new, dr, &newpr);
104978064Sume		if (error != 0 || newpr == NULL) {
105078064Sume			nd6log((LOG_NOTICE, "prelist_update: "
105178064Sume			    "nd6_prelist_add failed for %s/%d on %s "
105278064Sume			    "errno=%d, returnpr=%p\n",
1053165118Sbz			    ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr),
1054120941Sume			    new->ndpr_plen, if_name(new->ndpr_ifp),
1055120941Sume			    error, newpr));
105678064Sume			goto end; /* we should just give up in this case. */
105778064Sume		}
105853541Sshin
105978064Sume		/*
106078064Sume		 * XXX: from the ND point of view, we can ignore a prefix
106178064Sume		 * with the on-link bit being zero.  However, we need a
106278064Sume		 * prefix structure for references from autoconfigured
1063120941Sume		 * addresses.  Thus, we explicitly make sure that the prefix
106478064Sume		 * itself expires now.
106578064Sume		 */
106678064Sume		if (newpr->ndpr_raf_onlink == 0) {
106778064Sume			newpr->ndpr_vltime = 0;
106878064Sume			newpr->ndpr_pltime = 0;
106978064Sume			in6_init_prefix_ltimes(newpr);
107053541Sshin		}
107153541Sshin
107278064Sume		pr = newpr;
107378064Sume	}
107453541Sshin
107578064Sume	/*
107678064Sume	 * Address autoconfiguration based on Section 5.5.3 of RFC 2462.
107778064Sume	 * Note that pr must be non NULL at this point.
107878064Sume	 */
107962587Sitojun
108078064Sume	/* 5.5.3 (a). Ignore the prefix without the A bit set. */
108178064Sume	if (!new->ndpr_raf_auto)
1082151539Ssuz		goto end;
108362587Sitojun
108478064Sume	/*
108578064Sume	 * 5.5.3 (b). the link-local prefix should have been ignored in
108678064Sume	 * nd6_ra_input.
108778064Sume	 */
108862587Sitojun
1089151539Ssuz	/* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */
1090151539Ssuz	if (new->ndpr_pltime > new->ndpr_vltime) {
1091151539Ssuz		error = EINVAL;	/* XXX: won't be used */
1092151539Ssuz		goto end;
1093151539Ssuz	}
109462587Sitojun
1095171260Sdelphij	/*
1096151539Ssuz	 * 5.5.3 (d).  If the prefix advertised is not equal to the prefix of
1097151539Ssuz	 * an address configured by stateless autoconfiguration already in the
1098151539Ssuz	 * list of addresses associated with the interface, and the Valid
1099151539Ssuz	 * Lifetime is not 0, form an address.  We first check if we have
1100151539Ssuz	 * a matching prefix.
1101151539Ssuz	 * Note: we apply a clarification in rfc2462bis-02 here.  We only
1102151539Ssuz	 * consider autoconfigured addresses while RFC2462 simply said
1103151539Ssuz	 * "address".
110478064Sume	 */
1105120941Sume	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
110678064Sume		struct in6_ifaddr *ifa6;
1107151539Ssuz		u_int32_t remaininglifetime;
110853541Sshin
110978064Sume		if (ifa->ifa_addr->sa_family != AF_INET6)
111078064Sume			continue;
111153541Sshin
111278064Sume		ifa6 = (struct in6_ifaddr *)ifa;
111353541Sshin
111453541Sshin		/*
1115151539Ssuz		 * We only consider autoconfigured addresses as per rfc2462bis.
1116151539Ssuz		 */
1117151539Ssuz		if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF))
1118151539Ssuz			continue;
1119151539Ssuz
1120151539Ssuz		/*
112178064Sume		 * Spec is not clear here, but I believe we should concentrate
112278064Sume		 * on unicast (i.e. not anycast) addresses.
112378064Sume		 * XXX: other ia6_flags? detached or duplicated?
112453541Sshin		 */
112578064Sume		if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
112678064Sume			continue;
1127120941Sume
1128151539Ssuz		/*
1129151539Ssuz		 * Ignore the address if it is not associated with a prefix
1130151539Ssuz		 * or is associated with a prefix that is different from this
1131151539Ssuz		 * one.  (pr is never NULL here)
1132151539Ssuz		 */
1133151539Ssuz		if (ifa6->ia6_ndpr != pr)
113478064Sume			continue;
113553541Sshin
113678064Sume		if (ia6_match == NULL) /* remember the first one */
113778064Sume			ia6_match = ifa6;
113878064Sume
113978064Sume		/*
114078064Sume		 * An already autoconfigured address matched.  Now that we
114178064Sume		 * are sure there is at least one matched address, we can
114278064Sume		 * proceed to 5.5.3. (e): update the lifetimes according to the
114378064Sume		 * "two hours" rule and the privacy extension.
1144151539Ssuz		 * We apply some clarifications in rfc2462bis:
1145151539Ssuz		 * - use remaininglifetime instead of storedlifetime as a
1146151539Ssuz		 *   variable name
1147151539Ssuz		 * - remove the dead code in the "two-hour" rule
114878064Sume		 */
114978064Sume#define TWOHOUR		(120*60)
115078064Sume		lt6_tmp = ifa6->ia6_lifetime;
115178064Sume
1152112678Sume		if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME)
1153151539Ssuz			remaininglifetime = ND6_INFINITE_LIFETIME;
1154151539Ssuz		else if (time_second - ifa6->ia6_updatetime >
1155151539Ssuz			 lt6_tmp.ia6t_vltime) {
1156151539Ssuz			/*
1157151539Ssuz			 * The case of "invalid" address.  We should usually
1158151539Ssuz			 * not see this case.
1159151539Ssuz			 */
1160151539Ssuz			remaininglifetime = 0;
1161151539Ssuz		} else
1162151539Ssuz			remaininglifetime = lt6_tmp.ia6t_vltime -
1163151539Ssuz			    (time_second - ifa6->ia6_updatetime);
116478064Sume
1165112678Sume		/* when not updating, keep the current stored lifetime. */
1166151539Ssuz		lt6_tmp.ia6t_vltime = remaininglifetime;
1167112678Sume
116878064Sume		if (TWOHOUR < new->ndpr_vltime ||
1169151539Ssuz		    remaininglifetime < new->ndpr_vltime) {
117078064Sume			lt6_tmp.ia6t_vltime = new->ndpr_vltime;
1171151539Ssuz		} else if (remaininglifetime <= TWOHOUR) {
117278064Sume			if (auth) {
117378064Sume				lt6_tmp.ia6t_vltime = new->ndpr_vltime;
117478064Sume			}
117578064Sume		} else {
117678064Sume			/*
117778064Sume			 * new->ndpr_vltime <= TWOHOUR &&
1178151539Ssuz			 * TWOHOUR < remaininglifetime
117978064Sume			 */
118078064Sume			lt6_tmp.ia6t_vltime = TWOHOUR;
118153541Sshin		}
118253541Sshin
118378064Sume		/* The 2 hour rule is not imposed for preferred lifetime. */
118478064Sume		lt6_tmp.ia6t_pltime = new->ndpr_pltime;
118553541Sshin
118678064Sume		in6_init_address_ltimes(pr, &lt6_tmp);
118753541Sshin
1188171260Sdelphij		/*
1189151539Ssuz		 * We need to treat lifetimes for temporary addresses
1190151539Ssuz		 * differently, according to
1191151539Ssuz		 * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1);
1192151539Ssuz		 * we only update the lifetimes when they are in the maximum
1193151539Ssuz		 * intervals.
1194171260Sdelphij		 */
1195171260Sdelphij		if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {
1196151539Ssuz			u_int32_t maxvltime, maxpltime;
1197151539Ssuz
1198181803Sbz			if (V_ip6_temp_valid_lifetime >
1199151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1200181803Sbz			    V_ip6_desync_factor)) {
1201181803Sbz				maxvltime = V_ip6_temp_valid_lifetime -
1202151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1203181803Sbz				    V_ip6_desync_factor;
1204151539Ssuz			} else
1205151539Ssuz				maxvltime = 0;
1206181803Sbz			if (V_ip6_temp_preferred_lifetime >
1207151539Ssuz			    (u_int32_t)((time_second - ifa6->ia6_createtime) +
1208181803Sbz			    V_ip6_desync_factor)) {
1209181803Sbz				maxpltime = V_ip6_temp_preferred_lifetime -
1210151539Ssuz				    (time_second - ifa6->ia6_createtime) -
1211181803Sbz				    V_ip6_desync_factor;
1212151539Ssuz			} else
1213151539Ssuz				maxpltime = 0;
1214151539Ssuz
1215151539Ssuz			if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME ||
1216151539Ssuz			    lt6_tmp.ia6t_vltime > maxvltime) {
1217151539Ssuz				lt6_tmp.ia6t_vltime = maxvltime;
121878064Sume			}
1219151539Ssuz			if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME ||
1220151539Ssuz			    lt6_tmp.ia6t_pltime > maxpltime) {
1221151539Ssuz				lt6_tmp.ia6t_pltime = maxpltime;
122278064Sume			}
122378064Sume		}
122478064Sume		ifa6->ia6_lifetime = lt6_tmp;
1225151539Ssuz		ifa6->ia6_updatetime = time_second;
122653541Sshin	}
122778064Sume	if (ia6_match == NULL && new->ndpr_vltime) {
1228151539Ssuz		int ifidlen;
1229151539Ssuz
123078064Sume		/*
1231151539Ssuz		 * 5.5.3 (d) (continued)
123278064Sume		 * No address matched and the valid lifetime is non-zero.
123378064Sume		 * Create a new address.
123478064Sume		 */
1235151539Ssuz
1236151539Ssuz		/*
1237151539Ssuz		 * Prefix Length check:
1238151539Ssuz		 * If the sum of the prefix length and interface identifier
1239151539Ssuz		 * length does not equal 128 bits, the Prefix Information
1240151539Ssuz		 * option MUST be ignored.  The length of the interface
1241151539Ssuz		 * identifier is defined in a separate link-type specific
1242151539Ssuz		 * document.
1243151539Ssuz		 */
1244151539Ssuz		ifidlen = in6_if2idlen(ifp);
1245151539Ssuz		if (ifidlen < 0) {
1246151539Ssuz			/* this should not happen, so we always log it. */
1247151539Ssuz			log(LOG_ERR, "prelist_update: IFID undefined (%s)\n",
1248151539Ssuz			    if_name(ifp));
1249151539Ssuz			goto end;
1250151539Ssuz		}
1251151539Ssuz		if (ifidlen + pr->ndpr_plen != 128) {
1252151539Ssuz			nd6log((LOG_INFO,
1253151539Ssuz			    "prelist_update: invalid prefixlen "
1254151539Ssuz			    "%d for %s, ignored\n",
1255151539Ssuz			    pr->ndpr_plen, if_name(ifp)));
1256151539Ssuz			goto end;
1257151539Ssuz		}
1258151539Ssuz
1259151539Ssuz		if ((ia6 = in6_ifadd(new, mcast)) != NULL) {
126078064Sume			/*
126178064Sume			 * note that we should use pr (not new) for reference.
126278064Sume			 */
126378064Sume			pr->ndpr_refcnt++;
126478064Sume			ia6->ia6_ndpr = pr;
126553541Sshin
126678064Sume			/*
126778064Sume			 * RFC 3041 3.3 (2).
126878064Sume			 * When a new public address is created as described
126978064Sume			 * in RFC2462, also create a new temporary address.
127078064Sume			 *
127178064Sume			 * RFC 3041 3.5.
127278064Sume			 * When an interface connects to a new link, a new
127378064Sume			 * randomized interface identifier should be generated
127478064Sume			 * immediately together with a new set of temporary
127578064Sume			 * addresses.  Thus, we specifiy 1 as the 2nd arg of
127678064Sume			 * in6_tmpifadd().
127778064Sume			 */
1278181803Sbz			if (V_ip6_use_tempaddr) {
127978064Sume				int e;
1280151539Ssuz				if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) {
128178064Sume					nd6log((LOG_NOTICE, "prelist_update: "
128278064Sume					    "failed to create a temporary "
128378064Sume					    "address, errno=%d\n",
128478064Sume					    e));
128578064Sume				}
128678064Sume			}
128778064Sume
128878064Sume			/*
128978064Sume			 * A newly added address might affect the status
129078064Sume			 * of other addresses, so we check and update it.
129178064Sume			 * XXX: what if address duplication happens?
129278064Sume			 */
129378064Sume			pfxlist_onlink_check();
129478064Sume		} else {
129578064Sume			/* just set an error. do not bark here. */
129678064Sume			error = EADDRNOTAVAIL; /* XXX: might be unused. */
129778064Sume		}
129878064Sume	}
129978064Sume
130053541Sshin end:
130153541Sshin	splx(s);
130253541Sshin	return error;
130353541Sshin}
130453541Sshin
130553541Sshin/*
130662587Sitojun * A supplement function used in the on-link detection below;
130762587Sitojun * detect if a given prefix has a (probably) reachable advertising router.
130862587Sitojun * XXX: lengthy function name...
130962587Sitojun */
131078064Sumestatic struct nd_pfxrouter *
1311171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr)
131262587Sitojun{
131362587Sitojun	struct nd_pfxrouter *pfxrtr;
131462587Sitojun	struct rtentry *rt;
131562587Sitojun	struct llinfo_nd6 *ln;
131662587Sitojun
131762587Sitojun	for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
131862587Sitojun	     pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
131962587Sitojun		if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
1320120941Sume		    pfxrtr->router->ifp)) &&
132162587Sitojun		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
132262587Sitojun		    ND6_IS_LLINFO_PROBREACH(ln))
132362587Sitojun			break;	/* found */
132462587Sitojun	}
132562587Sitojun
1326120856Sume	return (pfxrtr);
132762587Sitojun}
132862587Sitojun
132962587Sitojun/*
133053541Sshin * Check if each prefix in the prefix list has at least one available router
133178064Sume * that advertised the prefix (a router is "available" if its neighbor cache
133278064Sume * entry is reachable or probably reachable).
133362587Sitojun * If the check fails, the prefix may be off-link, because, for example,
133453541Sshin * we have moved from the network but the lifetime of the prefix has not
133578064Sume * expired yet.  So we should not use the prefix if there is another prefix
133678064Sume * that has an available router.
133778064Sume * But, if there is no prefix that has an available router, we still regards
133878064Sume * all the prefixes as on-link.  This is because we can't tell if all the
133953541Sshin * routers are simply dead or if we really moved from the network and there
134053541Sshin * is no router around us.
134153541Sshin */
134262587Sitojunvoid
134353541Sshinpfxlist_onlink_check()
134453541Sshin{
134553541Sshin	struct nd_prefix *pr;
134678064Sume	struct in6_ifaddr *ifa;
1347151539Ssuz	struct nd_defrouter *dr;
1348151539Ssuz	struct nd_pfxrouter *pfxrtr = NULL;
134953541Sshin
135062587Sitojun	/*
135162587Sitojun	 * Check if there is a prefix that has a reachable advertising
135262587Sitojun	 * router.
135362587Sitojun	 */
1354181803Sbz	for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
135578064Sume		if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
135653541Sshin			break;
135762587Sitojun	}
135853541Sshin
1359151539Ssuz	/*
1360151539Ssuz	 * If we have no such prefix, check whether we still have a router
1361151539Ssuz	 * that does not advertise any prefixes.
1362151539Ssuz	 */
1363151465Ssuz	if (pr == NULL) {
1364181803Sbz		for (dr = TAILQ_FIRST(&V_nd_defrouter); dr;
1365151539Ssuz		    dr = TAILQ_NEXT(dr, dr_entry)) {
1366151539Ssuz			struct nd_prefix *pr0;
1367151539Ssuz
1368181803Sbz			for (pr0 = V_nd_prefix.lh_first; pr0;
1369151539Ssuz			    pr0 = pr0->ndpr_next) {
1370151539Ssuz				if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL)
1371151539Ssuz					break;
1372151539Ssuz			}
1373151539Ssuz			if (pfxrtr != NULL)
1374151539Ssuz				break;
1375151539Ssuz		}
1376151539Ssuz	}
1377181803Sbz	if (pr != NULL || (TAILQ_FIRST(&V_nd_defrouter) && pfxrtr == NULL)) {
1378171260Sdelphij		/*
1379151539Ssuz		 * There is at least one prefix that has a reachable router,
1380151539Ssuz		 * or at least a router which probably does not advertise
1381151539Ssuz		 * any prefixes.  The latter would be the case when we move
1382151539Ssuz		 * to a new link where we have a router that does not provide
1383151539Ssuz		 * prefixes and we configure an address by hand.
1384171260Sdelphij		 * Detach prefixes which have no reachable advertising
1385171260Sdelphij		 * router, and attach other prefixes.
1386171260Sdelphij		 */
1387181803Sbz		for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
138878064Sume			/* XXX: a link-local prefix should never be detached */
138978064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
139078064Sume				continue;
139178064Sume
139278064Sume			/*
139378064Sume			 * we aren't interested in prefixes without the L bit
139478064Sume			 * set.
139578064Sume			 */
139678064Sume			if (pr->ndpr_raf_onlink == 0)
139778064Sume				continue;
139878064Sume
139978064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
140078064Sume			    find_pfxlist_reachable_router(pr) == NULL)
140178064Sume				pr->ndpr_stateflags |= NDPRF_DETACHED;
140278064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
140378064Sume			    find_pfxlist_reachable_router(pr) != 0)
140478064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
140553541Sshin		}
140678064Sume	} else {
140778064Sume		/* there is no prefix that has a reachable router */
1408181803Sbz		for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
140978064Sume			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
141078064Sume				continue;
141178064Sume
141278064Sume			if (pr->ndpr_raf_onlink == 0)
141378064Sume				continue;
141478064Sume
141578064Sume			if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
141678064Sume				pr->ndpr_stateflags &= ~NDPRF_DETACHED;
141753541Sshin		}
141862587Sitojun	}
141978064Sume
142078064Sume	/*
142178064Sume	 * Remove each interface route associated with a (just) detached
142278064Sume	 * prefix, and reinstall the interface route for a (just) attached
142378064Sume	 * prefix.  Note that all attempt of reinstallation does not
142478064Sume	 * necessarily success, when a same prefix is shared among multiple
142578064Sume	 * interfaces.  Such cases will be handled in nd6_prefix_onlink,
142678064Sume	 * so we don't have to care about them.
142778064Sume	 */
1428181803Sbz	for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
142978064Sume		int e;
1430165118Sbz		char ip6buf[INET6_ADDRSTRLEN];
143178064Sume
143278064Sume		if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
143378064Sume			continue;
143478064Sume
143578064Sume		if (pr->ndpr_raf_onlink == 0)
143678064Sume			continue;
143778064Sume
143878064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
143978064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
144078064Sume			if ((e = nd6_prefix_offlink(pr)) != 0) {
144178064Sume				nd6log((LOG_ERR,
144278064Sume				    "pfxlist_onlink_check: failed to "
1443151479Ssuz				    "make %s/%d offlink, errno=%d\n",
1444165118Sbz				    ip6_sprintf(ip6buf,
1445165118Sbz					    &pr->ndpr_prefix.sin6_addr),
1446165118Sbz					    pr->ndpr_plen, e));
144778064Sume			}
144878064Sume		}
144978064Sume		if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
145078064Sume		    (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
145178064Sume		    pr->ndpr_raf_onlink) {
145278064Sume			if ((e = nd6_prefix_onlink(pr)) != 0) {
145378064Sume				nd6log((LOG_ERR,
145478064Sume				    "pfxlist_onlink_check: failed to "
1455151479Ssuz				    "make %s/%d onlink, errno=%d\n",
1456165118Sbz				    ip6_sprintf(ip6buf,
1457165118Sbz					    &pr->ndpr_prefix.sin6_addr),
1458165118Sbz					    pr->ndpr_plen, e));
145978064Sume			}
146078064Sume		}
146178064Sume	}
146278064Sume
146378064Sume	/*
146478064Sume	 * Changes on the prefix status might affect address status as well.
146578064Sume	 * Make sure that all addresses derived from an attached prefix are
146678064Sume	 * attached, and that all addresses derived from a detached prefix are
146778064Sume	 * detached.  Note, however, that a manually configured address should
146878064Sume	 * always be attached.
146978064Sume	 * The precise detection logic is same as the one for prefixes.
147078064Sume	 */
1471181803Sbz	for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) {
1472120941Sume		if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
147378064Sume			continue;
147478064Sume
147578064Sume		if (ifa->ia6_ndpr == NULL) {
147678064Sume			/*
147778064Sume			 * This can happen when we first configure the address
147878064Sume			 * (i.e. the address exists, but the prefix does not).
147978064Sume			 * XXX: complicated relationships...
148078064Sume			 */
148178064Sume			continue;
148278064Sume		}
148378064Sume
148478064Sume		if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
148578064Sume			break;
148678064Sume	}
148778064Sume	if (ifa) {
1488181803Sbz		for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) {
148978064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
149078064Sume				continue;
149178064Sume
149278064Sume			if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
149378064Sume				continue;
149478064Sume
1495151539Ssuz			if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) {
1496151539Ssuz				if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1497151539Ssuz					ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1498151539Ssuz					ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1499151539Ssuz					nd6_dad_start((struct ifaddr *)ifa, 0);
1500151539Ssuz				}
1501151539Ssuz			} else {
150278064Sume				ifa->ia6_flags |= IN6_IFF_DETACHED;
1503151539Ssuz			}
150478064Sume		}
150578064Sume	}
150662587Sitojun	else {
1507181803Sbz		for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) {
150878064Sume			if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
150978064Sume				continue;
151078064Sume
1511151539Ssuz			if (ifa->ia6_flags & IN6_IFF_DETACHED) {
1512151539Ssuz				ifa->ia6_flags &= ~IN6_IFF_DETACHED;
1513151539Ssuz				ifa->ia6_flags |= IN6_IFF_TENTATIVE;
1514151539Ssuz				/* Do we need a delay in this case? */
1515151539Ssuz				nd6_dad_start((struct ifaddr *)ifa, 0);
1516151539Ssuz			}
151778064Sume		}
151853541Sshin	}
151953541Sshin}
152053541Sshin
152178064Sumeint
1522171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr)
152353541Sshin{
152478064Sume	struct ifaddr *ifa;
152578064Sume	struct ifnet *ifp = pr->ndpr_ifp;
152678064Sume	struct sockaddr_in6 mask6;
152778064Sume	struct nd_prefix *opr;
152878064Sume	u_long rtflags;
152978064Sume	int error = 0;
153078064Sume	struct rtentry *rt = NULL;
1531165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
153253541Sshin
153378064Sume	/* sanity check */
153478064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
153578064Sume		nd6log((LOG_ERR,
153678064Sume		    "nd6_prefix_onlink: %s/%d is already on-link\n",
1537165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
1538165118Sbz		    pr->ndpr_plen));
1539151465Ssuz		return (EEXIST);
154078064Sume	}
154178064Sume
154253541Sshin	/*
154378064Sume	 * Add the interface route associated with the prefix.  Before
154478064Sume	 * installing the route, check if there's the same prefix on another
154578064Sume	 * interface, and the prefix has already installed the interface route.
154678064Sume	 * Although such a configuration is expected to be rare, we explicitly
154778064Sume	 * allow it.
154853541Sshin	 */
1549181803Sbz	for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
155078064Sume		if (opr == pr)
155178064Sume			continue;
155278064Sume
155378064Sume		if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
155478064Sume			continue;
155578064Sume
155678064Sume		if (opr->ndpr_plen == pr->ndpr_plen &&
155778064Sume		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1558120941Sume		    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen))
1559120856Sume			return (0);
156078064Sume	}
156178064Sume
156278064Sume	/*
1563120941Sume	 * We prefer link-local addresses as the associated interface address.
156478064Sume	 */
156578064Sume	/* search for a link-local addr */
156678064Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
1567120941Sume	    IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
156878064Sume	if (ifa == NULL) {
156978064Sume		/* XXX: freebsd does not have ifa_ifwithaf */
1570120941Sume		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
157178064Sume			if (ifa->ifa_addr->sa_family == AF_INET6)
157278064Sume				break;
157378064Sume		}
157478064Sume		/* should we care about ia6_flags? */
157578064Sume	}
157678064Sume	if (ifa == NULL) {
157778064Sume		/*
157878064Sume		 * This can still happen, when, for example, we receive an RA
157978064Sume		 * containing a prefix with the L bit set and the A bit clear,
158078064Sume		 * after removing all IPv6 addresses on the receiving
158178064Sume		 * interface.  This should, of course, be rare though.
158278064Sume		 */
158378064Sume		nd6log((LOG_NOTICE,
158478064Sume		    "nd6_prefix_onlink: failed to find any ifaddr"
158578064Sume		    " to add route for a prefix(%s/%d) on %s\n",
1586165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
158778064Sume		    pr->ndpr_plen, if_name(ifp)));
1588120856Sume		return (0);
158978064Sume	}
159078064Sume
159178064Sume	/*
159278064Sume	 * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
159378064Sume	 * ifa->ifa_rtrequest = nd6_rtrequest;
159478064Sume	 */
159578064Sume	bzero(&mask6, sizeof(mask6));
159678064Sume	mask6.sin6_len = sizeof(mask6);
159778064Sume	mask6.sin6_addr = pr->ndpr_mask;
159878064Sume	rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP;
159978064Sume	if (nd6_need_cache(ifp)) {
160078064Sume		/* explicitly set in case ifa_flags does not set the flag. */
160178064Sume		rtflags |= RTF_CLONING;
160278064Sume	} else {
160378064Sume		/*
160478064Sume		 * explicitly clear the cloning bit in case ifa_flags sets it.
160578064Sume		 */
160678064Sume		rtflags &= ~RTF_CLONING;
160778064Sume	}
160878064Sume	error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
1609120941Sume	    ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
161078064Sume	if (error == 0) {
161178064Sume		if (rt != NULL) /* this should be non NULL, though */
161278064Sume			nd6_rtmsg(RTM_ADD, rt);
161378064Sume		pr->ndpr_stateflags |= NDPRF_ONLINK;
1614120941Sume	} else {
1615165118Sbz		char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN];
161678064Sume		nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
161778064Sume		    " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
161878064Sume		    "errno = %d\n",
1619165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
162078064Sume		    pr->ndpr_plen, if_name(ifp),
1621165118Sbz		    ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
1622165118Sbz		    ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error));
162378064Sume	}
162478064Sume
1625120727Ssam	if (rt != NULL) {
1626120727Ssam		RT_LOCK(rt);
1627122334Ssam		RT_REMREF(rt);
1628120727Ssam		RT_UNLOCK(rt);
1629120727Ssam	}
163078064Sume
1631120856Sume	return (error);
163278064Sume}
163378064Sume
163478064Sumeint
1635171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr)
163678064Sume{
163778064Sume	int error = 0;
163878064Sume	struct ifnet *ifp = pr->ndpr_ifp;
163978064Sume	struct nd_prefix *opr;
164078064Sume	struct sockaddr_in6 sa6, mask6;
164178064Sume	struct rtentry *rt = NULL;
1642165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
164378064Sume
164478064Sume	/* sanity check */
164578064Sume	if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
164678064Sume		nd6log((LOG_ERR,
164778064Sume		    "nd6_prefix_offlink: %s/%d is already off-link\n",
1648165118Sbz		    ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
1649165118Sbz		    pr->ndpr_plen));
1650120856Sume		return (EEXIST);
165178064Sume	}
165278064Sume
165353541Sshin	bzero(&sa6, sizeof(sa6));
165453541Sshin	sa6.sin6_family = AF_INET6;
165553541Sshin	sa6.sin6_len = sizeof(sa6);
165653541Sshin	bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
1657120941Sume	    sizeof(struct in6_addr));
165853541Sshin	bzero(&mask6, sizeof(mask6));
165953541Sshin	mask6.sin6_family = AF_INET6;
166053541Sshin	mask6.sin6_len = sizeof(sa6);
166153541Sshin	bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
166278064Sume	error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
1663120941Sume	    (struct sockaddr *)&mask6, 0, &rt);
166478064Sume	if (error == 0) {
166578064Sume		pr->ndpr_stateflags &= ~NDPRF_ONLINK;
166653541Sshin
166778064Sume		/* report the route deletion to the routing socket. */
166878064Sume		if (rt != NULL)
166978064Sume			nd6_rtmsg(RTM_DELETE, rt);
167053541Sshin
167178064Sume		/*
167278064Sume		 * There might be the same prefix on another interface,
167378064Sume		 * the prefix which could not be on-link just because we have
167478064Sume		 * the interface route (see comments in nd6_prefix_onlink).
167578064Sume		 * If there's one, try to make the prefix on-link on the
167678064Sume		 * interface.
167778064Sume		 */
1678181803Sbz		for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
167978064Sume			if (opr == pr)
168078064Sume				continue;
168153541Sshin
168278064Sume			if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
168378064Sume				continue;
168453541Sshin
168578064Sume			/*
168678064Sume			 * KAME specific: detached prefixes should not be
168778064Sume			 * on-link.
168878064Sume			 */
168978064Sume			if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
169078064Sume				continue;
169178064Sume
169278064Sume			if (opr->ndpr_plen == pr->ndpr_plen &&
169378064Sume			    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
1694120941Sume			    &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
169578064Sume				int e;
169678064Sume
169778064Sume				if ((e = nd6_prefix_onlink(opr)) != 0) {
169878064Sume					nd6log((LOG_ERR,
169978064Sume					    "nd6_prefix_offlink: failed to "
170078064Sume					    "recover a prefix %s/%d from %s "
170178064Sume					    "to %s (errno = %d)\n",
1702165118Sbz					    ip6_sprintf(ip6buf,
1703165118Sbz						&opr->ndpr_prefix.sin6_addr),
170478064Sume					    opr->ndpr_plen, if_name(ifp),
170578064Sume					    if_name(opr->ndpr_ifp), e));
170678064Sume				}
170778064Sume			}
170878064Sume		}
1709120941Sume	} else {
171078064Sume		/* XXX: can we still set the NDPRF_ONLINK flag? */
171178064Sume		nd6log((LOG_ERR,
171278064Sume		    "nd6_prefix_offlink: failed to delete route: "
171378064Sume		    "%s/%d on %s (errno = %d)\n",
1714165118Sbz		    ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen,
1715165118Sbz		    if_name(ifp), error));
171678064Sume	}
171753541Sshin
1718120941Sume	if (rt != NULL) {
1719108269Sru		RTFREE(rt);
1720120941Sume	}
172153541Sshin
1722120856Sume	return (error);
172353541Sshin}
172453541Sshin
172553541Sshinstatic struct in6_ifaddr *
1726171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast)
172753541Sshin{
172878064Sume	struct ifnet *ifp = pr->ndpr_ifp;
172953541Sshin	struct ifaddr *ifa;
173078064Sume	struct in6_aliasreq ifra;
173178064Sume	struct in6_ifaddr *ia, *ib;
173278064Sume	int error, plen0;
173353541Sshin	struct in6_addr mask;
173478064Sume	int prefixlen = pr->ndpr_plen;
1735151539Ssuz	int updateflags;
1736165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
173753541Sshin
1738121168Sume	in6_prefixlen2mask(&mask, prefixlen);
173953541Sshin
174078064Sume	/*
174178064Sume	 * find a link-local address (will be interface ID).
174278064Sume	 * Is it really mandatory? Theoretically, a global or a site-local
174378064Sume	 * address can be configured without a link-local address, if we
174478064Sume	 * have a unique interface identifier...
174578064Sume	 *
174678064Sume	 * it is not mandatory to have a link-local address, we can generate
174778064Sume	 * interface identifier on the fly.  we do this because:
174878064Sume	 * (1) it should be the easiest way to find interface identifier.
174978064Sume	 * (2) RFC2462 5.4 suggesting the use of the same interface identifier
175078064Sume	 * for multiple addresses on a single interface, and possible shortcut
175178064Sume	 * of DAD.  we omitted DAD for this reason in the past.
1752120941Sume	 * (3) a user can prevent autoconfiguration of global address
175378064Sume	 * by removing link-local address by hand (this is partly because we
1754108533Sschweikh	 * don't have other way to control the use of IPv6 on an interface.
175578064Sume	 * this has been our design choice - cf. NRL's "ifconfig auto").
175678064Sume	 * (4) it is easier to manage when an interface has addresses
175778064Sume	 * with the same interface identifier, than to have multiple addresses
175878064Sume	 * with different interface identifiers.
175978064Sume	 */
1760120941Sume	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
176153541Sshin	if (ifa)
176253541Sshin		ib = (struct in6_ifaddr *)ifa;
176353541Sshin	else
176453541Sshin		return NULL;
176553541Sshin
176653541Sshin	/* prefixlen + ifidlen must be equal to 128 */
176778064Sume	plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
176878064Sume	if (prefixlen != plen0) {
176978064Sume		nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
177078064Sume		    "(prefix=%d ifid=%d)\n",
177178064Sume		    if_name(ifp), prefixlen, 128 - plen0));
177253541Sshin		return NULL;
177353541Sshin	}
177453541Sshin
177553541Sshin	/* make ifaddr */
177653541Sshin
177778064Sume	bzero(&ifra, sizeof(ifra));
177878064Sume	/*
177978064Sume	 * in6_update_ifa() does not use ifra_name, but we accurately set it
178078064Sume	 * for safety.
178178064Sume	 */
178278064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
178378064Sume	ifra.ifra_addr.sin6_family = AF_INET6;
178478064Sume	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
178578064Sume	/* prefix */
1786151539Ssuz	ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr;
178778064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
178878064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
178978064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
179078064Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
179153541Sshin
179253541Sshin	/* interface ID */
1793120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
1794151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
1795120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
1796151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
1797120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1798151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
1799120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1800151539Ssuz	    (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
1801120941Sume
180278064Sume	/* new prefix mask. */
180378064Sume	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
180478064Sume	ifra.ifra_prefixmask.sin6_family = AF_INET6;
180578064Sume	bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
1806120941Sume	    sizeof(ifra.ifra_prefixmask.sin6_addr));
180753541Sshin
1808151539Ssuz	/* lifetimes. */
180978064Sume	ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
181078064Sume	ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
181153541Sshin
181278064Sume	/* XXX: scope zone ID? */
181353541Sshin
181478064Sume	ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
1815151539Ssuz
1816171260Sdelphij	/*
1817151539Ssuz	 * Make sure that we do not have this address already.  This should
1818151539Ssuz	 * usually not happen, but we can still see this case, e.g., if we
1819151539Ssuz	 * have manually configured the exact address to be configured.
182078064Sume	 */
1821151539Ssuz	if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
1822151539Ssuz		/* this should be rare enough to make an explicit log */
1823151539Ssuz		log(LOG_INFO, "in6_ifadd: %s is already configured\n",
1824165118Sbz		    ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr));
1825151539Ssuz		return (NULL);
1826151539Ssuz	}
182753541Sshin
182853541Sshin	/*
1829151539Ssuz	 * Allocate ifaddr structure, link into chain, etc.
1830151539Ssuz	 * If we are going to create a new address upon receiving a multicasted
1831151539Ssuz	 * RA, we need to impose a random delay before starting DAD.
1832151539Ssuz	 * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2]
183353541Sshin	 */
1834151539Ssuz	updateflags = 0;
1835151539Ssuz	if (mcast)
1836151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1837151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) {
183878064Sume		nd6log((LOG_ERR,
183978064Sume		    "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
1840165118Sbz		    ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr),
1841165118Sbz		    if_name(ifp), error));
1842120856Sume		return (NULL);	/* ifaddr must not have been allocated. */
184353541Sshin	}
184453541Sshin
184578064Sume	ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
184653541Sshin
1847120941Sume	return (ia);		/* this is always non-NULL */
184853541Sshin}
184953541Sshin
1850171259Sdelphij/*
1851171259Sdelphij * ia0 - corresponding public address
1852171259Sdelphij */
185353541Sshinint
1854171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay)
185553541Sshin{
185678064Sume	struct ifnet *ifp = ia0->ia_ifa.ifa_ifp;
1857151539Ssuz	struct in6_ifaddr *newia, *ia;
185878064Sume	struct in6_aliasreq ifra;
185978064Sume	int i, error;
186078064Sume	int trylimit = 3;	/* XXX: adhoc value */
1861151539Ssuz	int updateflags;
186278064Sume	u_int32_t randid[2];
186378064Sume	time_t vltime0, pltime0;
186453541Sshin
186578064Sume	bzero(&ifra, sizeof(ifra));
186678064Sume	strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
186778064Sume	ifra.ifra_addr = ia0->ia_addr;
186878064Sume	/* copy prefix mask */
186978064Sume	ifra.ifra_prefixmask = ia0->ia_prefixmask;
187078064Sume	/* clear the old IFID */
187178064Sume	for (i = 0; i < 4; i++) {
1872120941Sume		ifra.ifra_addr.sin6_addr.s6_addr32[i] &=
1873120941Sume		    ifra.ifra_prefixmask.sin6_addr.s6_addr32[i];
187478064Sume	}
187553541Sshin
187678064Sume  again:
1877151539Ssuz	if (in6_get_tmpifid(ifp, (u_int8_t *)randid,
1878151539Ssuz	    (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) {
1879151539Ssuz		nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good "
1880151539Ssuz		    "random IFID\n"));
1881151539Ssuz		return (EINVAL);
1882151539Ssuz	}
1883120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
1884120941Sume	    (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2]));
1885120941Sume	ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
1886120941Sume	    (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3]));
188753541Sshin
1888171260Sdelphij	/*
1889151539Ssuz	 * in6_get_tmpifid() quite likely provided a unique interface ID.
1890151539Ssuz	 * However, we may still have a chance to see collision, because
1891151539Ssuz	 * there may be a time lag between generation of the ID and generation
1892151539Ssuz	 * of the address.  So, we'll do one more sanity check.
189378064Sume	 */
1894181803Sbz	for (ia = V_in6_ifaddr; ia; ia = ia->ia_next) {
1895151539Ssuz		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr,
1896151539Ssuz		    &ifra.ifra_addr.sin6_addr)) {
1897171260Sdelphij			if (trylimit-- == 0) {
1898151539Ssuz				/*
1899151539Ssuz				 * Give up.  Something strange should have
1900151539Ssuz				 * happened.
1901151539Ssuz				 */
1902151539Ssuz				nd6log((LOG_NOTICE, "in6_tmpifadd: failed to "
1903151539Ssuz				    "find a unique random IFID\n"));
1904151539Ssuz				return (EEXIST);
1905151539Ssuz			}
1906151539Ssuz			forcegen = 1;
1907151539Ssuz			goto again;
190878064Sume		}
190953541Sshin	}
191053541Sshin
191178064Sume	/*
191278064Sume	 * The Valid Lifetime is the lower of the Valid Lifetime of the
191378064Sume         * public address or TEMP_VALID_LIFETIME.
191478064Sume	 * The Preferred Lifetime is the lower of the Preferred Lifetime
191578064Sume         * of the public address or TEMP_PREFERRED_LIFETIME -
191678064Sume         * DESYNC_FACTOR.
191778064Sume	 */
1918151539Ssuz	if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) {
191978064Sume		vltime0 = IFA6_IS_INVALID(ia0) ? 0 :
1920151539Ssuz		    (ia0->ia6_lifetime.ia6t_vltime -
1921151539Ssuz		    (time_second - ia0->ia6_updatetime));
1922181803Sbz		if (vltime0 > V_ip6_temp_valid_lifetime)
1923181803Sbz			vltime0 = V_ip6_temp_valid_lifetime;
192478064Sume	} else
1925181803Sbz		vltime0 = V_ip6_temp_valid_lifetime;
1926151539Ssuz	if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) {
192778064Sume		pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 :
1928151539Ssuz		    (ia0->ia6_lifetime.ia6t_pltime -
1929151539Ssuz		    (time_second - ia0->ia6_updatetime));
1930181803Sbz		if (pltime0 > V_ip6_temp_preferred_lifetime - V_ip6_desync_factor){
1931181803Sbz			pltime0 = V_ip6_temp_preferred_lifetime -
1932181803Sbz			    V_ip6_desync_factor;
193378064Sume		}
193478064Sume	} else
1935181803Sbz		pltime0 = V_ip6_temp_preferred_lifetime - V_ip6_desync_factor;
193678064Sume	ifra.ifra_lifetime.ia6t_vltime = vltime0;
193778064Sume	ifra.ifra_lifetime.ia6t_pltime = pltime0;
193853541Sshin
193978064Sume	/*
194078064Sume	 * A temporary address is created only if this calculated Preferred
194178064Sume	 * Lifetime is greater than REGEN_ADVANCE time units.
194278064Sume	 */
1943181803Sbz	if (ifra.ifra_lifetime.ia6t_pltime <= V_ip6_temp_regen_advance)
1944120856Sume		return (0);
194553541Sshin
194678064Sume	/* XXX: scope zone ID? */
194778064Sume
194878064Sume	ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY);
194978064Sume
195078064Sume	/* allocate ifaddr structure, link into chain, etc. */
1951151539Ssuz	updateflags = 0;
1952151539Ssuz	if (delay)
1953151539Ssuz		updateflags |= IN6_IFAUPDATE_DADDELAY;
1954151539Ssuz	if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0)
1955120856Sume		return (error);
195678064Sume
195778064Sume	newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
195878064Sume	if (newia == NULL) {	/* XXX: can it happen? */
195978064Sume		nd6log((LOG_ERR,
196078064Sume		    "in6_tmpifadd: ifa update succeeded, but we got "
196178064Sume		    "no ifaddr\n"));
1962120856Sume		return (EINVAL); /* XXX */
196353541Sshin	}
196478064Sume	newia->ia6_ndpr = ia0->ia6_ndpr;
196578064Sume	newia->ia6_ndpr->ndpr_refcnt++;
196653541Sshin
196778407Sume	/*
196878407Sume	 * A newly added address might affect the status of other addresses.
196978407Sume	 * XXX: when the temporary address is generated with a new public
197078407Sume	 * address, the onlink check is redundant.  However, it would be safe
197178407Sume	 * to do the check explicitly everywhere a new address is generated,
197278407Sume	 * and, in fact, we surely need the check when we create a new
197378407Sume	 * temporary address due to deprecation of an old temporary address.
197478407Sume	 */
197578407Sume	pfxlist_onlink_check();
197678407Sume
1977120856Sume	return (0);
1978120941Sume}
197953541Sshin
1980151539Ssuzstatic int
198153541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr)
198253541Sshin{
198353541Sshin	if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
198453541Sshin		ndpr->ndpr_preferred = 0;
198553541Sshin	else
198653541Sshin		ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
198753541Sshin	if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
198853541Sshin		ndpr->ndpr_expire = 0;
198953541Sshin	else
199053541Sshin		ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
199153541Sshin
199253541Sshin	return 0;
199353541Sshin}
199453541Sshin
199553541Sshinstatic void
199678064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
199753541Sshin{
199878064Sume	/* init ia6t_expire */
199978064Sume	if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
200078064Sume		lt6->ia6t_expire = 0;
200178064Sume	else {
200278064Sume		lt6->ia6t_expire = time_second;
200378064Sume		lt6->ia6t_expire += lt6->ia6t_vltime;
200453541Sshin	}
200562587Sitojun
200653541Sshin	/* init ia6t_preferred */
200753541Sshin	if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
200853541Sshin		lt6->ia6t_preferred = 0;
200953541Sshin	else {
201053541Sshin		lt6->ia6t_preferred = time_second;
201153541Sshin		lt6->ia6t_preferred += lt6->ia6t_pltime;
201253541Sshin	}
201353541Sshin}
201453541Sshin
201553541Sshin/*
201653541Sshin * Delete all the routing table entries that use the specified gateway.
201753541Sshin * XXX: this function causes search through all entries of routing table, so
201853541Sshin * it shouldn't be called when acting as a router.
201953541Sshin */
202053541Sshinvoid
2021171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
202253541Sshin{
2023178888Sjulian
2024181803Sbz	struct radix_node_head *rnh = V_rt_tables[0][AF_INET6];
202553541Sshin	int s = splnet();
202653541Sshin
202753541Sshin	/* We'll care only link-local addresses */
202853541Sshin	if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
202953541Sshin		splx(s);
203053541Sshin		return;
203153541Sshin	}
203253541Sshin
2033108250Shsu	RADIX_NODE_HEAD_LOCK(rnh);
203453541Sshin	rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
2035108250Shsu	RADIX_NODE_HEAD_UNLOCK(rnh);
203653541Sshin	splx(s);
203753541Sshin}
203853541Sshin
203953541Sshinstatic int
2040171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg)
204153541Sshin{
204253541Sshin#define SIN6(s)	((struct sockaddr_in6 *)s)
204353541Sshin	struct rtentry *rt = (struct rtentry *)rn;
204453541Sshin	struct in6_addr *gate = (struct in6_addr *)arg;
204553541Sshin
204653541Sshin	if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
2047120856Sume		return (0);
204853541Sshin
2049120941Sume	if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) {
2050120856Sume		return (0);
2051120941Sume	}
205253541Sshin
205353541Sshin	/*
205478064Sume	 * Do not delete a static route.
205578064Sume	 * XXX: this seems to be a bit ad-hoc. Should we consider the
205678064Sume	 * 'cloned' bit instead?
205778064Sume	 */
205878064Sume	if ((rt->rt_flags & RTF_STATIC) != 0)
2059120856Sume		return (0);
206078064Sume
206178064Sume	/*
206253541Sshin	 * We delete only host route. This means, in particular, we don't
206353541Sshin	 * delete default route.
206453541Sshin	 */
206553541Sshin	if ((rt->rt_flags & RTF_HOST) == 0)
2066120856Sume		return (0);
206753541Sshin
2068120941Sume	return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
2069120941Sume	    rt_mask(rt), rt->rt_flags, 0));
207053541Sshin#undef SIN6
207153541Sshin}
207262587Sitojun
207362587Sitojunint
2074171259Sdelphijnd6_setdefaultiface(int ifindex)
207562587Sitojun{
207662587Sitojun	int error = 0;
207762587Sitojun
2078181803Sbz	if (ifindex < 0 || V_if_index < ifindex)
2079120856Sume		return (EINVAL);
2080151539Ssuz	if (ifindex != 0 && !ifnet_byindex(ifindex))
2081151539Ssuz		return (EINVAL);
208262587Sitojun
2083181803Sbz	if (V_nd6_defifindex != ifindex) {
2084181803Sbz		V_nd6_defifindex = ifindex;
2085181803Sbz		if (V_nd6_defifindex > 0)
2086181803Sbz			V_nd6_defifp = ifnet_byindex(V_nd6_defifindex);
208762587Sitojun		else
2088181803Sbz			V_nd6_defifp = NULL;
208962587Sitojun
209062587Sitojun		/*
209162587Sitojun		 * Our current implementation assumes one-to-one maping between
209262587Sitojun		 * interfaces and links, so it would be natural to use the
209362587Sitojun		 * default interface as the default link.
209462587Sitojun		 */
2095181803Sbz		scope6_setdefault(V_nd6_defifp);
209662587Sitojun	}
209762587Sitojun
2098120856Sume	return (error);
209962587Sitojun}
2100