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> 4253541Sshin#include <sys/socket.h> 4353541Sshin#include <sys/sockio.h> 4453541Sshin#include <sys/time.h> 4578064Sume#include <sys/kernel.h> 46185751Simp#include <sys/lock.h> 4753541Sshin#include <sys/errno.h> 48185747Skmacy#include <sys/rwlock.h> 4953541Sshin#include <sys/syslog.h> 5078064Sume#include <sys/queue.h> 5153541Sshin 5253541Sshin#include <net/if.h> 5353541Sshin#include <net/if_types.h> 5453541Sshin#include <net/if_dl.h> 5553541Sshin#include <net/route.h> 5653541Sshin#include <net/radix.h> 57185571Sbz#include <net/vnet.h> 5853541Sshin 5953541Sshin#include <netinet/in.h> 60186119Sqingli#include <net/if_llatbl.h> 6153541Sshin#include <netinet6/in6_var.h> 6278064Sume#include <netinet6/in6_ifattach.h> 6362587Sitojun#include <netinet/ip6.h> 6453541Sshin#include <netinet6/ip6_var.h> 6553541Sshin#include <netinet6/nd6.h> 6662587Sitojun#include <netinet/icmp6.h> 6762587Sitojun#include <netinet6/scope6_var.h> 6853541Sshin 69175162Sobrienstatic int rtpref(struct nd_defrouter *); 70175162Sobrienstatic struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); 71241916Sdelphijstatic int prelist_update(struct nd_prefixctl *, struct nd_defrouter *, 72241916Sdelphij struct mbuf *, int); 73241916Sdelphijstatic struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int); 74241916Sdelphijstatic struct nd_pfxrouter *pfxrtr_lookup(struct nd_prefix *, 75241916Sdelphij struct nd_defrouter *); 76175162Sobrienstatic void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *); 77175162Sobrienstatic void pfxrtr_del(struct nd_pfxrouter *); 7862587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router 79175162Sobrien(struct nd_prefix *); 80175162Sobrienstatic void defrouter_delreq(struct nd_defrouter *); 81175162Sobrienstatic void nd6_rtmsg(int, struct rtentry *); 8253541Sshin 83175162Sobrienstatic int in6_init_prefix_ltimes(struct nd_prefix *); 84241916Sdelphijstatic void in6_init_address_ltimes(struct nd_prefix *, 85241916Sdelphij struct in6_addrlifetime *); 8653541Sshin 87229547Sbzstatic int nd6_prefix_onlink(struct nd_prefix *); 88229547Sbzstatic int nd6_prefix_offlink(struct nd_prefix *); 89229547Sbz 90175162Sobrienstatic int rt6_deleteroute(struct radix_node *, void *); 9153541Sshin 92195699SrwatsonVNET_DECLARE(int, nd6_recalc_reachtm_interval); 93195727Srwatson#define V_nd6_recalc_reachtm_interval VNET(nd6_recalc_reachtm_interval) 9453541Sshin 95215701Sdimstatic VNET_DEFINE(struct ifnet *, nd6_defifp); 96207369SbzVNET_DEFINE(int, nd6_defifindex); 97195727Srwatson#define V_nd6_defifp VNET(nd6_defifp) 9862587Sitojun 99207369SbzVNET_DEFINE(int, ip6_use_tempaddr) = 0; 100207369Sbz 101195699SrwatsonVNET_DEFINE(int, ip6_desync_factor); 102207369SbzVNET_DEFINE(u_int32_t, ip6_temp_preferred_lifetime) = DEF_TEMP_PREFERRED_LIFETIME; 103207369SbzVNET_DEFINE(u_int32_t, ip6_temp_valid_lifetime) = DEF_TEMP_VALID_LIFETIME; 10478064Sume 105207369SbzVNET_DEFINE(int, ip6_temp_regen_advance) = TEMPADDR_REGEN_ADVANCE; 106207369Sbz 107151539Ssuz/* RTPREF_MEDIUM has to be 0! */ 108151539Ssuz#define RTPREF_HIGH 1 109151539Ssuz#define RTPREF_MEDIUM 0 110151539Ssuz#define RTPREF_LOW (-1) 111151539Ssuz#define RTPREF_RESERVED (-2) 112151539Ssuz#define RTPREF_INVALID (-3) /* internal */ 113151539Ssuz 11478064Sume/* 11553541Sshin * Receive Router Solicitation Message - just for routers. 11653541Sshin * Router solicitation/advertisement is mostly managed by userland program 11753541Sshin * (rtadvd) so here we have no function like nd6_ra_output(). 11853541Sshin * 11953541Sshin * Based on RFC 2461 12053541Sshin */ 12153541Sshinvoid 122171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len) 12353541Sshin{ 12453541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 12553541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 12662587Sitojun struct nd_router_solicit *nd_rs; 12753541Sshin struct in6_addr saddr6 = ip6->ip6_src; 12853541Sshin char *lladdr = NULL; 12953541Sshin int lladdrlen = 0; 13053541Sshin union nd_opts ndopts; 131165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 13253541Sshin 133222728Shrs /* 134222728Shrs * Accept RS only when V_ip6_forwarding=1 and the interface has 135222728Shrs * no ND6_IFF_ACCEPT_RTADV. 136222728Shrs */ 137222728Shrs if (!V_ip6_forwarding || ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) 13862587Sitojun goto freeit; 13953541Sshin 14053541Sshin /* Sanity checks */ 14153541Sshin if (ip6->ip6_hlim != 255) { 14278064Sume nd6log((LOG_ERR, 14378064Sume "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 144165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 145165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 14678064Sume goto bad; 14753541Sshin } 14853541Sshin 14953541Sshin /* 15053541Sshin * Don't update the neighbor cache, if src = ::. 15153541Sshin * This indicates that the src has no IP address assigned yet. 15253541Sshin */ 15353541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 15462587Sitojun goto freeit; 15562587Sitojun 15662587Sitojun#ifndef PULLDOWN_TEST 15762587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 15862587Sitojun nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 15962587Sitojun#else 16062587Sitojun IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 16162587Sitojun if (nd_rs == NULL) { 162190964Srwatson ICMP6STAT_INC(icp6s_tooshort); 16353541Sshin return; 16462587Sitojun } 16562587Sitojun#endif 16653541Sshin 16753541Sshin icmp6len -= sizeof(*nd_rs); 16853541Sshin nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 16953541Sshin if (nd6_options(&ndopts) < 0) { 17078064Sume nd6log((LOG_INFO, 17178064Sume "nd6_rs_input: invalid ND option, ignored\n")); 17278064Sume /* nd6_options have incremented stats */ 17362587Sitojun goto freeit; 17453541Sshin } 17553541Sshin 17653541Sshin if (ndopts.nd_opts_src_lladdr) { 17753541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 17853541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 17953541Sshin } 18053541Sshin 18153541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 18278064Sume nd6log((LOG_INFO, 18353541Sshin "nd6_rs_input: lladdrlen mismatch for %s " 18453541Sshin "(if %d, RS packet %d)\n", 185165118Sbz ip6_sprintf(ip6bufs, &saddr6), 186120941Sume ifp->if_addrlen, lladdrlen - 2)); 18778064Sume goto bad; 18853541Sshin } 18953541Sshin 19053541Sshin nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 19162587Sitojun 19262587Sitojun freeit: 19362587Sitojun m_freem(m); 19478064Sume return; 19578064Sume 19678064Sume bad: 197190964Srwatson ICMP6STAT_INC(icp6s_badrs); 19878064Sume m_freem(m); 19953541Sshin} 20053541Sshin 20153541Sshin/* 20253541Sshin * Receive Router Advertisement Message. 20353541Sshin * 20453541Sshin * Based on RFC 2461 20553541Sshin * TODO: on-link bit on prefix information 20653541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 20753541Sshin */ 20853541Sshinvoid 209171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len) 21053541Sshin{ 21153541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 212121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 21353541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 21462587Sitojun struct nd_router_advert *nd_ra; 21553541Sshin struct in6_addr saddr6 = ip6->ip6_src; 216151539Ssuz int mcast = 0; 21753541Sshin union nd_opts ndopts; 21853541Sshin struct nd_defrouter *dr; 219165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 22053541Sshin 221118498Sume /* 222222728Shrs * We only accept RAs only when the per-interface flag 223222728Shrs * ND6_IFF_ACCEPT_RTADV is on the receiving interface. 224118498Sume */ 225222728Shrs if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 22662587Sitojun goto freeit; 22753541Sshin 22853541Sshin if (ip6->ip6_hlim != 255) { 22978064Sume nd6log((LOG_ERR, 23078064Sume "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 231165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 232165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 23378064Sume goto bad; 23453541Sshin } 23553541Sshin 23653541Sshin if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 23778064Sume nd6log((LOG_ERR, 23853541Sshin "nd6_ra_input: src %s is not link-local\n", 239165118Sbz ip6_sprintf(ip6bufs, &saddr6))); 24078064Sume goto bad; 24162587Sitojun } 24262587Sitojun 24362587Sitojun#ifndef PULLDOWN_TEST 24462587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 24562587Sitojun nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); 24662587Sitojun#else 24762587Sitojun IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); 24862587Sitojun if (nd_ra == NULL) { 249190964Srwatson ICMP6STAT_INC(icp6s_tooshort); 25053541Sshin return; 25153541Sshin } 25262587Sitojun#endif 25353541Sshin 25453541Sshin icmp6len -= sizeof(*nd_ra); 25553541Sshin nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 25653541Sshin if (nd6_options(&ndopts) < 0) { 25778064Sume nd6log((LOG_INFO, 25878064Sume "nd6_ra_input: invalid ND option, ignored\n")); 25978064Sume /* nd6_options have incremented stats */ 26062587Sitojun goto freeit; 26153541Sshin } 26253541Sshin 26353541Sshin { 26453541Sshin struct nd_defrouter dr0; 26553541Sshin u_int32_t advreachable = nd_ra->nd_ra_reachable; 26653541Sshin 267151539Ssuz /* remember if this is a multicasted advertisement */ 268151539Ssuz if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 269151539Ssuz mcast = 1; 270151539Ssuz 271151539Ssuz bzero(&dr0, sizeof(dr0)); 27253541Sshin dr0.rtaddr = saddr6; 27353541Sshin dr0.flags = nd_ra->nd_ra_flags_reserved; 274222728Shrs /* 275225521Shrs * Effectively-disable routes from RA messages when 276225521Shrs * ND6_IFF_NO_RADR enabled on the receiving interface or 277225521Shrs * (ip6.forwarding == 1 && ip6.rfc6204w3 != 1). 278222728Shrs */ 279225521Shrs if (ndi->flags & ND6_IFF_NO_RADR) 280222728Shrs dr0.rtlifetime = 0; 281225521Shrs else if (V_ip6_forwarding && !V_ip6_rfc6204w3) 282225521Shrs dr0.rtlifetime = 0; 283222728Shrs else 284222728Shrs dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 285253970Shrs dr0.expire = time_uptime + dr0.rtlifetime; 28653541Sshin dr0.ifp = ifp; 28753541Sshin /* unspecified or not? (RFC 2461 6.3.4) */ 28853541Sshin if (advreachable) { 28990868Smike advreachable = ntohl(advreachable); 29053541Sshin if (advreachable <= MAX_REACHABLE_TIME && 29153541Sshin ndi->basereachable != advreachable) { 29253541Sshin ndi->basereachable = advreachable; 29353541Sshin ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 294181803Sbz ndi->recalctm = V_nd6_recalc_reachtm_interval; /* reset */ 29553541Sshin } 29653541Sshin } 29753541Sshin if (nd_ra->nd_ra_retransmit) 29853541Sshin ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 299281232Sdelphij if (nd_ra->nd_ra_curhoplimit) { 300281232Sdelphij if (ndi->chlim < nd_ra->nd_ra_curhoplimit) 301281232Sdelphij ndi->chlim = nd_ra->nd_ra_curhoplimit; 302281232Sdelphij else if (ndi->chlim != nd_ra->nd_ra_curhoplimit) { 303281232Sdelphij log(LOG_ERR, "RA with a lower CurHopLimit sent from " 304281232Sdelphij "%s on %s (current = %d, received = %d). " 305281232Sdelphij "Ignored.\n", ip6_sprintf(ip6bufs, &ip6->ip6_src), 306281232Sdelphij if_name(ifp), ndi->chlim, nd_ra->nd_ra_curhoplimit); 307281232Sdelphij } 308281232Sdelphij } 30953541Sshin dr = defrtrlist_update(&dr0); 31053541Sshin } 31153541Sshin 31253541Sshin /* 31353541Sshin * prefix 31453541Sshin */ 31553541Sshin if (ndopts.nd_opts_pi) { 31653541Sshin struct nd_opt_hdr *pt; 31778064Sume struct nd_opt_prefix_info *pi = NULL; 318151539Ssuz struct nd_prefixctl pr; 31953541Sshin 32053541Sshin for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 32153541Sshin pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 32253541Sshin pt = (struct nd_opt_hdr *)((caddr_t)pt + 32353541Sshin (pt->nd_opt_len << 3))) { 32453541Sshin if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 32553541Sshin continue; 32653541Sshin pi = (struct nd_opt_prefix_info *)pt; 32753541Sshin 32853541Sshin if (pi->nd_opt_pi_len != 4) { 32978064Sume nd6log((LOG_INFO, 33078064Sume "nd6_ra_input: invalid option " 33178064Sume "len %d for prefix information option, " 33278064Sume "ignored\n", pi->nd_opt_pi_len)); 33353541Sshin continue; 33453541Sshin } 33553541Sshin 33653541Sshin if (128 < pi->nd_opt_pi_prefix_len) { 33778064Sume nd6log((LOG_INFO, 33878064Sume "nd6_ra_input: invalid prefix " 33978064Sume "len %d for prefix information option, " 34078064Sume "ignored\n", pi->nd_opt_pi_prefix_len)); 34153541Sshin continue; 34253541Sshin } 34353541Sshin 34453541Sshin if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 34553541Sshin || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 34678064Sume nd6log((LOG_INFO, 34778064Sume "nd6_ra_input: invalid prefix " 34878064Sume "%s, ignored\n", 349165118Sbz ip6_sprintf(ip6bufs, 350165118Sbz &pi->nd_opt_pi_prefix))); 35153541Sshin continue; 35253541Sshin } 35353541Sshin 35453541Sshin bzero(&pr, sizeof(pr)); 35553541Sshin pr.ndpr_prefix.sin6_family = AF_INET6; 35653541Sshin pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 35753541Sshin pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 35853541Sshin pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 35953541Sshin 36053541Sshin pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 361120941Sume ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 36253541Sshin pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 363120941Sume ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 36453541Sshin pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 36553541Sshin pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 366120941Sume pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); 367151539Ssuz (void)prelist_update(&pr, dr, m, mcast); 36853541Sshin } 36953541Sshin } 37053541Sshin 37153541Sshin /* 37253541Sshin * MTU 37353541Sshin */ 37453541Sshin if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 375121283Sume u_long mtu; 376121283Sume u_long maxmtu; 37753541Sshin 378121283Sume mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 379120941Sume 38053541Sshin /* lower bound */ 38153541Sshin if (mtu < IPV6_MMTU) { 38278064Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " 383121283Sume "mtu=%lu sent from %s, ignoring\n", 384165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src))); 38553541Sshin goto skip; 38653541Sshin } 38753541Sshin 38853541Sshin /* upper bound */ 389121283Sume maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu) 390121283Sume ? ndi->maxmtu : ifp->if_mtu; 391121283Sume if (mtu <= maxmtu) { 392121283Sume int change = (ndi->linkmtu != mtu); 39353541Sshin 394121283Sume ndi->linkmtu = mtu; 395121283Sume if (change) /* in6_maxmtu may change */ 396121283Sume in6_setmaxmtu(); 39753541Sshin } else { 398121283Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " 399121283Sume "mtu=%lu sent from %s; " 400121283Sume "exceeds maxmtu %lu, ignoring\n", 401165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu)); 40253541Sshin } 40353541Sshin } 40453541Sshin 40553541Sshin skip: 406120941Sume 40753541Sshin /* 40895023Ssuz * Source link layer address 40953541Sshin */ 41053541Sshin { 41153541Sshin char *lladdr = NULL; 41253541Sshin int lladdrlen = 0; 413120941Sume 41453541Sshin if (ndopts.nd_opts_src_lladdr) { 41553541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 41653541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 41753541Sshin } 41853541Sshin 41953541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 42078064Sume nd6log((LOG_INFO, 42153541Sshin "nd6_ra_input: lladdrlen mismatch for %s " 422165118Sbz "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6), 423120941Sume ifp->if_addrlen, lladdrlen - 2)); 42478064Sume goto bad; 42553541Sshin } 42653541Sshin 427120941Sume nd6_cache_lladdr(ifp, &saddr6, lladdr, 428120941Sume lladdrlen, ND_ROUTER_ADVERT, 0); 42962587Sitojun 43062587Sitojun /* 43162587Sitojun * Installing a link-layer address might change the state of the 43262587Sitojun * router's neighbor cache, which might also affect our on-link 43362587Sitojun * detection of adveritsed prefixes. 43462587Sitojun */ 43562587Sitojun pfxlist_onlink_check(); 43653541Sshin } 43762587Sitojun 43878064Sume freeit: 43962587Sitojun m_freem(m); 44078064Sume return; 44178064Sume 44278064Sume bad: 443190964Srwatson ICMP6STAT_INC(icp6s_badra); 44478064Sume m_freem(m); 44553541Sshin} 44653541Sshin 44753541Sshin/* 44853541Sshin * default router list proccessing sub routines 44953541Sshin */ 45062587Sitojun 45162587Sitojun/* tell the change to user processes watching the routing socket. */ 45262587Sitojunstatic void 453171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt) 45462587Sitojun{ 45562587Sitojun struct rt_addrinfo info; 456191337Srwatson struct ifnet *ifp; 457194760Srwatson struct ifaddr *ifa; 45862587Sitojun 45962587Sitojun bzero((caddr_t)&info, sizeof(info)); 46062587Sitojun info.rti_info[RTAX_DST] = rt_key(rt); 46162587Sitojun info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 46262587Sitojun info.rti_info[RTAX_NETMASK] = rt_mask(rt); 463191337Srwatson ifp = rt->rt_ifp; 464191337Srwatson if (ifp != NULL) { 465229621Sjhb IF_ADDR_RLOCK(ifp); 466194760Srwatson ifa = TAILQ_FIRST(&ifp->if_addrhead); 467194760Srwatson info.rti_info[RTAX_IFP] = ifa->ifa_addr; 468194760Srwatson ifa_ref(ifa); 469229621Sjhb IF_ADDR_RUNLOCK(ifp); 470151539Ssuz info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 471194760Srwatson } else 472194760Srwatson ifa = NULL; 47362587Sitojun 474231852Sbz rt_missmsg_fib(cmd, &info, rt->rt_flags, 0, rt->rt_fibnum); 475194760Srwatson if (ifa != NULL) 476194760Srwatson ifa_free(ifa); 47762587Sitojun} 47862587Sitojun 479229547Sbzstatic void 480171259Sdelphijdefrouter_addreq(struct nd_defrouter *new) 48153541Sshin{ 48253541Sshin struct sockaddr_in6 def, mask, gate; 48362587Sitojun struct rtentry *newrt = NULL; 484151539Ssuz int error; 48553541Sshin 486128397Sluigi bzero(&def, sizeof(def)); 487128397Sluigi bzero(&mask, sizeof(mask)); 488128397Sluigi bzero(&gate, sizeof(gate)); 48953541Sshin 490120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 491120941Sume sizeof(struct sockaddr_in6); 492151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 49353541Sshin gate.sin6_addr = new->rtaddr; 49453541Sshin 495231852Sbz error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def, 496120941Sume (struct sockaddr *)&gate, (struct sockaddr *)&mask, 497231852Sbz RTF_GATEWAY, &newrt, RT_DEFAULT_FIB); 49862587Sitojun if (newrt) { 49978064Sume nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 500186119Sqingli RTFREE(newrt); 50162587Sitojun } 502151539Ssuz if (error == 0) 503151539Ssuz new->installed = 1; 50453541Sshin return; 50553541Sshin} 50653541Sshin 50753541Sshinstruct nd_defrouter * 508171259Sdelphijdefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) 50953541Sshin{ 51053541Sshin struct nd_defrouter *dr; 51153541Sshin 512228966Sjhb TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { 51353541Sshin if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 514120856Sume return (dr); 51562587Sitojun } 51653541Sshin 517120856Sume return (NULL); /* search failed */ 51853541Sshin} 51953541Sshin 520151539Ssuz/* 521151539Ssuz * Remove the default route for a given router. 522151539Ssuz * This is just a subroutine function for defrouter_select(), and should 523151539Ssuz * not be called from anywhere else. 524151539Ssuz */ 525151539Ssuzstatic void 526171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr) 52753541Sshin{ 52853541Sshin struct sockaddr_in6 def, mask, gate; 52962587Sitojun struct rtentry *oldrt = NULL; 53053541Sshin 531128397Sluigi bzero(&def, sizeof(def)); 532128397Sluigi bzero(&mask, sizeof(mask)); 533128397Sluigi bzero(&gate, sizeof(gate)); 53453541Sshin 535120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 536120941Sume sizeof(struct sockaddr_in6); 537151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 53853541Sshin gate.sin6_addr = dr->rtaddr; 53953541Sshin 540231852Sbz in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def, 541120941Sume (struct sockaddr *)&gate, 542231852Sbz (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, RT_DEFAULT_FIB); 54362587Sitojun if (oldrt) { 54478064Sume nd6_rtmsg(RTM_DELETE, oldrt); 545108269Sru RTFREE(oldrt); 54662587Sitojun } 54753541Sshin 548151539Ssuz dr->installed = 0; 54953541Sshin} 55053541Sshin 551151539Ssuz/* 552151539Ssuz * remove all default routes from default router list 553151539Ssuz */ 55453541Sshinvoid 555171259Sdelphijdefrouter_reset(void) 556151539Ssuz{ 557151539Ssuz struct nd_defrouter *dr; 558151539Ssuz 559228966Sjhb TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) 560151539Ssuz defrouter_delreq(dr); 561151539Ssuz 562151539Ssuz /* 563151539Ssuz * XXX should we also nuke any default routers in the kernel, by 564151539Ssuz * going through them by rtalloc1()? 565151539Ssuz */ 566151539Ssuz} 567151539Ssuz 568151539Ssuzvoid 569171259Sdelphijdefrtrlist_del(struct nd_defrouter *dr) 57053541Sshin{ 57153541Sshin struct nd_defrouter *deldr = NULL; 57253541Sshin struct nd_prefix *pr; 57353541Sshin 57453541Sshin /* 57553541Sshin * Flush all the routing table entries that use the router 57653541Sshin * as a next hop. 57753541Sshin */ 578222728Shrs if (ND_IFINFO(dr->ifp)->flags & ND6_IFF_ACCEPT_RTADV) 57953541Sshin rt6_flush(&dr->rtaddr, dr->ifp); 58053541Sshin 581151539Ssuz if (dr->installed) { 582151539Ssuz deldr = dr; 583151539Ssuz defrouter_delreq(dr); 584151539Ssuz } 585181803Sbz TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 58653541Sshin 58753541Sshin /* 58853541Sshin * Also delete all the pointers to the router in each prefix lists. 58953541Sshin */ 590228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 59153541Sshin struct nd_pfxrouter *pfxrtr; 59253541Sshin if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 59353541Sshin pfxrtr_del(pfxrtr); 59453541Sshin } 59553541Sshin pfxlist_onlink_check(); 59653541Sshin 59753541Sshin /* 59862587Sitojun * If the router is the primary one, choose a new one. 59962587Sitojun * Note that defrouter_select() will remove the current gateway 60062587Sitojun * from the routing table. 60153541Sshin */ 60253541Sshin if (deldr) 60362587Sitojun defrouter_select(); 60462587Sitojun 60553541Sshin free(dr, M_IP6NDP); 60653541Sshin} 60753541Sshin 60862587Sitojun/* 609151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and 610151539Ssuz * draft-ietf-ipngwg-router-selection: 611151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred. 612151539Ssuz * If we have more than one (probably) reachable router, prefer ones 613151539Ssuz * with the highest router preference. 61462587Sitojun * 2) When no routers on the list are known to be reachable or 61562587Sitojun * probably reachable, routers SHOULD be selected in a round-robin 616151539Ssuz * fashion, regardless of router preference values. 61762587Sitojun * 3) If the Default Router List is empty, assume that all 61862587Sitojun * destinations are on-link. 619151539Ssuz * 620151539Ssuz * We assume nd_defrouter is sorted by router preference value. 621151539Ssuz * Since the code below covers both with and without router preference cases, 622151539Ssuz * we do not need to classify the cases by ifdef. 623151539Ssuz * 624151539Ssuz * At this moment, we do not try to install more than one default router, 625151539Ssuz * even when the multipath routing is available, because we're not sure about 626151539Ssuz * the benefits for stub hosts comparing to the risk of making the code 627151539Ssuz * complicated and the possibility of introducing bugs. 62862587Sitojun */ 62962587Sitojunvoid 630171259Sdelphijdefrouter_select(void) 63162587Sitojun{ 632151539Ssuz struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; 633186119Sqingli struct llentry *ln = NULL; 63462587Sitojun 63562587Sitojun /* 636151539Ssuz * Let's handle easy case (3) first: 637151539Ssuz * If default router list is empty, there's nothing to be done. 638151539Ssuz */ 639241686Sandre if (TAILQ_EMPTY(&V_nd_defrouter)) 640151539Ssuz return; 641151539Ssuz 642151539Ssuz /* 64362587Sitojun * Search for a (probably) reachable router from the list. 644151539Ssuz * We just pick up the first reachable one (if any), assuming that 645151539Ssuz * the ordering rule of the list described in defrtrlist_update(). 64662587Sitojun */ 647228966Sjhb TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { 648243148Sae IF_AFDATA_RLOCK(dr->ifp); 649151539Ssuz if (selected_dr == NULL && 650186119Sqingli (ln = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && 65162587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) { 652151539Ssuz selected_dr = dr; 65362587Sitojun } 654243148Sae IF_AFDATA_RUNLOCK(dr->ifp); 655188113Sbz if (ln != NULL) { 656186148Skmacy LLE_RUNLOCK(ln); 657188113Sbz ln = NULL; 658188113Sbz } 65962587Sitojun 660151539Ssuz if (dr->installed && installed_dr == NULL) 661151539Ssuz installed_dr = dr; 662151539Ssuz else if (dr->installed && installed_dr) { 663151539Ssuz /* this should not happen. warn for diagnosis. */ 664151539Ssuz log(LOG_ERR, "defrouter_select: more than one router" 665151539Ssuz " is installed\n"); 66662587Sitojun } 66762587Sitojun } 668151539Ssuz /* 669151539Ssuz * If none of the default routers was found to be reachable, 670151539Ssuz * round-robin the list regardless of preference. 671151539Ssuz * Otherwise, if we have an installed router, check if the selected 672151539Ssuz * (reachable) router should really be preferred to the installed one. 673151539Ssuz * We only prefer the new router when the old one is not reachable 674151539Ssuz * or when the new one has a really higher preference value. 675151539Ssuz */ 676151539Ssuz if (selected_dr == NULL) { 677151539Ssuz if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry)) 678181803Sbz selected_dr = TAILQ_FIRST(&V_nd_defrouter); 679151539Ssuz else 680151539Ssuz selected_dr = TAILQ_NEXT(installed_dr, dr_entry); 681186119Sqingli } else if (installed_dr) { 682243148Sae IF_AFDATA_RLOCK(installed_dr->ifp); 683186119Sqingli if ((ln = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && 684186119Sqingli ND6_IS_LLINFO_PROBREACH(ln) && 685186119Sqingli rtpref(selected_dr) <= rtpref(installed_dr)) { 686186119Sqingli selected_dr = installed_dr; 687186119Sqingli } 688243148Sae IF_AFDATA_RUNLOCK(installed_dr->ifp); 689186148Skmacy if (ln != NULL) 690186148Skmacy LLE_RUNLOCK(ln); 691151539Ssuz } 69262587Sitojun 693151539Ssuz /* 694151539Ssuz * If the selected router is different than the installed one, 695151539Ssuz * remove the installed router and install the selected one. 696151539Ssuz * Note that the selected router is never NULL here. 697151539Ssuz */ 698151539Ssuz if (installed_dr != selected_dr) { 699151539Ssuz if (installed_dr) 700151539Ssuz defrouter_delreq(installed_dr); 701151539Ssuz defrouter_addreq(selected_dr); 702151539Ssuz } 703151539Ssuz 70462587Sitojun return; 70562587Sitojun} 70662587Sitojun 707151539Ssuz/* 708151539Ssuz * for default router selection 709151539Ssuz * regards router-preference field as a 2-bit signed integer 710151539Ssuz */ 711151539Ssuzstatic int 712151539Ssuzrtpref(struct nd_defrouter *dr) 713151539Ssuz{ 714151539Ssuz switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) { 715151539Ssuz case ND_RA_FLAG_RTPREF_HIGH: 716151539Ssuz return (RTPREF_HIGH); 717151539Ssuz case ND_RA_FLAG_RTPREF_MEDIUM: 718156871Ssuz case ND_RA_FLAG_RTPREF_RSV: 719151539Ssuz return (RTPREF_MEDIUM); 720151539Ssuz case ND_RA_FLAG_RTPREF_LOW: 721151539Ssuz return (RTPREF_LOW); 722151539Ssuz default: 723151539Ssuz /* 724151539Ssuz * This case should never happen. If it did, it would mean a 725151539Ssuz * serious bug of kernel internal. We thus always bark here. 726151539Ssuz * Or, can we even panic? 727151539Ssuz */ 728151539Ssuz log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags); 729151539Ssuz return (RTPREF_INVALID); 730151539Ssuz } 731151539Ssuz /* NOTREACHED */ 732151539Ssuz} 733151539Ssuz 73453541Sshinstatic struct nd_defrouter * 735171259Sdelphijdefrtrlist_update(struct nd_defrouter *new) 73653541Sshin{ 73753541Sshin struct nd_defrouter *dr, *n; 73853541Sshin 73953541Sshin if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 74053541Sshin /* entry exists */ 74153541Sshin if (new->rtlifetime == 0) { 74253541Sshin defrtrlist_del(dr); 74353541Sshin dr = NULL; 74453541Sshin } else { 745151539Ssuz int oldpref = rtpref(dr); 746151539Ssuz 74753541Sshin /* override */ 74853541Sshin dr->flags = new->flags; /* xxx flag check */ 74953541Sshin dr->rtlifetime = new->rtlifetime; 75053541Sshin dr->expire = new->expire; 751151539Ssuz 752151539Ssuz /* 753151539Ssuz * If the preference does not change, there's no need 754227460Sqingli * to sort the entries. Also make sure the selected 755227460Sqingli * router is still installed in the kernel. 756151539Ssuz */ 757241686Sandre if (dr->installed && rtpref(new) == oldpref) 758151539Ssuz return (dr); 759151539Ssuz 760151539Ssuz /* 761151539Ssuz * preferred router may be changed, so relocate 762151539Ssuz * this router. 763151539Ssuz * XXX: calling TAILQ_REMOVE directly is a bad manner. 764151539Ssuz * However, since defrtrlist_del() has many side 765151539Ssuz * effects, we intentionally do so here. 766151539Ssuz * defrouter_select() below will handle routing 767151539Ssuz * changes later. 768151539Ssuz */ 769181803Sbz TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 770151539Ssuz n = dr; 771151539Ssuz goto insert; 77253541Sshin } 773120856Sume return (dr); 77453541Sshin } 77553541Sshin 77653541Sshin /* entry does not exist */ 777241686Sandre if (new->rtlifetime == 0) 778120856Sume return (NULL); 77953541Sshin 78053541Sshin n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 781241686Sandre if (n == NULL) 782120856Sume return (NULL); 78353541Sshin bzero(n, sizeof(*n)); 78453541Sshin *n = *new; 78562587Sitojun 786151539Ssuzinsert: 78762587Sitojun /* 788151539Ssuz * Insert the new router in the Default Router List; 789151539Ssuz * The Default Router List should be in the descending order 790151539Ssuz * of router-preferece. Routers with the same preference are 791151539Ssuz * sorted in the arriving time order. 79262587Sitojun */ 793151539Ssuz 794151539Ssuz /* insert at the end of the group */ 795228966Sjhb TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { 796151539Ssuz if (rtpref(n) > rtpref(dr)) 797151539Ssuz break; 798151539Ssuz } 799151539Ssuz if (dr) 800151539Ssuz TAILQ_INSERT_BEFORE(dr, n, dr_entry); 801151539Ssuz else 802181803Sbz TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry); 803151539Ssuz 804151539Ssuz defrouter_select(); 805151539Ssuz 806120856Sume return (n); 80753541Sshin} 80853541Sshin 80953541Sshinstatic struct nd_pfxrouter * 810171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) 81153541Sshin{ 81253541Sshin struct nd_pfxrouter *search; 813120941Sume 814228966Sjhb LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) { 81553541Sshin if (search->router == dr) 81653541Sshin break; 81753541Sshin } 81853541Sshin 819120856Sume return (search); 82053541Sshin} 82153541Sshin 82253541Sshinstatic void 823171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) 82453541Sshin{ 82553541Sshin struct nd_pfxrouter *new; 82653541Sshin 82753541Sshin new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 82853541Sshin if (new == NULL) 82953541Sshin return; 83053541Sshin bzero(new, sizeof(*new)); 83153541Sshin new->router = dr; 83253541Sshin 83353541Sshin LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 83453541Sshin 83553541Sshin pfxlist_onlink_check(); 83653541Sshin} 83753541Sshin 83853541Sshinstatic void 839171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr) 84053541Sshin{ 84153541Sshin LIST_REMOVE(pfr, pfr_entry); 84253541Sshin free(pfr, M_IP6NDP); 84353541Sshin} 84453541Sshin 84578064Sumestruct nd_prefix * 846171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key) 84753541Sshin{ 84853541Sshin struct nd_prefix *search; 84953541Sshin 850228966Sjhb LIST_FOREACH(search, &V_nd_prefix, ndpr_entry) { 851151539Ssuz if (key->ndpr_ifp == search->ndpr_ifp && 852151539Ssuz key->ndpr_plen == search->ndpr_plen && 853151539Ssuz in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr, 854151539Ssuz &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) { 85553541Sshin break; 85653541Sshin } 85753541Sshin } 85853541Sshin 859120856Sume return (search); 86053541Sshin} 86153541Sshin 86278064Sumeint 863171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr, 864171259Sdelphij struct nd_prefix **newp) 86553541Sshin{ 86678064Sume struct nd_prefix *new = NULL; 867151539Ssuz int error = 0; 868241686Sandre int i; 869165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 87053541Sshin 87153541Sshin new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 87253541Sshin if (new == NULL) 873120941Sume return(ENOMEM); 87453541Sshin bzero(new, sizeof(*new)); 875151539Ssuz new->ndpr_ifp = pr->ndpr_ifp; 876151539Ssuz new->ndpr_prefix = pr->ndpr_prefix; 877151539Ssuz new->ndpr_plen = pr->ndpr_plen; 878151539Ssuz new->ndpr_vltime = pr->ndpr_vltime; 879151539Ssuz new->ndpr_pltime = pr->ndpr_pltime; 880151539Ssuz new->ndpr_flags = pr->ndpr_flags; 881151539Ssuz if ((error = in6_init_prefix_ltimes(new)) != 0) { 882151539Ssuz free(new, M_IP6NDP); 883151539Ssuz return(error); 884151539Ssuz } 885253970Shrs new->ndpr_lastupdate = time_uptime; 88678064Sume if (newp != NULL) 88778064Sume *newp = new; 88853541Sshin 889120941Sume /* initialization */ 89053541Sshin LIST_INIT(&new->ndpr_advrtrs); 89153541Sshin in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 89253541Sshin /* make prefix in the canonical form */ 89353541Sshin for (i = 0; i < 4; i++) 89453541Sshin new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 895120941Sume new->ndpr_mask.s6_addr32[i]; 89653541Sshin 89753541Sshin /* link ndpr_entry to nd_prefix list */ 898181803Sbz LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry); 89953541Sshin 90078064Sume /* ND_OPT_PI_FLAG_ONLINK processing */ 90178064Sume if (new->ndpr_raf_onlink) { 90278064Sume int e; 90378064Sume 90478064Sume if ((e = nd6_prefix_onlink(new)) != 0) { 90578064Sume nd6log((LOG_ERR, "nd6_prelist_add: failed to make " 90678064Sume "the prefix %s/%d on-link on %s (errno=%d)\n", 907165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 90878064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 90978064Sume /* proceed anyway. XXX: is it correct? */ 91078064Sume } 91178064Sume } 91278064Sume 913120941Sume if (dr) 91453541Sshin pfxrtr_add(new, dr); 91553541Sshin 91653541Sshin return 0; 91753541Sshin} 91853541Sshin 91953541Sshinvoid 920171259Sdelphijprelist_remove(struct nd_prefix *pr) 92153541Sshin{ 92253541Sshin struct nd_pfxrouter *pfr, *next; 923241686Sandre int e; 924165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 92553541Sshin 92678064Sume /* make sure to invalidate the prefix until it is really freed. */ 92778064Sume pr->ndpr_vltime = 0; 92878064Sume pr->ndpr_pltime = 0; 929151539Ssuz 93078064Sume /* 93178064Sume * Though these flags are now meaningless, we'd rather keep the value 932151479Ssuz * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users 933151479Ssuz * when executing "ndp -p". 93478064Sume */ 935151479Ssuz 93678064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && 93778064Sume (e = nd6_prefix_offlink(pr)) != 0) { 93878064Sume nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " 93978064Sume "on %s, errno=%d\n", 940165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 94178064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 94278064Sume /* what should we do? */ 94378064Sume } 94478064Sume 94578064Sume if (pr->ndpr_refcnt > 0) 94678064Sume return; /* notice here? */ 94778064Sume 94853541Sshin /* unlink ndpr_entry from nd_prefix list */ 94953541Sshin LIST_REMOVE(pr, ndpr_entry); 95053541Sshin 95153541Sshin /* free list of routers that adversed the prefix */ 952228966Sjhb LIST_FOREACH_SAFE(pfr, &pr->ndpr_advrtrs, pfr_entry, next) { 95353541Sshin free(pfr, M_IP6NDP); 95453541Sshin } 95553541Sshin free(pr, M_IP6NDP); 95653541Sshin 95753541Sshin pfxlist_onlink_check(); 95853541Sshin} 95953541Sshin 960171259Sdelphij/* 961171259Sdelphij * dr - may be NULL 962171259Sdelphij */ 963171259Sdelphij 964151539Ssuzstatic int 965171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, 966171259Sdelphij struct mbuf *m, int mcast) 96753541Sshin{ 96878064Sume struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 96978064Sume struct ifaddr *ifa; 97078064Sume struct ifnet *ifp = new->ndpr_ifp; 97153541Sshin struct nd_prefix *pr; 97253541Sshin int error = 0; 97378064Sume int newprefix = 0; 97453541Sshin int auth; 97578064Sume struct in6_addrlifetime lt6_tmp; 976165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 97753541Sshin 97853541Sshin auth = 0; 97953541Sshin if (m) { 98053541Sshin /* 98153541Sshin * Authenticity for NA consists authentication for 98253541Sshin * both IP header and IP datagrams, doesn't it ? 98353541Sshin */ 98453541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 985120941Sume auth = ((m->m_flags & M_AUTHIPHDR) && 986120941Sume (m->m_flags & M_AUTHIPDGM)); 98753541Sshin#endif 98853541Sshin } 98953541Sshin 99078064Sume if ((pr = nd6_prefix_lookup(new)) != NULL) { 99178064Sume /* 99278064Sume * nd6_prefix_lookup() ensures that pr and new have the same 99378064Sume * prefix on a same interface. 99478064Sume */ 99553541Sshin 99653541Sshin /* 99778064Sume * Update prefix information. Note that the on-link (L) bit 99878064Sume * and the autonomous (A) bit should NOT be changed from 1 99978064Sume * to 0. 100053541Sshin */ 100178064Sume if (new->ndpr_raf_onlink == 1) 100278064Sume pr->ndpr_raf_onlink = 1; 100378064Sume if (new->ndpr_raf_auto == 1) 100478064Sume pr->ndpr_raf_auto = 1; 100578064Sume if (new->ndpr_raf_onlink) { 100678064Sume pr->ndpr_vltime = new->ndpr_vltime; 100778064Sume pr->ndpr_pltime = new->ndpr_pltime; 1008151539Ssuz (void)in6_init_prefix_ltimes(pr); /* XXX error case? */ 1009253970Shrs pr->ndpr_lastupdate = time_uptime; 101078064Sume } 101153541Sshin 101278064Sume if (new->ndpr_raf_onlink && 101378064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 101478064Sume int e; 101553541Sshin 101678064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 101778064Sume nd6log((LOG_ERR, 101878064Sume "prelist_update: failed to make " 101978064Sume "the prefix %s/%d on-link on %s " 102078064Sume "(errno=%d)\n", 1021165118Sbz ip6_sprintf(ip6buf, 1022165118Sbz &pr->ndpr_prefix.sin6_addr), 102378064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 102478064Sume /* proceed anyway. XXX: is it correct? */ 102553541Sshin } 102678064Sume } 102753541Sshin 102878064Sume if (dr && pfxrtr_lookup(pr, dr) == NULL) 102978064Sume pfxrtr_add(pr, dr); 103078064Sume } else { 103178064Sume struct nd_prefix *newpr = NULL; 103253541Sshin 103378064Sume newprefix = 1; 103453541Sshin 103578064Sume if (new->ndpr_vltime == 0) 103678064Sume goto end; 103778064Sume if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 103878064Sume goto end; 103953541Sshin 104078064Sume error = nd6_prelist_add(new, dr, &newpr); 104178064Sume if (error != 0 || newpr == NULL) { 104278064Sume nd6log((LOG_NOTICE, "prelist_update: " 104378064Sume "nd6_prelist_add failed for %s/%d on %s " 104478064Sume "errno=%d, returnpr=%p\n", 1045165118Sbz ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr), 1046120941Sume new->ndpr_plen, if_name(new->ndpr_ifp), 1047120941Sume error, newpr)); 104878064Sume goto end; /* we should just give up in this case. */ 104978064Sume } 105053541Sshin 105178064Sume /* 105278064Sume * XXX: from the ND point of view, we can ignore a prefix 105378064Sume * with the on-link bit being zero. However, we need a 105478064Sume * prefix structure for references from autoconfigured 1055120941Sume * addresses. Thus, we explicitly make sure that the prefix 105678064Sume * itself expires now. 105778064Sume */ 105878064Sume if (newpr->ndpr_raf_onlink == 0) { 105978064Sume newpr->ndpr_vltime = 0; 106078064Sume newpr->ndpr_pltime = 0; 106178064Sume in6_init_prefix_ltimes(newpr); 106253541Sshin } 106353541Sshin 106478064Sume pr = newpr; 106578064Sume } 106653541Sshin 106778064Sume /* 106878064Sume * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 106978064Sume * Note that pr must be non NULL at this point. 107078064Sume */ 107162587Sitojun 107278064Sume /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 107378064Sume if (!new->ndpr_raf_auto) 1074151539Ssuz goto end; 107562587Sitojun 107678064Sume /* 107778064Sume * 5.5.3 (b). the link-local prefix should have been ignored in 107878064Sume * nd6_ra_input. 107978064Sume */ 108062587Sitojun 1081151539Ssuz /* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */ 1082151539Ssuz if (new->ndpr_pltime > new->ndpr_vltime) { 1083151539Ssuz error = EINVAL; /* XXX: won't be used */ 1084151539Ssuz goto end; 1085151539Ssuz } 108662587Sitojun 1087171260Sdelphij /* 1088151539Ssuz * 5.5.3 (d). If the prefix advertised is not equal to the prefix of 1089151539Ssuz * an address configured by stateless autoconfiguration already in the 1090151539Ssuz * list of addresses associated with the interface, and the Valid 1091151539Ssuz * Lifetime is not 0, form an address. We first check if we have 1092151539Ssuz * a matching prefix. 1093151539Ssuz * Note: we apply a clarification in rfc2462bis-02 here. We only 1094151539Ssuz * consider autoconfigured addresses while RFC2462 simply said 1095151539Ssuz * "address". 109678064Sume */ 1097229621Sjhb IF_ADDR_RLOCK(ifp); 1098191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 109978064Sume struct in6_ifaddr *ifa6; 1100151539Ssuz u_int32_t remaininglifetime; 110153541Sshin 110278064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 110378064Sume continue; 110453541Sshin 110578064Sume ifa6 = (struct in6_ifaddr *)ifa; 110653541Sshin 110753541Sshin /* 1108151539Ssuz * We only consider autoconfigured addresses as per rfc2462bis. 1109151539Ssuz */ 1110151539Ssuz if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF)) 1111151539Ssuz continue; 1112151539Ssuz 1113151539Ssuz /* 111478064Sume * Spec is not clear here, but I believe we should concentrate 111578064Sume * on unicast (i.e. not anycast) addresses. 111678064Sume * XXX: other ia6_flags? detached or duplicated? 111753541Sshin */ 111878064Sume if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 111978064Sume continue; 1120120941Sume 1121151539Ssuz /* 1122151539Ssuz * Ignore the address if it is not associated with a prefix 1123151539Ssuz * or is associated with a prefix that is different from this 1124151539Ssuz * one. (pr is never NULL here) 1125151539Ssuz */ 1126151539Ssuz if (ifa6->ia6_ndpr != pr) 112778064Sume continue; 112853541Sshin 112978064Sume if (ia6_match == NULL) /* remember the first one */ 113078064Sume ia6_match = ifa6; 113178064Sume 113278064Sume /* 113378064Sume * An already autoconfigured address matched. Now that we 113478064Sume * are sure there is at least one matched address, we can 113578064Sume * proceed to 5.5.3. (e): update the lifetimes according to the 113678064Sume * "two hours" rule and the privacy extension. 1137151539Ssuz * We apply some clarifications in rfc2462bis: 1138151539Ssuz * - use remaininglifetime instead of storedlifetime as a 1139151539Ssuz * variable name 1140151539Ssuz * - remove the dead code in the "two-hour" rule 114178064Sume */ 114278064Sume#define TWOHOUR (120*60) 114378064Sume lt6_tmp = ifa6->ia6_lifetime; 114478064Sume 1145112678Sume if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 1146151539Ssuz remaininglifetime = ND6_INFINITE_LIFETIME; 1147253970Shrs else if (time_uptime - ifa6->ia6_updatetime > 1148151539Ssuz lt6_tmp.ia6t_vltime) { 1149151539Ssuz /* 1150151539Ssuz * The case of "invalid" address. We should usually 1151151539Ssuz * not see this case. 1152151539Ssuz */ 1153151539Ssuz remaininglifetime = 0; 1154151539Ssuz } else 1155151539Ssuz remaininglifetime = lt6_tmp.ia6t_vltime - 1156253970Shrs (time_uptime - ifa6->ia6_updatetime); 115778064Sume 1158112678Sume /* when not updating, keep the current stored lifetime. */ 1159151539Ssuz lt6_tmp.ia6t_vltime = remaininglifetime; 1160112678Sume 116178064Sume if (TWOHOUR < new->ndpr_vltime || 1162151539Ssuz remaininglifetime < new->ndpr_vltime) { 116378064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 1164151539Ssuz } else if (remaininglifetime <= TWOHOUR) { 116578064Sume if (auth) { 116678064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 116778064Sume } 116878064Sume } else { 116978064Sume /* 117078064Sume * new->ndpr_vltime <= TWOHOUR && 1171151539Ssuz * TWOHOUR < remaininglifetime 117278064Sume */ 117378064Sume lt6_tmp.ia6t_vltime = TWOHOUR; 117453541Sshin } 117553541Sshin 117678064Sume /* The 2 hour rule is not imposed for preferred lifetime. */ 117778064Sume lt6_tmp.ia6t_pltime = new->ndpr_pltime; 117853541Sshin 117978064Sume in6_init_address_ltimes(pr, <6_tmp); 118053541Sshin 1181171260Sdelphij /* 1182151539Ssuz * We need to treat lifetimes for temporary addresses 1183151539Ssuz * differently, according to 1184151539Ssuz * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1); 1185151539Ssuz * we only update the lifetimes when they are in the maximum 1186151539Ssuz * intervals. 1187171260Sdelphij */ 1188171260Sdelphij if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 1189151539Ssuz u_int32_t maxvltime, maxpltime; 1190151539Ssuz 1191181803Sbz if (V_ip6_temp_valid_lifetime > 1192253970Shrs (u_int32_t)((time_uptime - ifa6->ia6_createtime) + 1193181803Sbz V_ip6_desync_factor)) { 1194181803Sbz maxvltime = V_ip6_temp_valid_lifetime - 1195253970Shrs (time_uptime - ifa6->ia6_createtime) - 1196181803Sbz V_ip6_desync_factor; 1197151539Ssuz } else 1198151539Ssuz maxvltime = 0; 1199181803Sbz if (V_ip6_temp_preferred_lifetime > 1200253970Shrs (u_int32_t)((time_uptime - ifa6->ia6_createtime) + 1201181803Sbz V_ip6_desync_factor)) { 1202181803Sbz maxpltime = V_ip6_temp_preferred_lifetime - 1203253970Shrs (time_uptime - ifa6->ia6_createtime) - 1204181803Sbz V_ip6_desync_factor; 1205151539Ssuz } else 1206151539Ssuz maxpltime = 0; 1207151539Ssuz 1208151539Ssuz if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME || 1209151539Ssuz lt6_tmp.ia6t_vltime > maxvltime) { 1210151539Ssuz lt6_tmp.ia6t_vltime = maxvltime; 121178064Sume } 1212151539Ssuz if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || 1213151539Ssuz lt6_tmp.ia6t_pltime > maxpltime) { 1214151539Ssuz lt6_tmp.ia6t_pltime = maxpltime; 121578064Sume } 121678064Sume } 121778064Sume ifa6->ia6_lifetime = lt6_tmp; 1218253970Shrs ifa6->ia6_updatetime = time_uptime; 121953541Sshin } 1220229621Sjhb IF_ADDR_RUNLOCK(ifp); 122178064Sume if (ia6_match == NULL && new->ndpr_vltime) { 1222151539Ssuz int ifidlen; 1223151539Ssuz 122478064Sume /* 1225151539Ssuz * 5.5.3 (d) (continued) 122678064Sume * No address matched and the valid lifetime is non-zero. 122778064Sume * Create a new address. 122878064Sume */ 1229151539Ssuz 1230151539Ssuz /* 1231151539Ssuz * Prefix Length check: 1232151539Ssuz * If the sum of the prefix length and interface identifier 1233151539Ssuz * length does not equal 128 bits, the Prefix Information 1234151539Ssuz * option MUST be ignored. The length of the interface 1235151539Ssuz * identifier is defined in a separate link-type specific 1236151539Ssuz * document. 1237151539Ssuz */ 1238151539Ssuz ifidlen = in6_if2idlen(ifp); 1239151539Ssuz if (ifidlen < 0) { 1240151539Ssuz /* this should not happen, so we always log it. */ 1241151539Ssuz log(LOG_ERR, "prelist_update: IFID undefined (%s)\n", 1242151539Ssuz if_name(ifp)); 1243151539Ssuz goto end; 1244151539Ssuz } 1245151539Ssuz if (ifidlen + pr->ndpr_plen != 128) { 1246151539Ssuz nd6log((LOG_INFO, 1247151539Ssuz "prelist_update: invalid prefixlen " 1248151539Ssuz "%d for %s, ignored\n", 1249151539Ssuz pr->ndpr_plen, if_name(ifp))); 1250151539Ssuz goto end; 1251151539Ssuz } 1252151539Ssuz 1253151539Ssuz if ((ia6 = in6_ifadd(new, mcast)) != NULL) { 125478064Sume /* 125578064Sume * note that we should use pr (not new) for reference. 125678064Sume */ 125778064Sume pr->ndpr_refcnt++; 125878064Sume ia6->ia6_ndpr = pr; 125953541Sshin 126078064Sume /* 126178064Sume * RFC 3041 3.3 (2). 126278064Sume * When a new public address is created as described 126378064Sume * in RFC2462, also create a new temporary address. 126478064Sume * 126578064Sume * RFC 3041 3.5. 126678064Sume * When an interface connects to a new link, a new 126778064Sume * randomized interface identifier should be generated 126878064Sume * immediately together with a new set of temporary 126978064Sume * addresses. Thus, we specifiy 1 as the 2nd arg of 127078064Sume * in6_tmpifadd(). 127178064Sume */ 1272181803Sbz if (V_ip6_use_tempaddr) { 127378064Sume int e; 1274151539Ssuz if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) { 127578064Sume nd6log((LOG_NOTICE, "prelist_update: " 127678064Sume "failed to create a temporary " 127778064Sume "address, errno=%d\n", 127878064Sume e)); 127978064Sume } 128078064Sume } 1281194760Srwatson ifa_free(&ia6->ia_ifa); 128278064Sume 128378064Sume /* 128478064Sume * A newly added address might affect the status 128578064Sume * of other addresses, so we check and update it. 128678064Sume * XXX: what if address duplication happens? 128778064Sume */ 128878064Sume pfxlist_onlink_check(); 128978064Sume } else { 129078064Sume /* just set an error. do not bark here. */ 129178064Sume error = EADDRNOTAVAIL; /* XXX: might be unused. */ 129278064Sume } 129378064Sume } 129478064Sume 129553541Sshin end: 129653541Sshin return error; 129753541Sshin} 129853541Sshin 129953541Sshin/* 130062587Sitojun * A supplement function used in the on-link detection below; 130162587Sitojun * detect if a given prefix has a (probably) reachable advertising router. 130262587Sitojun * XXX: lengthy function name... 130362587Sitojun */ 130478064Sumestatic struct nd_pfxrouter * 1305171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr) 130662587Sitojun{ 130762587Sitojun struct nd_pfxrouter *pfxrtr; 1308186119Sqingli struct llentry *ln; 1309186162Skmacy int canreach; 131062587Sitojun 1311228966Sjhb LIST_FOREACH(pfxrtr, &pr->ndpr_advrtrs, pfr_entry) { 1312243148Sae IF_AFDATA_RLOCK(pfxrtr->router->ifp); 1313186162Skmacy ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp); 1314243148Sae IF_AFDATA_RUNLOCK(pfxrtr->router->ifp); 1315186198Skmacy if (ln == NULL) 1316186198Skmacy continue; 1317186198Skmacy canreach = ND6_IS_LLINFO_PROBREACH(ln); 1318186198Skmacy LLE_RUNLOCK(ln); 1319186162Skmacy if (canreach) 1320186162Skmacy break; 132162587Sitojun } 1322120856Sume return (pfxrtr); 132362587Sitojun} 132462587Sitojun 132562587Sitojun/* 132653541Sshin * Check if each prefix in the prefix list has at least one available router 132778064Sume * that advertised the prefix (a router is "available" if its neighbor cache 132878064Sume * entry is reachable or probably reachable). 132962587Sitojun * If the check fails, the prefix may be off-link, because, for example, 133053541Sshin * we have moved from the network but the lifetime of the prefix has not 133178064Sume * expired yet. So we should not use the prefix if there is another prefix 133278064Sume * that has an available router. 133378064Sume * But, if there is no prefix that has an available router, we still regards 133478064Sume * all the prefixes as on-link. This is because we can't tell if all the 133553541Sshin * routers are simply dead or if we really moved from the network and there 133653541Sshin * is no router around us. 133753541Sshin */ 133862587Sitojunvoid 133953541Sshinpfxlist_onlink_check() 134053541Sshin{ 134153541Sshin struct nd_prefix *pr; 134278064Sume struct in6_ifaddr *ifa; 1343151539Ssuz struct nd_defrouter *dr; 1344151539Ssuz struct nd_pfxrouter *pfxrtr = NULL; 134553541Sshin 134662587Sitojun /* 134762587Sitojun * Check if there is a prefix that has a reachable advertising 134862587Sitojun * router. 134962587Sitojun */ 1350228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 135178064Sume if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 135253541Sshin break; 135362587Sitojun } 135453541Sshin 1355151539Ssuz /* 1356151539Ssuz * If we have no such prefix, check whether we still have a router 1357151539Ssuz * that does not advertise any prefixes. 1358151539Ssuz */ 1359151465Ssuz if (pr == NULL) { 1360228966Sjhb TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) { 1361151539Ssuz struct nd_prefix *pr0; 1362151539Ssuz 1363228966Sjhb LIST_FOREACH(pr0, &V_nd_prefix, ndpr_entry) { 1364151539Ssuz if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) 1365151539Ssuz break; 1366151539Ssuz } 1367151539Ssuz if (pfxrtr != NULL) 1368151539Ssuz break; 1369151539Ssuz } 1370151539Ssuz } 1371228966Sjhb if (pr != NULL || (!TAILQ_EMPTY(&V_nd_defrouter) && pfxrtr == NULL)) { 1372171260Sdelphij /* 1373151539Ssuz * There is at least one prefix that has a reachable router, 1374151539Ssuz * or at least a router which probably does not advertise 1375151539Ssuz * any prefixes. The latter would be the case when we move 1376151539Ssuz * to a new link where we have a router that does not provide 1377151539Ssuz * prefixes and we configure an address by hand. 1378171260Sdelphij * Detach prefixes which have no reachable advertising 1379171260Sdelphij * router, and attach other prefixes. 1380171260Sdelphij */ 1381228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 138278064Sume /* XXX: a link-local prefix should never be detached */ 138378064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 138478064Sume continue; 138578064Sume 138678064Sume /* 138778064Sume * we aren't interested in prefixes without the L bit 138878064Sume * set. 138978064Sume */ 139078064Sume if (pr->ndpr_raf_onlink == 0) 139178064Sume continue; 139278064Sume 1393196649Sqingli if (pr->ndpr_raf_auto == 0) 1394196649Sqingli continue; 1395196649Sqingli 139678064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 139778064Sume find_pfxlist_reachable_router(pr) == NULL) 139878064Sume pr->ndpr_stateflags |= NDPRF_DETACHED; 139978064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 140078064Sume find_pfxlist_reachable_router(pr) != 0) 140178064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 140253541Sshin } 140378064Sume } else { 140478064Sume /* there is no prefix that has a reachable router */ 1405228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 140678064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 140778064Sume continue; 140878064Sume 140978064Sume if (pr->ndpr_raf_onlink == 0) 141078064Sume continue; 141178064Sume 1412196649Sqingli if (pr->ndpr_raf_auto == 0) 1413196649Sqingli continue; 1414196649Sqingli 141578064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 141678064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 141753541Sshin } 141862587Sitojun } 141978064Sume 142078064Sume /* 142178064Sume * Remove each interface route associated with a (just) detached 142278064Sume * prefix, and reinstall the interface route for a (just) attached 142378064Sume * prefix. Note that all attempt of reinstallation does not 142478064Sume * necessarily success, when a same prefix is shared among multiple 142578064Sume * interfaces. Such cases will be handled in nd6_prefix_onlink, 142678064Sume * so we don't have to care about them. 142778064Sume */ 1428228966Sjhb LIST_FOREACH(pr, &V_nd_prefix, ndpr_entry) { 142978064Sume int e; 1430165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 143178064Sume 143278064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 143378064Sume continue; 143478064Sume 143578064Sume if (pr->ndpr_raf_onlink == 0) 143678064Sume continue; 143778064Sume 1438196649Sqingli if (pr->ndpr_raf_auto == 0) 1439196649Sqingli continue; 1440196649Sqingli 144178064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 144278064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 144378064Sume if ((e = nd6_prefix_offlink(pr)) != 0) { 144478064Sume nd6log((LOG_ERR, 144578064Sume "pfxlist_onlink_check: failed to " 1446151479Ssuz "make %s/%d offlink, errno=%d\n", 1447165118Sbz ip6_sprintf(ip6buf, 1448165118Sbz &pr->ndpr_prefix.sin6_addr), 1449165118Sbz pr->ndpr_plen, e)); 145078064Sume } 145178064Sume } 145278064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 145378064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 145478064Sume pr->ndpr_raf_onlink) { 145578064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 145678064Sume nd6log((LOG_ERR, 145778064Sume "pfxlist_onlink_check: failed to " 1458151479Ssuz "make %s/%d onlink, errno=%d\n", 1459165118Sbz ip6_sprintf(ip6buf, 1460165118Sbz &pr->ndpr_prefix.sin6_addr), 1461165118Sbz pr->ndpr_plen, e)); 146278064Sume } 146378064Sume } 146478064Sume } 146578064Sume 146678064Sume /* 146778064Sume * Changes on the prefix status might affect address status as well. 146878064Sume * Make sure that all addresses derived from an attached prefix are 146978064Sume * attached, and that all addresses derived from a detached prefix are 147078064Sume * detached. Note, however, that a manually configured address should 147178064Sume * always be attached. 147278064Sume * The precise detection logic is same as the one for prefixes. 1473194971Srwatson * 1474194971Srwatson * XXXRW: in6_ifaddrhead locking. 147578064Sume */ 1476194907Srwatson TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { 1477120941Sume if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) 147878064Sume continue; 147978064Sume 148078064Sume if (ifa->ia6_ndpr == NULL) { 148178064Sume /* 148278064Sume * This can happen when we first configure the address 148378064Sume * (i.e. the address exists, but the prefix does not). 148478064Sume * XXX: complicated relationships... 148578064Sume */ 148678064Sume continue; 148778064Sume } 148878064Sume 148978064Sume if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 149078064Sume break; 149178064Sume } 149278064Sume if (ifa) { 1493194907Srwatson TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { 149478064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 149578064Sume continue; 149678064Sume 149778064Sume if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 149878064Sume continue; 149978064Sume 1500151539Ssuz if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) { 1501151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1502151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1503151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1504151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1505151539Ssuz } 1506151539Ssuz } else { 150778064Sume ifa->ia6_flags |= IN6_IFF_DETACHED; 1508151539Ssuz } 150978064Sume } 151078064Sume } 151162587Sitojun else { 1512194907Srwatson TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) { 151378064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 151478064Sume continue; 151578064Sume 1516151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1517151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1518151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1519151539Ssuz /* Do we need a delay in this case? */ 1520151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1521151539Ssuz } 152278064Sume } 152353541Sshin } 152453541Sshin} 152553541Sshin 1526229547Sbzstatic int 1527231852Sbznd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa) 1528231852Sbz{ 1529231852Sbz static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1530231852Sbz struct radix_node_head *rnh; 1531231852Sbz struct rtentry *rt; 1532231852Sbz struct sockaddr_in6 mask6; 1533231852Sbz u_long rtflags; 1534231852Sbz int error, a_failure, fibnum; 1535231852Sbz 1536231852Sbz /* 1537231852Sbz * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 1538231852Sbz * ifa->ifa_rtrequest = nd6_rtrequest; 1539231852Sbz */ 1540231852Sbz bzero(&mask6, sizeof(mask6)); 1541231852Sbz mask6.sin6_len = sizeof(mask6); 1542231852Sbz mask6.sin6_addr = pr->ndpr_mask; 1543231852Sbz rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP; 1544231852Sbz 1545231852Sbz a_failure = 0; 1546231852Sbz for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 1547231852Sbz 1548231852Sbz rt = NULL; 1549231852Sbz error = in6_rtrequest(RTM_ADD, 1550231852Sbz (struct sockaddr *)&pr->ndpr_prefix, ifa->ifa_addr, 1551231852Sbz (struct sockaddr *)&mask6, rtflags, &rt, fibnum); 1552231852Sbz if (error == 0) { 1553231852Sbz KASSERT(rt != NULL, ("%s: in6_rtrequest return no " 1554231852Sbz "error(%d) but rt is NULL, pr=%p, ifa=%p", __func__, 1555231852Sbz error, pr, ifa)); 1556231852Sbz 1557231852Sbz rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6); 1558231852Sbz /* XXX what if rhn == NULL? */ 1559231852Sbz RADIX_NODE_HEAD_LOCK(rnh); 1560231852Sbz RT_LOCK(rt); 1561231852Sbz if (rt_setgate(rt, rt_key(rt), 1562231852Sbz (struct sockaddr *)&null_sdl) == 0) { 1563231852Sbz struct sockaddr_dl *dl; 1564231852Sbz 1565231852Sbz dl = (struct sockaddr_dl *)rt->rt_gateway; 1566231852Sbz dl->sdl_type = rt->rt_ifp->if_type; 1567231852Sbz dl->sdl_index = rt->rt_ifp->if_index; 1568231852Sbz } 1569231852Sbz RADIX_NODE_HEAD_UNLOCK(rnh); 1570231852Sbz nd6_rtmsg(RTM_ADD, rt); 1571231852Sbz RT_UNLOCK(rt); 1572231852Sbz pr->ndpr_stateflags |= NDPRF_ONLINK; 1573231852Sbz } else { 1574231852Sbz char ip6buf[INET6_ADDRSTRLEN]; 1575231852Sbz char ip6bufg[INET6_ADDRSTRLEN]; 1576231852Sbz char ip6bufm[INET6_ADDRSTRLEN]; 1577231852Sbz struct sockaddr_in6 *sin6; 1578231852Sbz 1579231852Sbz sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 1580231852Sbz nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add " 1581231852Sbz "route for a prefix (%s/%d) on %s, gw=%s, mask=%s, " 1582231852Sbz "flags=%lx errno = %d\n", 1583231852Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1584231852Sbz pr->ndpr_plen, if_name(pr->ndpr_ifp), 1585231852Sbz ip6_sprintf(ip6bufg, &sin6->sin6_addr), 1586231852Sbz ip6_sprintf(ip6bufm, &mask6.sin6_addr), 1587231852Sbz rtflags, error)); 1588231852Sbz 1589231852Sbz /* Save last error to return, see rtinit(). */ 1590231852Sbz a_failure = error; 1591231852Sbz } 1592231852Sbz 1593231852Sbz if (rt != NULL) { 1594231852Sbz RT_LOCK(rt); 1595231852Sbz RT_REMREF(rt); 1596231852Sbz RT_UNLOCK(rt); 1597231852Sbz } 1598231852Sbz } 1599231852Sbz 1600231852Sbz /* Return the last error we got. */ 1601231852Sbz return (a_failure); 1602231852Sbz} 1603231852Sbz 1604231852Sbzstatic int 1605171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr) 160653541Sshin{ 160778064Sume struct ifaddr *ifa; 160878064Sume struct ifnet *ifp = pr->ndpr_ifp; 160978064Sume struct nd_prefix *opr; 161078064Sume int error = 0; 1611165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 161253541Sshin 161378064Sume /* sanity check */ 161478064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 161578064Sume nd6log((LOG_ERR, 161678064Sume "nd6_prefix_onlink: %s/%d is already on-link\n", 1617165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1618165118Sbz pr->ndpr_plen)); 1619151465Ssuz return (EEXIST); 162078064Sume } 162178064Sume 162253541Sshin /* 162378064Sume * Add the interface route associated with the prefix. Before 162478064Sume * installing the route, check if there's the same prefix on another 162578064Sume * interface, and the prefix has already installed the interface route. 162678064Sume * Although such a configuration is expected to be rare, we explicitly 162778064Sume * allow it. 162853541Sshin */ 1629228966Sjhb LIST_FOREACH(opr, &V_nd_prefix, ndpr_entry) { 163078064Sume if (opr == pr) 163178064Sume continue; 163278064Sume 163378064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 163478064Sume continue; 163578064Sume 163678064Sume if (opr->ndpr_plen == pr->ndpr_plen && 163778064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1638120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) 1639120856Sume return (0); 164078064Sume } 164178064Sume 164278064Sume /* 1643120941Sume * We prefer link-local addresses as the associated interface address. 164478064Sume */ 164578064Sume /* search for a link-local addr */ 164678064Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 1647120941Sume IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); 164878064Sume if (ifa == NULL) { 164978064Sume /* XXX: freebsd does not have ifa_ifwithaf */ 1650229621Sjhb IF_ADDR_RLOCK(ifp); 1651191340Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 165278064Sume if (ifa->ifa_addr->sa_family == AF_INET6) 165378064Sume break; 165478064Sume } 1655194760Srwatson if (ifa != NULL) 1656194760Srwatson ifa_ref(ifa); 1657229621Sjhb IF_ADDR_RUNLOCK(ifp); 165878064Sume /* should we care about ia6_flags? */ 165978064Sume } 166078064Sume if (ifa == NULL) { 166178064Sume /* 166278064Sume * This can still happen, when, for example, we receive an RA 166378064Sume * containing a prefix with the L bit set and the A bit clear, 166478064Sume * after removing all IPv6 addresses on the receiving 166578064Sume * interface. This should, of course, be rare though. 166678064Sume */ 166778064Sume nd6log((LOG_NOTICE, 166878064Sume "nd6_prefix_onlink: failed to find any ifaddr" 166978064Sume " to add route for a prefix(%s/%d) on %s\n", 1670165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 167178064Sume pr->ndpr_plen, if_name(ifp))); 1672120856Sume return (0); 167378064Sume } 167478064Sume 1675231852Sbz error = nd6_prefix_onlink_rtrequest(pr, ifa); 167678064Sume 1677194760Srwatson if (ifa != NULL) 1678194760Srwatson ifa_free(ifa); 167978064Sume 1680120856Sume return (error); 168178064Sume} 168278064Sume 1683229547Sbzstatic int 1684171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr) 168578064Sume{ 168678064Sume int error = 0; 168778064Sume struct ifnet *ifp = pr->ndpr_ifp; 168878064Sume struct nd_prefix *opr; 168978064Sume struct sockaddr_in6 sa6, mask6; 1690231852Sbz struct rtentry *rt; 1691165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 1692231852Sbz int fibnum, a_failure; 169378064Sume 169478064Sume /* sanity check */ 169578064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 169678064Sume nd6log((LOG_ERR, 169778064Sume "nd6_prefix_offlink: %s/%d is already off-link\n", 1698165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1699165118Sbz pr->ndpr_plen)); 1700120856Sume return (EEXIST); 170178064Sume } 170278064Sume 170353541Sshin bzero(&sa6, sizeof(sa6)); 170453541Sshin sa6.sin6_family = AF_INET6; 170553541Sshin sa6.sin6_len = sizeof(sa6); 170653541Sshin bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 1707120941Sume sizeof(struct in6_addr)); 170853541Sshin bzero(&mask6, sizeof(mask6)); 170953541Sshin mask6.sin6_family = AF_INET6; 171053541Sshin mask6.sin6_len = sizeof(sa6); 171153541Sshin bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 1712231852Sbz 1713231852Sbz a_failure = 0; 1714231852Sbz for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 1715231852Sbz rt = NULL; 1716231852Sbz error = in6_rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 1717231852Sbz (struct sockaddr *)&mask6, 0, &rt, fibnum); 1718231852Sbz if (error == 0) { 1719231852Sbz /* report the route deletion to the routing socket. */ 1720231852Sbz if (rt != NULL) 1721231852Sbz nd6_rtmsg(RTM_DELETE, rt); 1722231852Sbz } else { 1723231852Sbz /* Save last error to return, see rtinit(). */ 1724231852Sbz a_failure = error; 1725231852Sbz } 1726231852Sbz if (rt != NULL) { 1727231852Sbz RTFREE(rt); 1728231852Sbz } 1729231852Sbz } 1730231852Sbz error = a_failure; 1731252141Sqingli a_failure = 1; 173278064Sume if (error == 0) { 173378064Sume pr->ndpr_stateflags &= ~NDPRF_ONLINK; 173453541Sshin 173578064Sume /* 173678064Sume * There might be the same prefix on another interface, 173778064Sume * the prefix which could not be on-link just because we have 173878064Sume * the interface route (see comments in nd6_prefix_onlink). 173978064Sume * If there's one, try to make the prefix on-link on the 174078064Sume * interface. 174178064Sume */ 1742228966Sjhb LIST_FOREACH(opr, &V_nd_prefix, ndpr_entry) { 174378064Sume if (opr == pr) 174478064Sume continue; 174553541Sshin 174678064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 174778064Sume continue; 174853541Sshin 174978064Sume /* 175078064Sume * KAME specific: detached prefixes should not be 175178064Sume * on-link. 175278064Sume */ 175378064Sume if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 175478064Sume continue; 175578064Sume 175678064Sume if (opr->ndpr_plen == pr->ndpr_plen && 175778064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1758120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 175978064Sume int e; 176078064Sume 176178064Sume if ((e = nd6_prefix_onlink(opr)) != 0) { 176278064Sume nd6log((LOG_ERR, 176378064Sume "nd6_prefix_offlink: failed to " 176478064Sume "recover a prefix %s/%d from %s " 176578064Sume "to %s (errno = %d)\n", 1766165118Sbz ip6_sprintf(ip6buf, 1767165118Sbz &opr->ndpr_prefix.sin6_addr), 176878064Sume opr->ndpr_plen, if_name(ifp), 176978064Sume if_name(opr->ndpr_ifp), e)); 1770252141Sqingli } else 1771252141Sqingli a_failure = 0; 177278064Sume } 177378064Sume } 1774120941Sume } else { 177578064Sume /* XXX: can we still set the NDPRF_ONLINK flag? */ 177678064Sume nd6log((LOG_ERR, 177778064Sume "nd6_prefix_offlink: failed to delete route: " 177878064Sume "%s/%d on %s (errno = %d)\n", 1779165118Sbz ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen, 1780165118Sbz if_name(ifp), error)); 178178064Sume } 178253541Sshin 1783252141Sqingli if (a_failure) 1784252141Sqingli lltable_prefix_free(AF_INET6, (struct sockaddr *)&sa6, 1785252141Sqingli (struct sockaddr *)&mask6, LLE_STATIC); 1786252141Sqingli 1787120856Sume return (error); 178853541Sshin} 178953541Sshin 179053541Sshinstatic struct in6_ifaddr * 1791171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast) 179253541Sshin{ 179378064Sume struct ifnet *ifp = pr->ndpr_ifp; 179453541Sshin struct ifaddr *ifa; 179578064Sume struct in6_aliasreq ifra; 179678064Sume struct in6_ifaddr *ia, *ib; 179778064Sume int error, plen0; 179853541Sshin struct in6_addr mask; 179978064Sume int prefixlen = pr->ndpr_plen; 1800151539Ssuz int updateflags; 1801165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 180253541Sshin 1803121168Sume in6_prefixlen2mask(&mask, prefixlen); 180453541Sshin 180578064Sume /* 180678064Sume * find a link-local address (will be interface ID). 180778064Sume * Is it really mandatory? Theoretically, a global or a site-local 180878064Sume * address can be configured without a link-local address, if we 180978064Sume * have a unique interface identifier... 181078064Sume * 181178064Sume * it is not mandatory to have a link-local address, we can generate 181278064Sume * interface identifier on the fly. we do this because: 181378064Sume * (1) it should be the easiest way to find interface identifier. 181478064Sume * (2) RFC2462 5.4 suggesting the use of the same interface identifier 181578064Sume * for multiple addresses on a single interface, and possible shortcut 181678064Sume * of DAD. we omitted DAD for this reason in the past. 1817120941Sume * (3) a user can prevent autoconfiguration of global address 181878064Sume * by removing link-local address by hand (this is partly because we 1819108533Sschweikh * don't have other way to control the use of IPv6 on an interface. 182078064Sume * this has been our design choice - cf. NRL's "ifconfig auto"). 182178064Sume * (4) it is easier to manage when an interface has addresses 182278064Sume * with the same interface identifier, than to have multiple addresses 182378064Sume * with different interface identifiers. 182478064Sume */ 1825120941Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ 182653541Sshin if (ifa) 182753541Sshin ib = (struct in6_ifaddr *)ifa; 182853541Sshin else 182953541Sshin return NULL; 183053541Sshin 183153541Sshin /* prefixlen + ifidlen must be equal to 128 */ 183278064Sume plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 183378064Sume if (prefixlen != plen0) { 1834194760Srwatson ifa_free(ifa); 183578064Sume nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 183678064Sume "(prefix=%d ifid=%d)\n", 183778064Sume if_name(ifp), prefixlen, 128 - plen0)); 183853541Sshin return NULL; 183953541Sshin } 184053541Sshin 184153541Sshin /* make ifaddr */ 184253541Sshin 184378064Sume bzero(&ifra, sizeof(ifra)); 184478064Sume /* 184578064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 184678064Sume * for safety. 184778064Sume */ 184878064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 184978064Sume ifra.ifra_addr.sin6_family = AF_INET6; 185078064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 185178064Sume /* prefix */ 1852151539Ssuz ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr; 185378064Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 185478064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 185578064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 185678064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 185753541Sshin 185853541Sshin /* interface ID */ 1859120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] |= 1860151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); 1861120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] |= 1862151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); 1863120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1864151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); 1865120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1866151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); 1867194760Srwatson ifa_free(ifa); 1868120941Sume 186978064Sume /* new prefix mask. */ 187078064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 187178064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 187278064Sume bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 1873120941Sume sizeof(ifra.ifra_prefixmask.sin6_addr)); 187453541Sshin 1875151539Ssuz /* lifetimes. */ 187678064Sume ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 187778064Sume ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 187853541Sshin 187978064Sume /* XXX: scope zone ID? */ 188053541Sshin 188178064Sume ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 1882151539Ssuz 1883171260Sdelphij /* 1884151539Ssuz * Make sure that we do not have this address already. This should 1885151539Ssuz * usually not happen, but we can still see this case, e.g., if we 1886151539Ssuz * have manually configured the exact address to be configured. 188778064Sume */ 1888194760Srwatson ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, 1889194760Srwatson &ifra.ifra_addr.sin6_addr); 1890194760Srwatson if (ifa != NULL) { 1891194760Srwatson ifa_free(ifa); 1892151539Ssuz /* this should be rare enough to make an explicit log */ 1893151539Ssuz log(LOG_INFO, "in6_ifadd: %s is already configured\n", 1894165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr)); 1895151539Ssuz return (NULL); 1896151539Ssuz } 189753541Sshin 189853541Sshin /* 1899151539Ssuz * Allocate ifaddr structure, link into chain, etc. 1900151539Ssuz * If we are going to create a new address upon receiving a multicasted 1901151539Ssuz * RA, we need to impose a random delay before starting DAD. 1902151539Ssuz * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] 190353541Sshin */ 1904151539Ssuz updateflags = 0; 1905151539Ssuz if (mcast) 1906151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1907151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { 190878064Sume nd6log((LOG_ERR, 190978064Sume "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 1910165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr), 1911165118Sbz if_name(ifp), error)); 1912120856Sume return (NULL); /* ifaddr must not have been allocated. */ 191353541Sshin } 191453541Sshin 191578064Sume ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 1916194760Srwatson /* 1917194760Srwatson * XXXRW: Assumption of non-NULLness here might not be true with 1918194760Srwatson * fine-grained locking -- should we validate it? Or just return 1919194760Srwatson * earlier ifa rather than looking it up again? 1920194760Srwatson */ 1921194760Srwatson return (ia); /* this is always non-NULL and referenced. */ 192253541Sshin} 192353541Sshin 1924171259Sdelphij/* 1925171259Sdelphij * ia0 - corresponding public address 1926171259Sdelphij */ 192753541Sshinint 1928171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) 192953541Sshin{ 193078064Sume struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 1931151539Ssuz struct in6_ifaddr *newia, *ia; 193278064Sume struct in6_aliasreq ifra; 193378064Sume int i, error; 193478064Sume int trylimit = 3; /* XXX: adhoc value */ 1935151539Ssuz int updateflags; 193678064Sume u_int32_t randid[2]; 193778064Sume time_t vltime0, pltime0; 193853541Sshin 193978064Sume bzero(&ifra, sizeof(ifra)); 194078064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 194178064Sume ifra.ifra_addr = ia0->ia_addr; 194278064Sume /* copy prefix mask */ 194378064Sume ifra.ifra_prefixmask = ia0->ia_prefixmask; 194478064Sume /* clear the old IFID */ 194578064Sume for (i = 0; i < 4; i++) { 1946120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[i] &= 1947120941Sume ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 194878064Sume } 194953541Sshin 195078064Sume again: 1951151539Ssuz if (in6_get_tmpifid(ifp, (u_int8_t *)randid, 1952151539Ssuz (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { 1953151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good " 1954151539Ssuz "random IFID\n")); 1955151539Ssuz return (EINVAL); 1956151539Ssuz } 1957120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1958120941Sume (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 1959120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1960120941Sume (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 196153541Sshin 1962171260Sdelphij /* 1963151539Ssuz * in6_get_tmpifid() quite likely provided a unique interface ID. 1964151539Ssuz * However, we may still have a chance to see collision, because 1965151539Ssuz * there may be a time lag between generation of the ID and generation 1966151539Ssuz * of the address. So, we'll do one more sanity check. 196778064Sume */ 1968194971Srwatson IN6_IFADDR_RLOCK(); 1969194907Srwatson TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { 1970151539Ssuz if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 1971151539Ssuz &ifra.ifra_addr.sin6_addr)) { 1972171260Sdelphij if (trylimit-- == 0) { 1973194971Srwatson IN6_IFADDR_RUNLOCK(); 1974151539Ssuz /* 1975151539Ssuz * Give up. Something strange should have 1976151539Ssuz * happened. 1977151539Ssuz */ 1978151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " 1979151539Ssuz "find a unique random IFID\n")); 1980151539Ssuz return (EEXIST); 1981151539Ssuz } 1982194971Srwatson IN6_IFADDR_RUNLOCK(); 1983151539Ssuz forcegen = 1; 1984151539Ssuz goto again; 198578064Sume } 198653541Sshin } 1987194971Srwatson IN6_IFADDR_RUNLOCK(); 198853541Sshin 198978064Sume /* 199078064Sume * The Valid Lifetime is the lower of the Valid Lifetime of the 199178064Sume * public address or TEMP_VALID_LIFETIME. 199278064Sume * The Preferred Lifetime is the lower of the Preferred Lifetime 199378064Sume * of the public address or TEMP_PREFERRED_LIFETIME - 199478064Sume * DESYNC_FACTOR. 199578064Sume */ 1996151539Ssuz if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 199778064Sume vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 1998151539Ssuz (ia0->ia6_lifetime.ia6t_vltime - 1999253970Shrs (time_uptime - ia0->ia6_updatetime)); 2000181803Sbz if (vltime0 > V_ip6_temp_valid_lifetime) 2001181803Sbz vltime0 = V_ip6_temp_valid_lifetime; 200278064Sume } else 2003181803Sbz vltime0 = V_ip6_temp_valid_lifetime; 2004151539Ssuz if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 200578064Sume pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 2006151539Ssuz (ia0->ia6_lifetime.ia6t_pltime - 2007253970Shrs (time_uptime - ia0->ia6_updatetime)); 2008181803Sbz if (pltime0 > V_ip6_temp_preferred_lifetime - V_ip6_desync_factor){ 2009181803Sbz pltime0 = V_ip6_temp_preferred_lifetime - 2010181803Sbz V_ip6_desync_factor; 201178064Sume } 201278064Sume } else 2013181803Sbz pltime0 = V_ip6_temp_preferred_lifetime - V_ip6_desync_factor; 201478064Sume ifra.ifra_lifetime.ia6t_vltime = vltime0; 201578064Sume ifra.ifra_lifetime.ia6t_pltime = pltime0; 201653541Sshin 201778064Sume /* 201878064Sume * A temporary address is created only if this calculated Preferred 201978064Sume * Lifetime is greater than REGEN_ADVANCE time units. 202078064Sume */ 2021181803Sbz if (ifra.ifra_lifetime.ia6t_pltime <= V_ip6_temp_regen_advance) 2022120856Sume return (0); 202353541Sshin 202478064Sume /* XXX: scope zone ID? */ 202578064Sume 202678064Sume ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 202778064Sume 202878064Sume /* allocate ifaddr structure, link into chain, etc. */ 2029151539Ssuz updateflags = 0; 2030151539Ssuz if (delay) 2031151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 2032151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) 2033120856Sume return (error); 203478064Sume 203578064Sume newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 203678064Sume if (newia == NULL) { /* XXX: can it happen? */ 203778064Sume nd6log((LOG_ERR, 203878064Sume "in6_tmpifadd: ifa update succeeded, but we got " 203978064Sume "no ifaddr\n")); 2040120856Sume return (EINVAL); /* XXX */ 204153541Sshin } 204278064Sume newia->ia6_ndpr = ia0->ia6_ndpr; 204378064Sume newia->ia6_ndpr->ndpr_refcnt++; 2044194760Srwatson ifa_free(&newia->ia_ifa); 204553541Sshin 204678407Sume /* 204778407Sume * A newly added address might affect the status of other addresses. 204878407Sume * XXX: when the temporary address is generated with a new public 204978407Sume * address, the onlink check is redundant. However, it would be safe 205078407Sume * to do the check explicitly everywhere a new address is generated, 205178407Sume * and, in fact, we surely need the check when we create a new 205278407Sume * temporary address due to deprecation of an old temporary address. 205378407Sume */ 205478407Sume pfxlist_onlink_check(); 205578407Sume 2056120856Sume return (0); 2057120941Sume} 205853541Sshin 2059151539Ssuzstatic int 206053541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr) 206153541Sshin{ 206253541Sshin if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 206353541Sshin ndpr->ndpr_preferred = 0; 206453541Sshin else 2065253970Shrs ndpr->ndpr_preferred = time_uptime + ndpr->ndpr_pltime; 206653541Sshin if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 206753541Sshin ndpr->ndpr_expire = 0; 206853541Sshin else 2069253970Shrs ndpr->ndpr_expire = time_uptime + ndpr->ndpr_vltime; 207053541Sshin 207153541Sshin return 0; 207253541Sshin} 207353541Sshin 207453541Sshinstatic void 207578064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 207653541Sshin{ 207778064Sume /* init ia6t_expire */ 207878064Sume if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 207978064Sume lt6->ia6t_expire = 0; 208078064Sume else { 2081253970Shrs lt6->ia6t_expire = time_uptime; 208278064Sume lt6->ia6t_expire += lt6->ia6t_vltime; 208353541Sshin } 208462587Sitojun 208553541Sshin /* init ia6t_preferred */ 208653541Sshin if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 208753541Sshin lt6->ia6t_preferred = 0; 208853541Sshin else { 2089253970Shrs lt6->ia6t_preferred = time_uptime; 209053541Sshin lt6->ia6t_preferred += lt6->ia6t_pltime; 209153541Sshin } 209253541Sshin} 209353541Sshin 209453541Sshin/* 209553541Sshin * Delete all the routing table entries that use the specified gateway. 209653541Sshin * XXX: this function causes search through all entries of routing table, so 209753541Sshin * it shouldn't be called when acting as a router. 209853541Sshin */ 209953541Sshinvoid 2100171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp) 210153541Sshin{ 2102193232Sbz struct radix_node_head *rnh; 2103231852Sbz u_int fibnum; 210453541Sshin 210553541Sshin /* We'll care only link-local addresses */ 2106241686Sandre if (!IN6_IS_ADDR_LINKLOCAL(gateway)) 210753541Sshin return; 210853541Sshin 2109231852Sbz /* XXX Do we really need to walk any but the default FIB? */ 2110231852Sbz for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { 2111231852Sbz rnh = rt_tables_get_rnh(fibnum, AF_INET6); 2112231852Sbz if (rnh == NULL) 2113231852Sbz continue; 2114193232Sbz 2115231852Sbz RADIX_NODE_HEAD_LOCK(rnh); 2116231852Sbz rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 2117231852Sbz RADIX_NODE_HEAD_UNLOCK(rnh); 2118231852Sbz } 211953541Sshin} 212053541Sshin 212153541Sshinstatic int 2122171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg) 212353541Sshin{ 212453541Sshin#define SIN6(s) ((struct sockaddr_in6 *)s) 212553541Sshin struct rtentry *rt = (struct rtentry *)rn; 212653541Sshin struct in6_addr *gate = (struct in6_addr *)arg; 212753541Sshin 212853541Sshin if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 2129120856Sume return (0); 213053541Sshin 2131120941Sume if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) { 2132120856Sume return (0); 2133120941Sume } 213453541Sshin 213553541Sshin /* 213678064Sume * Do not delete a static route. 213778064Sume * XXX: this seems to be a bit ad-hoc. Should we consider the 213878064Sume * 'cloned' bit instead? 213978064Sume */ 214078064Sume if ((rt->rt_flags & RTF_STATIC) != 0) 2141120856Sume return (0); 214278064Sume 214378064Sume /* 214453541Sshin * We delete only host route. This means, in particular, we don't 214553541Sshin * delete default route. 214653541Sshin */ 214753541Sshin if ((rt->rt_flags & RTF_HOST) == 0) 2148120856Sume return (0); 214953541Sshin 2150231852Sbz return (in6_rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 2151231852Sbz rt_mask(rt), rt->rt_flags, NULL, rt->rt_fibnum)); 215253541Sshin#undef SIN6 215353541Sshin} 215462587Sitojun 215562587Sitojunint 2156171259Sdelphijnd6_setdefaultiface(int ifindex) 215762587Sitojun{ 215862587Sitojun int error = 0; 215962587Sitojun 2160181803Sbz if (ifindex < 0 || V_if_index < ifindex) 2161120856Sume return (EINVAL); 2162151539Ssuz if (ifindex != 0 && !ifnet_byindex(ifindex)) 2163151539Ssuz return (EINVAL); 216462587Sitojun 2165181803Sbz if (V_nd6_defifindex != ifindex) { 2166181803Sbz V_nd6_defifindex = ifindex; 2167181803Sbz if (V_nd6_defifindex > 0) 2168181803Sbz V_nd6_defifp = ifnet_byindex(V_nd6_defifindex); 216962587Sitojun else 2170181803Sbz V_nd6_defifp = NULL; 217162587Sitojun 217262587Sitojun /* 217362587Sitojun * Our current implementation assumes one-to-one maping between 217462587Sitojun * interfaces and links, so it would be natural to use the 217562587Sitojun * default interface as the default link. 217662587Sitojun */ 2177181803Sbz scope6_setdefault(V_nd6_defifp); 217862587Sitojun } 217962587Sitojun 2180120856Sume return (error); 218162587Sitojun} 2182