1139826Simp/*- 253541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 353541Sshin * All rights reserved. 453541Sshin * 553541Sshin * Redistribution and use in source and binary forms, with or without 653541Sshin * modification, are permitted provided that the following conditions 753541Sshin * are met: 853541Sshin * 1. Redistributions of source code must retain the above copyright 953541Sshin * notice, this list of conditions and the following disclaimer. 1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1153541Sshin * notice, this list of conditions and the following disclaimer in the 1253541Sshin * documentation and/or other materials provided with the distribution. 1353541Sshin * 3. Neither the name of the project nor the names of its contributors 1453541Sshin * may be used to endorse or promote products derived from this software 1553541Sshin * without specific prior written permission. 1653541Sshin * 1753541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1853541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1953541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2053541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2153541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2253541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2353541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2453541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2553541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2653541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2753541Sshin * SUCH DAMAGE. 28174510Sobrien * 29174510Sobrien * $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $ 3053541Sshin */ 3153541Sshin 32174510Sobrien#include <sys/cdefs.h> 33174510Sobrien__FBSDID("$FreeBSD$"); 34174510Sobrien 3562587Sitojun#include "opt_inet.h" 3662587Sitojun#include "opt_inet6.h" 3762587Sitojun 3853541Sshin#include <sys/param.h> 3953541Sshin#include <sys/systm.h> 4053541Sshin#include <sys/malloc.h> 4153541Sshin#include <sys/mbuf.h> 42303458Ssbruno#include <sys/refcount.h> 4353541Sshin#include <sys/socket.h> 4453541Sshin#include <sys/sockio.h> 4553541Sshin#include <sys/time.h> 4678064Sume#include <sys/kernel.h> 47185751Simp#include <sys/lock.h> 4853541Sshin#include <sys/errno.h> 49185747Skmacy#include <sys/rwlock.h> 5053541Sshin#include <sys/syslog.h> 5178064Sume#include <sys/queue.h> 5253541Sshin 5353541Sshin#include <net/if.h> 5453541Sshin#include <net/if_types.h> 5553541Sshin#include <net/if_dl.h> 5653541Sshin#include <net/route.h> 5753541Sshin#include <net/radix.h> 58185571Sbz#include <net/vnet.h> 5953541Sshin 6053541Sshin#include <netinet/in.h> 61186119Sqingli#include <net/if_llatbl.h> 6253541Sshin#include <netinet6/in6_var.h> 6378064Sume#include <netinet6/in6_ifattach.h> 6462587Sitojun#include <netinet/ip6.h> 6553541Sshin#include <netinet6/ip6_var.h> 6653541Sshin#include <netinet6/nd6.h> 6762587Sitojun#include <netinet/icmp6.h> 6862587Sitojun#include <netinet6/scope6_var.h> 6953541Sshin 70175162Sobrienstatic int rtpref(struct nd_defrouter *); 71175162Sobrienstatic struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); 72241916Sdelphijstatic int prelist_update(struct nd_prefixctl *, struct nd_defrouter *, 73241916Sdelphij struct mbuf *, int); 74241916Sdelphijstatic struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int); 75241916Sdelphijstatic struct nd_pfxrouter *pfxrtr_lookup(struct nd_prefix *, 76241916Sdelphij struct nd_defrouter *); 77175162Sobrienstatic void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *); 78175162Sobrienstatic void pfxrtr_del(struct nd_pfxrouter *); 7962587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router 80175162Sobrien(struct nd_prefix *); 81175162Sobrienstatic void defrouter_delreq(struct nd_defrouter *); 82175162Sobrienstatic void nd6_rtmsg(int, struct rtentry *); 8353541Sshin 84175162Sobrienstatic int in6_init_prefix_ltimes(struct nd_prefix *); 85241916Sdelphijstatic void in6_init_address_ltimes(struct nd_prefix *, 86241916Sdelphij struct in6_addrlifetime *); 8753541Sshin 88229547Sbzstatic int nd6_prefix_onlink(struct nd_prefix *); 89229547Sbzstatic int nd6_prefix_offlink(struct nd_prefix *); 90229547Sbz 91175162Sobrienstatic int rt6_deleteroute(struct radix_node *, void *); 9253541Sshin 93195699SrwatsonVNET_DECLARE(int, nd6_recalc_reachtm_interval); 94195727Srwatson#define V_nd6_recalc_reachtm_interval VNET(nd6_recalc_reachtm_interval) 9553541Sshin 96215701Sdimstatic VNET_DEFINE(struct ifnet *, nd6_defifp); 97207369SbzVNET_DEFINE(int, nd6_defifindex); 98195727Srwatson#define V_nd6_defifp VNET(nd6_defifp) 9962587Sitojun 100207369SbzVNET_DEFINE(int, ip6_use_tempaddr) = 0; 101207369Sbz 102195699SrwatsonVNET_DEFINE(int, ip6_desync_factor); 103207369SbzVNET_DEFINE(u_int32_t, ip6_temp_preferred_lifetime) = DEF_TEMP_PREFERRED_LIFETIME; 104207369SbzVNET_DEFINE(u_int32_t, ip6_temp_valid_lifetime) = DEF_TEMP_VALID_LIFETIME; 10578064Sume 106207369SbzVNET_DEFINE(int, ip6_temp_regen_advance) = TEMPADDR_REGEN_ADVANCE; 107207369Sbz 108151539Ssuz/* RTPREF_MEDIUM has to be 0! */ 109151539Ssuz#define RTPREF_HIGH 1 110151539Ssuz#define RTPREF_MEDIUM 0 111151539Ssuz#define RTPREF_LOW (-1) 112151539Ssuz#define RTPREF_RESERVED (-2) 113151539Ssuz#define RTPREF_INVALID (-3) /* internal */ 114151539Ssuz 11578064Sume/* 11653541Sshin * Receive Router Solicitation Message - just for routers. 11753541Sshin * Router solicitation/advertisement is mostly managed by userland program 11853541Sshin * (rtadvd) so here we have no function like nd6_ra_output(). 11953541Sshin * 12053541Sshin * Based on RFC 2461 12153541Sshin */ 12253541Sshinvoid 123171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len) 12453541Sshin{ 12553541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 12653541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 12762587Sitojun struct nd_router_solicit *nd_rs; 12853541Sshin struct in6_addr saddr6 = ip6->ip6_src; 12953541Sshin char *lladdr = NULL; 13053541Sshin int lladdrlen = 0; 13153541Sshin union nd_opts ndopts; 132165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 13353541Sshin 134222728Shrs /* 135222728Shrs * Accept RS only when V_ip6_forwarding=1 and the interface has 136222728Shrs * no ND6_IFF_ACCEPT_RTADV. 137222728Shrs */ 138222728Shrs if (!V_ip6_forwarding || ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) 13962587Sitojun goto freeit; 14053541Sshin 14153541Sshin /* Sanity checks */ 14253541Sshin if (ip6->ip6_hlim != 255) { 14378064Sume nd6log((LOG_ERR, 14478064Sume "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 145165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 146165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 14778064Sume goto bad; 14853541Sshin } 14953541Sshin 15053541Sshin /* 15153541Sshin * Don't update the neighbor cache, if src = ::. 15253541Sshin * This indicates that the src has no IP address assigned yet. 15353541Sshin */ 15453541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 15562587Sitojun goto freeit; 15662587Sitojun 15762587Sitojun#ifndef PULLDOWN_TEST 15862587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 15962587Sitojun nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 16062587Sitojun#else 16162587Sitojun IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 16262587Sitojun if (nd_rs == NULL) { 163190964Srwatson ICMP6STAT_INC(icp6s_tooshort); 16453541Sshin return; 16562587Sitojun } 16662587Sitojun#endif 16753541Sshin 16853541Sshin icmp6len -= sizeof(*nd_rs); 16953541Sshin nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 17053541Sshin if (nd6_options(&ndopts) < 0) { 17178064Sume nd6log((LOG_INFO, 17278064Sume "nd6_rs_input: invalid ND option, ignored\n")); 17378064Sume /* nd6_options have incremented stats */ 17462587Sitojun goto freeit; 17553541Sshin } 17653541Sshin 17753541Sshin if (ndopts.nd_opts_src_lladdr) { 17853541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 17953541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 18053541Sshin } 18153541Sshin 18253541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 18378064Sume nd6log((LOG_INFO, 18453541Sshin "nd6_rs_input: lladdrlen mismatch for %s " 18553541Sshin "(if %d, RS packet %d)\n", 186165118Sbz ip6_sprintf(ip6bufs, &saddr6), 187120941Sume ifp->if_addrlen, lladdrlen - 2)); 18878064Sume goto bad; 18953541Sshin } 19053541Sshin 19153541Sshin nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 19262587Sitojun 19362587Sitojun freeit: 19462587Sitojun m_freem(m); 19578064Sume return; 19678064Sume 19778064Sume bad: 198190964Srwatson ICMP6STAT_INC(icp6s_badrs); 19978064Sume m_freem(m); 20053541Sshin} 20153541Sshin 20253541Sshin/* 20353541Sshin * Receive Router Advertisement Message. 20453541Sshin * 20553541Sshin * Based on RFC 2461 20653541Sshin * TODO: on-link bit on prefix information 20753541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 20853541Sshin */ 20953541Sshinvoid 210171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len) 21153541Sshin{ 21253541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 213121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 21453541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 21562587Sitojun struct nd_router_advert *nd_ra; 21653541Sshin struct in6_addr saddr6 = ip6->ip6_src; 217151539Ssuz int mcast = 0; 21853541Sshin union nd_opts ndopts; 21953541Sshin struct nd_defrouter *dr; 220165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 22153541Sshin 222303458Ssbruno dr = NULL; 223303458Ssbruno 224118498Sume /* 225222728Shrs * We only accept RAs only when the per-interface flag 226222728Shrs * ND6_IFF_ACCEPT_RTADV is on the receiving interface. 227118498Sume */ 228222728Shrs if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 22962587Sitojun goto freeit; 23053541Sshin 23153541Sshin if (ip6->ip6_hlim != 255) { 23278064Sume nd6log((LOG_ERR, 23378064Sume "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 234165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 235165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 23678064Sume goto bad; 23753541Sshin } 23853541Sshin 23953541Sshin if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 24078064Sume nd6log((LOG_ERR, 24153541Sshin "nd6_ra_input: src %s is not link-local\n", 242165118Sbz ip6_sprintf(ip6bufs, &saddr6))); 24378064Sume goto bad; 24462587Sitojun } 24562587Sitojun 24662587Sitojun#ifndef PULLDOWN_TEST 24762587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 24862587Sitojun nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); 24962587Sitojun#else 25062587Sitojun IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); 25162587Sitojun if (nd_ra == NULL) { 252190964Srwatson ICMP6STAT_INC(icp6s_tooshort); 25353541Sshin return; 25453541Sshin } 25562587Sitojun#endif 25653541Sshin 25753541Sshin icmp6len -= sizeof(*nd_ra); 25853541Sshin nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 25953541Sshin if (nd6_options(&ndopts) < 0) { 26078064Sume nd6log((LOG_INFO, 26178064Sume "nd6_ra_input: invalid ND option, ignored\n")); 26278064Sume /* nd6_options have incremented stats */ 26362587Sitojun goto freeit; 26453541Sshin } 26553541Sshin 26653541Sshin { 26753541Sshin struct nd_defrouter dr0; 26853541Sshin u_int32_t advreachable = nd_ra->nd_ra_reachable; 26953541Sshin 270151539Ssuz /* remember if this is a multicasted advertisement */ 271151539Ssuz if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 272151539Ssuz mcast = 1; 273151539Ssuz 274151539Ssuz bzero(&dr0, sizeof(dr0)); 27553541Sshin dr0.rtaddr = saddr6; 276299145Smarkj dr0.raflags = nd_ra->nd_ra_flags_reserved; 277222728Shrs /* 278225521Shrs * Effectively-disable routes from RA messages when 279225521Shrs * ND6_IFF_NO_RADR enabled on the receiving interface or 280225521Shrs * (ip6.forwarding == 1 && ip6.rfc6204w3 != 1). 281222728Shrs */ 282225521Shrs if (ndi->flags & ND6_IFF_NO_RADR) 283222728Shrs dr0.rtlifetime = 0; 284225521Shrs else if (V_ip6_forwarding && !V_ip6_rfc6204w3) 285225521Shrs dr0.rtlifetime = 0; 286222728Shrs else 287222728Shrs dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 288253970Shrs dr0.expire = time_uptime + dr0.rtlifetime; 28953541Sshin dr0.ifp = ifp; 29053541Sshin /* unspecified or not? (RFC 2461 6.3.4) */ 29153541Sshin if (advreachable) { 29290868Smike advreachable = ntohl(advreachable); 29353541Sshin if (advreachable <= MAX_REACHABLE_TIME && 29453541Sshin ndi->basereachable != advreachable) { 29553541Sshin ndi->basereachable = advreachable; 29653541Sshin ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 297181803Sbz ndi->recalctm = V_nd6_recalc_reachtm_interval; /* reset */ 29853541Sshin } 29953541Sshin } 30053541Sshin if (nd_ra->nd_ra_retransmit) 30153541Sshin ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 302281230Sdelphij if (nd_ra->nd_ra_curhoplimit) { 303281230Sdelphij if (ndi->chlim < nd_ra->nd_ra_curhoplimit) 304281230Sdelphij ndi->chlim = nd_ra->nd_ra_curhoplimit; 305281230Sdelphij else if (ndi->chlim != nd_ra->nd_ra_curhoplimit) { 306281230Sdelphij log(LOG_ERR, "RA with a lower CurHopLimit sent from " 307281230Sdelphij "%s on %s (current = %d, received = %d). " 308281230Sdelphij "Ignored.\n", ip6_sprintf(ip6bufs, &ip6->ip6_src), 309281230Sdelphij if_name(ifp), ndi->chlim, nd_ra->nd_ra_curhoplimit); 310281230Sdelphij } 311281230Sdelphij } 31253541Sshin dr = defrtrlist_update(&dr0); 31353541Sshin } 31453541Sshin 31553541Sshin /* 31653541Sshin * prefix 31753541Sshin */ 31853541Sshin if (ndopts.nd_opts_pi) { 31953541Sshin struct nd_opt_hdr *pt; 32078064Sume struct nd_opt_prefix_info *pi = NULL; 321151539Ssuz struct nd_prefixctl pr; 32253541Sshin 32353541Sshin for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 32453541Sshin pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 32553541Sshin pt = (struct nd_opt_hdr *)((caddr_t)pt + 32653541Sshin (pt->nd_opt_len << 3))) { 32753541Sshin if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 32853541Sshin continue; 32953541Sshin pi = (struct nd_opt_prefix_info *)pt; 33053541Sshin 33153541Sshin if (pi->nd_opt_pi_len != 4) { 33278064Sume nd6log((LOG_INFO, 33378064Sume "nd6_ra_input: invalid option " 33478064Sume "len %d for prefix information option, " 33578064Sume "ignored\n", pi->nd_opt_pi_len)); 33653541Sshin continue; 33753541Sshin } 33853541Sshin 33953541Sshin if (128 < pi->nd_opt_pi_prefix_len) { 34078064Sume nd6log((LOG_INFO, 34178064Sume "nd6_ra_input: invalid prefix " 34278064Sume "len %d for prefix information option, " 34378064Sume "ignored\n", pi->nd_opt_pi_prefix_len)); 34453541Sshin continue; 34553541Sshin } 34653541Sshin 34753541Sshin if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 34853541Sshin || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 34978064Sume nd6log((LOG_INFO, 35078064Sume "nd6_ra_input: invalid prefix " 35178064Sume "%s, ignored\n", 352165118Sbz ip6_sprintf(ip6bufs, 353165118Sbz &pi->nd_opt_pi_prefix))); 35453541Sshin continue; 35553541Sshin } 35653541Sshin 35753541Sshin bzero(&pr, sizeof(pr)); 35853541Sshin pr.ndpr_prefix.sin6_family = AF_INET6; 35953541Sshin pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 36053541Sshin pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 36153541Sshin pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 36253541Sshin 36353541Sshin pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 364120941Sume ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 36553541Sshin pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 366120941Sume ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 36753541Sshin pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 36853541Sshin pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 369120941Sume pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); 370151539Ssuz (void)prelist_update(&pr, dr, m, mcast); 37153541Sshin } 37253541Sshin } 373303458Ssbruno if (dr != NULL) { 374303458Ssbruno defrouter_rele(dr); 375303458Ssbruno dr = NULL; 376303458Ssbruno } 37753541Sshin 37853541Sshin /* 37953541Sshin * MTU 38053541Sshin */ 38153541Sshin if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 382121283Sume u_long mtu; 383121283Sume u_long maxmtu; 38453541Sshin 385121283Sume mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 386120941Sume 38753541Sshin /* lower bound */ 38853541Sshin if (mtu < IPV6_MMTU) { 38978064Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " 390121283Sume "mtu=%lu sent from %s, ignoring\n", 391165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src))); 39253541Sshin goto skip; 39353541Sshin } 39453541Sshin 39553541Sshin /* upper bound */ 396121283Sume maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu) 397121283Sume ? ndi->maxmtu : ifp->if_mtu; 398121283Sume if (mtu <= maxmtu) { 399121283Sume int change = (ndi->linkmtu != mtu); 40053541Sshin 401121283Sume ndi->linkmtu = mtu; 402121283Sume if (change) /* in6_maxmtu may change */ 403121283Sume in6_setmaxmtu(); 40453541Sshin } else { 405121283Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " 406121283Sume "mtu=%lu sent from %s; " 407121283Sume "exceeds maxmtu %lu, ignoring\n", 408165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu)); 40953541Sshin } 41053541Sshin } 41153541Sshin 41253541Sshin skip: 413120941Sume 41453541Sshin /* 41595023Ssuz * Source link layer address 41653541Sshin */ 41753541Sshin { 41853541Sshin char *lladdr = NULL; 41953541Sshin int lladdrlen = 0; 420120941Sume 42153541Sshin if (ndopts.nd_opts_src_lladdr) { 42253541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 42353541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 42453541Sshin } 42553541Sshin 42653541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 42778064Sume nd6log((LOG_INFO, 42853541Sshin "nd6_ra_input: lladdrlen mismatch for %s " 429165118Sbz "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6), 430120941Sume ifp->if_addrlen, lladdrlen - 2)); 43178064Sume goto bad; 43253541Sshin } 43353541Sshin 434120941Sume nd6_cache_lladdr(ifp, &saddr6, lladdr, 435120941Sume lladdrlen, ND_ROUTER_ADVERT, 0); 43662587Sitojun 43762587Sitojun /* 43862587Sitojun * Installing a link-layer address might change the state of the 43962587Sitojun * router's neighbor cache, which might also affect our on-link 44062587Sitojun * detection of adveritsed prefixes. 44162587Sitojun */ 44262587Sitojun pfxlist_onlink_check(); 44353541Sshin } 44462587Sitojun 44578064Sume freeit: 44662587Sitojun m_freem(m); 44778064Sume return; 44878064Sume 44978064Sume bad: 450190964Srwatson ICMP6STAT_INC(icp6s_badra); 45178064Sume m_freem(m); 45253541Sshin} 45353541Sshin 45462587Sitojun/* tell the change to user processes watching the routing socket. */ 45562587Sitojunstatic void 456171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt) 45762587Sitojun{ 45862587Sitojun struct rt_addrinfo info; 459191337Srwatson struct ifnet *ifp; 460194760Srwatson struct ifaddr *ifa; 46162587Sitojun 46262587Sitojun bzero((caddr_t)&info, sizeof(info)); 46362587Sitojun info.rti_info[RTAX_DST] = rt_key(rt); 46462587Sitojun info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 46562587Sitojun info.rti_info[RTAX_NETMASK] = rt_mask(rt); 466191337Srwatson ifp = rt->rt_ifp; 467191337Srwatson if (ifp != NULL) { 468229621Sjhb IF_ADDR_RLOCK(ifp); 469194760Srwatson ifa = TAILQ_FIRST(&ifp->if_addrhead); 470194760Srwatson info.rti_info[RTAX_IFP] = ifa->ifa_addr; 471194760Srwatson ifa_ref(ifa); 472229621Sjhb IF_ADDR_RUNLOCK(ifp); 473151539Ssuz info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 474194760Srwatson } else 475194760Srwatson ifa = NULL; 47662587Sitojun 477231852Sbz rt_missmsg_fib(cmd, &info, rt->rt_flags, 0, rt->rt_fibnum); 478194760Srwatson if (ifa != NULL) 479194760Srwatson ifa_free(ifa); 48062587Sitojun} 48162587Sitojun 482303458Ssbruno/* 483303458Ssbruno * default router list proccessing sub routines 484303458Ssbruno */ 485303458Ssbruno 486229547Sbzstatic void 487171259Sdelphijdefrouter_addreq(struct nd_defrouter *new) 48853541Sshin{ 48953541Sshin struct sockaddr_in6 def, mask, gate; 49062587Sitojun struct rtentry *newrt = NULL; 491151539Ssuz int error; 49253541Sshin 493128397Sluigi bzero(&def, sizeof(def)); 494128397Sluigi bzero(&mask, sizeof(mask)); 495128397Sluigi bzero(&gate, sizeof(gate)); 49653541Sshin 497120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 498120941Sume sizeof(struct sockaddr_in6); 499151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 50053541Sshin gate.sin6_addr = new->rtaddr; 50153541Sshin 502231852Sbz error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def, 503120941Sume (struct sockaddr *)&gate, (struct sockaddr *)&mask, 504231852Sbz RTF_GATEWAY, &newrt, RT_DEFAULT_FIB); 50562587Sitojun if (newrt) { 50678064Sume nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 507186119Sqingli RTFREE(newrt); 50862587Sitojun } 509151539Ssuz if (error == 0) 510151539Ssuz new->installed = 1; 51153541Sshin} 51253541Sshin 51353541Sshinstruct nd_defrouter * 514303458Ssbrunodefrouter_lookup_locked(struct in6_addr *addr, struct ifnet *ifp) 51553541Sshin{ 51653541Sshin struct nd_defrouter *dr; 51753541Sshin 518303458Ssbruno ND6_LOCK_ASSERT(); 519303458Ssbruno TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) 520303458Ssbruno if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) { 521303458Ssbruno defrouter_ref(dr); 522120856Sume return (dr); 523303458Ssbruno } 524303458Ssbruno return (NULL); 525303458Ssbruno} 52653541Sshin 527303458Ssbrunostruct nd_defrouter * 528303458Ssbrunodefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) 529303458Ssbruno{ 530303458Ssbruno struct nd_defrouter *dr; 531303458Ssbruno 532303458Ssbruno ND6_RLOCK(); 533303458Ssbruno dr = defrouter_lookup_locked(addr, ifp); 534303458Ssbruno ND6_RUNLOCK(); 535303458Ssbruno return (dr); 53653541Sshin} 53753541Sshin 538303458Ssbrunovoid 539303458Ssbrunodefrouter_ref(struct nd_defrouter *dr) 540303458Ssbruno{ 541303458Ssbruno 542303458Ssbruno refcount_acquire(&dr->refcnt); 543303458Ssbruno} 544303458Ssbruno 545303458Ssbrunovoid 546303458Ssbrunodefrouter_rele(struct nd_defrouter *dr) 547303458Ssbruno{ 548303458Ssbruno 549303458Ssbruno if (refcount_release(&dr->refcnt)) 550303458Ssbruno free(dr, M_IP6NDP); 551303458Ssbruno} 552303458Ssbruno 553151539Ssuz/* 554151539Ssuz * Remove the default route for a given router. 555151539Ssuz * This is just a subroutine function for defrouter_select(), and should 556151539Ssuz * not be called from anywhere else. 557151539Ssuz */ 558151539Ssuzstatic void 559171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr) 56053541Sshin{ 56153541Sshin struct sockaddr_in6 def, mask, gate; 56262587Sitojun struct rtentry *oldrt = NULL; 56353541Sshin 564128397Sluigi bzero(&def, sizeof(def)); 565128397Sluigi bzero(&mask, sizeof(mask)); 566128397Sluigi bzero(&gate, sizeof(gate)); 56753541Sshin 568120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 569120941Sume sizeof(struct sockaddr_in6); 570151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 57153541Sshin gate.sin6_addr = dr->rtaddr; 57253541Sshin 573231852Sbz in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def, 574120941Sume (struct sockaddr *)&gate, 575231852Sbz (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, RT_DEFAULT_FIB); 57662587Sitojun if (oldrt) { 57778064Sume nd6_rtmsg(RTM_DELETE, oldrt); 578108269Sru RTFREE(oldrt); 57962587Sitojun } 58053541Sshin 581151539Ssuz dr->installed = 0; 58253541Sshin} 58353541Sshin 584151539Ssuz/* 585303458Ssbruno * Remove all default routes from default router list. 586151539Ssuz */ 58753541Sshinvoid 588171259Sdelphijdefrouter_reset(void) 589151539Ssuz{ 590303458Ssbruno struct nd_defrouter *dr, **dra; 591303458Ssbruno int count, i; 592151539Ssuz 593303458Ssbruno count = i = 0; 594303458Ssbruno 595303458Ssbruno /* 596303458Ssbruno * We can't delete routes with the ND lock held, so make a copy of the 597303458Ssbruno * current default router list and use that when deleting routes. 598303458Ssbruno */ 599303458Ssbruno ND6_RLOCK(); 600228966Sjhb TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) 601303458Ssbruno count++; 602303458Ssbruno ND6_RUNLOCK(); 603151539Ssuz 604303458Ssbruno dra = malloc(count * sizeof(*dra), M_TEMP, M_WAITOK | M_ZERO); 605303458Ssbruno 606303458Ssbruno ND6_RLOCK(); 607303458Ssbruno TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { 608303458Ssbruno if (i == count) 609303458Ssbruno break; 610303458Ssbruno defrouter_ref(dr); 611303458Ssbruno dra[i++] = dr; 612303458Ssbruno } 613303458Ssbruno ND6_RUNLOCK(); 614303458Ssbruno 615303458Ssbruno for (i = 0; i < count && dra[i] != NULL; i++) { 616303458Ssbruno defrouter_delreq(dra[i]); 617303458Ssbruno defrouter_rele(dra[i]); 618303458Ssbruno } 619303458Ssbruno free(dra, M_TEMP); 620303458Ssbruno 621151539Ssuz /* 622151539Ssuz * XXX should we also nuke any default routers in the kernel, by 623151539Ssuz * going through them by rtalloc1()? 624151539Ssuz */ 625151539Ssuz} 626151539Ssuz 627303458Ssbruno/* 628303458Ssbruno * Look up a matching default router list entry and remove it. Returns true if a 629303458Ssbruno * matching entry was found, false otherwise. 630303458Ssbruno */ 631303458Ssbrunobool 632303458Ssbrunodefrouter_remove(struct in6_addr *addr, struct ifnet *ifp) 633303458Ssbruno{ 634303458Ssbruno struct nd_defrouter *dr; 635303458Ssbruno 636303458Ssbruno ND6_WLOCK(); 637303458Ssbruno dr = defrouter_lookup_locked(addr, ifp); 638303458Ssbruno if (dr == NULL) { 639303458Ssbruno ND6_WUNLOCK(); 640303458Ssbruno return (false); 641303458Ssbruno } 642303458Ssbruno 643303458Ssbruno defrouter_unlink(dr, NULL); 644303458Ssbruno ND6_WUNLOCK(); 645303458Ssbruno defrouter_del(dr); 646303458Ssbruno defrouter_rele(dr); 647303458Ssbruno return (true); 648303458Ssbruno} 649303458Ssbruno 650303458Ssbruno/* 651303458Ssbruno * Remove a router from the global list and optionally stash it in a 652303458Ssbruno * caller-supplied queue. 653303458Ssbruno * 654303458Ssbruno * The ND lock must be held. 655303458Ssbruno */ 656151539Ssuzvoid 657303458Ssbrunodefrouter_unlink(struct nd_defrouter *dr, struct nd_drhead *drq) 65853541Sshin{ 659303458Ssbruno 660303458Ssbruno ND6_WLOCK_ASSERT(); 661303458Ssbruno TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 662303458Ssbruno if (drq != NULL) 663303458Ssbruno TAILQ_INSERT_TAIL(drq, dr, dr_entry); 664303458Ssbruno} 665303458Ssbruno 666303458Ssbrunovoid 667303458Ssbrunodefrouter_del(struct nd_defrouter *dr) 668303458Ssbruno{ 66953541Sshin struct nd_defrouter *deldr = NULL; 67053541Sshin struct nd_prefix *pr; 67153541Sshin 672303458Ssbruno ND6_UNLOCK_ASSERT(); 673303458Ssbruno 67453541Sshin /* 67553541Sshin * Flush all the routing table entries that use the router 67653541Sshin * as a next hop. 67753541Sshin */ 678222728Shrs if (ND_IFINFO(dr->ifp)->flags & ND6_IFF_ACCEPT_RTADV) 67953541Sshin rt6_flush(&dr->rtaddr, dr->ifp); 68053541Sshin 681151539Ssuz if (dr->installed) { 682151539Ssuz deldr = dr; 683151539Ssuz defrouter_delreq(dr); 684151539Ssuz } 68553541Sshin 68653541Sshin /* 68753541Sshin * Also delete all the pointers to the router in each prefix lists. 68853541Sshin */ 689228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 69053541Sshin struct nd_pfxrouter *pfxrtr; 69153541Sshin if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 69253541Sshin pfxrtr_del(pfxrtr); 69353541Sshin } 69453541Sshin pfxlist_onlink_check(); 69553541Sshin 69653541Sshin /* 69762587Sitojun * If the router is the primary one, choose a new one. 69862587Sitojun * Note that defrouter_select() will remove the current gateway 69962587Sitojun * from the routing table. 70053541Sshin */ 70153541Sshin if (deldr) 70262587Sitojun defrouter_select(); 70362587Sitojun 704303458Ssbruno /* 705303458Ssbruno * Release the list reference. 706303458Ssbruno */ 707303458Ssbruno defrouter_rele(dr); 70853541Sshin} 70953541Sshin 71062587Sitojun/* 711151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and 712151539Ssuz * draft-ietf-ipngwg-router-selection: 713151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred. 714151539Ssuz * If we have more than one (probably) reachable router, prefer ones 715151539Ssuz * with the highest router preference. 71662587Sitojun * 2) When no routers on the list are known to be reachable or 71762587Sitojun * probably reachable, routers SHOULD be selected in a round-robin 718151539Ssuz * fashion, regardless of router preference values. 71962587Sitojun * 3) If the Default Router List is empty, assume that all 72062587Sitojun * destinations are on-link. 721151539Ssuz * 722151539Ssuz * We assume nd_defrouter is sorted by router preference value. 723151539Ssuz * Since the code below covers both with and without router preference cases, 724151539Ssuz * we do not need to classify the cases by ifdef. 725151539Ssuz * 726151539Ssuz * At this moment, we do not try to install more than one default router, 727151539Ssuz * even when the multipath routing is available, because we're not sure about 728151539Ssuz * the benefits for stub hosts comparing to the risk of making the code 729151539Ssuz * complicated and the possibility of introducing bugs. 73062587Sitojun */ 73162587Sitojunvoid 732171259Sdelphijdefrouter_select(void) 73362587Sitojun{ 734303458Ssbruno struct nd_defrouter *dr, *selected_dr, *installed_dr; 735186119Sqingli struct llentry *ln = NULL; 73662587Sitojun 737303458Ssbruno ND6_RLOCK(); 73862587Sitojun /* 739151539Ssuz * Let's handle easy case (3) first: 740151539Ssuz * If default router list is empty, there's nothing to be done. 741151539Ssuz */ 742303458Ssbruno if (TAILQ_EMPTY(&V_nd_defrouter)) { 743303458Ssbruno ND6_RUNLOCK(); 744151539Ssuz return; 745303458Ssbruno } 746151539Ssuz 747151539Ssuz /* 74862587Sitojun * Search for a (probably) reachable router from the list. 749151539Ssuz * We just pick up the first reachable one (if any), assuming that 750151539Ssuz * the ordering rule of the list described in defrtrlist_update(). 75162587Sitojun */ 752303458Ssbruno selected_dr = installed_dr = NULL; 753228966Sjhb TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { 754243148Sae IF_AFDATA_RLOCK(dr->ifp); 755151539Ssuz if (selected_dr == NULL && 756186119Sqingli (ln = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && 75762587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) { 758151539Ssuz selected_dr = dr; 759303458Ssbruno defrouter_ref(selected_dr); 76062587Sitojun } 761243148Sae IF_AFDATA_RUNLOCK(dr->ifp); 762188113Sbz if (ln != NULL) { 763186148Skmacy LLE_RUNLOCK(ln); 764188113Sbz ln = NULL; 765188113Sbz } 76662587Sitojun 767303458Ssbruno if (dr->installed) { 768303458Ssbruno if (installed_dr == NULL) { 769303458Ssbruno installed_dr = dr; 770303458Ssbruno defrouter_ref(installed_dr); 771303458Ssbruno } else { 772303458Ssbruno /* this should not happen. warn for diagnosis. */ 773303458Ssbruno log(LOG_ERR, 774303458Ssbruno "defrouter_select: more than one router is installed\n"); 775303458Ssbruno } 77662587Sitojun } 77762587Sitojun } 778151539Ssuz /* 779151539Ssuz * If none of the default routers was found to be reachable, 780151539Ssuz * round-robin the list regardless of preference. 781151539Ssuz * Otherwise, if we have an installed router, check if the selected 782151539Ssuz * (reachable) router should really be preferred to the installed one. 783151539Ssuz * We only prefer the new router when the old one is not reachable 784151539Ssuz * or when the new one has a really higher preference value. 785151539Ssuz */ 786151539Ssuz if (selected_dr == NULL) { 787303458Ssbruno if (installed_dr == NULL || 788303458Ssbruno TAILQ_NEXT(installed_dr, dr_entry) == NULL) 789181803Sbz selected_dr = TAILQ_FIRST(&V_nd_defrouter); 790151539Ssuz else 791151539Ssuz selected_dr = TAILQ_NEXT(installed_dr, dr_entry); 792303458Ssbruno defrouter_ref(selected_dr); 793303458Ssbruno } else if (installed_dr != NULL) { 794243148Sae IF_AFDATA_RLOCK(installed_dr->ifp); 795186119Sqingli if ((ln = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && 796186119Sqingli ND6_IS_LLINFO_PROBREACH(ln) && 797186119Sqingli rtpref(selected_dr) <= rtpref(installed_dr)) { 798303458Ssbruno defrouter_rele(selected_dr); 799186119Sqingli selected_dr = installed_dr; 800186119Sqingli } 801243148Sae IF_AFDATA_RUNLOCK(installed_dr->ifp); 802186148Skmacy if (ln != NULL) 803186148Skmacy LLE_RUNLOCK(ln); 804151539Ssuz } 805303458Ssbruno ND6_RUNLOCK(); 80662587Sitojun 807151539Ssuz /* 808151539Ssuz * If the selected router is different than the installed one, 809151539Ssuz * remove the installed router and install the selected one. 810151539Ssuz * Note that the selected router is never NULL here. 811151539Ssuz */ 812151539Ssuz if (installed_dr != selected_dr) { 813303458Ssbruno if (installed_dr != NULL) { 814151539Ssuz defrouter_delreq(installed_dr); 815303458Ssbruno defrouter_rele(installed_dr); 816303458Ssbruno } 817151539Ssuz defrouter_addreq(selected_dr); 818151539Ssuz } 819303458Ssbruno defrouter_rele(selected_dr); 82062587Sitojun} 82162587Sitojun 822151539Ssuz/* 823151539Ssuz * for default router selection 824151539Ssuz * regards router-preference field as a 2-bit signed integer 825151539Ssuz */ 826151539Ssuzstatic int 827151539Ssuzrtpref(struct nd_defrouter *dr) 828151539Ssuz{ 829299145Smarkj switch (dr->raflags & ND_RA_FLAG_RTPREF_MASK) { 830151539Ssuz case ND_RA_FLAG_RTPREF_HIGH: 831151539Ssuz return (RTPREF_HIGH); 832151539Ssuz case ND_RA_FLAG_RTPREF_MEDIUM: 833156871Ssuz case ND_RA_FLAG_RTPREF_RSV: 834151539Ssuz return (RTPREF_MEDIUM); 835151539Ssuz case ND_RA_FLAG_RTPREF_LOW: 836151539Ssuz return (RTPREF_LOW); 837151539Ssuz default: 838151539Ssuz /* 839151539Ssuz * This case should never happen. If it did, it would mean a 840151539Ssuz * serious bug of kernel internal. We thus always bark here. 841151539Ssuz * Or, can we even panic? 842151539Ssuz */ 843299145Smarkj log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->raflags); 844151539Ssuz return (RTPREF_INVALID); 845151539Ssuz } 846151539Ssuz /* NOTREACHED */ 847151539Ssuz} 848151539Ssuz 84953541Sshinstatic struct nd_defrouter * 850171259Sdelphijdefrtrlist_update(struct nd_defrouter *new) 85153541Sshin{ 85253541Sshin struct nd_defrouter *dr, *n; 853299014Smarkj int oldpref; 85453541Sshin 855303458Ssbruno if (new->rtlifetime == 0) { 856303458Ssbruno defrouter_remove(&new->rtaddr, new->ifp); 857303458Ssbruno return (NULL); 858303458Ssbruno } 859151539Ssuz 860303458Ssbruno ND6_WLOCK(); 861303458Ssbruno dr = defrouter_lookup_locked(&new->rtaddr, new->ifp); 862303458Ssbruno if (dr != NULL) { 863299014Smarkj oldpref = rtpref(dr); 864151539Ssuz 865299014Smarkj /* override */ 866299145Smarkj dr->raflags = new->raflags; /* XXX flag check */ 867299014Smarkj dr->rtlifetime = new->rtlifetime; 868299014Smarkj dr->expire = new->expire; 869151539Ssuz 870299014Smarkj /* 871299014Smarkj * If the preference does not change, there's no need 872299014Smarkj * to sort the entries. Also make sure the selected 873299014Smarkj * router is still installed in the kernel. 874299014Smarkj */ 875303458Ssbruno if (dr->installed && rtpref(new) == oldpref) { 876303458Ssbruno ND6_WUNLOCK(); 877299014Smarkj return (dr); 878303458Ssbruno } 879299014Smarkj 880299014Smarkj /* 881299014Smarkj * The preferred router may have changed, so relocate this 882299014Smarkj * router. 883299014Smarkj */ 884299014Smarkj TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 885299014Smarkj n = dr; 886303458Ssbruno } else { 887303458Ssbruno n = malloc(sizeof(*n), M_IP6NDP, M_NOWAIT | M_ZERO); 888303458Ssbruno if (n == NULL) { 889303458Ssbruno ND6_WUNLOCK(); 890303458Ssbruno return (NULL); 891303458Ssbruno } 892303458Ssbruno memcpy(n, new, sizeof(*n)); 893303458Ssbruno /* Initialize with an extra reference for the caller. */ 894303458Ssbruno refcount_init(&n->refcnt, 2); 89553541Sshin } 89653541Sshin 89762587Sitojun /* 898151539Ssuz * Insert the new router in the Default Router List; 899151539Ssuz * The Default Router List should be in the descending order 900151539Ssuz * of router-preferece. Routers with the same preference are 901151539Ssuz * sorted in the arriving time order. 90262587Sitojun */ 903151539Ssuz 904151539Ssuz /* insert at the end of the group */ 905228966Sjhb TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { 906151539Ssuz if (rtpref(n) > rtpref(dr)) 907151539Ssuz break; 908151539Ssuz } 909303458Ssbruno if (dr != NULL) 910151539Ssuz TAILQ_INSERT_BEFORE(dr, n, dr_entry); 911151539Ssuz else 912181803Sbz TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry); 913303458Ssbruno ND6_WUNLOCK(); 914151539Ssuz 915151539Ssuz defrouter_select(); 916151539Ssuz 917120856Sume return (n); 91853541Sshin} 91953541Sshin 92053541Sshinstatic struct nd_pfxrouter * 921171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) 92253541Sshin{ 92353541Sshin struct nd_pfxrouter *search; 924120941Sume 925228966Sjhb LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) { 92653541Sshin if (search->router == dr) 92753541Sshin break; 92853541Sshin } 92953541Sshin 930120856Sume return (search); 93153541Sshin} 93253541Sshin 93353541Sshinstatic void 934171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) 93553541Sshin{ 93653541Sshin struct nd_pfxrouter *new; 93753541Sshin 938299014Smarkj new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT | M_ZERO); 93953541Sshin if (new == NULL) 94053541Sshin return; 94153541Sshin new->router = dr; 942303458Ssbruno defrouter_ref(dr); 94353541Sshin 94453541Sshin LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 94553541Sshin 94653541Sshin pfxlist_onlink_check(); 94753541Sshin} 94853541Sshin 94953541Sshinstatic void 950171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr) 95153541Sshin{ 952303458Ssbruno 95353541Sshin LIST_REMOVE(pfr, pfr_entry); 954303458Ssbruno defrouter_rele(pfr->router); 95553541Sshin free(pfr, M_IP6NDP); 95653541Sshin} 95753541Sshin 95878064Sumestruct nd_prefix * 959171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key) 96053541Sshin{ 96153541Sshin struct nd_prefix *search; 96253541Sshin 963228966Sjhb LIST_FOREACH(search, &V_nd_prefix, ndpr_entry) { 964151539Ssuz if (key->ndpr_ifp == search->ndpr_ifp && 965151539Ssuz key->ndpr_plen == search->ndpr_plen && 966151539Ssuz in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr, 967151539Ssuz &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) { 96853541Sshin break; 96953541Sshin } 97053541Sshin } 97153541Sshin 972120856Sume return (search); 97353541Sshin} 97453541Sshin 97578064Sumeint 976171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr, 977171259Sdelphij struct nd_prefix **newp) 97853541Sshin{ 97978064Sume struct nd_prefix *new = NULL; 980151539Ssuz int error = 0; 981241686Sandre int i; 982165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 98353541Sshin 984299014Smarkj new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT | M_ZERO); 98553541Sshin if (new == NULL) 986299014Smarkj return (ENOMEM); 987151539Ssuz new->ndpr_ifp = pr->ndpr_ifp; 988151539Ssuz new->ndpr_prefix = pr->ndpr_prefix; 989151539Ssuz new->ndpr_plen = pr->ndpr_plen; 990151539Ssuz new->ndpr_vltime = pr->ndpr_vltime; 991151539Ssuz new->ndpr_pltime = pr->ndpr_pltime; 992151539Ssuz new->ndpr_flags = pr->ndpr_flags; 993151539Ssuz if ((error = in6_init_prefix_ltimes(new)) != 0) { 994151539Ssuz free(new, M_IP6NDP); 995303458Ssbruno return (error); 996151539Ssuz } 997253970Shrs new->ndpr_lastupdate = time_uptime; 99853541Sshin 999120941Sume /* initialization */ 100053541Sshin LIST_INIT(&new->ndpr_advrtrs); 100153541Sshin in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 100253541Sshin /* make prefix in the canonical form */ 100353541Sshin for (i = 0; i < 4; i++) 100453541Sshin new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 1005120941Sume new->ndpr_mask.s6_addr32[i]; 100653541Sshin 100753541Sshin /* link ndpr_entry to nd_prefix list */ 1008181803Sbz LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry); 100953541Sshin 101078064Sume /* ND_OPT_PI_FLAG_ONLINK processing */ 101178064Sume if (new->ndpr_raf_onlink) { 101278064Sume int e; 101378064Sume 101478064Sume if ((e = nd6_prefix_onlink(new)) != 0) { 101578064Sume nd6log((LOG_ERR, "nd6_prelist_add: failed to make " 101678064Sume "the prefix %s/%d on-link on %s (errno=%d)\n", 1017165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 101878064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 101978064Sume /* proceed anyway. XXX: is it correct? */ 102078064Sume } 102178064Sume } 102278064Sume 1023303458Ssbruno if (dr != NULL) 102453541Sshin pfxrtr_add(new, dr); 1025303458Ssbruno if (newp != NULL) 1026303458Ssbruno *newp = new; 1027303458Ssbruno return (0); 102853541Sshin} 102953541Sshin 103053541Sshinvoid 1031171259Sdelphijprelist_remove(struct nd_prefix *pr) 103253541Sshin{ 103353541Sshin struct nd_pfxrouter *pfr, *next; 1034241686Sandre int e; 1035165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 103653541Sshin 103778064Sume /* make sure to invalidate the prefix until it is really freed. */ 103878064Sume pr->ndpr_vltime = 0; 103978064Sume pr->ndpr_pltime = 0; 1040151539Ssuz 104178064Sume /* 104278064Sume * Though these flags are now meaningless, we'd rather keep the value 1043151479Ssuz * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users 1044151479Ssuz * when executing "ndp -p". 104578064Sume */ 1046151479Ssuz 104778064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && 104878064Sume (e = nd6_prefix_offlink(pr)) != 0) { 104978064Sume nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " 105078064Sume "on %s, errno=%d\n", 1051165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 105278064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 105378064Sume /* what should we do? */ 105478064Sume } 105578064Sume 105678064Sume if (pr->ndpr_refcnt > 0) 105778064Sume return; /* notice here? */ 105878064Sume 105953541Sshin /* unlink ndpr_entry from nd_prefix list */ 106053541Sshin LIST_REMOVE(pr, ndpr_entry); 106153541Sshin 1062299145Smarkj /* free list of routers that advertised the prefix */ 1063228966Sjhb LIST_FOREACH_SAFE(pfr, &pr->ndpr_advrtrs, pfr_entry, next) { 1064299145Smarkj pfxrtr_del(pfr); 106553541Sshin } 106653541Sshin free(pr, M_IP6NDP); 106753541Sshin 106853541Sshin pfxlist_onlink_check(); 106953541Sshin} 107053541Sshin 1071171259Sdelphij/* 1072171259Sdelphij * dr - may be NULL 1073171259Sdelphij */ 1074171259Sdelphij 1075151539Ssuzstatic int 1076171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, 1077171259Sdelphij struct mbuf *m, int mcast) 107853541Sshin{ 107978064Sume struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 108078064Sume struct ifaddr *ifa; 108178064Sume struct ifnet *ifp = new->ndpr_ifp; 108253541Sshin struct nd_prefix *pr; 108353541Sshin int error = 0; 108453541Sshin int auth; 108578064Sume struct in6_addrlifetime lt6_tmp; 1086165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 108753541Sshin 108853541Sshin auth = 0; 108953541Sshin if (m) { 109053541Sshin /* 109153541Sshin * Authenticity for NA consists authentication for 109253541Sshin * both IP header and IP datagrams, doesn't it ? 109353541Sshin */ 109453541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 1095120941Sume auth = ((m->m_flags & M_AUTHIPHDR) && 1096120941Sume (m->m_flags & M_AUTHIPDGM)); 109753541Sshin#endif 109853541Sshin } 109953541Sshin 110078064Sume if ((pr = nd6_prefix_lookup(new)) != NULL) { 110178064Sume /* 110278064Sume * nd6_prefix_lookup() ensures that pr and new have the same 110378064Sume * prefix on a same interface. 110478064Sume */ 110553541Sshin 110653541Sshin /* 110778064Sume * Update prefix information. Note that the on-link (L) bit 110878064Sume * and the autonomous (A) bit should NOT be changed from 1 110978064Sume * to 0. 111053541Sshin */ 111178064Sume if (new->ndpr_raf_onlink == 1) 111278064Sume pr->ndpr_raf_onlink = 1; 111378064Sume if (new->ndpr_raf_auto == 1) 111478064Sume pr->ndpr_raf_auto = 1; 111578064Sume if (new->ndpr_raf_onlink) { 111678064Sume pr->ndpr_vltime = new->ndpr_vltime; 111778064Sume pr->ndpr_pltime = new->ndpr_pltime; 1118151539Ssuz (void)in6_init_prefix_ltimes(pr); /* XXX error case? */ 1119253970Shrs pr->ndpr_lastupdate = time_uptime; 112078064Sume } 112153541Sshin 112278064Sume if (new->ndpr_raf_onlink && 112378064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 112478064Sume int e; 112553541Sshin 112678064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 112778064Sume nd6log((LOG_ERR, 112878064Sume "prelist_update: failed to make " 112978064Sume "the prefix %s/%d on-link on %s " 113078064Sume "(errno=%d)\n", 1131165118Sbz ip6_sprintf(ip6buf, 1132165118Sbz &pr->ndpr_prefix.sin6_addr), 113378064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 113478064Sume /* proceed anyway. XXX: is it correct? */ 113553541Sshin } 113678064Sume } 113753541Sshin 113878064Sume if (dr && pfxrtr_lookup(pr, dr) == NULL) 113978064Sume pfxrtr_add(pr, dr); 114078064Sume } else { 114178064Sume if (new->ndpr_vltime == 0) 114278064Sume goto end; 114378064Sume if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 114478064Sume goto end; 114553541Sshin 1146303458Ssbruno error = nd6_prelist_add(new, dr, &pr); 1147303458Ssbruno if (error != 0) { 114878064Sume nd6log((LOG_NOTICE, "prelist_update: " 1149303458Ssbruno "nd6_prelist_add failed for %s/%d on %s errno=%d\n", 1150165118Sbz ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr), 1151303458Ssbruno new->ndpr_plen, if_name(new->ndpr_ifp), error)); 115278064Sume goto end; /* we should just give up in this case. */ 115378064Sume } 115453541Sshin 115578064Sume /* 115678064Sume * XXX: from the ND point of view, we can ignore a prefix 115778064Sume * with the on-link bit being zero. However, we need a 115878064Sume * prefix structure for references from autoconfigured 1159120941Sume * addresses. Thus, we explicitly make sure that the prefix 116078064Sume * itself expires now. 116178064Sume */ 1162303458Ssbruno if (pr->ndpr_raf_onlink == 0) { 1163303458Ssbruno pr->ndpr_vltime = 0; 1164303458Ssbruno pr->ndpr_pltime = 0; 1165303458Ssbruno in6_init_prefix_ltimes(pr); 116653541Sshin } 116778064Sume } 116853541Sshin 116978064Sume /* 117078064Sume * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 117178064Sume * Note that pr must be non NULL at this point. 117278064Sume */ 117362587Sitojun 117478064Sume /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 117578064Sume if (!new->ndpr_raf_auto) 1176151539Ssuz goto end; 117762587Sitojun 117878064Sume /* 117978064Sume * 5.5.3 (b). the link-local prefix should have been ignored in 118078064Sume * nd6_ra_input. 118178064Sume */ 118262587Sitojun 1183151539Ssuz /* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */ 1184151539Ssuz if (new->ndpr_pltime > new->ndpr_vltime) { 1185151539Ssuz error = EINVAL; /* XXX: won't be used */ 1186151539Ssuz goto end; 1187151539Ssuz } 118862587Sitojun 1189171260Sdelphij /* 1190151539Ssuz * 5.5.3 (d). If the prefix advertised is not equal to the prefix of 1191151539Ssuz * an address configured by stateless autoconfiguration already in the 1192151539Ssuz * list of addresses associated with the interface, and the Valid 1193151539Ssuz * Lifetime is not 0, form an address. We first check if we have 1194151539Ssuz * a matching prefix. 1195151539Ssuz * Note: we apply a clarification in rfc2462bis-02 here. We only 1196151539Ssuz * consider autoconfigured addresses while RFC2462 simply said 1197151539Ssuz * "address". 119878064Sume */ 1199229621Sjhb IF_ADDR_RLOCK(ifp); 1200191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 120178064Sume struct in6_ifaddr *ifa6; 1202151539Ssuz u_int32_t remaininglifetime; 120353541Sshin 120478064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 120578064Sume continue; 120653541Sshin 120778064Sume ifa6 = (struct in6_ifaddr *)ifa; 120853541Sshin 120953541Sshin /* 1210151539Ssuz * We only consider autoconfigured addresses as per rfc2462bis. 1211151539Ssuz */ 1212151539Ssuz if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF)) 1213151539Ssuz continue; 1214151539Ssuz 1215151539Ssuz /* 121678064Sume * Spec is not clear here, but I believe we should concentrate 121778064Sume * on unicast (i.e. not anycast) addresses. 121878064Sume * XXX: other ia6_flags? detached or duplicated? 121953541Sshin */ 122078064Sume if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 122178064Sume continue; 1222120941Sume 1223151539Ssuz /* 1224151539Ssuz * Ignore the address if it is not associated with a prefix 1225151539Ssuz * or is associated with a prefix that is different from this 1226151539Ssuz * one. (pr is never NULL here) 1227151539Ssuz */ 1228151539Ssuz if (ifa6->ia6_ndpr != pr) 122978064Sume continue; 123053541Sshin 123178064Sume if (ia6_match == NULL) /* remember the first one */ 123278064Sume ia6_match = ifa6; 123378064Sume 123478064Sume /* 123578064Sume * An already autoconfigured address matched. Now that we 123678064Sume * are sure there is at least one matched address, we can 123778064Sume * proceed to 5.5.3. (e): update the lifetimes according to the 123878064Sume * "two hours" rule and the privacy extension. 1239151539Ssuz * We apply some clarifications in rfc2462bis: 1240151539Ssuz * - use remaininglifetime instead of storedlifetime as a 1241151539Ssuz * variable name 1242151539Ssuz * - remove the dead code in the "two-hour" rule 124378064Sume */ 124478064Sume#define TWOHOUR (120*60) 124578064Sume lt6_tmp = ifa6->ia6_lifetime; 124678064Sume 1247112678Sume if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 1248151539Ssuz remaininglifetime = ND6_INFINITE_LIFETIME; 1249253970Shrs else if (time_uptime - ifa6->ia6_updatetime > 1250151539Ssuz lt6_tmp.ia6t_vltime) { 1251151539Ssuz /* 1252151539Ssuz * The case of "invalid" address. We should usually 1253151539Ssuz * not see this case. 1254151539Ssuz */ 1255151539Ssuz remaininglifetime = 0; 1256151539Ssuz } else 1257151539Ssuz remaininglifetime = lt6_tmp.ia6t_vltime - 1258253970Shrs (time_uptime - ifa6->ia6_updatetime); 125978064Sume 1260112678Sume /* when not updating, keep the current stored lifetime. */ 1261151539Ssuz lt6_tmp.ia6t_vltime = remaininglifetime; 1262112678Sume 126378064Sume if (TWOHOUR < new->ndpr_vltime || 1264151539Ssuz remaininglifetime < new->ndpr_vltime) { 126578064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 1266151539Ssuz } else if (remaininglifetime <= TWOHOUR) { 126778064Sume if (auth) { 126878064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 126978064Sume } 127078064Sume } else { 127178064Sume /* 127278064Sume * new->ndpr_vltime <= TWOHOUR && 1273151539Ssuz * TWOHOUR < remaininglifetime 127478064Sume */ 127578064Sume lt6_tmp.ia6t_vltime = TWOHOUR; 127653541Sshin } 127753541Sshin 127878064Sume /* The 2 hour rule is not imposed for preferred lifetime. */ 127978064Sume lt6_tmp.ia6t_pltime = new->ndpr_pltime; 128053541Sshin 128178064Sume in6_init_address_ltimes(pr, <6_tmp); 128253541Sshin 1283171260Sdelphij /* 1284151539Ssuz * We need to treat lifetimes for temporary addresses 1285151539Ssuz * differently, according to 1286151539Ssuz * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1); 1287151539Ssuz * we only update the lifetimes when they are in the maximum 1288151539Ssuz * intervals. 1289171260Sdelphij */ 1290171260Sdelphij if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 1291151539Ssuz u_int32_t maxvltime, maxpltime; 1292151539Ssuz 1293181803Sbz if (V_ip6_temp_valid_lifetime > 1294253970Shrs (u_int32_t)((time_uptime - ifa6->ia6_createtime) + 1295181803Sbz V_ip6_desync_factor)) { 1296181803Sbz maxvltime = V_ip6_temp_valid_lifetime - 1297253970Shrs (time_uptime - ifa6->ia6_createtime) - 1298181803Sbz V_ip6_desync_factor; 1299151539Ssuz } else 1300151539Ssuz maxvltime = 0; 1301181803Sbz if (V_ip6_temp_preferred_lifetime > 1302253970Shrs (u_int32_t)((time_uptime - ifa6->ia6_createtime) + 1303181803Sbz V_ip6_desync_factor)) { 1304181803Sbz maxpltime = V_ip6_temp_preferred_lifetime - 1305253970Shrs (time_uptime - ifa6->ia6_createtime) - 1306181803Sbz V_ip6_desync_factor; 1307151539Ssuz } else 1308151539Ssuz maxpltime = 0; 1309151539Ssuz 1310151539Ssuz if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME || 1311151539Ssuz lt6_tmp.ia6t_vltime > maxvltime) { 1312151539Ssuz lt6_tmp.ia6t_vltime = maxvltime; 131378064Sume } 1314151539Ssuz if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || 1315151539Ssuz lt6_tmp.ia6t_pltime > maxpltime) { 1316151539Ssuz lt6_tmp.ia6t_pltime = maxpltime; 131778064Sume } 131878064Sume } 131978064Sume ifa6->ia6_lifetime = lt6_tmp; 1320253970Shrs ifa6->ia6_updatetime = time_uptime; 132153541Sshin } 1322229621Sjhb IF_ADDR_RUNLOCK(ifp); 132378064Sume if (ia6_match == NULL && new->ndpr_vltime) { 1324151539Ssuz int ifidlen; 1325151539Ssuz 132678064Sume /* 1327151539Ssuz * 5.5.3 (d) (continued) 132878064Sume * No address matched and the valid lifetime is non-zero. 132978064Sume * Create a new address. 133078064Sume */ 1331151539Ssuz 1332151539Ssuz /* 1333151539Ssuz * Prefix Length check: 1334151539Ssuz * If the sum of the prefix length and interface identifier 1335151539Ssuz * length does not equal 128 bits, the Prefix Information 1336151539Ssuz * option MUST be ignored. The length of the interface 1337151539Ssuz * identifier is defined in a separate link-type specific 1338151539Ssuz * document. 1339151539Ssuz */ 1340151539Ssuz ifidlen = in6_if2idlen(ifp); 1341151539Ssuz if (ifidlen < 0) { 1342151539Ssuz /* this should not happen, so we always log it. */ 1343151539Ssuz log(LOG_ERR, "prelist_update: IFID undefined (%s)\n", 1344151539Ssuz if_name(ifp)); 1345151539Ssuz goto end; 1346151539Ssuz } 1347151539Ssuz if (ifidlen + pr->ndpr_plen != 128) { 1348151539Ssuz nd6log((LOG_INFO, 1349151539Ssuz "prelist_update: invalid prefixlen " 1350151539Ssuz "%d for %s, ignored\n", 1351151539Ssuz pr->ndpr_plen, if_name(ifp))); 1352151539Ssuz goto end; 1353151539Ssuz } 1354151539Ssuz 1355151539Ssuz if ((ia6 = in6_ifadd(new, mcast)) != NULL) { 135678064Sume /* 135778064Sume * note that we should use pr (not new) for reference. 135878064Sume */ 135978064Sume pr->ndpr_refcnt++; 136078064Sume ia6->ia6_ndpr = pr; 136153541Sshin 136278064Sume /* 136378064Sume * RFC 3041 3.3 (2). 136478064Sume * When a new public address is created as described 136578064Sume * in RFC2462, also create a new temporary address. 136678064Sume * 136778064Sume * RFC 3041 3.5. 136878064Sume * When an interface connects to a new link, a new 136978064Sume * randomized interface identifier should be generated 137078064Sume * immediately together with a new set of temporary 137178064Sume * addresses. Thus, we specifiy 1 as the 2nd arg of 137278064Sume * in6_tmpifadd(). 137378064Sume */ 1374181803Sbz if (V_ip6_use_tempaddr) { 137578064Sume int e; 1376151539Ssuz if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) { 137778064Sume nd6log((LOG_NOTICE, "prelist_update: " 137878064Sume "failed to create a temporary " 137978064Sume "address, errno=%d\n", 138078064Sume e)); 138178064Sume } 138278064Sume } 1383194760Srwatson ifa_free(&ia6->ia_ifa); 138478064Sume 138578064Sume /* 138678064Sume * A newly added address might affect the status 138778064Sume * of other addresses, so we check and update it. 138878064Sume * XXX: what if address duplication happens? 138978064Sume */ 139078064Sume pfxlist_onlink_check(); 139178064Sume } else { 139278064Sume /* just set an error. do not bark here. */ 139378064Sume error = EADDRNOTAVAIL; /* XXX: might be unused. */ 139478064Sume } 139578064Sume } 139678064Sume 139753541Sshin end: 139853541Sshin return error; 139953541Sshin} 140053541Sshin 140153541Sshin/* 140262587Sitojun * A supplement function used in the on-link detection below; 140362587Sitojun * detect if a given prefix has a (probably) reachable advertising router. 140462587Sitojun * XXX: lengthy function name... 140562587Sitojun */ 140678064Sumestatic struct nd_pfxrouter * 1407171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr) 140862587Sitojun{ 140962587Sitojun struct nd_pfxrouter *pfxrtr; 1410186119Sqingli struct llentry *ln; 1411186162Skmacy int canreach; 141262587Sitojun 1413228966Sjhb LIST_FOREACH(pfxrtr, &pr->ndpr_advrtrs, pfr_entry) { 1414243148Sae IF_AFDATA_RLOCK(pfxrtr->router->ifp); 1415186162Skmacy ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp); 1416243148Sae IF_AFDATA_RUNLOCK(pfxrtr->router->ifp); 1417186198Skmacy if (ln == NULL) 1418186198Skmacy continue; 1419186198Skmacy canreach = ND6_IS_LLINFO_PROBREACH(ln); 1420186198Skmacy LLE_RUNLOCK(ln); 1421186162Skmacy if (canreach) 1422186162Skmacy break; 142362587Sitojun } 1424120856Sume return (pfxrtr); 142562587Sitojun} 142662587Sitojun 142762587Sitojun/* 142853541Sshin * Check if each prefix in the prefix list has at least one available router 142978064Sume * that advertised the prefix (a router is "available" if its neighbor cache 143078064Sume * entry is reachable or probably reachable). 143162587Sitojun * If the check fails, the prefix may be off-link, because, for example, 143253541Sshin * we have moved from the network but the lifetime of the prefix has not 143378064Sume * expired yet. So we should not use the prefix if there is another prefix 143478064Sume * that has an available router. 143578064Sume * But, if there is no prefix that has an available router, we still regards 143678064Sume * all the prefixes as on-link. This is because we can't tell if all the 143753541Sshin * routers are simply dead or if we really moved from the network and there 143853541Sshin * is no router around us. 143953541Sshin */ 144062587Sitojunvoid 144153541Sshinpfxlist_onlink_check() 144253541Sshin{ 144353541Sshin struct nd_prefix *pr; 144478064Sume struct in6_ifaddr *ifa; 1445151539Ssuz struct nd_defrouter *dr; 1446151539Ssuz struct nd_pfxrouter *pfxrtr = NULL; 144753541Sshin 144862587Sitojun /* 144962587Sitojun * Check if there is a prefix that has a reachable advertising 145062587Sitojun * router. 145162587Sitojun */ 1452228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 145378064Sume if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 145453541Sshin break; 145562587Sitojun } 145653541Sshin 1457151539Ssuz /* 1458151539Ssuz * If we have no such prefix, check whether we still have a router 1459151539Ssuz * that does not advertise any prefixes. 1460151539Ssuz */ 1461151465Ssuz if (pr == NULL) { 1462303458Ssbruno ND6_RLOCK(); 1463228966Sjhb TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { 1464151539Ssuz struct nd_prefix *pr0; 1465151539Ssuz 1466228966Sjhb LIST_FOREACH(pr0, &V_nd_prefix, ndpr_entry) { 1467151539Ssuz if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) 1468151539Ssuz break; 1469151539Ssuz } 1470151539Ssuz if (pfxrtr != NULL) 1471151539Ssuz break; 1472151539Ssuz } 1473303458Ssbruno ND6_RUNLOCK(); 1474151539Ssuz } 1475228966Sjhb if (pr != NULL || (!TAILQ_EMPTY(&V_nd_defrouter) && pfxrtr == NULL)) { 1476171260Sdelphij /* 1477151539Ssuz * There is at least one prefix that has a reachable router, 1478151539Ssuz * or at least a router which probably does not advertise 1479151539Ssuz * any prefixes. The latter would be the case when we move 1480151539Ssuz * to a new link where we have a router that does not provide 1481151539Ssuz * prefixes and we configure an address by hand. 1482171260Sdelphij * Detach prefixes which have no reachable advertising 1483171260Sdelphij * router, and attach other prefixes. 1484171260Sdelphij */ 1485228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 148678064Sume /* XXX: a link-local prefix should never be detached */ 148778064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 148878064Sume continue; 148978064Sume 149078064Sume /* 149178064Sume * we aren't interested in prefixes without the L bit 149278064Sume * set. 149378064Sume */ 149478064Sume if (pr->ndpr_raf_onlink == 0) 149578064Sume continue; 149678064Sume 1497196649Sqingli if (pr->ndpr_raf_auto == 0) 1498196649Sqingli continue; 1499196649Sqingli 150078064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 150178064Sume find_pfxlist_reachable_router(pr) == NULL) 150278064Sume pr->ndpr_stateflags |= NDPRF_DETACHED; 150378064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 150478064Sume find_pfxlist_reachable_router(pr) != 0) 150578064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 150653541Sshin } 150778064Sume } else { 150878064Sume /* there is no prefix that has a reachable router */ 1509228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 151078064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 151178064Sume continue; 151278064Sume 151378064Sume if (pr->ndpr_raf_onlink == 0) 151478064Sume continue; 151578064Sume 1516196649Sqingli if (pr->ndpr_raf_auto == 0) 1517196649Sqingli continue; 1518196649Sqingli 151978064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 152078064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 152153541Sshin } 152262587Sitojun } 152378064Sume 152478064Sume /* 152578064Sume * Remove each interface route associated with a (just) detached 152678064Sume * prefix, and reinstall the interface route for a (just) attached 152778064Sume * prefix. Note that all attempt of reinstallation does not 152878064Sume * necessarily success, when a same prefix is shared among multiple 152978064Sume * interfaces. Such cases will be handled in nd6_prefix_onlink, 153078064Sume * so we don't have to care about them. 153178064Sume */ 1532228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 153378064Sume int e; 1534165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 153578064Sume 153678064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 153778064Sume continue; 153878064Sume 153978064Sume if (pr->ndpr_raf_onlink == 0) 154078064Sume continue; 154178064Sume 1542196649Sqingli if (pr->ndpr_raf_auto == 0) 1543196649Sqingli continue; 1544196649Sqingli 154578064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 154678064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 154778064Sume if ((e = nd6_prefix_offlink(pr)) != 0) { 154878064Sume nd6log((LOG_ERR, 154978064Sume "pfxlist_onlink_check: failed to " 1550151479Ssuz "make %s/%d offlink, errno=%d\n", 1551165118Sbz ip6_sprintf(ip6buf, 1552165118Sbz &pr->ndpr_prefix.sin6_addr), 1553165118Sbz pr->ndpr_plen, e)); 155478064Sume } 155578064Sume } 155678064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 155778064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 155878064Sume pr->ndpr_raf_onlink) { 155978064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 156078064Sume nd6log((LOG_ERR, 156178064Sume "pfxlist_onlink_check: failed to " 1562151479Ssuz "make %s/%d onlink, errno=%d\n", 1563165118Sbz ip6_sprintf(ip6buf, 1564165118Sbz &pr->ndpr_prefix.sin6_addr), 1565165118Sbz pr->ndpr_plen, e)); 156678064Sume } 156778064Sume } 156878064Sume } 156978064Sume 157078064Sume /* 157178064Sume * Changes on the prefix status might affect address status as well. 157278064Sume * Make sure that all addresses derived from an attached prefix are 157378064Sume * attached, and that all addresses derived from a detached prefix are 157478064Sume * detached. Note, however, that a manually configured address should 157578064Sume * always be attached. 157678064Sume * The precise detection logic is same as the one for prefixes. 1577194971Srwatson * 1578194971Srwatson * XXXRW: in6_ifaddrhead locking. 157978064Sume */ 1580194907Srwatson TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { 1581120941Sume if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) 158278064Sume continue; 158378064Sume 158478064Sume if (ifa->ia6_ndpr == NULL) { 158578064Sume /* 158678064Sume * This can happen when we first configure the address 158778064Sume * (i.e. the address exists, but the prefix does not). 158878064Sume * XXX: complicated relationships... 158978064Sume */ 159078064Sume continue; 159178064Sume } 159278064Sume 159378064Sume if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 159478064Sume break; 159578064Sume } 159678064Sume if (ifa) { 1597194907Srwatson TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { 159878064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 159978064Sume continue; 160078064Sume 160178064Sume if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 160278064Sume continue; 160378064Sume 1604151539Ssuz if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) { 1605151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1606151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1607151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1608151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1609151539Ssuz } 1610151539Ssuz } else { 161178064Sume ifa->ia6_flags |= IN6_IFF_DETACHED; 1612151539Ssuz } 161378064Sume } 161478064Sume } 161562587Sitojun else { 1616194907Srwatson TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { 161778064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 161878064Sume continue; 161978064Sume 1620151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1621151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1622151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1623151539Ssuz /* Do we need a delay in this case? */ 1624151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1625151539Ssuz } 162678064Sume } 162753541Sshin } 162853541Sshin} 162953541Sshin 1630229547Sbzstatic int 1631231852Sbznd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) 1632231852Sbz{ 1633231852Sbz static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1634231852Sbz struct radix_node_head *rnh; 1635231852Sbz struct rtentry *rt; 1636231852Sbz struct sockaddr_in6 mask6; 1637231852Sbz u_long rtflags; 1638231852Sbz int error, a_failure, fibnum; 1639231852Sbz 1640231852Sbz /* 1641231852Sbz * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 1642231852Sbz * ifa->ifa_rtrequest = nd6_rtrequest; 1643231852Sbz */ 1644231852Sbz bzero(&mask6, sizeof(mask6)); 1645231852Sbz mask6.sin6_len = sizeof(mask6); 1646231852Sbz mask6.sin6_addr = pr->ndpr_mask; 1647231852Sbz rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP; 1648231852Sbz 1649231852Sbz a_failure = 0; 1650231852Sbz for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 1651231852Sbz 1652231852Sbz rt = NULL; 1653231852Sbz error = in6_rtrequest(RTM_ADD, 1654231852Sbz (struct sockaddr *)&pr->ndpr_prefix, ifa->ifa_addr, 1655231852Sbz (struct sockaddr *)&mask6, rtflags, &rt, fibnum); 1656231852Sbz if (error == 0) { 1657231852Sbz KASSERT(rt != NULL, ("%s: in6_rtrequest return no " 1658231852Sbz "error(%d) but rt is NULL, pr=%p, ifa=%p", __func__, 1659231852Sbz error, pr, ifa)); 1660231852Sbz 1661231852Sbz rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6); 1662231852Sbz /* XXX what if rhn == NULL? */ 1663231852Sbz RADIX_NODE_HEAD_LOCK(rnh); 1664231852Sbz RT_LOCK(rt); 1665231852Sbz if (rt_setgate(rt, rt_key(rt), 1666231852Sbz (struct sockaddr *)&null_sdl) == 0) { 1667231852Sbz struct sockaddr_dl *dl; 1668231852Sbz 1669231852Sbz dl = (struct sockaddr_dl *)rt->rt_gateway; 1670231852Sbz dl->sdl_type = rt->rt_ifp->if_type; 1671231852Sbz dl->sdl_index = rt->rt_ifp->if_index; 1672231852Sbz } 1673231852Sbz RADIX_NODE_HEAD_UNLOCK(rnh); 1674231852Sbz nd6_rtmsg(RTM_ADD, rt); 1675231852Sbz RT_UNLOCK(rt); 1676231852Sbz pr->ndpr_stateflags |= NDPRF_ONLINK; 1677231852Sbz } else { 1678231852Sbz char ip6buf[INET6_ADDRSTRLEN]; 1679231852Sbz char ip6bufg[INET6_ADDRSTRLEN]; 1680231852Sbz char ip6bufm[INET6_ADDRSTRLEN]; 1681231852Sbz struct sockaddr_in6 *sin6; 1682231852Sbz 1683231852Sbz sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 1684231852Sbz nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add " 1685231852Sbz "route for a prefix (%s/%d) on %s, gw=%s, mask=%s, " 1686231852Sbz "flags=%lx errno = %d\n", 1687231852Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1688231852Sbz pr->ndpr_plen, if_name(pr->ndpr_ifp), 1689231852Sbz ip6_sprintf(ip6bufg, &sin6->sin6_addr), 1690231852Sbz ip6_sprintf(ip6bufm, &mask6.sin6_addr), 1691231852Sbz rtflags, error)); 1692231852Sbz 1693231852Sbz /* Save last error to return, see rtinit(). */ 1694231852Sbz a_failure = error; 1695231852Sbz } 1696231852Sbz 1697231852Sbz if (rt != NULL) { 1698231852Sbz RT_LOCK(rt); 1699231852Sbz RT_REMREF(rt); 1700231852Sbz RT_UNLOCK(rt); 1701231852Sbz } 1702231852Sbz } 1703231852Sbz 1704231852Sbz /* Return the last error we got. */ 1705231852Sbz return (a_failure); 1706231852Sbz} 1707231852Sbz 1708231852Sbzstatic int 1709171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr) 171053541Sshin{ 171178064Sume struct ifaddr *ifa; 171278064Sume struct ifnet *ifp = pr->ndpr_ifp; 171378064Sume struct nd_prefix *opr; 171478064Sume int error = 0; 1715165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 171653541Sshin 171778064Sume /* sanity check */ 171878064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 171978064Sume nd6log((LOG_ERR, 172078064Sume "nd6_prefix_onlink: %s/%d is already on-link\n", 1721165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1722165118Sbz pr->ndpr_plen)); 1723151465Ssuz return (EEXIST); 172478064Sume } 172578064Sume 172653541Sshin /* 172778064Sume * Add the interface route associated with the prefix. Before 172878064Sume * installing the route, check if there's the same prefix on another 172978064Sume * interface, and the prefix has already installed the interface route. 173078064Sume * Although such a configuration is expected to be rare, we explicitly 173178064Sume * allow it. 173253541Sshin */ 1733228966Sjhb LIST_FOREACH(opr, &V_nd_prefix, ndpr_entry) { 173478064Sume if (opr == pr) 173578064Sume continue; 173678064Sume 173778064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 173878064Sume continue; 173978064Sume 174078064Sume if (opr->ndpr_plen == pr->ndpr_plen && 174178064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1742120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) 1743120856Sume return (0); 174478064Sume } 174578064Sume 174678064Sume /* 1747120941Sume * We prefer link-local addresses as the associated interface address. 174878064Sume */ 174978064Sume /* search for a link-local addr */ 175078064Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 1751120941Sume IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); 175278064Sume if (ifa == NULL) { 175378064Sume /* XXX: freebsd does not have ifa_ifwithaf */ 1754229621Sjhb IF_ADDR_RLOCK(ifp); 1755191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 175678064Sume if (ifa->ifa_addr->sa_family == AF_INET6) 175778064Sume break; 175878064Sume } 1759194760Srwatson if (ifa != NULL) 1760194760Srwatson ifa_ref(ifa); 1761229621Sjhb IF_ADDR_RUNLOCK(ifp); 176278064Sume /* should we care about ia6_flags? */ 176378064Sume } 176478064Sume if (ifa == NULL) { 176578064Sume /* 176678064Sume * This can still happen, when, for example, we receive an RA 176778064Sume * containing a prefix with the L bit set and the A bit clear, 176878064Sume * after removing all IPv6 addresses on the receiving 176978064Sume * interface. This should, of course, be rare though. 177078064Sume */ 177178064Sume nd6log((LOG_NOTICE, 177278064Sume "nd6_prefix_onlink: failed to find any ifaddr" 177378064Sume " to add route for a prefix(%s/%d) on %s\n", 1774165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 177578064Sume pr->ndpr_plen, if_name(ifp))); 1776120856Sume return (0); 177778064Sume } 177878064Sume 1779231852Sbz error = nd6_prefix_onlink_rtrequest(pr, ifa); 178078064Sume 1781194760Srwatson if (ifa != NULL) 1782194760Srwatson ifa_free(ifa); 178378064Sume 1784120856Sume return (error); 178578064Sume} 178678064Sume 1787229547Sbzstatic int 1788171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr) 178978064Sume{ 179078064Sume int error = 0; 179178064Sume struct ifnet *ifp = pr->ndpr_ifp; 179278064Sume struct nd_prefix *opr; 179378064Sume struct sockaddr_in6 sa6, mask6; 1794231852Sbz struct rtentry *rt; 1795165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 1796231852Sbz int fibnum, a_failure; 179778064Sume 179878064Sume /* sanity check */ 179978064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 180078064Sume nd6log((LOG_ERR, 180178064Sume "nd6_prefix_offlink: %s/%d is already off-link\n", 1802165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1803165118Sbz pr->ndpr_plen)); 1804120856Sume return (EEXIST); 180578064Sume } 180678064Sume 180753541Sshin bzero(&sa6, sizeof(sa6)); 180853541Sshin sa6.sin6_family = AF_INET6; 180953541Sshin sa6.sin6_len = sizeof(sa6); 181053541Sshin bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 1811120941Sume sizeof(struct in6_addr)); 181253541Sshin bzero(&mask6, sizeof(mask6)); 181353541Sshin mask6.sin6_family = AF_INET6; 181453541Sshin mask6.sin6_len = sizeof(sa6); 181553541Sshin bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 1816231852Sbz 1817231852Sbz a_failure = 0; 1818231852Sbz for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 1819231852Sbz rt = NULL; 1820231852Sbz error = in6_rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 1821231852Sbz (struct sockaddr *)&mask6, 0, &rt, fibnum); 1822231852Sbz if (error == 0) { 1823231852Sbz /* report the route deletion to the routing socket. */ 1824231852Sbz if (rt != NULL) 1825231852Sbz nd6_rtmsg(RTM_DELETE, rt); 1826231852Sbz } else { 1827231852Sbz /* Save last error to return, see rtinit(). */ 1828231852Sbz a_failure = error; 1829231852Sbz } 1830231852Sbz if (rt != NULL) { 1831231852Sbz RTFREE(rt); 1832231852Sbz } 1833231852Sbz } 1834231852Sbz error = a_failure; 1835252141Sqingli a_failure = 1; 183678064Sume if (error == 0) { 183778064Sume pr->ndpr_stateflags &= ~NDPRF_ONLINK; 183853541Sshin 183978064Sume /* 184078064Sume * There might be the same prefix on another interface, 184178064Sume * the prefix which could not be on-link just because we have 184278064Sume * the interface route (see comments in nd6_prefix_onlink). 184378064Sume * If there's one, try to make the prefix on-link on the 184478064Sume * interface. 184578064Sume */ 1846228966Sjhb LIST_FOREACH(opr, &V_nd_prefix, ndpr_entry) { 184778064Sume if (opr == pr) 184878064Sume continue; 184953541Sshin 185078064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 185178064Sume continue; 185253541Sshin 185378064Sume /* 185478064Sume * KAME specific: detached prefixes should not be 185578064Sume * on-link. 185678064Sume */ 185778064Sume if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 185878064Sume continue; 185978064Sume 186078064Sume if (opr->ndpr_plen == pr->ndpr_plen && 186178064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1862120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 186378064Sume int e; 186478064Sume 186578064Sume if ((e = nd6_prefix_onlink(opr)) != 0) { 186678064Sume nd6log((LOG_ERR, 186778064Sume "nd6_prefix_offlink: failed to " 186878064Sume "recover a prefix %s/%d from %s " 186978064Sume "to %s (errno = %d)\n", 1870165118Sbz ip6_sprintf(ip6buf, 1871165118Sbz &opr->ndpr_prefix.sin6_addr), 187278064Sume opr->ndpr_plen, if_name(ifp), 187378064Sume if_name(opr->ndpr_ifp), e)); 1874252141Sqingli } else 1875252141Sqingli a_failure = 0; 187678064Sume } 187778064Sume } 1878120941Sume } else { 187978064Sume /* XXX: can we still set the NDPRF_ONLINK flag? */ 188078064Sume nd6log((LOG_ERR, 188178064Sume "nd6_prefix_offlink: failed to delete route: " 188278064Sume "%s/%d on %s (errno = %d)\n", 1883165118Sbz ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen, 1884165118Sbz if_name(ifp), error)); 188578064Sume } 188653541Sshin 1887252141Sqingli if (a_failure) 1888252141Sqingli lltable_prefix_free(AF_INET6, (struct sockaddr *)&sa6, 1889252141Sqingli (struct sockaddr *)&mask6, LLE_STATIC); 1890252141Sqingli 1891120856Sume return (error); 189253541Sshin} 189353541Sshin 189453541Sshinstatic struct in6_ifaddr * 1895171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast) 189653541Sshin{ 189778064Sume struct ifnet *ifp = pr->ndpr_ifp; 189853541Sshin struct ifaddr *ifa; 189978064Sume struct in6_aliasreq ifra; 190078064Sume struct in6_ifaddr *ia, *ib; 190178064Sume int error, plen0; 190253541Sshin struct in6_addr mask; 190378064Sume int prefixlen = pr->ndpr_plen; 1904151539Ssuz int updateflags; 1905165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 190653541Sshin 1907121168Sume in6_prefixlen2mask(&mask, prefixlen); 190853541Sshin 190978064Sume /* 191078064Sume * find a link-local address (will be interface ID). 191178064Sume * Is it really mandatory? Theoretically, a global or a site-local 191278064Sume * address can be configured without a link-local address, if we 191378064Sume * have a unique interface identifier... 191478064Sume * 191578064Sume * it is not mandatory to have a link-local address, we can generate 191678064Sume * interface identifier on the fly. we do this because: 191778064Sume * (1) it should be the easiest way to find interface identifier. 191878064Sume * (2) RFC2462 5.4 suggesting the use of the same interface identifier 191978064Sume * for multiple addresses on a single interface, and possible shortcut 192078064Sume * of DAD. we omitted DAD for this reason in the past. 1921120941Sume * (3) a user can prevent autoconfiguration of global address 192278064Sume * by removing link-local address by hand (this is partly because we 1923108533Sschweikh * don't have other way to control the use of IPv6 on an interface. 192478064Sume * this has been our design choice - cf. NRL's "ifconfig auto"). 192578064Sume * (4) it is easier to manage when an interface has addresses 192678064Sume * with the same interface identifier, than to have multiple addresses 192778064Sume * with different interface identifiers. 192878064Sume */ 1929120941Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ 193053541Sshin if (ifa) 193153541Sshin ib = (struct in6_ifaddr *)ifa; 193253541Sshin else 193353541Sshin return NULL; 193453541Sshin 193553541Sshin /* prefixlen + ifidlen must be equal to 128 */ 193678064Sume plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 193778064Sume if (prefixlen != plen0) { 1938194760Srwatson ifa_free(ifa); 193978064Sume nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 194078064Sume "(prefix=%d ifid=%d)\n", 194178064Sume if_name(ifp), prefixlen, 128 - plen0)); 194253541Sshin return NULL; 194353541Sshin } 194453541Sshin 194553541Sshin /* make ifaddr */ 194653541Sshin 194778064Sume bzero(&ifra, sizeof(ifra)); 194878064Sume /* 194978064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 195078064Sume * for safety. 195178064Sume */ 195278064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 195378064Sume ifra.ifra_addr.sin6_family = AF_INET6; 195478064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 195578064Sume /* prefix */ 1956151539Ssuz ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr; 195778064Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 195878064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 195978064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 196078064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 196153541Sshin 196253541Sshin /* interface ID */ 1963120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] |= 1964151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); 1965120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] |= 1966151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); 1967120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1968151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); 1969120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1970151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); 1971194760Srwatson ifa_free(ifa); 1972120941Sume 197378064Sume /* new prefix mask. */ 197478064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 197578064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 197678064Sume bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 1977120941Sume sizeof(ifra.ifra_prefixmask.sin6_addr)); 197853541Sshin 1979151539Ssuz /* lifetimes. */ 198078064Sume ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 198178064Sume ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 198253541Sshin 198378064Sume /* XXX: scope zone ID? */ 198453541Sshin 198578064Sume ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 1986151539Ssuz 1987171260Sdelphij /* 1988151539Ssuz * Make sure that we do not have this address already. This should 1989151539Ssuz * usually not happen, but we can still see this case, e.g., if we 1990151539Ssuz * have manually configured the exact address to be configured. 199178064Sume */ 1992194760Srwatson ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, 1993194760Srwatson &ifra.ifra_addr.sin6_addr); 1994194760Srwatson if (ifa != NULL) { 1995194760Srwatson ifa_free(ifa); 1996151539Ssuz /* this should be rare enough to make an explicit log */ 1997151539Ssuz log(LOG_INFO, "in6_ifadd: %s is already configured\n", 1998165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr)); 1999151539Ssuz return (NULL); 2000151539Ssuz } 200153541Sshin 200253541Sshin /* 2003151539Ssuz * Allocate ifaddr structure, link into chain, etc. 2004151539Ssuz * If we are going to create a new address upon receiving a multicasted 2005151539Ssuz * RA, we need to impose a random delay before starting DAD. 2006151539Ssuz * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] 200753541Sshin */ 2008151539Ssuz updateflags = 0; 2009151539Ssuz if (mcast) 2010151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 2011151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { 201278064Sume nd6log((LOG_ERR, 201378064Sume "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 2014165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr), 2015165118Sbz if_name(ifp), error)); 2016120856Sume return (NULL); /* ifaddr must not have been allocated. */ 201753541Sshin } 201853541Sshin 201978064Sume ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 2020194760Srwatson /* 2021194760Srwatson * XXXRW: Assumption of non-NULLness here might not be true with 2022194760Srwatson * fine-grained locking -- should we validate it? Or just return 2023194760Srwatson * earlier ifa rather than looking it up again? 2024194760Srwatson */ 2025194760Srwatson return (ia); /* this is always non-NULL and referenced. */ 202653541Sshin} 202753541Sshin 2028171259Sdelphij/* 2029171259Sdelphij * ia0 - corresponding public address 2030171259Sdelphij */ 203153541Sshinint 2032171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) 203353541Sshin{ 203478064Sume struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 2035151539Ssuz struct in6_ifaddr *newia, *ia; 203678064Sume struct in6_aliasreq ifra; 203778064Sume int i, error; 203878064Sume int trylimit = 3; /* XXX: adhoc value */ 2039151539Ssuz int updateflags; 204078064Sume u_int32_t randid[2]; 204178064Sume time_t vltime0, pltime0; 204253541Sshin 204378064Sume bzero(&ifra, sizeof(ifra)); 204478064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 204578064Sume ifra.ifra_addr = ia0->ia_addr; 204678064Sume /* copy prefix mask */ 204778064Sume ifra.ifra_prefixmask = ia0->ia_prefixmask; 204878064Sume /* clear the old IFID */ 204978064Sume for (i = 0; i < 4; i++) { 2050120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[i] &= 2051120941Sume ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 205278064Sume } 205353541Sshin 205478064Sume again: 2055151539Ssuz if (in6_get_tmpifid(ifp, (u_int8_t *)randid, 2056151539Ssuz (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { 2057151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good " 2058151539Ssuz "random IFID\n")); 2059151539Ssuz return (EINVAL); 2060151539Ssuz } 2061120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 2062120941Sume (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 2063120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 2064120941Sume (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 206553541Sshin 2066171260Sdelphij /* 2067151539Ssuz * in6_get_tmpifid() quite likely provided a unique interface ID. 2068151539Ssuz * However, we may still have a chance to see collision, because 2069151539Ssuz * there may be a time lag between generation of the ID and generation 2070151539Ssuz * of the address. So, we'll do one more sanity check. 207178064Sume */ 2072194971Srwatson IN6_IFADDR_RLOCK(); 2073194907Srwatson TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { 2074151539Ssuz if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 2075151539Ssuz &ifra.ifra_addr.sin6_addr)) { 2076171260Sdelphij if (trylimit-- == 0) { 2077194971Srwatson IN6_IFADDR_RUNLOCK(); 2078151539Ssuz /* 2079151539Ssuz * Give up. Something strange should have 2080151539Ssuz * happened. 2081151539Ssuz */ 2082151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " 2083151539Ssuz "find a unique random IFID\n")); 2084151539Ssuz return (EEXIST); 2085151539Ssuz } 2086194971Srwatson IN6_IFADDR_RUNLOCK(); 2087151539Ssuz forcegen = 1; 2088151539Ssuz goto again; 208978064Sume } 209053541Sshin } 2091194971Srwatson IN6_IFADDR_RUNLOCK(); 209253541Sshin 209378064Sume /* 209478064Sume * The Valid Lifetime is the lower of the Valid Lifetime of the 209578064Sume * public address or TEMP_VALID_LIFETIME. 209678064Sume * The Preferred Lifetime is the lower of the Preferred Lifetime 209778064Sume * of the public address or TEMP_PREFERRED_LIFETIME - 209878064Sume * DESYNC_FACTOR. 209978064Sume */ 2100151539Ssuz if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 210178064Sume vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 2102151539Ssuz (ia0->ia6_lifetime.ia6t_vltime - 2103253970Shrs (time_uptime - ia0->ia6_updatetime)); 2104181803Sbz if (vltime0 > V_ip6_temp_valid_lifetime) 2105181803Sbz vltime0 = V_ip6_temp_valid_lifetime; 210678064Sume } else 2107181803Sbz vltime0 = V_ip6_temp_valid_lifetime; 2108151539Ssuz if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 210978064Sume pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 2110151539Ssuz (ia0->ia6_lifetime.ia6t_pltime - 2111253970Shrs (time_uptime - ia0->ia6_updatetime)); 2112181803Sbz if (pltime0 > V_ip6_temp_preferred_lifetime - V_ip6_desync_factor){ 2113181803Sbz pltime0 = V_ip6_temp_preferred_lifetime - 2114181803Sbz V_ip6_desync_factor; 211578064Sume } 211678064Sume } else 2117181803Sbz pltime0 = V_ip6_temp_preferred_lifetime - V_ip6_desync_factor; 211878064Sume ifra.ifra_lifetime.ia6t_vltime = vltime0; 211978064Sume ifra.ifra_lifetime.ia6t_pltime = pltime0; 212053541Sshin 212178064Sume /* 212278064Sume * A temporary address is created only if this calculated Preferred 212378064Sume * Lifetime is greater than REGEN_ADVANCE time units. 212478064Sume */ 2125181803Sbz if (ifra.ifra_lifetime.ia6t_pltime <= V_ip6_temp_regen_advance) 2126120856Sume return (0); 212753541Sshin 212878064Sume /* XXX: scope zone ID? */ 212978064Sume 213078064Sume ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 213178064Sume 213278064Sume /* allocate ifaddr structure, link into chain, etc. */ 2133151539Ssuz updateflags = 0; 2134151539Ssuz if (delay) 2135151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 2136151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) 2137120856Sume return (error); 213878064Sume 213978064Sume newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 214078064Sume if (newia == NULL) { /* XXX: can it happen? */ 214178064Sume nd6log((LOG_ERR, 214278064Sume "in6_tmpifadd: ifa update succeeded, but we got " 214378064Sume "no ifaddr\n")); 2144120856Sume return (EINVAL); /* XXX */ 214553541Sshin } 214678064Sume newia->ia6_ndpr = ia0->ia6_ndpr; 214778064Sume newia->ia6_ndpr->ndpr_refcnt++; 2148194760Srwatson ifa_free(&newia->ia_ifa); 214953541Sshin 215078407Sume /* 215178407Sume * A newly added address might affect the status of other addresses. 215278407Sume * XXX: when the temporary address is generated with a new public 215378407Sume * address, the onlink check is redundant. However, it would be safe 215478407Sume * to do the check explicitly everywhere a new address is generated, 215578407Sume * and, in fact, we surely need the check when we create a new 215678407Sume * temporary address due to deprecation of an old temporary address. 215778407Sume */ 215878407Sume pfxlist_onlink_check(); 215978407Sume 2160120856Sume return (0); 2161120941Sume} 216253541Sshin 2163151539Ssuzstatic int 216453541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr) 216553541Sshin{ 216653541Sshin if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 216753541Sshin ndpr->ndpr_preferred = 0; 216853541Sshin else 2169253970Shrs ndpr->ndpr_preferred = time_uptime + ndpr->ndpr_pltime; 217053541Sshin if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 217153541Sshin ndpr->ndpr_expire = 0; 217253541Sshin else 2173253970Shrs ndpr->ndpr_expire = time_uptime + ndpr->ndpr_vltime; 217453541Sshin 217553541Sshin return 0; 217653541Sshin} 217753541Sshin 217853541Sshinstatic void 217978064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 218053541Sshin{ 218178064Sume /* init ia6t_expire */ 218278064Sume if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 218378064Sume lt6->ia6t_expire = 0; 218478064Sume else { 2185253970Shrs lt6->ia6t_expire = time_uptime; 218678064Sume lt6->ia6t_expire += lt6->ia6t_vltime; 218753541Sshin } 218862587Sitojun 218953541Sshin /* init ia6t_preferred */ 219053541Sshin if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 219153541Sshin lt6->ia6t_preferred = 0; 219253541Sshin else { 2193253970Shrs lt6->ia6t_preferred = time_uptime; 219453541Sshin lt6->ia6t_preferred += lt6->ia6t_pltime; 219553541Sshin } 219653541Sshin} 219753541Sshin 219853541Sshin/* 219953541Sshin * Delete all the routing table entries that use the specified gateway. 220053541Sshin * XXX: this function causes search through all entries of routing table, so 220153541Sshin * it shouldn't be called when acting as a router. 220253541Sshin */ 220353541Sshinvoid 2204171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp) 220553541Sshin{ 2206193232Sbz struct radix_node_head *rnh; 2207231852Sbz u_int fibnum; 220853541Sshin 220953541Sshin /* We'll care only link-local addresses */ 2210241686Sandre if (!IN6_IS_ADDR_LINKLOCAL(gateway)) 221153541Sshin return; 221253541Sshin 2213231852Sbz /* XXX Do we really need to walk any but the default FIB? */ 2214231852Sbz for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 2215231852Sbz rnh = rt_tables_get_rnh(fibnum, AF_INET6); 2216231852Sbz if (rnh == NULL) 2217231852Sbz continue; 2218193232Sbz 2219231852Sbz RADIX_NODE_HEAD_LOCK(rnh); 2220231852Sbz rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 2221231852Sbz RADIX_NODE_HEAD_UNLOCK(rnh); 2222231852Sbz } 222353541Sshin} 222453541Sshin 222553541Sshinstatic int 2226171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg) 222753541Sshin{ 222853541Sshin#define SIN6(s) ((struct sockaddr_in6 *)s) 222953541Sshin struct rtentry *rt = (struct rtentry *)rn; 223053541Sshin struct in6_addr *gate = (struct in6_addr *)arg; 223153541Sshin 223253541Sshin if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 2233120856Sume return (0); 223453541Sshin 2235120941Sume if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) { 2236120856Sume return (0); 2237120941Sume } 223853541Sshin 223953541Sshin /* 224078064Sume * Do not delete a static route. 224178064Sume * XXX: this seems to be a bit ad-hoc. Should we consider the 224278064Sume * 'cloned' bit instead? 224378064Sume */ 224478064Sume if ((rt->rt_flags & RTF_STATIC) != 0) 2245120856Sume return (0); 224678064Sume 224778064Sume /* 224853541Sshin * We delete only host route. This means, in particular, we don't 224953541Sshin * delete default route. 225053541Sshin */ 225153541Sshin if ((rt->rt_flags & RTF_HOST) == 0) 2252120856Sume return (0); 225353541Sshin 2254231852Sbz return (in6_rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 2255231852Sbz rt_mask(rt), rt->rt_flags, NULL, rt->rt_fibnum)); 225653541Sshin#undef SIN6 225753541Sshin} 225862587Sitojun 225962587Sitojunint 2260171259Sdelphijnd6_setdefaultiface(int ifindex) 226162587Sitojun{ 226262587Sitojun int error = 0; 226362587Sitojun 2264181803Sbz if (ifindex < 0 || V_if_index < ifindex) 2265120856Sume return (EINVAL); 2266151539Ssuz if (ifindex != 0 && !ifnet_byindex(ifindex)) 2267151539Ssuz return (EINVAL); 226862587Sitojun 2269181803Sbz if (V_nd6_defifindex != ifindex) { 2270181803Sbz V_nd6_defifindex = ifindex; 2271181803Sbz if (V_nd6_defifindex > 0) 2272181803Sbz V_nd6_defifp = ifnet_byindex(V_nd6_defifindex); 227362587Sitojun else 2274181803Sbz V_nd6_defifp = NULL; 227562587Sitojun 227662587Sitojun /* 227762587Sitojun * Our current implementation assumes one-to-one maping between 227862587Sitojun * interfaces and links, so it would be natural to use the 227962587Sitojun * default interface as the default link. 228062587Sitojun */ 2281181803Sbz scope6_setdefault(V_nd6_defifp); 228262587Sitojun } 228362587Sitojun 2284120856Sume return (error); 228562587Sitojun} 2286