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