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