nd6_rtr.c revision 151539
162587Sitojun/* $FreeBSD: head/sys/netinet6/nd6_rtr.c 151539 2005-10-21 16:23:01Z suz $ */ 278064Sume/* $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $ */ 362587Sitojun 4139826Simp/*- 553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 653541Sshin * All rights reserved. 753541Sshin * 853541Sshin * Redistribution and use in source and binary forms, with or without 953541Sshin * modification, are permitted provided that the following conditions 1053541Sshin * are met: 1153541Sshin * 1. Redistributions of source code must retain the above copyright 1253541Sshin * notice, this list of conditions and the following disclaimer. 1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1453541Sshin * notice, this list of conditions and the following disclaimer in the 1553541Sshin * documentation and/or other materials provided with the distribution. 1653541Sshin * 3. Neither the name of the project nor the names of its contributors 1753541Sshin * may be used to endorse or promote products derived from this software 1853541Sshin * without specific prior written permission. 1953541Sshin * 2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2353541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3053541Sshin * SUCH DAMAGE. 3153541Sshin */ 3253541Sshin 3362587Sitojun#include "opt_inet.h" 3462587Sitojun#include "opt_inet6.h" 3562587Sitojun 3653541Sshin#include <sys/param.h> 3753541Sshin#include <sys/systm.h> 3853541Sshin#include <sys/malloc.h> 3953541Sshin#include <sys/mbuf.h> 4053541Sshin#include <sys/socket.h> 4153541Sshin#include <sys/sockio.h> 4253541Sshin#include <sys/time.h> 4378064Sume#include <sys/kernel.h> 4453541Sshin#include <sys/errno.h> 4553541Sshin#include <sys/syslog.h> 4678064Sume#include <sys/queue.h> 4753541Sshin 4853541Sshin#include <net/if.h> 4953541Sshin#include <net/if_types.h> 5053541Sshin#include <net/if_dl.h> 5153541Sshin#include <net/route.h> 5253541Sshin#include <net/radix.h> 5353541Sshin 5453541Sshin#include <netinet/in.h> 5553541Sshin#include <netinet6/in6_var.h> 5678064Sume#include <netinet6/in6_ifattach.h> 5762587Sitojun#include <netinet/ip6.h> 5853541Sshin#include <netinet6/ip6_var.h> 5953541Sshin#include <netinet6/nd6.h> 6062587Sitojun#include <netinet/icmp6.h> 6162587Sitojun#include <netinet6/scope6_var.h> 6253541Sshin 6353541Sshin#include <net/net_osdep.h> 6453541Sshin 6562587Sitojun#define SDL(s) ((struct sockaddr_dl *)s) 6653541Sshin 67151539Ssuzstatic int rtpref __P((struct nd_defrouter *)); 6862587Sitojunstatic struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *)); 69151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *, 70151539Ssuz struct mbuf *, int)); 71151539Ssuzstatic struct in6_ifaddr *in6_ifadd __P((struct nd_prefixctl *, int)); 7262587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, 7378064Sume struct nd_defrouter *)); 7462587Sitojunstatic void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *)); 7562587Sitojunstatic void pfxrtr_del __P((struct nd_pfxrouter *)); 7662587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router 7778064Sume __P((struct nd_prefix *)); 78151539Ssuzstatic void defrouter_delreq __P((struct nd_defrouter *)); 7978064Sumestatic void nd6_rtmsg __P((int, struct rtentry *)); 8053541Sshin 81151539Ssuzstatic int in6_init_prefix_ltimes __P((struct nd_prefix *)); 82120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *, 83120941Sume struct in6_addrlifetime *)); 8453541Sshin 8562587Sitojunstatic int rt6_deleteroute __P((struct radix_node *, void *)); 8653541Sshin 8762587Sitojunextern int nd6_recalc_reachtm_interval; 8853541Sshin 8978064Sumestatic struct ifnet *nd6_defifp; 9062587Sitojunint nd6_defifindex; 9162587Sitojun 9278064Sumeint ip6_use_tempaddr = 0; 9378064Sume 9478064Sumeint ip6_desync_factor; 9578064Sumeu_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME; 9678064Sumeu_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME; 9753541Sshin/* 9878064Sume * shorter lifetimes for debugging purposes. 9978064Sumeint ip6_temp_preferred_lifetime = 800; 10078064Sumestatic int ip6_temp_valid_lifetime = 1800; 10178064Sume*/ 10278064Sumeint ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE; 10378064Sume 104151539Ssuz/* RTPREF_MEDIUM has to be 0! */ 105151539Ssuz#define RTPREF_HIGH 1 106151539Ssuz#define RTPREF_MEDIUM 0 107151539Ssuz#define RTPREF_LOW (-1) 108151539Ssuz#define RTPREF_RESERVED (-2) 109151539Ssuz#define RTPREF_INVALID (-3) /* internal */ 110151539Ssuz 11178064Sume/* 11253541Sshin * Receive Router Solicitation Message - just for routers. 11353541Sshin * Router solicitation/advertisement is mostly managed by userland program 11453541Sshin * (rtadvd) so here we have no function like nd6_ra_output(). 11553541Sshin * 11653541Sshin * Based on RFC 2461 11753541Sshin */ 11853541Sshinvoid 11953541Sshinnd6_rs_input(m, off, icmp6len) 12053541Sshin struct mbuf *m; 12153541Sshin int off, icmp6len; 12253541Sshin{ 12353541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 12453541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 12562587Sitojun struct nd_router_solicit *nd_rs; 12653541Sshin struct in6_addr saddr6 = ip6->ip6_src; 12753541Sshin char *lladdr = NULL; 12853541Sshin int lladdrlen = 0; 12953541Sshin union nd_opts ndopts; 13053541Sshin 13153541Sshin /* If I'm not a router, ignore it. */ 13253541Sshin if (ip6_accept_rtadv != 0 || ip6_forwarding != 1) 13362587Sitojun goto freeit; 13453541Sshin 13553541Sshin /* Sanity checks */ 13653541Sshin if (ip6->ip6_hlim != 255) { 13778064Sume nd6log((LOG_ERR, 13878064Sume "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 13978064Sume ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), 14078064Sume ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); 14178064Sume goto bad; 14253541Sshin } 14353541Sshin 14453541Sshin /* 14553541Sshin * Don't update the neighbor cache, if src = ::. 14653541Sshin * This indicates that the src has no IP address assigned yet. 14753541Sshin */ 14853541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 14962587Sitojun goto freeit; 15062587Sitojun 15162587Sitojun#ifndef PULLDOWN_TEST 15262587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 15362587Sitojun nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 15462587Sitojun#else 15562587Sitojun IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 15662587Sitojun if (nd_rs == NULL) { 15762587Sitojun icmp6stat.icp6s_tooshort++; 15853541Sshin return; 15962587Sitojun } 16062587Sitojun#endif 16153541Sshin 16253541Sshin icmp6len -= sizeof(*nd_rs); 16353541Sshin nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 16453541Sshin if (nd6_options(&ndopts) < 0) { 16578064Sume nd6log((LOG_INFO, 16678064Sume "nd6_rs_input: invalid ND option, ignored\n")); 16778064Sume /* nd6_options have incremented stats */ 16862587Sitojun goto freeit; 16953541Sshin } 17053541Sshin 17153541Sshin if (ndopts.nd_opts_src_lladdr) { 17253541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 17353541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 17453541Sshin } 17553541Sshin 17653541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 17778064Sume nd6log((LOG_INFO, 17853541Sshin "nd6_rs_input: lladdrlen mismatch for %s " 17953541Sshin "(if %d, RS packet %d)\n", 180120941Sume ip6_sprintf(&saddr6), 181120941Sume ifp->if_addrlen, lladdrlen - 2)); 18278064Sume goto bad; 18353541Sshin } 18453541Sshin 18553541Sshin nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 18662587Sitojun 18762587Sitojun freeit: 18862587Sitojun m_freem(m); 18978064Sume return; 19078064Sume 19178064Sume bad: 19278064Sume icmp6stat.icp6s_badrs++; 19378064Sume m_freem(m); 19453541Sshin} 19553541Sshin 19653541Sshin/* 19753541Sshin * Receive Router Advertisement Message. 19853541Sshin * 19953541Sshin * Based on RFC 2461 20053541Sshin * TODO: on-link bit on prefix information 20153541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 20253541Sshin */ 20353541Sshinvoid 20453541Sshinnd6_ra_input(m, off, icmp6len) 20553541Sshin struct mbuf *m; 20653541Sshin int off, icmp6len; 20753541Sshin{ 20853541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 209121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 21053541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 21162587Sitojun struct nd_router_advert *nd_ra; 21253541Sshin struct in6_addr saddr6 = ip6->ip6_src; 213151539Ssuz int mcast = 0; 21453541Sshin union nd_opts ndopts; 21553541Sshin struct nd_defrouter *dr; 21653541Sshin 217118498Sume /* 218118498Sume * We only accept RAs only when 219118498Sume * the system-wide variable allows the acceptance, and 220118498Sume * per-interface variable allows RAs on the receiving interface. 221118498Sume */ 22253541Sshin if (ip6_accept_rtadv == 0) 22362587Sitojun goto freeit; 224118498Sume if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 225118498Sume goto freeit; 22653541Sshin 22753541Sshin if (ip6->ip6_hlim != 255) { 22878064Sume nd6log((LOG_ERR, 22978064Sume "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 23078064Sume ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), 23178064Sume ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); 23278064Sume goto bad; 23353541Sshin } 23453541Sshin 23553541Sshin if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 23678064Sume nd6log((LOG_ERR, 23753541Sshin "nd6_ra_input: src %s is not link-local\n", 23878064Sume ip6_sprintf(&saddr6))); 23978064Sume goto bad; 24062587Sitojun } 24162587Sitojun 24262587Sitojun#ifndef PULLDOWN_TEST 24362587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 24462587Sitojun nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); 24562587Sitojun#else 24662587Sitojun IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); 24762587Sitojun if (nd_ra == NULL) { 24862587Sitojun icmp6stat.icp6s_tooshort++; 24953541Sshin return; 25053541Sshin } 25162587Sitojun#endif 25253541Sshin 25353541Sshin icmp6len -= sizeof(*nd_ra); 25453541Sshin nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 25553541Sshin if (nd6_options(&ndopts) < 0) { 25678064Sume nd6log((LOG_INFO, 25778064Sume "nd6_ra_input: invalid ND option, ignored\n")); 25878064Sume /* nd6_options have incremented stats */ 25962587Sitojun goto freeit; 26053541Sshin } 26153541Sshin 26253541Sshin { 26353541Sshin struct nd_defrouter dr0; 26453541Sshin u_int32_t advreachable = nd_ra->nd_ra_reachable; 26553541Sshin 266151539Ssuz /* remember if this is a multicasted advertisement */ 267151539Ssuz if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 268151539Ssuz mcast = 1; 269151539Ssuz 270151539Ssuz bzero(&dr0, sizeof(dr0)); 27153541Sshin dr0.rtaddr = saddr6; 27253541Sshin dr0.flags = nd_ra->nd_ra_flags_reserved; 273151539Ssuz if (rtpref(&dr0) == RTPREF_RESERVED) { 274151539Ssuz /* 275151539Ssuz * "reserved" router preference should be treated as 276151539Ssuz * 0-lifetime. Note that rtpref() covers the case that the 277151539Ssuz * kernel is not configured to support the preference 278151539Ssuz * extension. 279151539Ssuz */ 280151539Ssuz dr0.rtlifetime = 0; 281151539Ssuz } else 282151539Ssuz dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 28353541Sshin dr0.expire = time_second + dr0.rtlifetime; 28453541Sshin dr0.ifp = ifp; 28553541Sshin /* unspecified or not? (RFC 2461 6.3.4) */ 28653541Sshin if (advreachable) { 28790868Smike advreachable = ntohl(advreachable); 28853541Sshin if (advreachable <= MAX_REACHABLE_TIME && 28953541Sshin ndi->basereachable != advreachable) { 29053541Sshin ndi->basereachable = advreachable; 29153541Sshin ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 29253541Sshin ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */ 29353541Sshin } 29453541Sshin } 29553541Sshin if (nd_ra->nd_ra_retransmit) 29653541Sshin ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 29753541Sshin if (nd_ra->nd_ra_curhoplimit) 29853541Sshin ndi->chlim = nd_ra->nd_ra_curhoplimit; 29953541Sshin dr = defrtrlist_update(&dr0); 30053541Sshin } 30153541Sshin 30253541Sshin /* 30353541Sshin * prefix 30453541Sshin */ 30553541Sshin if (ndopts.nd_opts_pi) { 30653541Sshin struct nd_opt_hdr *pt; 30778064Sume struct nd_opt_prefix_info *pi = NULL; 308151539Ssuz struct nd_prefixctl pr; 30953541Sshin 31053541Sshin for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 31153541Sshin pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 31253541Sshin pt = (struct nd_opt_hdr *)((caddr_t)pt + 31353541Sshin (pt->nd_opt_len << 3))) { 31453541Sshin if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 31553541Sshin continue; 31653541Sshin pi = (struct nd_opt_prefix_info *)pt; 31753541Sshin 31853541Sshin if (pi->nd_opt_pi_len != 4) { 31978064Sume nd6log((LOG_INFO, 32078064Sume "nd6_ra_input: invalid option " 32178064Sume "len %d for prefix information option, " 32278064Sume "ignored\n", pi->nd_opt_pi_len)); 32353541Sshin continue; 32453541Sshin } 32553541Sshin 32653541Sshin if (128 < pi->nd_opt_pi_prefix_len) { 32778064Sume nd6log((LOG_INFO, 32878064Sume "nd6_ra_input: invalid prefix " 32978064Sume "len %d for prefix information option, " 33078064Sume "ignored\n", pi->nd_opt_pi_prefix_len)); 33153541Sshin continue; 33253541Sshin } 33353541Sshin 33453541Sshin if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 33553541Sshin || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 33678064Sume nd6log((LOG_INFO, 33778064Sume "nd6_ra_input: invalid prefix " 33878064Sume "%s, ignored\n", 33978064Sume ip6_sprintf(&pi->nd_opt_pi_prefix))); 34053541Sshin continue; 34153541Sshin } 34253541Sshin 34353541Sshin bzero(&pr, sizeof(pr)); 34453541Sshin pr.ndpr_prefix.sin6_family = AF_INET6; 34553541Sshin pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 34653541Sshin pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 34753541Sshin pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 34853541Sshin 34953541Sshin pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 350120941Sume ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 35153541Sshin pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 352120941Sume ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 35353541Sshin pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 35453541Sshin pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 355120941Sume pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); 356151539Ssuz (void)prelist_update(&pr, dr, m, mcast); 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); 452151539Ssuz if (rt->rt_ifp) { 453151539Ssuz info.rti_info[RTAX_IFP] = 454151539Ssuz TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 455151539Ssuz info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 456151539Ssuz } 45762587Sitojun 45862587Sitojun rt_missmsg(cmd, &info, rt->rt_flags, 0); 45962587Sitojun} 46062587Sitojun 46153541Sshinvoid 46253541Sshindefrouter_addreq(new) 46353541Sshin struct nd_defrouter *new; 46453541Sshin{ 46553541Sshin struct sockaddr_in6 def, mask, gate; 46662587Sitojun struct rtentry *newrt = NULL; 467151539Ssuz int s; 468151539Ssuz int error; 46953541Sshin 470128397Sluigi bzero(&def, sizeof(def)); 471128397Sluigi bzero(&mask, sizeof(mask)); 472128397Sluigi bzero(&gate, sizeof(gate)); 47353541Sshin 474120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 475120941Sume sizeof(struct sockaddr_in6); 476151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 47753541Sshin gate.sin6_addr = new->rtaddr; 47853541Sshin 479151539Ssuz s = splnet(); 480151539Ssuz error = rtrequest(RTM_ADD, (struct sockaddr *)&def, 481120941Sume (struct sockaddr *)&gate, (struct sockaddr *)&mask, 482120941Sume RTF_GATEWAY, &newrt); 48362587Sitojun if (newrt) { 484120727Ssam RT_LOCK(newrt); 48578064Sume nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 486122334Ssam RT_REMREF(newrt); 487120727Ssam RT_UNLOCK(newrt); 48862587Sitojun } 489151539Ssuz if (error == 0) 490151539Ssuz new->installed = 1; 491151539Ssuz splx(s); 49253541Sshin return; 49353541Sshin} 49453541Sshin 49553541Sshinstruct nd_defrouter * 49653541Sshindefrouter_lookup(addr, ifp) 49753541Sshin struct in6_addr *addr; 49853541Sshin struct ifnet *ifp; 49953541Sshin{ 50053541Sshin struct nd_defrouter *dr; 50153541Sshin 50262587Sitojun for (dr = TAILQ_FIRST(&nd_defrouter); dr; 50362587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 50453541Sshin if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 505120856Sume return (dr); 50662587Sitojun } 50753541Sshin 508120856Sume return (NULL); /* search failed */ 50953541Sshin} 51053541Sshin 511151539Ssuz/* 512151539Ssuz * Remove the default route for a given router. 513151539Ssuz * This is just a subroutine function for defrouter_select(), and should 514151539Ssuz * not be called from anywhere else. 515151539Ssuz */ 516151539Ssuzstatic void 517151539Ssuzdefrouter_delreq(dr) 51853541Sshin struct nd_defrouter *dr; 51953541Sshin{ 52053541Sshin struct sockaddr_in6 def, mask, gate; 52162587Sitojun struct rtentry *oldrt = NULL; 52253541Sshin 523128397Sluigi bzero(&def, sizeof(def)); 524128397Sluigi bzero(&mask, sizeof(mask)); 525128397Sluigi bzero(&gate, sizeof(gate)); 52653541Sshin 527120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 528120941Sume sizeof(struct sockaddr_in6); 529151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 53053541Sshin gate.sin6_addr = dr->rtaddr; 53153541Sshin 53253541Sshin rtrequest(RTM_DELETE, (struct sockaddr *)&def, 533120941Sume (struct sockaddr *)&gate, 534120941Sume (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); 53562587Sitojun if (oldrt) { 53678064Sume nd6_rtmsg(RTM_DELETE, oldrt); 537108269Sru RTFREE(oldrt); 53862587Sitojun } 53953541Sshin 540151539Ssuz dr->installed = 0; 54153541Sshin} 54253541Sshin 543151539Ssuz/* 544151539Ssuz * remove all default routes from default router list 545151539Ssuz */ 54653541Sshinvoid 547151539Ssuzdefrouter_reset() 548151539Ssuz{ 549151539Ssuz struct nd_defrouter *dr; 550151539Ssuz 551151539Ssuz for (dr = TAILQ_FIRST(&nd_defrouter); dr; 552151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) 553151539Ssuz defrouter_delreq(dr); 554151539Ssuz 555151539Ssuz /* 556151539Ssuz * XXX should we also nuke any default routers in the kernel, by 557151539Ssuz * going through them by rtalloc1()? 558151539Ssuz */ 559151539Ssuz} 560151539Ssuz 561151539Ssuzvoid 56253541Sshindefrtrlist_del(dr) 56353541Sshin struct nd_defrouter *dr; 56453541Sshin{ 56553541Sshin struct nd_defrouter *deldr = NULL; 56653541Sshin struct nd_prefix *pr; 56753541Sshin 56853541Sshin /* 56953541Sshin * Flush all the routing table entries that use the router 57053541Sshin * as a next hop. 57153541Sshin */ 572120941Sume if (!ip6_forwarding && ip6_accept_rtadv) /* XXX: better condition? */ 57353541Sshin rt6_flush(&dr->rtaddr, dr->ifp); 57453541Sshin 575151539Ssuz if (dr->installed) { 576151539Ssuz deldr = dr; 577151539Ssuz defrouter_delreq(dr); 578151539Ssuz } 57962587Sitojun TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 58053541Sshin 58153541Sshin /* 58253541Sshin * Also delete all the pointers to the router in each prefix lists. 58353541Sshin */ 58462587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 58553541Sshin struct nd_pfxrouter *pfxrtr; 58653541Sshin if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 58753541Sshin pfxrtr_del(pfxrtr); 58853541Sshin } 58953541Sshin pfxlist_onlink_check(); 59053541Sshin 59153541Sshin /* 59262587Sitojun * If the router is the primary one, choose a new one. 59362587Sitojun * Note that defrouter_select() will remove the current gateway 59462587Sitojun * from the routing table. 59553541Sshin */ 59653541Sshin if (deldr) 59762587Sitojun defrouter_select(); 59862587Sitojun 59953541Sshin free(dr, M_IP6NDP); 60053541Sshin} 60153541Sshin 60262587Sitojun/* 603151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and 604151539Ssuz * draft-ietf-ipngwg-router-selection: 605151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred. 606151539Ssuz * If we have more than one (probably) reachable router, prefer ones 607151539Ssuz * with the highest router preference. 60862587Sitojun * 2) When no routers on the list are known to be reachable or 60962587Sitojun * probably reachable, routers SHOULD be selected in a round-robin 610151539Ssuz * fashion, regardless of router preference values. 61162587Sitojun * 3) If the Default Router List is empty, assume that all 61262587Sitojun * destinations are on-link. 613151539Ssuz * 614151539Ssuz * We assume nd_defrouter is sorted by router preference value. 615151539Ssuz * Since the code below covers both with and without router preference cases, 616151539Ssuz * we do not need to classify the cases by ifdef. 617151539Ssuz * 618151539Ssuz * At this moment, we do not try to install more than one default router, 619151539Ssuz * even when the multipath routing is available, because we're not sure about 620151539Ssuz * the benefits for stub hosts comparing to the risk of making the code 621151539Ssuz * complicated and the possibility of introducing bugs. 62262587Sitojun */ 62362587Sitojunvoid 62462587Sitojundefrouter_select() 62562587Sitojun{ 62662587Sitojun int s = splnet(); 627151539Ssuz struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; 62862587Sitojun struct rtentry *rt = NULL; 62962587Sitojun struct llinfo_nd6 *ln = NULL; 63062587Sitojun 63162587Sitojun /* 632151539Ssuz * This function should be called only when acting as an autoconfigured 633151539Ssuz * host. Although the remaining part of this function is not effective 634151539Ssuz * if the node is not an autoconfigured host, we explicitly exclude 635151539Ssuz * such cases here for safety. 636151539Ssuz */ 637151539Ssuz if (ip6_forwarding || !ip6_accept_rtadv) { 638151539Ssuz nd6log((LOG_WARNING, 639151539Ssuz "defrouter_select: called unexpectedly (forwarding=%d, " 640151539Ssuz "accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv)); 641151539Ssuz splx(s); 642151539Ssuz return; 643151539Ssuz } 644151539Ssuz 645151539Ssuz /* 646151539Ssuz * Let's handle easy case (3) first: 647151539Ssuz * If default router list is empty, there's nothing to be done. 648151539Ssuz */ 649151539Ssuz if (!TAILQ_FIRST(&nd_defrouter)) { 650151539Ssuz splx(s); 651151539Ssuz return; 652151539Ssuz } 653151539Ssuz 654151539Ssuz /* 65562587Sitojun * Search for a (probably) reachable router from the list. 656151539Ssuz * We just pick up the first reachable one (if any), assuming that 657151539Ssuz * the ordering rule of the list described in defrtrlist_update(). 65862587Sitojun */ 65962587Sitojun for (dr = TAILQ_FIRST(&nd_defrouter); dr; 66062587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 661151539Ssuz if (selected_dr == NULL && 662151539Ssuz (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && 66362587Sitojun (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 66462587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) { 665151539Ssuz selected_dr = dr; 66662587Sitojun } 66762587Sitojun 668151539Ssuz if (dr->installed && installed_dr == NULL) 669151539Ssuz installed_dr = dr; 670151539Ssuz else if (dr->installed && installed_dr) { 671151539Ssuz /* this should not happen. warn for diagnosis. */ 672151539Ssuz log(LOG_ERR, "defrouter_select: more than one router" 673151539Ssuz " is installed\n"); 67462587Sitojun } 67562587Sitojun } 676151539Ssuz /* 677151539Ssuz * If none of the default routers was found to be reachable, 678151539Ssuz * round-robin the list regardless of preference. 679151539Ssuz * Otherwise, if we have an installed router, check if the selected 680151539Ssuz * (reachable) router should really be preferred to the installed one. 681151539Ssuz * We only prefer the new router when the old one is not reachable 682151539Ssuz * or when the new one has a really higher preference value. 683151539Ssuz */ 684151539Ssuz if (selected_dr == NULL) { 685151539Ssuz if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry)) 686151539Ssuz selected_dr = TAILQ_FIRST(&nd_defrouter); 687151539Ssuz else 688151539Ssuz selected_dr = TAILQ_NEXT(installed_dr, dr_entry); 689151539Ssuz } else if (installed_dr && 690151539Ssuz (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && 691151539Ssuz (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 692151539Ssuz ND6_IS_LLINFO_PROBREACH(ln) && 693151539Ssuz rtpref(selected_dr) <= rtpref(installed_dr)) { 694151539Ssuz selected_dr = installed_dr; 695151539Ssuz } 69662587Sitojun 697151539Ssuz /* 698151539Ssuz * If the selected router is different than the installed one, 699151539Ssuz * remove the installed router and install the selected one. 700151539Ssuz * Note that the selected router is never NULL here. 701151539Ssuz */ 702151539Ssuz if (installed_dr != selected_dr) { 703151539Ssuz if (installed_dr) 704151539Ssuz defrouter_delreq(installed_dr); 705151539Ssuz defrouter_addreq(selected_dr); 706151539Ssuz } 707151539Ssuz 70862587Sitojun splx(s); 70962587Sitojun return; 71062587Sitojun} 71162587Sitojun 712151539Ssuz/* 713151539Ssuz * for default router selection 714151539Ssuz * regards router-preference field as a 2-bit signed integer 715151539Ssuz */ 716151539Ssuzstatic int 717151539Ssuzrtpref(struct nd_defrouter *dr) 718151539Ssuz{ 719151539Ssuz switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) { 720151539Ssuz case ND_RA_FLAG_RTPREF_HIGH: 721151539Ssuz return (RTPREF_HIGH); 722151539Ssuz case ND_RA_FLAG_RTPREF_MEDIUM: 723151539Ssuz return (RTPREF_MEDIUM); 724151539Ssuz case ND_RA_FLAG_RTPREF_RSV: 725151539Ssuz return (RTPREF_RESERVED); 726151539Ssuz case ND_RA_FLAG_RTPREF_LOW: 727151539Ssuz return (RTPREF_LOW); 728151539Ssuz default: 729151539Ssuz /* 730151539Ssuz * This case should never happen. If it did, it would mean a 731151539Ssuz * serious bug of kernel internal. We thus always bark here. 732151539Ssuz * Or, can we even panic? 733151539Ssuz */ 734151539Ssuz log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags); 735151539Ssuz return (RTPREF_INVALID); 736151539Ssuz } 737151539Ssuz /* NOTREACHED */ 738151539Ssuz} 739151539Ssuz 74053541Sshinstatic struct nd_defrouter * 74153541Sshindefrtrlist_update(new) 74253541Sshin struct nd_defrouter *new; 74353541Sshin{ 74453541Sshin struct nd_defrouter *dr, *n; 74553541Sshin int s = splnet(); 74653541Sshin 74753541Sshin if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 74853541Sshin /* entry exists */ 74953541Sshin if (new->rtlifetime == 0) { 75053541Sshin defrtrlist_del(dr); 75153541Sshin dr = NULL; 75253541Sshin } else { 753151539Ssuz int oldpref = rtpref(dr); 754151539Ssuz 75553541Sshin /* override */ 75653541Sshin dr->flags = new->flags; /* xxx flag check */ 75753541Sshin dr->rtlifetime = new->rtlifetime; 75853541Sshin dr->expire = new->expire; 759151539Ssuz 760151539Ssuz /* 761151539Ssuz * If the preference does not change, there's no need 762151539Ssuz * to sort the entries. 763151539Ssuz */ 764151539Ssuz if (rtpref(new) == oldpref) { 765151539Ssuz splx(s); 766151539Ssuz return (dr); 767151539Ssuz } 768151539Ssuz 769151539Ssuz /* 770151539Ssuz * preferred router may be changed, so relocate 771151539Ssuz * this router. 772151539Ssuz * XXX: calling TAILQ_REMOVE directly is a bad manner. 773151539Ssuz * However, since defrtrlist_del() has many side 774151539Ssuz * effects, we intentionally do so here. 775151539Ssuz * defrouter_select() below will handle routing 776151539Ssuz * changes later. 777151539Ssuz */ 778151539Ssuz TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 779151539Ssuz n = dr; 780151539Ssuz goto insert; 78153541Sshin } 78253541Sshin splx(s); 783120856Sume return (dr); 78453541Sshin } 78553541Sshin 78653541Sshin /* entry does not exist */ 78753541Sshin if (new->rtlifetime == 0) { 78853541Sshin splx(s); 789120856Sume return (NULL); 79053541Sshin } 79153541Sshin 79253541Sshin n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 79353541Sshin if (n == NULL) { 79453541Sshin splx(s); 795120856Sume return (NULL); 79653541Sshin } 79753541Sshin bzero(n, sizeof(*n)); 79853541Sshin *n = *new; 79962587Sitojun 800151539Ssuzinsert: 80162587Sitojun /* 802151539Ssuz * Insert the new router in the Default Router List; 803151539Ssuz * The Default Router List should be in the descending order 804151539Ssuz * of router-preferece. Routers with the same preference are 805151539Ssuz * sorted in the arriving time order. 80662587Sitojun */ 807151539Ssuz 808151539Ssuz /* insert at the end of the group */ 809151539Ssuz for (dr = TAILQ_FIRST(&nd_defrouter); dr; 810151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 811151539Ssuz if (rtpref(n) > rtpref(dr)) 812151539Ssuz break; 813151539Ssuz } 814151539Ssuz if (dr) 815151539Ssuz TAILQ_INSERT_BEFORE(dr, n, dr_entry); 816151539Ssuz else 817151539Ssuz TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry); 818151539Ssuz 819151539Ssuz defrouter_select(); 820151539Ssuz 82153541Sshin splx(s); 822120941Sume 823120856Sume return (n); 82453541Sshin} 82553541Sshin 82653541Sshinstatic struct nd_pfxrouter * 82753541Sshinpfxrtr_lookup(pr, dr) 82853541Sshin struct nd_prefix *pr; 82953541Sshin struct nd_defrouter *dr; 83053541Sshin{ 83153541Sshin struct nd_pfxrouter *search; 832120941Sume 83362587Sitojun for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { 83453541Sshin if (search->router == dr) 83553541Sshin break; 83653541Sshin } 83753541Sshin 838120856Sume return (search); 83953541Sshin} 84053541Sshin 84153541Sshinstatic void 84253541Sshinpfxrtr_add(pr, dr) 84353541Sshin struct nd_prefix *pr; 84453541Sshin struct nd_defrouter *dr; 84553541Sshin{ 84653541Sshin struct nd_pfxrouter *new; 84753541Sshin 84853541Sshin new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 84953541Sshin if (new == NULL) 85053541Sshin return; 85153541Sshin bzero(new, sizeof(*new)); 85253541Sshin new->router = dr; 85353541Sshin 85453541Sshin LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 85553541Sshin 85653541Sshin pfxlist_onlink_check(); 85753541Sshin} 85853541Sshin 85953541Sshinstatic void 86053541Sshinpfxrtr_del(pfr) 86153541Sshin struct nd_pfxrouter *pfr; 86253541Sshin{ 86353541Sshin LIST_REMOVE(pfr, pfr_entry); 86453541Sshin free(pfr, M_IP6NDP); 86553541Sshin} 86653541Sshin 86778064Sumestruct nd_prefix * 868151539Ssuznd6_prefix_lookup(key) 869151539Ssuz struct nd_prefixctl *key; 87053541Sshin{ 87153541Sshin struct nd_prefix *search; 87253541Sshin 87362587Sitojun for (search = nd_prefix.lh_first; search; search = search->ndpr_next) { 874151539Ssuz if (key->ndpr_ifp == search->ndpr_ifp && 875151539Ssuz key->ndpr_plen == search->ndpr_plen && 876151539Ssuz in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr, 877151539Ssuz &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) { 87853541Sshin break; 87953541Sshin } 88053541Sshin } 88153541Sshin 882120856Sume return (search); 88353541Sshin} 88453541Sshin 88578064Sumeint 88678064Sumend6_prelist_add(pr, dr, newp) 887151539Ssuz struct nd_prefixctl *pr; 888151539Ssuz struct nd_prefix **newp; 88953541Sshin struct nd_defrouter *dr; 89053541Sshin{ 89178064Sume struct nd_prefix *new = NULL; 892151539Ssuz int error = 0; 89353541Sshin int i, s; 89453541Sshin 89553541Sshin new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 89653541Sshin if (new == NULL) 897120941Sume return(ENOMEM); 89853541Sshin bzero(new, sizeof(*new)); 899151539Ssuz new->ndpr_ifp = pr->ndpr_ifp; 900151539Ssuz new->ndpr_prefix = pr->ndpr_prefix; 901151539Ssuz new->ndpr_plen = pr->ndpr_plen; 902151539Ssuz new->ndpr_vltime = pr->ndpr_vltime; 903151539Ssuz new->ndpr_pltime = pr->ndpr_pltime; 904151539Ssuz new->ndpr_flags = pr->ndpr_flags; 905151539Ssuz if ((error = in6_init_prefix_ltimes(new)) != 0) { 906151539Ssuz free(new, M_IP6NDP); 907151539Ssuz return(error); 908151539Ssuz } 909151539Ssuz new->ndpr_lastupdate = time_second; 91078064Sume if (newp != NULL) 91178064Sume *newp = new; 91253541Sshin 913120941Sume /* initialization */ 91453541Sshin LIST_INIT(&new->ndpr_advrtrs); 91553541Sshin in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 91653541Sshin /* make prefix in the canonical form */ 91753541Sshin for (i = 0; i < 4; i++) 91853541Sshin new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 919120941Sume new->ndpr_mask.s6_addr32[i]; 92053541Sshin 92153541Sshin s = splnet(); 92253541Sshin /* link ndpr_entry to nd_prefix list */ 92353541Sshin LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry); 92453541Sshin splx(s); 92553541Sshin 92678064Sume /* ND_OPT_PI_FLAG_ONLINK processing */ 92778064Sume if (new->ndpr_raf_onlink) { 92878064Sume int e; 92978064Sume 93078064Sume if ((e = nd6_prefix_onlink(new)) != 0) { 93178064Sume nd6log((LOG_ERR, "nd6_prelist_add: failed to make " 93278064Sume "the prefix %s/%d on-link on %s (errno=%d)\n", 93378064Sume ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 93478064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 93578064Sume /* proceed anyway. XXX: is it correct? */ 93678064Sume } 93778064Sume } 93878064Sume 939120941Sume if (dr) 94053541Sshin pfxrtr_add(new, dr); 94153541Sshin 94253541Sshin return 0; 94353541Sshin} 94453541Sshin 94553541Sshinvoid 94653541Sshinprelist_remove(pr) 94753541Sshin struct nd_prefix *pr; 94853541Sshin{ 94953541Sshin struct nd_pfxrouter *pfr, *next; 95078064Sume int e, s; 95153541Sshin 95278064Sume /* make sure to invalidate the prefix until it is really freed. */ 95378064Sume pr->ndpr_vltime = 0; 95478064Sume pr->ndpr_pltime = 0; 955151539Ssuz 95678064Sume /* 95778064Sume * Though these flags are now meaningless, we'd rather keep the value 958151479Ssuz * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users 959151479Ssuz * when executing "ndp -p". 96078064Sume */ 961151479Ssuz 96278064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && 96378064Sume (e = nd6_prefix_offlink(pr)) != 0) { 96478064Sume nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " 96578064Sume "on %s, errno=%d\n", 96678064Sume ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 96778064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 96878064Sume /* what should we do? */ 96978064Sume } 97078064Sume 97178064Sume if (pr->ndpr_refcnt > 0) 97278064Sume return; /* notice here? */ 97378064Sume 97453541Sshin s = splnet(); 97578064Sume 97653541Sshin /* unlink ndpr_entry from nd_prefix list */ 97753541Sshin LIST_REMOVE(pr, ndpr_entry); 97853541Sshin 97953541Sshin /* free list of routers that adversed the prefix */ 98062587Sitojun for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { 98162587Sitojun next = pfr->pfr_next; 98253541Sshin 98353541Sshin free(pfr, M_IP6NDP); 98453541Sshin } 98578064Sume splx(s); 98678064Sume 98753541Sshin free(pr, M_IP6NDP); 98853541Sshin 98953541Sshin pfxlist_onlink_check(); 99053541Sshin} 99153541Sshin 992151539Ssuzstatic int 993151539Ssuzprelist_update(new, dr, m, mcast) 994151539Ssuz struct nd_prefixctl *new; 99553541Sshin struct nd_defrouter *dr; /* may be NULL */ 99653541Sshin struct mbuf *m; 997151539Ssuz int mcast; 99853541Sshin{ 99978064Sume struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 100078064Sume struct ifaddr *ifa; 100178064Sume struct ifnet *ifp = new->ndpr_ifp; 100253541Sshin struct nd_prefix *pr; 100353541Sshin int s = splnet(); 100453541Sshin int error = 0; 100578064Sume int newprefix = 0; 100653541Sshin int auth; 100778064Sume struct in6_addrlifetime lt6_tmp; 100853541Sshin 100953541Sshin auth = 0; 101053541Sshin if (m) { 101153541Sshin /* 101253541Sshin * Authenticity for NA consists authentication for 101353541Sshin * both IP header and IP datagrams, doesn't it ? 101453541Sshin */ 101553541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 1016120941Sume auth = ((m->m_flags & M_AUTHIPHDR) && 1017120941Sume (m->m_flags & M_AUTHIPDGM)); 101853541Sshin#endif 101953541Sshin } 102053541Sshin 102178064Sume if ((pr = nd6_prefix_lookup(new)) != NULL) { 102278064Sume /* 102378064Sume * nd6_prefix_lookup() ensures that pr and new have the same 102478064Sume * prefix on a same interface. 102578064Sume */ 102653541Sshin 102753541Sshin /* 102878064Sume * Update prefix information. Note that the on-link (L) bit 102978064Sume * and the autonomous (A) bit should NOT be changed from 1 103078064Sume * to 0. 103153541Sshin */ 103278064Sume if (new->ndpr_raf_onlink == 1) 103378064Sume pr->ndpr_raf_onlink = 1; 103478064Sume if (new->ndpr_raf_auto == 1) 103578064Sume pr->ndpr_raf_auto = 1; 103678064Sume if (new->ndpr_raf_onlink) { 103778064Sume pr->ndpr_vltime = new->ndpr_vltime; 103878064Sume pr->ndpr_pltime = new->ndpr_pltime; 1039151539Ssuz (void)in6_init_prefix_ltimes(pr); /* XXX error case? */ 1040151539Ssuz pr->ndpr_lastupdate = time_second; 104178064Sume } 104253541Sshin 104378064Sume if (new->ndpr_raf_onlink && 104478064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 104578064Sume int e; 104653541Sshin 104778064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 104878064Sume nd6log((LOG_ERR, 104978064Sume "prelist_update: failed to make " 105078064Sume "the prefix %s/%d on-link on %s " 105178064Sume "(errno=%d)\n", 105278064Sume ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 105378064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 105478064Sume /* proceed anyway. XXX: is it correct? */ 105553541Sshin } 105678064Sume } 105753541Sshin 105878064Sume if (dr && pfxrtr_lookup(pr, dr) == NULL) 105978064Sume pfxrtr_add(pr, dr); 106078064Sume } else { 106178064Sume struct nd_prefix *newpr = NULL; 106253541Sshin 106378064Sume newprefix = 1; 106453541Sshin 106578064Sume if (new->ndpr_vltime == 0) 106678064Sume goto end; 106778064Sume if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 106878064Sume goto end; 106953541Sshin 107078064Sume error = nd6_prelist_add(new, dr, &newpr); 107178064Sume if (error != 0 || newpr == NULL) { 107278064Sume nd6log((LOG_NOTICE, "prelist_update: " 107378064Sume "nd6_prelist_add failed for %s/%d on %s " 107478064Sume "errno=%d, returnpr=%p\n", 107578064Sume ip6_sprintf(&new->ndpr_prefix.sin6_addr), 1076120941Sume new->ndpr_plen, if_name(new->ndpr_ifp), 1077120941Sume error, newpr)); 107878064Sume goto end; /* we should just give up in this case. */ 107978064Sume } 108053541Sshin 108178064Sume /* 108278064Sume * XXX: from the ND point of view, we can ignore a prefix 108378064Sume * with the on-link bit being zero. However, we need a 108478064Sume * prefix structure for references from autoconfigured 1085120941Sume * addresses. Thus, we explicitly make sure that the prefix 108678064Sume * itself expires now. 108778064Sume */ 108878064Sume if (newpr->ndpr_raf_onlink == 0) { 108978064Sume newpr->ndpr_vltime = 0; 109078064Sume newpr->ndpr_pltime = 0; 109178064Sume in6_init_prefix_ltimes(newpr); 109253541Sshin } 109353541Sshin 109478064Sume pr = newpr; 109578064Sume } 109653541Sshin 109778064Sume /* 109878064Sume * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 109978064Sume * Note that pr must be non NULL at this point. 110078064Sume */ 110162587Sitojun 110278064Sume /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 110378064Sume if (!new->ndpr_raf_auto) 1104151539Ssuz goto end; 110562587Sitojun 110678064Sume /* 110778064Sume * 5.5.3 (b). the link-local prefix should have been ignored in 110878064Sume * nd6_ra_input. 110978064Sume */ 111062587Sitojun 1111151539Ssuz /* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */ 1112151539Ssuz if (new->ndpr_pltime > new->ndpr_vltime) { 1113151539Ssuz error = EINVAL; /* XXX: won't be used */ 1114151539Ssuz goto end; 1115151539Ssuz } 111662587Sitojun 111778064Sume /* 1118151539Ssuz * 5.5.3 (d). If the prefix advertised is not equal to the prefix of 1119151539Ssuz * an address configured by stateless autoconfiguration already in the 1120151539Ssuz * list of addresses associated with the interface, and the Valid 1121151539Ssuz * Lifetime is not 0, form an address. We first check if we have 1122151539Ssuz * a matching prefix. 1123151539Ssuz * Note: we apply a clarification in rfc2462bis-02 here. We only 1124151539Ssuz * consider autoconfigured addresses while RFC2462 simply said 1125151539Ssuz * "address". 112678064Sume */ 1127120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 112878064Sume struct in6_ifaddr *ifa6; 1129151539Ssuz u_int32_t remaininglifetime; 113053541Sshin 113178064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 113278064Sume continue; 113353541Sshin 113478064Sume ifa6 = (struct in6_ifaddr *)ifa; 113553541Sshin 113653541Sshin /* 1137151539Ssuz * We only consider autoconfigured addresses as per rfc2462bis. 1138151539Ssuz */ 1139151539Ssuz if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF)) 1140151539Ssuz continue; 1141151539Ssuz 1142151539Ssuz /* 114378064Sume * Spec is not clear here, but I believe we should concentrate 114478064Sume * on unicast (i.e. not anycast) addresses. 114578064Sume * XXX: other ia6_flags? detached or duplicated? 114653541Sshin */ 114778064Sume if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 114878064Sume continue; 1149120941Sume 1150151539Ssuz /* 1151151539Ssuz * Ignore the address if it is not associated with a prefix 1152151539Ssuz * or is associated with a prefix that is different from this 1153151539Ssuz * one. (pr is never NULL here) 1154151539Ssuz */ 1155151539Ssuz if (ifa6->ia6_ndpr != pr) 115678064Sume continue; 115753541Sshin 115878064Sume if (ia6_match == NULL) /* remember the first one */ 115978064Sume ia6_match = ifa6; 116078064Sume 116178064Sume /* 116278064Sume * An already autoconfigured address matched. Now that we 116378064Sume * are sure there is at least one matched address, we can 116478064Sume * proceed to 5.5.3. (e): update the lifetimes according to the 116578064Sume * "two hours" rule and the privacy extension. 1166151539Ssuz * We apply some clarifications in rfc2462bis: 1167151539Ssuz * - use remaininglifetime instead of storedlifetime as a 1168151539Ssuz * variable name 1169151539Ssuz * - remove the dead code in the "two-hour" rule 117078064Sume */ 117178064Sume#define TWOHOUR (120*60) 117278064Sume lt6_tmp = ifa6->ia6_lifetime; 117378064Sume 1174112678Sume if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 1175151539Ssuz remaininglifetime = ND6_INFINITE_LIFETIME; 1176151539Ssuz else if (time_second - ifa6->ia6_updatetime > 1177151539Ssuz lt6_tmp.ia6t_vltime) { 1178151539Ssuz /* 1179151539Ssuz * The case of "invalid" address. We should usually 1180151539Ssuz * not see this case. 1181151539Ssuz */ 1182151539Ssuz remaininglifetime = 0; 1183151539Ssuz } else 1184151539Ssuz remaininglifetime = lt6_tmp.ia6t_vltime - 1185151539Ssuz (time_second - ifa6->ia6_updatetime); 118678064Sume 1187112678Sume /* when not updating, keep the current stored lifetime. */ 1188151539Ssuz lt6_tmp.ia6t_vltime = remaininglifetime; 1189112678Sume 119078064Sume if (TWOHOUR < new->ndpr_vltime || 1191151539Ssuz remaininglifetime < new->ndpr_vltime) { 119278064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 1193151539Ssuz } else if (remaininglifetime <= TWOHOUR) { 119478064Sume if (auth) { 119578064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 119678064Sume } 119778064Sume } else { 119878064Sume /* 119978064Sume * new->ndpr_vltime <= TWOHOUR && 1200151539Ssuz * TWOHOUR < remaininglifetime 120178064Sume */ 120278064Sume lt6_tmp.ia6t_vltime = TWOHOUR; 120353541Sshin } 120453541Sshin 120578064Sume /* The 2 hour rule is not imposed for preferred lifetime. */ 120678064Sume lt6_tmp.ia6t_pltime = new->ndpr_pltime; 120753541Sshin 120878064Sume in6_init_address_ltimes(pr, <6_tmp); 120953541Sshin 1210151539Ssuz /* 1211151539Ssuz * We need to treat lifetimes for temporary addresses 1212151539Ssuz * differently, according to 1213151539Ssuz * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1); 1214151539Ssuz * we only update the lifetimes when they are in the maximum 1215151539Ssuz * intervals. 1216151539Ssuz */ 1217151539Ssuz if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 1218151539Ssuz u_int32_t maxvltime, maxpltime; 1219151539Ssuz 1220151539Ssuz if (ip6_temp_valid_lifetime > 1221151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1222151539Ssuz ip6_desync_factor)) { 1223151539Ssuz maxvltime = ip6_temp_valid_lifetime - 1224151539Ssuz (time_second - ifa6->ia6_createtime) - 1225151539Ssuz ip6_desync_factor; 1226151539Ssuz } else 1227151539Ssuz maxvltime = 0; 1228151539Ssuz if (ip6_temp_preferred_lifetime > 1229151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1230151539Ssuz ip6_desync_factor)) { 1231151539Ssuz maxpltime = ip6_temp_preferred_lifetime - 1232151539Ssuz (time_second - ifa6->ia6_createtime) - 1233151539Ssuz ip6_desync_factor; 1234151539Ssuz } else 1235151539Ssuz maxpltime = 0; 1236151539Ssuz 1237151539Ssuz if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME || 1238151539Ssuz lt6_tmp.ia6t_vltime > maxvltime) { 1239151539Ssuz lt6_tmp.ia6t_vltime = maxvltime; 124078064Sume } 1241151539Ssuz if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || 1242151539Ssuz lt6_tmp.ia6t_pltime > maxpltime) { 1243151539Ssuz lt6_tmp.ia6t_pltime = maxpltime; 124478064Sume } 124578064Sume } 124678064Sume ifa6->ia6_lifetime = lt6_tmp; 1247151539Ssuz ifa6->ia6_updatetime = time_second; 124853541Sshin } 124978064Sume if (ia6_match == NULL && new->ndpr_vltime) { 1250151539Ssuz int ifidlen; 1251151539Ssuz 125278064Sume /* 1253151539Ssuz * 5.5.3 (d) (continued) 125478064Sume * No address matched and the valid lifetime is non-zero. 125578064Sume * Create a new address. 125678064Sume */ 1257151539Ssuz 1258151539Ssuz /* 1259151539Ssuz * Prefix Length check: 1260151539Ssuz * If the sum of the prefix length and interface identifier 1261151539Ssuz * length does not equal 128 bits, the Prefix Information 1262151539Ssuz * option MUST be ignored. The length of the interface 1263151539Ssuz * identifier is defined in a separate link-type specific 1264151539Ssuz * document. 1265151539Ssuz */ 1266151539Ssuz ifidlen = in6_if2idlen(ifp); 1267151539Ssuz if (ifidlen < 0) { 1268151539Ssuz /* this should not happen, so we always log it. */ 1269151539Ssuz log(LOG_ERR, "prelist_update: IFID undefined (%s)\n", 1270151539Ssuz if_name(ifp)); 1271151539Ssuz goto end; 1272151539Ssuz } 1273151539Ssuz if (ifidlen + pr->ndpr_plen != 128) { 1274151539Ssuz nd6log((LOG_INFO, 1275151539Ssuz "prelist_update: invalid prefixlen " 1276151539Ssuz "%d for %s, ignored\n", 1277151539Ssuz pr->ndpr_plen, if_name(ifp))); 1278151539Ssuz goto end; 1279151539Ssuz } 1280151539Ssuz 1281151539Ssuz if ((ia6 = in6_ifadd(new, mcast)) != NULL) { 128278064Sume /* 128378064Sume * note that we should use pr (not new) for reference. 128478064Sume */ 128578064Sume pr->ndpr_refcnt++; 128678064Sume ia6->ia6_ndpr = pr; 128753541Sshin 128878064Sume /* 128978064Sume * RFC 3041 3.3 (2). 129078064Sume * When a new public address is created as described 129178064Sume * in RFC2462, also create a new temporary address. 129278064Sume * 129378064Sume * RFC 3041 3.5. 129478064Sume * When an interface connects to a new link, a new 129578064Sume * randomized interface identifier should be generated 129678064Sume * immediately together with a new set of temporary 129778064Sume * addresses. Thus, we specifiy 1 as the 2nd arg of 129878064Sume * in6_tmpifadd(). 129978064Sume */ 130078064Sume if (ip6_use_tempaddr) { 130178064Sume int e; 1302151539Ssuz if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) { 130378064Sume nd6log((LOG_NOTICE, "prelist_update: " 130478064Sume "failed to create a temporary " 130578064Sume "address, errno=%d\n", 130678064Sume e)); 130778064Sume } 130878064Sume } 130978064Sume 131078064Sume /* 131178064Sume * A newly added address might affect the status 131278064Sume * of other addresses, so we check and update it. 131378064Sume * XXX: what if address duplication happens? 131478064Sume */ 131578064Sume pfxlist_onlink_check(); 131678064Sume } else { 131778064Sume /* just set an error. do not bark here. */ 131878064Sume error = EADDRNOTAVAIL; /* XXX: might be unused. */ 131978064Sume } 132078064Sume } 132178064Sume 132253541Sshin end: 132353541Sshin splx(s); 132453541Sshin return error; 132553541Sshin} 132653541Sshin 132753541Sshin/* 132862587Sitojun * A supplement function used in the on-link detection below; 132962587Sitojun * detect if a given prefix has a (probably) reachable advertising router. 133062587Sitojun * XXX: lengthy function name... 133162587Sitojun */ 133278064Sumestatic struct nd_pfxrouter * 133362587Sitojunfind_pfxlist_reachable_router(pr) 133462587Sitojun struct nd_prefix *pr; 133562587Sitojun{ 133662587Sitojun struct nd_pfxrouter *pfxrtr; 133762587Sitojun struct rtentry *rt; 133862587Sitojun struct llinfo_nd6 *ln; 133962587Sitojun 134062587Sitojun for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr; 134162587Sitojun pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { 134262587Sitojun if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0, 1343120941Sume pfxrtr->router->ifp)) && 134462587Sitojun (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 134562587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) 134662587Sitojun break; /* found */ 134762587Sitojun } 134862587Sitojun 1349120856Sume return (pfxrtr); 135062587Sitojun} 135162587Sitojun 135262587Sitojun/* 135353541Sshin * Check if each prefix in the prefix list has at least one available router 135478064Sume * that advertised the prefix (a router is "available" if its neighbor cache 135578064Sume * entry is reachable or probably reachable). 135662587Sitojun * If the check fails, the prefix may be off-link, because, for example, 135753541Sshin * we have moved from the network but the lifetime of the prefix has not 135878064Sume * expired yet. So we should not use the prefix if there is another prefix 135978064Sume * that has an available router. 136078064Sume * But, if there is no prefix that has an available router, we still regards 136178064Sume * all the prefixes as on-link. This is because we can't tell if all the 136253541Sshin * routers are simply dead or if we really moved from the network and there 136353541Sshin * is no router around us. 136453541Sshin */ 136562587Sitojunvoid 136653541Sshinpfxlist_onlink_check() 136753541Sshin{ 136853541Sshin struct nd_prefix *pr; 136978064Sume struct in6_ifaddr *ifa; 1370151539Ssuz struct nd_defrouter *dr; 1371151539Ssuz struct nd_pfxrouter *pfxrtr = NULL; 137253541Sshin 137362587Sitojun /* 137462587Sitojun * Check if there is a prefix that has a reachable advertising 137562587Sitojun * router. 137662587Sitojun */ 137762587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 137878064Sume if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 137953541Sshin break; 138062587Sitojun } 138153541Sshin 1382151539Ssuz /* 1383151539Ssuz * If we have no such prefix, check whether we still have a router 1384151539Ssuz * that does not advertise any prefixes. 1385151539Ssuz */ 1386151465Ssuz if (pr == NULL) { 1387151539Ssuz for (dr = TAILQ_FIRST(&nd_defrouter); dr; 1388151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 1389151539Ssuz struct nd_prefix *pr0; 1390151539Ssuz 1391151539Ssuz for (pr0 = nd_prefix.lh_first; pr0; 1392151539Ssuz pr0 = pr0->ndpr_next) { 1393151539Ssuz if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) 1394151539Ssuz break; 1395151539Ssuz } 1396151539Ssuz if (pfxrtr != NULL) 1397151539Ssuz break; 1398151539Ssuz } 1399151539Ssuz } 1400151539Ssuz if (pr != NULL || (TAILQ_FIRST(&nd_defrouter) && pfxrtr == NULL)) { 1401151539Ssuz /* 1402151539Ssuz * There is at least one prefix that has a reachable router, 1403151539Ssuz * or at least a router which probably does not advertise 1404151539Ssuz * any prefixes. The latter would be the case when we move 1405151539Ssuz * to a new link where we have a router that does not provide 1406151539Ssuz * prefixes and we configure an address by hand. 1407151539Ssuz * Detach prefixes which have no reachable advertising 1408151539Ssuz * router, and attach other prefixes. 1409151539Ssuz */ 141062587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 141178064Sume /* XXX: a link-local prefix should never be detached */ 141278064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 141378064Sume continue; 141478064Sume 141578064Sume /* 141678064Sume * we aren't interested in prefixes without the L bit 141778064Sume * set. 141878064Sume */ 141978064Sume if (pr->ndpr_raf_onlink == 0) 142078064Sume continue; 142178064Sume 142278064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 142378064Sume find_pfxlist_reachable_router(pr) == NULL) 142478064Sume pr->ndpr_stateflags |= NDPRF_DETACHED; 142578064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 142678064Sume find_pfxlist_reachable_router(pr) != 0) 142778064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 142853541Sshin } 142978064Sume } else { 143078064Sume /* there is no prefix that has a reachable router */ 143162587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 143278064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 143378064Sume continue; 143478064Sume 143578064Sume if (pr->ndpr_raf_onlink == 0) 143678064Sume continue; 143778064Sume 143878064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 143978064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 144053541Sshin } 144162587Sitojun } 144278064Sume 144378064Sume /* 144478064Sume * Remove each interface route associated with a (just) detached 144578064Sume * prefix, and reinstall the interface route for a (just) attached 144678064Sume * prefix. Note that all attempt of reinstallation does not 144778064Sume * necessarily success, when a same prefix is shared among multiple 144878064Sume * interfaces. Such cases will be handled in nd6_prefix_onlink, 144978064Sume * so we don't have to care about them. 145078064Sume */ 145178064Sume for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 145278064Sume int e; 145378064Sume 145478064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 145578064Sume continue; 145678064Sume 145778064Sume if (pr->ndpr_raf_onlink == 0) 145878064Sume continue; 145978064Sume 146078064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 146178064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 146278064Sume if ((e = nd6_prefix_offlink(pr)) != 0) { 146378064Sume nd6log((LOG_ERR, 146478064Sume "pfxlist_onlink_check: failed to " 1465151479Ssuz "make %s/%d offlink, errno=%d\n", 146678064Sume ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 146778064Sume pr->ndpr_plen, e)); 146878064Sume } 146978064Sume } 147078064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 147178064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 147278064Sume pr->ndpr_raf_onlink) { 147378064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 147478064Sume nd6log((LOG_ERR, 147578064Sume "pfxlist_onlink_check: failed to " 1476151479Ssuz "make %s/%d onlink, errno=%d\n", 147778064Sume ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 147878064Sume pr->ndpr_plen, e)); 147978064Sume } 148078064Sume } 148178064Sume } 148278064Sume 148378064Sume /* 148478064Sume * Changes on the prefix status might affect address status as well. 148578064Sume * Make sure that all addresses derived from an attached prefix are 148678064Sume * attached, and that all addresses derived from a detached prefix are 148778064Sume * detached. Note, however, that a manually configured address should 148878064Sume * always be attached. 148978064Sume * The precise detection logic is same as the one for prefixes. 149078064Sume */ 149178064Sume for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 1492120941Sume if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) 149378064Sume continue; 149478064Sume 149578064Sume if (ifa->ia6_ndpr == NULL) { 149678064Sume /* 149778064Sume * This can happen when we first configure the address 149878064Sume * (i.e. the address exists, but the prefix does not). 149978064Sume * XXX: complicated relationships... 150078064Sume */ 150178064Sume continue; 150278064Sume } 150378064Sume 150478064Sume if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 150578064Sume break; 150678064Sume } 150778064Sume if (ifa) { 150878064Sume for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 150978064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 151078064Sume continue; 151178064Sume 151278064Sume if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 151378064Sume continue; 151478064Sume 1515151539Ssuz if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) { 1516151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1517151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1518151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1519151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1520151539Ssuz } 1521151539Ssuz } else { 152278064Sume ifa->ia6_flags |= IN6_IFF_DETACHED; 1523151539Ssuz } 152478064Sume } 152578064Sume } 152662587Sitojun else { 152778064Sume for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 152878064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 152978064Sume continue; 153078064Sume 1531151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1532151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1533151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1534151539Ssuz /* Do we need a delay in this case? */ 1535151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1536151539Ssuz } 153778064Sume } 153853541Sshin } 153953541Sshin} 154053541Sshin 154178064Sumeint 154278064Sumend6_prefix_onlink(pr) 154353541Sshin struct nd_prefix *pr; 154453541Sshin{ 154578064Sume struct ifaddr *ifa; 154678064Sume struct ifnet *ifp = pr->ndpr_ifp; 154778064Sume struct sockaddr_in6 mask6; 154878064Sume struct nd_prefix *opr; 154978064Sume u_long rtflags; 155078064Sume int error = 0; 155178064Sume struct rtentry *rt = NULL; 155253541Sshin 155378064Sume /* sanity check */ 155478064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 155578064Sume nd6log((LOG_ERR, 155678064Sume "nd6_prefix_onlink: %s/%d is already on-link\n", 1557151465Ssuz ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen)); 1558151465Ssuz return (EEXIST); 155978064Sume } 156078064Sume 156153541Sshin /* 156278064Sume * Add the interface route associated with the prefix. Before 156378064Sume * installing the route, check if there's the same prefix on another 156478064Sume * interface, and the prefix has already installed the interface route. 156578064Sume * Although such a configuration is expected to be rare, we explicitly 156678064Sume * allow it. 156753541Sshin */ 156878064Sume for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 156978064Sume if (opr == pr) 157078064Sume continue; 157178064Sume 157278064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 157378064Sume continue; 157478064Sume 157578064Sume if (opr->ndpr_plen == pr->ndpr_plen && 157678064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1577120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) 1578120856Sume return (0); 157978064Sume } 158078064Sume 158178064Sume /* 1582120941Sume * We prefer link-local addresses as the associated interface address. 158378064Sume */ 158478064Sume /* search for a link-local addr */ 158578064Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 1586120941Sume IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); 158778064Sume if (ifa == NULL) { 158878064Sume /* XXX: freebsd does not have ifa_ifwithaf */ 1589120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 159078064Sume if (ifa->ifa_addr->sa_family == AF_INET6) 159178064Sume break; 159278064Sume } 159378064Sume /* should we care about ia6_flags? */ 159478064Sume } 159578064Sume if (ifa == NULL) { 159678064Sume /* 159778064Sume * This can still happen, when, for example, we receive an RA 159878064Sume * containing a prefix with the L bit set and the A bit clear, 159978064Sume * after removing all IPv6 addresses on the receiving 160078064Sume * interface. This should, of course, be rare though. 160178064Sume */ 160278064Sume nd6log((LOG_NOTICE, 160378064Sume "nd6_prefix_onlink: failed to find any ifaddr" 160478064Sume " to add route for a prefix(%s/%d) on %s\n", 160578064Sume ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 160678064Sume pr->ndpr_plen, if_name(ifp))); 1607120856Sume return (0); 160878064Sume } 160978064Sume 161078064Sume /* 161178064Sume * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 161278064Sume * ifa->ifa_rtrequest = nd6_rtrequest; 161378064Sume */ 161478064Sume bzero(&mask6, sizeof(mask6)); 161578064Sume mask6.sin6_len = sizeof(mask6); 161678064Sume mask6.sin6_addr = pr->ndpr_mask; 161778064Sume rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP; 161878064Sume if (nd6_need_cache(ifp)) { 161978064Sume /* explicitly set in case ifa_flags does not set the flag. */ 162078064Sume rtflags |= RTF_CLONING; 162178064Sume } else { 162278064Sume /* 162378064Sume * explicitly clear the cloning bit in case ifa_flags sets it. 162478064Sume */ 162578064Sume rtflags &= ~RTF_CLONING; 162678064Sume } 162778064Sume error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, 1628120941Sume ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt); 162978064Sume if (error == 0) { 163078064Sume if (rt != NULL) /* this should be non NULL, though */ 163178064Sume nd6_rtmsg(RTM_ADD, rt); 163278064Sume pr->ndpr_stateflags |= NDPRF_ONLINK; 1633120941Sume } else { 163478064Sume nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" 163578064Sume " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " 163678064Sume "errno = %d\n", 163778064Sume ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 163878064Sume pr->ndpr_plen, if_name(ifp), 163978064Sume ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), 164078064Sume ip6_sprintf(&mask6.sin6_addr), rtflags, error)); 164178064Sume } 164278064Sume 1643120727Ssam if (rt != NULL) { 1644120727Ssam RT_LOCK(rt); 1645122334Ssam RT_REMREF(rt); 1646120727Ssam RT_UNLOCK(rt); 1647120727Ssam } 164878064Sume 1649120856Sume return (error); 165078064Sume} 165178064Sume 165278064Sumeint 165378064Sumend6_prefix_offlink(pr) 165478064Sume struct nd_prefix *pr; 165578064Sume{ 165678064Sume int error = 0; 165778064Sume struct ifnet *ifp = pr->ndpr_ifp; 165878064Sume struct nd_prefix *opr; 165978064Sume struct sockaddr_in6 sa6, mask6; 166078064Sume struct rtentry *rt = NULL; 166178064Sume 166278064Sume /* sanity check */ 166378064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 166478064Sume nd6log((LOG_ERR, 166578064Sume "nd6_prefix_offlink: %s/%d is already off-link\n", 166678064Sume ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen)); 1667120856Sume return (EEXIST); 166878064Sume } 166978064Sume 167053541Sshin bzero(&sa6, sizeof(sa6)); 167153541Sshin sa6.sin6_family = AF_INET6; 167253541Sshin sa6.sin6_len = sizeof(sa6); 167353541Sshin bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 1674120941Sume sizeof(struct in6_addr)); 167553541Sshin bzero(&mask6, sizeof(mask6)); 167653541Sshin mask6.sin6_family = AF_INET6; 167753541Sshin mask6.sin6_len = sizeof(sa6); 167853541Sshin bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 167978064Sume error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 1680120941Sume (struct sockaddr *)&mask6, 0, &rt); 168178064Sume if (error == 0) { 168278064Sume pr->ndpr_stateflags &= ~NDPRF_ONLINK; 168353541Sshin 168478064Sume /* report the route deletion to the routing socket. */ 168578064Sume if (rt != NULL) 168678064Sume nd6_rtmsg(RTM_DELETE, rt); 168753541Sshin 168878064Sume /* 168978064Sume * There might be the same prefix on another interface, 169078064Sume * the prefix which could not be on-link just because we have 169178064Sume * the interface route (see comments in nd6_prefix_onlink). 169278064Sume * If there's one, try to make the prefix on-link on the 169378064Sume * interface. 169478064Sume */ 169578064Sume for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 169678064Sume if (opr == pr) 169778064Sume continue; 169853541Sshin 169978064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 170078064Sume continue; 170153541Sshin 170278064Sume /* 170378064Sume * KAME specific: detached prefixes should not be 170478064Sume * on-link. 170578064Sume */ 170678064Sume if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 170778064Sume continue; 170878064Sume 170978064Sume if (opr->ndpr_plen == pr->ndpr_plen && 171078064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1711120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 171278064Sume int e; 171378064Sume 171478064Sume if ((e = nd6_prefix_onlink(opr)) != 0) { 171578064Sume nd6log((LOG_ERR, 171678064Sume "nd6_prefix_offlink: failed to " 171778064Sume "recover a prefix %s/%d from %s " 171878064Sume "to %s (errno = %d)\n", 171978064Sume ip6_sprintf(&opr->ndpr_prefix.sin6_addr), 172078064Sume opr->ndpr_plen, if_name(ifp), 172178064Sume if_name(opr->ndpr_ifp), e)); 172278064Sume } 172378064Sume } 172478064Sume } 1725120941Sume } else { 172678064Sume /* XXX: can we still set the NDPRF_ONLINK flag? */ 172778064Sume nd6log((LOG_ERR, 172878064Sume "nd6_prefix_offlink: failed to delete route: " 172978064Sume "%s/%d on %s (errno = %d)\n", 173078064Sume ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp), 173178064Sume error)); 173278064Sume } 173353541Sshin 1734120941Sume if (rt != NULL) { 1735108269Sru RTFREE(rt); 1736120941Sume } 173753541Sshin 1738120856Sume return (error); 173953541Sshin} 174053541Sshin 174153541Sshinstatic struct in6_ifaddr * 1742151539Ssuzin6_ifadd(pr, mcast) 1743151539Ssuz struct nd_prefixctl *pr; 1744151539Ssuz int mcast; 174553541Sshin{ 174678064Sume struct ifnet *ifp = pr->ndpr_ifp; 174753541Sshin struct ifaddr *ifa; 174878064Sume struct in6_aliasreq ifra; 174978064Sume struct in6_ifaddr *ia, *ib; 175078064Sume int error, plen0; 175153541Sshin struct in6_addr mask; 175278064Sume int prefixlen = pr->ndpr_plen; 1753151539Ssuz int updateflags; 175453541Sshin 1755121168Sume in6_prefixlen2mask(&mask, prefixlen); 175653541Sshin 175778064Sume /* 175878064Sume * find a link-local address (will be interface ID). 175978064Sume * Is it really mandatory? Theoretically, a global or a site-local 176078064Sume * address can be configured without a link-local address, if we 176178064Sume * have a unique interface identifier... 176278064Sume * 176378064Sume * it is not mandatory to have a link-local address, we can generate 176478064Sume * interface identifier on the fly. we do this because: 176578064Sume * (1) it should be the easiest way to find interface identifier. 176678064Sume * (2) RFC2462 5.4 suggesting the use of the same interface identifier 176778064Sume * for multiple addresses on a single interface, and possible shortcut 176878064Sume * of DAD. we omitted DAD for this reason in the past. 1769120941Sume * (3) a user can prevent autoconfiguration of global address 177078064Sume * by removing link-local address by hand (this is partly because we 1771108533Sschweikh * don't have other way to control the use of IPv6 on an interface. 177278064Sume * this has been our design choice - cf. NRL's "ifconfig auto"). 177378064Sume * (4) it is easier to manage when an interface has addresses 177478064Sume * with the same interface identifier, than to have multiple addresses 177578064Sume * with different interface identifiers. 177678064Sume */ 1777120941Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ 177853541Sshin if (ifa) 177953541Sshin ib = (struct in6_ifaddr *)ifa; 178053541Sshin else 178153541Sshin return NULL; 178253541Sshin 178353541Sshin /* prefixlen + ifidlen must be equal to 128 */ 178478064Sume plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 178578064Sume if (prefixlen != plen0) { 178678064Sume nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 178778064Sume "(prefix=%d ifid=%d)\n", 178878064Sume if_name(ifp), prefixlen, 128 - plen0)); 178953541Sshin return NULL; 179053541Sshin } 179153541Sshin 179253541Sshin /* make ifaddr */ 179353541Sshin 179478064Sume bzero(&ifra, sizeof(ifra)); 179578064Sume /* 179678064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 179778064Sume * for safety. 179878064Sume */ 179978064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 180078064Sume ifra.ifra_addr.sin6_family = AF_INET6; 180178064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 180278064Sume /* prefix */ 1803151539Ssuz ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr; 180478064Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 180578064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 180678064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 180778064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 180853541Sshin 180953541Sshin /* interface ID */ 1810120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] |= 1811151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); 1812120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] |= 1813151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); 1814120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1815151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); 1816120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1817151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); 1818120941Sume 181978064Sume /* new prefix mask. */ 182078064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 182178064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 182278064Sume bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 1823120941Sume sizeof(ifra.ifra_prefixmask.sin6_addr)); 182453541Sshin 1825151539Ssuz /* lifetimes. */ 182678064Sume ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 182778064Sume ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 182853541Sshin 182978064Sume /* XXX: scope zone ID? */ 183053541Sshin 183178064Sume ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 1832151539Ssuz 1833151539Ssuz /* 1834151539Ssuz * Make sure that we do not have this address already. This should 1835151539Ssuz * usually not happen, but we can still see this case, e.g., if we 1836151539Ssuz * have manually configured the exact address to be configured. 183778064Sume */ 1838151539Ssuz if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { 1839151539Ssuz /* this should be rare enough to make an explicit log */ 1840151539Ssuz log(LOG_INFO, "in6_ifadd: %s is already configured\n", 1841151539Ssuz ip6_sprintf(&ifra.ifra_addr.sin6_addr)); 1842151539Ssuz return (NULL); 1843151539Ssuz } 184453541Sshin 184553541Sshin /* 1846151539Ssuz * Allocate ifaddr structure, link into chain, etc. 1847151539Ssuz * If we are going to create a new address upon receiving a multicasted 1848151539Ssuz * RA, we need to impose a random delay before starting DAD. 1849151539Ssuz * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] 185053541Sshin */ 1851151539Ssuz updateflags = 0; 1852151539Ssuz if (mcast) 1853151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1854151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { 185578064Sume nd6log((LOG_ERR, 185678064Sume "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 185778064Sume ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp), 185878064Sume error)); 1859120856Sume return (NULL); /* ifaddr must not have been allocated. */ 186053541Sshin } 186153541Sshin 186278064Sume ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 186353541Sshin 1864120941Sume return (ia); /* this is always non-NULL */ 186553541Sshin} 186653541Sshin 186753541Sshinint 1868151539Ssuzin6_tmpifadd(ia0, forcegen, delay) 186978064Sume const struct in6_ifaddr *ia0; /* corresponding public address */ 1870151539Ssuz int forcegen, delay; 187153541Sshin{ 187278064Sume struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 1873151539Ssuz struct in6_ifaddr *newia, *ia; 187478064Sume struct in6_aliasreq ifra; 187578064Sume int i, error; 187678064Sume int trylimit = 3; /* XXX: adhoc value */ 1877151539Ssuz int updateflags; 187878064Sume u_int32_t randid[2]; 187978064Sume time_t vltime0, pltime0; 188053541Sshin 188178064Sume bzero(&ifra, sizeof(ifra)); 188278064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 188378064Sume ifra.ifra_addr = ia0->ia_addr; 188478064Sume /* copy prefix mask */ 188578064Sume ifra.ifra_prefixmask = ia0->ia_prefixmask; 188678064Sume /* clear the old IFID */ 188778064Sume for (i = 0; i < 4; i++) { 1888120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[i] &= 1889120941Sume ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 189078064Sume } 189153541Sshin 189278064Sume again: 1893151539Ssuz if (in6_get_tmpifid(ifp, (u_int8_t *)randid, 1894151539Ssuz (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { 1895151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good " 1896151539Ssuz "random IFID\n")); 1897151539Ssuz return (EINVAL); 1898151539Ssuz } 1899120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1900120941Sume (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 1901120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1902120941Sume (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 190353541Sshin 1904151539Ssuz /* 1905151539Ssuz * in6_get_tmpifid() quite likely provided a unique interface ID. 1906151539Ssuz * However, we may still have a chance to see collision, because 1907151539Ssuz * there may be a time lag between generation of the ID and generation 1908151539Ssuz * of the address. So, we'll do one more sanity check. 190978064Sume */ 1910151539Ssuz for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 1911151539Ssuz if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 1912151539Ssuz &ifra.ifra_addr.sin6_addr)) { 1913151539Ssuz if (trylimit-- == 0) { 1914151539Ssuz /* 1915151539Ssuz * Give up. Something strange should have 1916151539Ssuz * happened. 1917151539Ssuz */ 1918151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " 1919151539Ssuz "find a unique random IFID\n")); 1920151539Ssuz return (EEXIST); 1921151539Ssuz } 1922151539Ssuz forcegen = 1; 1923151539Ssuz goto again; 192478064Sume } 192553541Sshin } 192653541Sshin 192778064Sume /* 192878064Sume * The Valid Lifetime is the lower of the Valid Lifetime of the 192978064Sume * public address or TEMP_VALID_LIFETIME. 193078064Sume * The Preferred Lifetime is the lower of the Preferred Lifetime 193178064Sume * of the public address or TEMP_PREFERRED_LIFETIME - 193278064Sume * DESYNC_FACTOR. 193378064Sume */ 1934151539Ssuz if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 193578064Sume vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 1936151539Ssuz (ia0->ia6_lifetime.ia6t_vltime - 1937151539Ssuz (time_second - ia0->ia6_updatetime)); 193878064Sume if (vltime0 > ip6_temp_valid_lifetime) 193978064Sume vltime0 = ip6_temp_valid_lifetime; 194078064Sume } else 194178064Sume vltime0 = ip6_temp_valid_lifetime; 1942151539Ssuz if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 194378064Sume pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 1944151539Ssuz (ia0->ia6_lifetime.ia6t_pltime - 1945151539Ssuz (time_second - ia0->ia6_updatetime)); 194678064Sume if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){ 194778064Sume pltime0 = ip6_temp_preferred_lifetime - 1948120941Sume ip6_desync_factor; 194978064Sume } 195078064Sume } else 195178064Sume pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor; 195278064Sume ifra.ifra_lifetime.ia6t_vltime = vltime0; 195378064Sume ifra.ifra_lifetime.ia6t_pltime = pltime0; 195453541Sshin 195578064Sume /* 195678064Sume * A temporary address is created only if this calculated Preferred 195778064Sume * Lifetime is greater than REGEN_ADVANCE time units. 195878064Sume */ 195978064Sume if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance) 1960120856Sume return (0); 196153541Sshin 196278064Sume /* XXX: scope zone ID? */ 196378064Sume 196478064Sume ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 196578064Sume 196678064Sume /* allocate ifaddr structure, link into chain, etc. */ 1967151539Ssuz updateflags = 0; 1968151539Ssuz if (delay) 1969151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1970151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) 1971120856Sume return (error); 197278064Sume 197378064Sume newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 197478064Sume if (newia == NULL) { /* XXX: can it happen? */ 197578064Sume nd6log((LOG_ERR, 197678064Sume "in6_tmpifadd: ifa update succeeded, but we got " 197778064Sume "no ifaddr\n")); 1978120856Sume return (EINVAL); /* XXX */ 197953541Sshin } 198078064Sume newia->ia6_ndpr = ia0->ia6_ndpr; 198178064Sume newia->ia6_ndpr->ndpr_refcnt++; 198253541Sshin 198378407Sume /* 198478407Sume * A newly added address might affect the status of other addresses. 198578407Sume * XXX: when the temporary address is generated with a new public 198678407Sume * address, the onlink check is redundant. However, it would be safe 198778407Sume * to do the check explicitly everywhere a new address is generated, 198878407Sume * and, in fact, we surely need the check when we create a new 198978407Sume * temporary address due to deprecation of an old temporary address. 199078407Sume */ 199178407Sume pfxlist_onlink_check(); 199278407Sume 1993120856Sume return (0); 1994120941Sume} 199553541Sshin 1996151539Ssuzstatic int 199753541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr) 199853541Sshin{ 199953541Sshin if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 200053541Sshin ndpr->ndpr_preferred = 0; 200153541Sshin else 200253541Sshin ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; 200353541Sshin if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 200453541Sshin ndpr->ndpr_expire = 0; 200553541Sshin else 200653541Sshin ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; 200753541Sshin 200853541Sshin return 0; 200953541Sshin} 201053541Sshin 201153541Sshinstatic void 201278064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 201353541Sshin{ 201478064Sume /* init ia6t_expire */ 201578064Sume if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 201678064Sume lt6->ia6t_expire = 0; 201778064Sume else { 201878064Sume lt6->ia6t_expire = time_second; 201978064Sume lt6->ia6t_expire += lt6->ia6t_vltime; 202053541Sshin } 202162587Sitojun 202253541Sshin /* init ia6t_preferred */ 202353541Sshin if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 202453541Sshin lt6->ia6t_preferred = 0; 202553541Sshin else { 202653541Sshin lt6->ia6t_preferred = time_second; 202753541Sshin lt6->ia6t_preferred += lt6->ia6t_pltime; 202853541Sshin } 202953541Sshin} 203053541Sshin 203153541Sshin/* 203253541Sshin * Delete all the routing table entries that use the specified gateway. 203353541Sshin * XXX: this function causes search through all entries of routing table, so 203453541Sshin * it shouldn't be called when acting as a router. 203553541Sshin */ 203653541Sshinvoid 203753541Sshinrt6_flush(gateway, ifp) 203878064Sume struct in6_addr *gateway; 203978064Sume struct ifnet *ifp; 204053541Sshin{ 204153541Sshin struct radix_node_head *rnh = rt_tables[AF_INET6]; 204253541Sshin int s = splnet(); 204353541Sshin 204453541Sshin /* We'll care only link-local addresses */ 204553541Sshin if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { 204653541Sshin splx(s); 204753541Sshin return; 204853541Sshin } 204953541Sshin 2050108250Shsu RADIX_NODE_HEAD_LOCK(rnh); 205153541Sshin rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 2052108250Shsu RADIX_NODE_HEAD_UNLOCK(rnh); 205353541Sshin splx(s); 205453541Sshin} 205553541Sshin 205653541Sshinstatic int 205753541Sshinrt6_deleteroute(rn, arg) 205853541Sshin struct radix_node *rn; 205953541Sshin void *arg; 206053541Sshin{ 206153541Sshin#define SIN6(s) ((struct sockaddr_in6 *)s) 206253541Sshin struct rtentry *rt = (struct rtentry *)rn; 206353541Sshin struct in6_addr *gate = (struct in6_addr *)arg; 206453541Sshin 206553541Sshin if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 2066120856Sume return (0); 206753541Sshin 2068120941Sume if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) { 2069120856Sume return (0); 2070120941Sume } 207153541Sshin 207253541Sshin /* 207378064Sume * Do not delete a static route. 207478064Sume * XXX: this seems to be a bit ad-hoc. Should we consider the 207578064Sume * 'cloned' bit instead? 207678064Sume */ 207778064Sume if ((rt->rt_flags & RTF_STATIC) != 0) 2078120856Sume return (0); 207978064Sume 208078064Sume /* 208153541Sshin * We delete only host route. This means, in particular, we don't 208253541Sshin * delete default route. 208353541Sshin */ 208453541Sshin if ((rt->rt_flags & RTF_HOST) == 0) 2085120856Sume return (0); 208653541Sshin 2087120941Sume return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 2088120941Sume rt_mask(rt), rt->rt_flags, 0)); 208953541Sshin#undef SIN6 209053541Sshin} 209162587Sitojun 209262587Sitojunint 209362587Sitojunnd6_setdefaultiface(ifindex) 209462587Sitojun int ifindex; 209562587Sitojun{ 209662587Sitojun int error = 0; 209762587Sitojun 209862587Sitojun if (ifindex < 0 || if_index < ifindex) 2099120856Sume return (EINVAL); 2100151539Ssuz if (ifindex != 0 && !ifnet_byindex(ifindex)) 2101151539Ssuz return (EINVAL); 210262587Sitojun 210362587Sitojun if (nd6_defifindex != ifindex) { 210462587Sitojun nd6_defifindex = ifindex; 210562587Sitojun if (nd6_defifindex > 0) 210683130Sjlemon nd6_defifp = ifnet_byindex(nd6_defifindex); 210762587Sitojun else 210862587Sitojun nd6_defifp = NULL; 210962587Sitojun 211062587Sitojun /* 211162587Sitojun * Our current implementation assumes one-to-one maping between 211262587Sitojun * interfaces and links, so it would be natural to use the 211362587Sitojun * default interface as the default link. 211462587Sitojun */ 211562587Sitojun scope6_setdefault(nd6_defifp); 211662587Sitojun } 211762587Sitojun 2118120856Sume return (error); 211962587Sitojun} 2120