nd6_rtr.c revision 190964
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: head/sys/netinet6/nd6_rtr.c 190964 2009-04-12 13:22:33Z rwatson $"); 34174510Sobrien 3562587Sitojun#include "opt_inet.h" 3662587Sitojun#include "opt_inet6.h" 37189106Sbz#include "opt_route.h" 3862587Sitojun 3953541Sshin#include <sys/param.h> 4053541Sshin#include <sys/systm.h> 4153541Sshin#include <sys/malloc.h> 4253541Sshin#include <sys/mbuf.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> 52181803Sbz#include <sys/vimage.h> 5353541Sshin 5453541Sshin#include <net/if.h> 5553541Sshin#include <net/if_types.h> 5653541Sshin#include <net/if_dl.h> 5753541Sshin#include <net/route.h> 5853541Sshin#include <net/radix.h> 59185571Sbz#include <net/vnet.h> 6053541Sshin 6153541Sshin#include <netinet/in.h> 62186119Sqingli#include <net/if_llatbl.h> 6353541Sshin#include <netinet6/in6_var.h> 6478064Sume#include <netinet6/in6_ifattach.h> 6562587Sitojun#include <netinet/ip6.h> 6653541Sshin#include <netinet6/ip6_var.h> 6753541Sshin#include <netinet6/nd6.h> 6862587Sitojun#include <netinet/icmp6.h> 6962587Sitojun#include <netinet6/scope6_var.h> 70185571Sbz#include <netinet6/vinet6.h> 7153541Sshin 72175162Sobrienstatic int rtpref(struct nd_defrouter *); 73175162Sobrienstatic struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); 74151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *, 75151539Ssuz struct mbuf *, int)); 76175162Sobrienstatic struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int); 7762587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, 7878064Sume struct nd_defrouter *)); 79175162Sobrienstatic void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *); 80175162Sobrienstatic void pfxrtr_del(struct nd_pfxrouter *); 8162587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router 82175162Sobrien(struct nd_prefix *); 83175162Sobrienstatic void defrouter_delreq(struct nd_defrouter *); 84175162Sobrienstatic void nd6_rtmsg(int, struct rtentry *); 8553541Sshin 86175162Sobrienstatic int in6_init_prefix_ltimes(struct nd_prefix *); 87120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *, 88120941Sume struct in6_addrlifetime *)); 8953541Sshin 90175162Sobrienstatic int rt6_deleteroute(struct radix_node *, void *); 9153541Sshin 92185348Szec#ifdef VIMAGE_GLOBALS 9362587Sitojunextern int nd6_recalc_reachtm_interval; 9453541Sshin 9578064Sumestatic struct ifnet *nd6_defifp; 9662587Sitojunint nd6_defifindex; 9762587Sitojun 98185088Szecint ip6_use_tempaddr; 9978064Sumeint ip6_desync_factor; 100185088Szecu_int32_t ip6_temp_preferred_lifetime; 101185088Szecu_int32_t ip6_temp_valid_lifetime; 102185088Szecint ip6_temp_regen_advance; 103185088Szec#endif 10478064Sume 105151539Ssuz/* RTPREF_MEDIUM has to be 0! */ 106151539Ssuz#define RTPREF_HIGH 1 107151539Ssuz#define RTPREF_MEDIUM 0 108151539Ssuz#define RTPREF_LOW (-1) 109151539Ssuz#define RTPREF_RESERVED (-2) 110151539Ssuz#define RTPREF_INVALID (-3) /* internal */ 111151539Ssuz 11278064Sume/* 11353541Sshin * Receive Router Solicitation Message - just for routers. 11453541Sshin * Router solicitation/advertisement is mostly managed by userland program 11553541Sshin * (rtadvd) so here we have no function like nd6_ra_output(). 11653541Sshin * 11753541Sshin * Based on RFC 2461 11853541Sshin */ 11953541Sshinvoid 120171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len) 12153541Sshin{ 122183550Szec INIT_VNET_INET6(curvnet); 12353541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 12453541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 12562587Sitojun struct nd_router_solicit *nd_rs; 12653541Sshin struct in6_addr saddr6 = ip6->ip6_src; 12753541Sshin char *lladdr = NULL; 12853541Sshin int lladdrlen = 0; 12953541Sshin union nd_opts ndopts; 130165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 13153541Sshin 13253541Sshin /* If I'm not a router, ignore it. */ 133181803Sbz if (V_ip6_accept_rtadv != 0 || V_ip6_forwarding != 1) 13462587Sitojun goto freeit; 13553541Sshin 13653541Sshin /* Sanity checks */ 13753541Sshin if (ip6->ip6_hlim != 255) { 13878064Sume nd6log((LOG_ERR, 13978064Sume "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 140165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 141165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 14278064Sume goto bad; 14353541Sshin } 14453541Sshin 14553541Sshin /* 14653541Sshin * Don't update the neighbor cache, if src = ::. 14753541Sshin * This indicates that the src has no IP address assigned yet. 14853541Sshin */ 14953541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 15062587Sitojun goto freeit; 15162587Sitojun 15262587Sitojun#ifndef PULLDOWN_TEST 15362587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 15462587Sitojun nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 15562587Sitojun#else 15662587Sitojun IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 15762587Sitojun if (nd_rs == NULL) { 158190964Srwatson ICMP6STAT_INC(icp6s_tooshort); 15953541Sshin return; 16062587Sitojun } 16162587Sitojun#endif 16253541Sshin 16353541Sshin icmp6len -= sizeof(*nd_rs); 16453541Sshin nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 16553541Sshin if (nd6_options(&ndopts) < 0) { 16678064Sume nd6log((LOG_INFO, 16778064Sume "nd6_rs_input: invalid ND option, ignored\n")); 16878064Sume /* nd6_options have incremented stats */ 16962587Sitojun goto freeit; 17053541Sshin } 17153541Sshin 17253541Sshin if (ndopts.nd_opts_src_lladdr) { 17353541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 17453541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 17553541Sshin } 17653541Sshin 17753541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 17878064Sume nd6log((LOG_INFO, 17953541Sshin "nd6_rs_input: lladdrlen mismatch for %s " 18053541Sshin "(if %d, RS packet %d)\n", 181165118Sbz ip6_sprintf(ip6bufs, &saddr6), 182120941Sume ifp->if_addrlen, lladdrlen - 2)); 18378064Sume goto bad; 18453541Sshin } 18553541Sshin 18653541Sshin nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 18762587Sitojun 18862587Sitojun freeit: 18962587Sitojun m_freem(m); 19078064Sume return; 19178064Sume 19278064Sume bad: 193190964Srwatson ICMP6STAT_INC(icp6s_badrs); 19478064Sume m_freem(m); 19553541Sshin} 19653541Sshin 19753541Sshin/* 19853541Sshin * Receive Router Advertisement Message. 19953541Sshin * 20053541Sshin * Based on RFC 2461 20153541Sshin * TODO: on-link bit on prefix information 20253541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 20353541Sshin */ 20453541Sshinvoid 205171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len) 20653541Sshin{ 207183550Szec INIT_VNET_INET6(curvnet); 20853541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 209121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 21053541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 21162587Sitojun struct nd_router_advert *nd_ra; 21253541Sshin struct in6_addr saddr6 = ip6->ip6_src; 213151539Ssuz int mcast = 0; 21453541Sshin union nd_opts ndopts; 21553541Sshin struct nd_defrouter *dr; 216165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 21753541Sshin 218118498Sume /* 219118498Sume * We only accept RAs only when 220118498Sume * the system-wide variable allows the acceptance, and 221118498Sume * per-interface variable allows RAs on the receiving interface. 222118498Sume */ 223181803Sbz if (V_ip6_accept_rtadv == 0) 22462587Sitojun goto freeit; 225118498Sume if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 226118498Sume goto freeit; 22753541Sshin 22853541Sshin if (ip6->ip6_hlim != 255) { 22978064Sume nd6log((LOG_ERR, 23078064Sume "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 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; 274156871Ssuz dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 27553541Sshin dr0.expire = time_second + dr0.rtlifetime; 27653541Sshin dr0.ifp = ifp; 27753541Sshin /* unspecified or not? (RFC 2461 6.3.4) */ 27853541Sshin if (advreachable) { 27990868Smike advreachable = ntohl(advreachable); 28053541Sshin if (advreachable <= MAX_REACHABLE_TIME && 28153541Sshin ndi->basereachable != advreachable) { 28253541Sshin ndi->basereachable = advreachable; 28353541Sshin ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 284181803Sbz ndi->recalctm = V_nd6_recalc_reachtm_interval; /* reset */ 28553541Sshin } 28653541Sshin } 28753541Sshin if (nd_ra->nd_ra_retransmit) 28853541Sshin ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 28953541Sshin if (nd_ra->nd_ra_curhoplimit) 29053541Sshin ndi->chlim = nd_ra->nd_ra_curhoplimit; 29153541Sshin dr = defrtrlist_update(&dr0); 29253541Sshin } 29353541Sshin 29453541Sshin /* 29553541Sshin * prefix 29653541Sshin */ 29753541Sshin if (ndopts.nd_opts_pi) { 29853541Sshin struct nd_opt_hdr *pt; 29978064Sume struct nd_opt_prefix_info *pi = NULL; 300151539Ssuz struct nd_prefixctl pr; 30153541Sshin 30253541Sshin for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 30353541Sshin pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 30453541Sshin pt = (struct nd_opt_hdr *)((caddr_t)pt + 30553541Sshin (pt->nd_opt_len << 3))) { 30653541Sshin if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 30753541Sshin continue; 30853541Sshin pi = (struct nd_opt_prefix_info *)pt; 30953541Sshin 31053541Sshin if (pi->nd_opt_pi_len != 4) { 31178064Sume nd6log((LOG_INFO, 31278064Sume "nd6_ra_input: invalid option " 31378064Sume "len %d for prefix information option, " 31478064Sume "ignored\n", pi->nd_opt_pi_len)); 31553541Sshin continue; 31653541Sshin } 31753541Sshin 31853541Sshin if (128 < pi->nd_opt_pi_prefix_len) { 31978064Sume nd6log((LOG_INFO, 32078064Sume "nd6_ra_input: invalid prefix " 32178064Sume "len %d for prefix information option, " 32278064Sume "ignored\n", pi->nd_opt_pi_prefix_len)); 32353541Sshin continue; 32453541Sshin } 32553541Sshin 32653541Sshin if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 32753541Sshin || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 32878064Sume nd6log((LOG_INFO, 32978064Sume "nd6_ra_input: invalid prefix " 33078064Sume "%s, ignored\n", 331165118Sbz ip6_sprintf(ip6bufs, 332165118Sbz &pi->nd_opt_pi_prefix))); 33353541Sshin continue; 33453541Sshin } 33553541Sshin 33653541Sshin bzero(&pr, sizeof(pr)); 33753541Sshin pr.ndpr_prefix.sin6_family = AF_INET6; 33853541Sshin pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 33953541Sshin pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 34053541Sshin pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 34153541Sshin 34253541Sshin pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 343120941Sume ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 34453541Sshin pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 345120941Sume ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 34653541Sshin pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 34753541Sshin pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 348120941Sume pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); 349151539Ssuz (void)prelist_update(&pr, dr, m, mcast); 35053541Sshin } 35153541Sshin } 35253541Sshin 35353541Sshin /* 35453541Sshin * MTU 35553541Sshin */ 35653541Sshin if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 357121283Sume u_long mtu; 358121283Sume u_long maxmtu; 35953541Sshin 360121283Sume mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 361120941Sume 36253541Sshin /* lower bound */ 36353541Sshin if (mtu < IPV6_MMTU) { 36478064Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " 365121283Sume "mtu=%lu sent from %s, ignoring\n", 366165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src))); 36753541Sshin goto skip; 36853541Sshin } 36953541Sshin 37053541Sshin /* upper bound */ 371121283Sume maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu) 372121283Sume ? ndi->maxmtu : ifp->if_mtu; 373121283Sume if (mtu <= maxmtu) { 374121283Sume int change = (ndi->linkmtu != mtu); 37553541Sshin 376121283Sume ndi->linkmtu = mtu; 377121283Sume if (change) /* in6_maxmtu may change */ 378121283Sume in6_setmaxmtu(); 37953541Sshin } else { 380121283Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " 381121283Sume "mtu=%lu sent from %s; " 382121283Sume "exceeds maxmtu %lu, ignoring\n", 383165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu)); 38453541Sshin } 38553541Sshin } 38653541Sshin 38753541Sshin skip: 388120941Sume 38953541Sshin /* 39095023Ssuz * Source link layer address 39153541Sshin */ 39253541Sshin { 39353541Sshin char *lladdr = NULL; 39453541Sshin int lladdrlen = 0; 395120941Sume 39653541Sshin if (ndopts.nd_opts_src_lladdr) { 39753541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 39853541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 39953541Sshin } 40053541Sshin 40153541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 40278064Sume nd6log((LOG_INFO, 40353541Sshin "nd6_ra_input: lladdrlen mismatch for %s " 404165118Sbz "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6), 405120941Sume ifp->if_addrlen, lladdrlen - 2)); 40678064Sume goto bad; 40753541Sshin } 40853541Sshin 409120941Sume nd6_cache_lladdr(ifp, &saddr6, lladdr, 410120941Sume lladdrlen, ND_ROUTER_ADVERT, 0); 41162587Sitojun 41262587Sitojun /* 41362587Sitojun * Installing a link-layer address might change the state of the 41462587Sitojun * router's neighbor cache, which might also affect our on-link 41562587Sitojun * detection of adveritsed prefixes. 41662587Sitojun */ 41762587Sitojun pfxlist_onlink_check(); 41853541Sshin } 41962587Sitojun 42078064Sume freeit: 42162587Sitojun m_freem(m); 42278064Sume return; 42378064Sume 42478064Sume bad: 425190964Srwatson ICMP6STAT_INC(icp6s_badra); 42678064Sume m_freem(m); 42753541Sshin} 42853541Sshin 42953541Sshin/* 43053541Sshin * default router list proccessing sub routines 43153541Sshin */ 43262587Sitojun 43362587Sitojun/* tell the change to user processes watching the routing socket. */ 43462587Sitojunstatic void 435171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt) 43662587Sitojun{ 43762587Sitojun struct rt_addrinfo info; 43862587Sitojun 43962587Sitojun bzero((caddr_t)&info, sizeof(info)); 44062587Sitojun info.rti_info[RTAX_DST] = rt_key(rt); 44162587Sitojun info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 44262587Sitojun info.rti_info[RTAX_NETMASK] = rt_mask(rt); 443151539Ssuz if (rt->rt_ifp) { 444151539Ssuz info.rti_info[RTAX_IFP] = 445151539Ssuz TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 446151539Ssuz info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 447151539Ssuz } 44862587Sitojun 44962587Sitojun rt_missmsg(cmd, &info, rt->rt_flags, 0); 45062587Sitojun} 45162587Sitojun 45253541Sshinvoid 453171259Sdelphijdefrouter_addreq(struct nd_defrouter *new) 45453541Sshin{ 45553541Sshin struct sockaddr_in6 def, mask, gate; 45662587Sitojun struct rtentry *newrt = NULL; 457151539Ssuz int s; 458151539Ssuz int error; 45953541Sshin 460128397Sluigi bzero(&def, sizeof(def)); 461128397Sluigi bzero(&mask, sizeof(mask)); 462128397Sluigi bzero(&gate, sizeof(gate)); 46353541Sshin 464120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 465120941Sume sizeof(struct sockaddr_in6); 466151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 46753541Sshin gate.sin6_addr = new->rtaddr; 46853541Sshin 469151539Ssuz s = splnet(); 470151539Ssuz error = rtrequest(RTM_ADD, (struct sockaddr *)&def, 471120941Sume (struct sockaddr *)&gate, (struct sockaddr *)&mask, 472120941Sume RTF_GATEWAY, &newrt); 47362587Sitojun if (newrt) { 47478064Sume nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 475186119Sqingli RTFREE(newrt); 47662587Sitojun } 477151539Ssuz if (error == 0) 478151539Ssuz new->installed = 1; 479151539Ssuz splx(s); 48053541Sshin return; 48153541Sshin} 48253541Sshin 48353541Sshinstruct nd_defrouter * 484171259Sdelphijdefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) 48553541Sshin{ 486183550Szec INIT_VNET_INET6(ifp->if_vnet); 48753541Sshin struct nd_defrouter *dr; 48853541Sshin 489181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 49062587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 49153541Sshin if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 492120856Sume return (dr); 49362587Sitojun } 49453541Sshin 495120856Sume return (NULL); /* search failed */ 49653541Sshin} 49753541Sshin 498151539Ssuz/* 499151539Ssuz * Remove the default route for a given router. 500151539Ssuz * This is just a subroutine function for defrouter_select(), and should 501151539Ssuz * not be called from anywhere else. 502151539Ssuz */ 503151539Ssuzstatic void 504171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr) 50553541Sshin{ 50653541Sshin struct sockaddr_in6 def, mask, gate; 50762587Sitojun struct rtentry *oldrt = NULL; 50853541Sshin 509128397Sluigi bzero(&def, sizeof(def)); 510128397Sluigi bzero(&mask, sizeof(mask)); 511128397Sluigi bzero(&gate, sizeof(gate)); 51253541Sshin 513120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 514120941Sume sizeof(struct sockaddr_in6); 515151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 51653541Sshin gate.sin6_addr = dr->rtaddr; 51753541Sshin 51853541Sshin rtrequest(RTM_DELETE, (struct sockaddr *)&def, 519120941Sume (struct sockaddr *)&gate, 520120941Sume (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); 52162587Sitojun if (oldrt) { 52278064Sume nd6_rtmsg(RTM_DELETE, oldrt); 523108269Sru RTFREE(oldrt); 52462587Sitojun } 52553541Sshin 526151539Ssuz dr->installed = 0; 52753541Sshin} 52853541Sshin 529151539Ssuz/* 530151539Ssuz * remove all default routes from default router list 531151539Ssuz */ 53253541Sshinvoid 533171259Sdelphijdefrouter_reset(void) 534151539Ssuz{ 535183550Szec INIT_VNET_INET6(curvnet); 536151539Ssuz struct nd_defrouter *dr; 537151539Ssuz 538181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 539151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) 540151539Ssuz defrouter_delreq(dr); 541151539Ssuz 542151539Ssuz /* 543151539Ssuz * XXX should we also nuke any default routers in the kernel, by 544151539Ssuz * going through them by rtalloc1()? 545151539Ssuz */ 546151539Ssuz} 547151539Ssuz 548151539Ssuzvoid 549171259Sdelphijdefrtrlist_del(struct nd_defrouter *dr) 55053541Sshin{ 551183550Szec INIT_VNET_INET6(curvnet); 55253541Sshin struct nd_defrouter *deldr = NULL; 55353541Sshin struct nd_prefix *pr; 55453541Sshin 55553541Sshin /* 55653541Sshin * Flush all the routing table entries that use the router 55753541Sshin * as a next hop. 55853541Sshin */ 559181803Sbz if (!V_ip6_forwarding && V_ip6_accept_rtadv) /* XXX: better condition? */ 56053541Sshin rt6_flush(&dr->rtaddr, dr->ifp); 56153541Sshin 562151539Ssuz if (dr->installed) { 563151539Ssuz deldr = dr; 564151539Ssuz defrouter_delreq(dr); 565151539Ssuz } 566181803Sbz TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 56753541Sshin 56853541Sshin /* 56953541Sshin * Also delete all the pointers to the router in each prefix lists. 57053541Sshin */ 571181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 57253541Sshin struct nd_pfxrouter *pfxrtr; 57353541Sshin if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 57453541Sshin pfxrtr_del(pfxrtr); 57553541Sshin } 57653541Sshin pfxlist_onlink_check(); 57753541Sshin 57853541Sshin /* 57962587Sitojun * If the router is the primary one, choose a new one. 58062587Sitojun * Note that defrouter_select() will remove the current gateway 58162587Sitojun * from the routing table. 58253541Sshin */ 58353541Sshin if (deldr) 58462587Sitojun defrouter_select(); 58562587Sitojun 58653541Sshin free(dr, M_IP6NDP); 58753541Sshin} 58853541Sshin 58962587Sitojun/* 590151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and 591151539Ssuz * draft-ietf-ipngwg-router-selection: 592151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred. 593151539Ssuz * If we have more than one (probably) reachable router, prefer ones 594151539Ssuz * with the highest router preference. 59562587Sitojun * 2) When no routers on the list are known to be reachable or 59662587Sitojun * probably reachable, routers SHOULD be selected in a round-robin 597151539Ssuz * fashion, regardless of router preference values. 59862587Sitojun * 3) If the Default Router List is empty, assume that all 59962587Sitojun * destinations are on-link. 600151539Ssuz * 601151539Ssuz * We assume nd_defrouter is sorted by router preference value. 602151539Ssuz * Since the code below covers both with and without router preference cases, 603151539Ssuz * we do not need to classify the cases by ifdef. 604151539Ssuz * 605151539Ssuz * At this moment, we do not try to install more than one default router, 606151539Ssuz * even when the multipath routing is available, because we're not sure about 607151539Ssuz * the benefits for stub hosts comparing to the risk of making the code 608151539Ssuz * complicated and the possibility of introducing bugs. 60962587Sitojun */ 61062587Sitojunvoid 611171259Sdelphijdefrouter_select(void) 61262587Sitojun{ 613183550Szec INIT_VNET_INET6(curvnet); 61462587Sitojun int s = splnet(); 615151539Ssuz struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; 616186119Sqingli struct llentry *ln = NULL; 61762587Sitojun 61862587Sitojun /* 619151539Ssuz * This function should be called only when acting as an autoconfigured 620151539Ssuz * host. Although the remaining part of this function is not effective 621151539Ssuz * if the node is not an autoconfigured host, we explicitly exclude 622151539Ssuz * such cases here for safety. 623151539Ssuz */ 624181803Sbz if (V_ip6_forwarding || !V_ip6_accept_rtadv) { 625151539Ssuz nd6log((LOG_WARNING, 626151539Ssuz "defrouter_select: called unexpectedly (forwarding=%d, " 627181803Sbz "accept_rtadv=%d)\n", V_ip6_forwarding, V_ip6_accept_rtadv)); 628151539Ssuz splx(s); 629151539Ssuz return; 630151539Ssuz } 631151539Ssuz 632151539Ssuz /* 633151539Ssuz * Let's handle easy case (3) first: 634151539Ssuz * If default router list is empty, there's nothing to be done. 635151539Ssuz */ 636181803Sbz if (!TAILQ_FIRST(&V_nd_defrouter)) { 637151539Ssuz splx(s); 638151539Ssuz return; 639151539Ssuz } 640151539Ssuz 641151539Ssuz /* 64262587Sitojun * Search for a (probably) reachable router from the list. 643151539Ssuz * We just pick up the first reachable one (if any), assuming that 644151539Ssuz * the ordering rule of the list described in defrtrlist_update(). 64562587Sitojun */ 646181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 64762587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 648186119Sqingli IF_AFDATA_LOCK(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 } 654186119Sqingli IF_AFDATA_UNLOCK(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) { 682186119Sqingli IF_AFDATA_LOCK(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 } 688186119Sqingli IF_AFDATA_UNLOCK(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 splx(s); 70562587Sitojun return; 70662587Sitojun} 70762587Sitojun 708151539Ssuz/* 709151539Ssuz * for default router selection 710151539Ssuz * regards router-preference field as a 2-bit signed integer 711151539Ssuz */ 712151539Ssuzstatic int 713151539Ssuzrtpref(struct nd_defrouter *dr) 714151539Ssuz{ 715151539Ssuz switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) { 716151539Ssuz case ND_RA_FLAG_RTPREF_HIGH: 717151539Ssuz return (RTPREF_HIGH); 718151539Ssuz case ND_RA_FLAG_RTPREF_MEDIUM: 719156871Ssuz case ND_RA_FLAG_RTPREF_RSV: 720151539Ssuz return (RTPREF_MEDIUM); 721151539Ssuz case ND_RA_FLAG_RTPREF_LOW: 722151539Ssuz return (RTPREF_LOW); 723151539Ssuz default: 724151539Ssuz /* 725151539Ssuz * This case should never happen. If it did, it would mean a 726151539Ssuz * serious bug of kernel internal. We thus always bark here. 727151539Ssuz * Or, can we even panic? 728151539Ssuz */ 729151539Ssuz log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags); 730151539Ssuz return (RTPREF_INVALID); 731151539Ssuz } 732151539Ssuz /* NOTREACHED */ 733151539Ssuz} 734151539Ssuz 73553541Sshinstatic struct nd_defrouter * 736171259Sdelphijdefrtrlist_update(struct nd_defrouter *new) 73753541Sshin{ 738183550Szec INIT_VNET_INET6(curvnet); 73953541Sshin struct nd_defrouter *dr, *n; 74053541Sshin int s = splnet(); 74153541Sshin 74253541Sshin if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 74353541Sshin /* entry exists */ 74453541Sshin if (new->rtlifetime == 0) { 74553541Sshin defrtrlist_del(dr); 74653541Sshin dr = NULL; 74753541Sshin } else { 748151539Ssuz int oldpref = rtpref(dr); 749151539Ssuz 75053541Sshin /* override */ 75153541Sshin dr->flags = new->flags; /* xxx flag check */ 75253541Sshin dr->rtlifetime = new->rtlifetime; 75353541Sshin dr->expire = new->expire; 754151539Ssuz 755151539Ssuz /* 756151539Ssuz * If the preference does not change, there's no need 757151539Ssuz * to sort the entries. 758151539Ssuz */ 759151539Ssuz if (rtpref(new) == oldpref) { 760151539Ssuz splx(s); 761151539Ssuz return (dr); 762151539Ssuz } 763151539Ssuz 764151539Ssuz /* 765151539Ssuz * preferred router may be changed, so relocate 766151539Ssuz * this router. 767151539Ssuz * XXX: calling TAILQ_REMOVE directly is a bad manner. 768151539Ssuz * However, since defrtrlist_del() has many side 769151539Ssuz * effects, we intentionally do so here. 770151539Ssuz * defrouter_select() below will handle routing 771151539Ssuz * changes later. 772151539Ssuz */ 773181803Sbz TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 774151539Ssuz n = dr; 775151539Ssuz goto insert; 77653541Sshin } 77753541Sshin splx(s); 778120856Sume return (dr); 77953541Sshin } 78053541Sshin 78153541Sshin /* entry does not exist */ 78253541Sshin if (new->rtlifetime == 0) { 78353541Sshin splx(s); 784120856Sume return (NULL); 78553541Sshin } 78653541Sshin 78753541Sshin n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 78853541Sshin if (n == NULL) { 78953541Sshin splx(s); 790120856Sume return (NULL); 79153541Sshin } 79253541Sshin bzero(n, sizeof(*n)); 79353541Sshin *n = *new; 79462587Sitojun 795151539Ssuzinsert: 79662587Sitojun /* 797151539Ssuz * Insert the new router in the Default Router List; 798151539Ssuz * The Default Router List should be in the descending order 799151539Ssuz * of router-preferece. Routers with the same preference are 800151539Ssuz * sorted in the arriving time order. 80162587Sitojun */ 802151539Ssuz 803151539Ssuz /* insert at the end of the group */ 804181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 805151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 806151539Ssuz if (rtpref(n) > rtpref(dr)) 807151539Ssuz break; 808151539Ssuz } 809151539Ssuz if (dr) 810151539Ssuz TAILQ_INSERT_BEFORE(dr, n, dr_entry); 811151539Ssuz else 812181803Sbz TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry); 813151539Ssuz 814151539Ssuz defrouter_select(); 815151539Ssuz 81653541Sshin splx(s); 817120941Sume 818120856Sume return (n); 81953541Sshin} 82053541Sshin 82153541Sshinstatic struct nd_pfxrouter * 822171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) 82353541Sshin{ 82453541Sshin struct nd_pfxrouter *search; 825120941Sume 82662587Sitojun for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { 82753541Sshin if (search->router == dr) 82853541Sshin break; 82953541Sshin } 83053541Sshin 831120856Sume return (search); 83253541Sshin} 83353541Sshin 83453541Sshinstatic void 835171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) 83653541Sshin{ 83753541Sshin struct nd_pfxrouter *new; 83853541Sshin 83953541Sshin new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 84053541Sshin if (new == NULL) 84153541Sshin return; 84253541Sshin bzero(new, sizeof(*new)); 84353541Sshin new->router = dr; 84453541Sshin 84553541Sshin LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 84653541Sshin 84753541Sshin pfxlist_onlink_check(); 84853541Sshin} 84953541Sshin 85053541Sshinstatic void 851171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr) 85253541Sshin{ 85353541Sshin LIST_REMOVE(pfr, pfr_entry); 85453541Sshin free(pfr, M_IP6NDP); 85553541Sshin} 85653541Sshin 85778064Sumestruct nd_prefix * 858171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key) 85953541Sshin{ 860183550Szec INIT_VNET_INET6(curvnet); 86153541Sshin struct nd_prefix *search; 86253541Sshin 863181887Sjulian for (search = V_nd_prefix.lh_first; 864181888Sjulian search; search = search->ndpr_next) { 865151539Ssuz if (key->ndpr_ifp == search->ndpr_ifp && 866151539Ssuz key->ndpr_plen == search->ndpr_plen && 867151539Ssuz in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr, 868151539Ssuz &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) { 86953541Sshin break; 87053541Sshin } 87153541Sshin } 87253541Sshin 873120856Sume return (search); 87453541Sshin} 87553541Sshin 87678064Sumeint 877171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr, 878171259Sdelphij struct nd_prefix **newp) 87953541Sshin{ 880183550Szec INIT_VNET_INET6(curvnet); 88178064Sume struct nd_prefix *new = NULL; 882151539Ssuz int error = 0; 88353541Sshin int i, s; 884165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 88553541Sshin 88653541Sshin new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 88753541Sshin if (new == NULL) 888120941Sume return(ENOMEM); 88953541Sshin bzero(new, sizeof(*new)); 890151539Ssuz new->ndpr_ifp = pr->ndpr_ifp; 891151539Ssuz new->ndpr_prefix = pr->ndpr_prefix; 892151539Ssuz new->ndpr_plen = pr->ndpr_plen; 893151539Ssuz new->ndpr_vltime = pr->ndpr_vltime; 894151539Ssuz new->ndpr_pltime = pr->ndpr_pltime; 895151539Ssuz new->ndpr_flags = pr->ndpr_flags; 896151539Ssuz if ((error = in6_init_prefix_ltimes(new)) != 0) { 897151539Ssuz free(new, M_IP6NDP); 898151539Ssuz return(error); 899151539Ssuz } 900151539Ssuz new->ndpr_lastupdate = time_second; 90178064Sume if (newp != NULL) 90278064Sume *newp = new; 90353541Sshin 904120941Sume /* initialization */ 90553541Sshin LIST_INIT(&new->ndpr_advrtrs); 90653541Sshin in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 90753541Sshin /* make prefix in the canonical form */ 90853541Sshin for (i = 0; i < 4; i++) 90953541Sshin new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 910120941Sume new->ndpr_mask.s6_addr32[i]; 91153541Sshin 91253541Sshin s = splnet(); 91353541Sshin /* link ndpr_entry to nd_prefix list */ 914181803Sbz LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry); 91553541Sshin splx(s); 91653541Sshin 91778064Sume /* ND_OPT_PI_FLAG_ONLINK processing */ 91878064Sume if (new->ndpr_raf_onlink) { 91978064Sume int e; 92078064Sume 92178064Sume if ((e = nd6_prefix_onlink(new)) != 0) { 92278064Sume nd6log((LOG_ERR, "nd6_prelist_add: failed to make " 92378064Sume "the prefix %s/%d on-link on %s (errno=%d)\n", 924165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 92578064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 92678064Sume /* proceed anyway. XXX: is it correct? */ 92778064Sume } 92878064Sume } 92978064Sume 930120941Sume if (dr) 93153541Sshin pfxrtr_add(new, dr); 93253541Sshin 93353541Sshin return 0; 93453541Sshin} 93553541Sshin 93653541Sshinvoid 937171259Sdelphijprelist_remove(struct nd_prefix *pr) 93853541Sshin{ 939183550Szec INIT_VNET_INET6(curvnet); 94053541Sshin struct nd_pfxrouter *pfr, *next; 94178064Sume int e, s; 942165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 94353541Sshin 94478064Sume /* make sure to invalidate the prefix until it is really freed. */ 94578064Sume pr->ndpr_vltime = 0; 94678064Sume pr->ndpr_pltime = 0; 947151539Ssuz 94878064Sume /* 94978064Sume * Though these flags are now meaningless, we'd rather keep the value 950151479Ssuz * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users 951151479Ssuz * when executing "ndp -p". 95278064Sume */ 953151479Ssuz 95478064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && 95578064Sume (e = nd6_prefix_offlink(pr)) != 0) { 95678064Sume nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " 95778064Sume "on %s, errno=%d\n", 958165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 95978064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 96078064Sume /* what should we do? */ 96178064Sume } 96278064Sume 96378064Sume if (pr->ndpr_refcnt > 0) 96478064Sume return; /* notice here? */ 96578064Sume 96653541Sshin s = splnet(); 96778064Sume 96853541Sshin /* unlink ndpr_entry from nd_prefix list */ 96953541Sshin LIST_REMOVE(pr, ndpr_entry); 97053541Sshin 97153541Sshin /* free list of routers that adversed the prefix */ 97262587Sitojun for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { 97362587Sitojun next = pfr->pfr_next; 97453541Sshin 97553541Sshin free(pfr, M_IP6NDP); 97653541Sshin } 97778064Sume splx(s); 97878064Sume 97953541Sshin free(pr, M_IP6NDP); 98053541Sshin 98153541Sshin pfxlist_onlink_check(); 98253541Sshin} 98353541Sshin 984171259Sdelphij/* 985171259Sdelphij * dr - may be NULL 986171259Sdelphij */ 987171259Sdelphij 988151539Ssuzstatic int 989171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, 990171259Sdelphij struct mbuf *m, int mcast) 99153541Sshin{ 992183550Szec INIT_VNET_INET6(curvnet); 99378064Sume struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 99478064Sume struct ifaddr *ifa; 99578064Sume struct ifnet *ifp = new->ndpr_ifp; 99653541Sshin struct nd_prefix *pr; 99753541Sshin int s = splnet(); 99853541Sshin int error = 0; 99978064Sume int newprefix = 0; 100053541Sshin int auth; 100178064Sume struct in6_addrlifetime lt6_tmp; 1002165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 100353541Sshin 100453541Sshin auth = 0; 100553541Sshin if (m) { 100653541Sshin /* 100753541Sshin * Authenticity for NA consists authentication for 100853541Sshin * both IP header and IP datagrams, doesn't it ? 100953541Sshin */ 101053541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 1011120941Sume auth = ((m->m_flags & M_AUTHIPHDR) && 1012120941Sume (m->m_flags & M_AUTHIPDGM)); 101353541Sshin#endif 101453541Sshin } 101553541Sshin 101678064Sume if ((pr = nd6_prefix_lookup(new)) != NULL) { 101778064Sume /* 101878064Sume * nd6_prefix_lookup() ensures that pr and new have the same 101978064Sume * prefix on a same interface. 102078064Sume */ 102153541Sshin 102253541Sshin /* 102378064Sume * Update prefix information. Note that the on-link (L) bit 102478064Sume * and the autonomous (A) bit should NOT be changed from 1 102578064Sume * to 0. 102653541Sshin */ 102778064Sume if (new->ndpr_raf_onlink == 1) 102878064Sume pr->ndpr_raf_onlink = 1; 102978064Sume if (new->ndpr_raf_auto == 1) 103078064Sume pr->ndpr_raf_auto = 1; 103178064Sume if (new->ndpr_raf_onlink) { 103278064Sume pr->ndpr_vltime = new->ndpr_vltime; 103378064Sume pr->ndpr_pltime = new->ndpr_pltime; 1034151539Ssuz (void)in6_init_prefix_ltimes(pr); /* XXX error case? */ 1035151539Ssuz pr->ndpr_lastupdate = time_second; 103678064Sume } 103753541Sshin 103878064Sume if (new->ndpr_raf_onlink && 103978064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 104078064Sume int e; 104153541Sshin 104278064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 104378064Sume nd6log((LOG_ERR, 104478064Sume "prelist_update: failed to make " 104578064Sume "the prefix %s/%d on-link on %s " 104678064Sume "(errno=%d)\n", 1047165118Sbz ip6_sprintf(ip6buf, 1048165118Sbz &pr->ndpr_prefix.sin6_addr), 104978064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 105078064Sume /* proceed anyway. XXX: is it correct? */ 105153541Sshin } 105278064Sume } 105353541Sshin 105478064Sume if (dr && pfxrtr_lookup(pr, dr) == NULL) 105578064Sume pfxrtr_add(pr, dr); 105678064Sume } else { 105778064Sume struct nd_prefix *newpr = NULL; 105853541Sshin 105978064Sume newprefix = 1; 106053541Sshin 106178064Sume if (new->ndpr_vltime == 0) 106278064Sume goto end; 106378064Sume if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 106478064Sume goto end; 106553541Sshin 106678064Sume error = nd6_prelist_add(new, dr, &newpr); 106778064Sume if (error != 0 || newpr == NULL) { 106878064Sume nd6log((LOG_NOTICE, "prelist_update: " 106978064Sume "nd6_prelist_add failed for %s/%d on %s " 107078064Sume "errno=%d, returnpr=%p\n", 1071165118Sbz ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr), 1072120941Sume new->ndpr_plen, if_name(new->ndpr_ifp), 1073120941Sume error, newpr)); 107478064Sume goto end; /* we should just give up in this case. */ 107578064Sume } 107653541Sshin 107778064Sume /* 107878064Sume * XXX: from the ND point of view, we can ignore a prefix 107978064Sume * with the on-link bit being zero. However, we need a 108078064Sume * prefix structure for references from autoconfigured 1081120941Sume * addresses. Thus, we explicitly make sure that the prefix 108278064Sume * itself expires now. 108378064Sume */ 108478064Sume if (newpr->ndpr_raf_onlink == 0) { 108578064Sume newpr->ndpr_vltime = 0; 108678064Sume newpr->ndpr_pltime = 0; 108778064Sume in6_init_prefix_ltimes(newpr); 108853541Sshin } 108953541Sshin 109078064Sume pr = newpr; 109178064Sume } 109253541Sshin 109378064Sume /* 109478064Sume * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 109578064Sume * Note that pr must be non NULL at this point. 109678064Sume */ 109762587Sitojun 109878064Sume /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 109978064Sume if (!new->ndpr_raf_auto) 1100151539Ssuz goto end; 110162587Sitojun 110278064Sume /* 110378064Sume * 5.5.3 (b). the link-local prefix should have been ignored in 110478064Sume * nd6_ra_input. 110578064Sume */ 110662587Sitojun 1107151539Ssuz /* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */ 1108151539Ssuz if (new->ndpr_pltime > new->ndpr_vltime) { 1109151539Ssuz error = EINVAL; /* XXX: won't be used */ 1110151539Ssuz goto end; 1111151539Ssuz } 111262587Sitojun 1113171260Sdelphij /* 1114151539Ssuz * 5.5.3 (d). If the prefix advertised is not equal to the prefix of 1115151539Ssuz * an address configured by stateless autoconfiguration already in the 1116151539Ssuz * list of addresses associated with the interface, and the Valid 1117151539Ssuz * Lifetime is not 0, form an address. We first check if we have 1118151539Ssuz * a matching prefix. 1119151539Ssuz * Note: we apply a clarification in rfc2462bis-02 here. We only 1120151539Ssuz * consider autoconfigured addresses while RFC2462 simply said 1121151539Ssuz * "address". 112278064Sume */ 1123120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 112478064Sume struct in6_ifaddr *ifa6; 1125151539Ssuz u_int32_t remaininglifetime; 112653541Sshin 112778064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 112878064Sume continue; 112953541Sshin 113078064Sume ifa6 = (struct in6_ifaddr *)ifa; 113153541Sshin 113253541Sshin /* 1133151539Ssuz * We only consider autoconfigured addresses as per rfc2462bis. 1134151539Ssuz */ 1135151539Ssuz if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF)) 1136151539Ssuz continue; 1137151539Ssuz 1138151539Ssuz /* 113978064Sume * Spec is not clear here, but I believe we should concentrate 114078064Sume * on unicast (i.e. not anycast) addresses. 114178064Sume * XXX: other ia6_flags? detached or duplicated? 114253541Sshin */ 114378064Sume if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 114478064Sume continue; 1145120941Sume 1146151539Ssuz /* 1147151539Ssuz * Ignore the address if it is not associated with a prefix 1148151539Ssuz * or is associated with a prefix that is different from this 1149151539Ssuz * one. (pr is never NULL here) 1150151539Ssuz */ 1151151539Ssuz if (ifa6->ia6_ndpr != pr) 115278064Sume continue; 115353541Sshin 115478064Sume if (ia6_match == NULL) /* remember the first one */ 115578064Sume ia6_match = ifa6; 115678064Sume 115778064Sume /* 115878064Sume * An already autoconfigured address matched. Now that we 115978064Sume * are sure there is at least one matched address, we can 116078064Sume * proceed to 5.5.3. (e): update the lifetimes according to the 116178064Sume * "two hours" rule and the privacy extension. 1162151539Ssuz * We apply some clarifications in rfc2462bis: 1163151539Ssuz * - use remaininglifetime instead of storedlifetime as a 1164151539Ssuz * variable name 1165151539Ssuz * - remove the dead code in the "two-hour" rule 116678064Sume */ 116778064Sume#define TWOHOUR (120*60) 116878064Sume lt6_tmp = ifa6->ia6_lifetime; 116978064Sume 1170112678Sume if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 1171151539Ssuz remaininglifetime = ND6_INFINITE_LIFETIME; 1172151539Ssuz else if (time_second - ifa6->ia6_updatetime > 1173151539Ssuz lt6_tmp.ia6t_vltime) { 1174151539Ssuz /* 1175151539Ssuz * The case of "invalid" address. We should usually 1176151539Ssuz * not see this case. 1177151539Ssuz */ 1178151539Ssuz remaininglifetime = 0; 1179151539Ssuz } else 1180151539Ssuz remaininglifetime = lt6_tmp.ia6t_vltime - 1181151539Ssuz (time_second - ifa6->ia6_updatetime); 118278064Sume 1183112678Sume /* when not updating, keep the current stored lifetime. */ 1184151539Ssuz lt6_tmp.ia6t_vltime = remaininglifetime; 1185112678Sume 118678064Sume if (TWOHOUR < new->ndpr_vltime || 1187151539Ssuz remaininglifetime < new->ndpr_vltime) { 118878064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 1189151539Ssuz } else if (remaininglifetime <= TWOHOUR) { 119078064Sume if (auth) { 119178064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 119278064Sume } 119378064Sume } else { 119478064Sume /* 119578064Sume * new->ndpr_vltime <= TWOHOUR && 1196151539Ssuz * TWOHOUR < remaininglifetime 119778064Sume */ 119878064Sume lt6_tmp.ia6t_vltime = TWOHOUR; 119953541Sshin } 120053541Sshin 120178064Sume /* The 2 hour rule is not imposed for preferred lifetime. */ 120278064Sume lt6_tmp.ia6t_pltime = new->ndpr_pltime; 120353541Sshin 120478064Sume in6_init_address_ltimes(pr, <6_tmp); 120553541Sshin 1206171260Sdelphij /* 1207151539Ssuz * We need to treat lifetimes for temporary addresses 1208151539Ssuz * differently, according to 1209151539Ssuz * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1); 1210151539Ssuz * we only update the lifetimes when they are in the maximum 1211151539Ssuz * intervals. 1212171260Sdelphij */ 1213171260Sdelphij if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 1214151539Ssuz u_int32_t maxvltime, maxpltime; 1215151539Ssuz 1216181803Sbz if (V_ip6_temp_valid_lifetime > 1217151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1218181803Sbz V_ip6_desync_factor)) { 1219181803Sbz maxvltime = V_ip6_temp_valid_lifetime - 1220151539Ssuz (time_second - ifa6->ia6_createtime) - 1221181803Sbz V_ip6_desync_factor; 1222151539Ssuz } else 1223151539Ssuz maxvltime = 0; 1224181803Sbz if (V_ip6_temp_preferred_lifetime > 1225151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1226181803Sbz V_ip6_desync_factor)) { 1227181803Sbz maxpltime = V_ip6_temp_preferred_lifetime - 1228151539Ssuz (time_second - ifa6->ia6_createtime) - 1229181803Sbz V_ip6_desync_factor; 1230151539Ssuz } else 1231151539Ssuz maxpltime = 0; 1232151539Ssuz 1233151539Ssuz if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME || 1234151539Ssuz lt6_tmp.ia6t_vltime > maxvltime) { 1235151539Ssuz lt6_tmp.ia6t_vltime = maxvltime; 123678064Sume } 1237151539Ssuz if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || 1238151539Ssuz lt6_tmp.ia6t_pltime > maxpltime) { 1239151539Ssuz lt6_tmp.ia6t_pltime = maxpltime; 124078064Sume } 124178064Sume } 124278064Sume ifa6->ia6_lifetime = lt6_tmp; 1243151539Ssuz ifa6->ia6_updatetime = time_second; 124453541Sshin } 124578064Sume if (ia6_match == NULL && new->ndpr_vltime) { 1246151539Ssuz int ifidlen; 1247151539Ssuz 124878064Sume /* 1249151539Ssuz * 5.5.3 (d) (continued) 125078064Sume * No address matched and the valid lifetime is non-zero. 125178064Sume * Create a new address. 125278064Sume */ 1253151539Ssuz 1254151539Ssuz /* 1255151539Ssuz * Prefix Length check: 1256151539Ssuz * If the sum of the prefix length and interface identifier 1257151539Ssuz * length does not equal 128 bits, the Prefix Information 1258151539Ssuz * option MUST be ignored. The length of the interface 1259151539Ssuz * identifier is defined in a separate link-type specific 1260151539Ssuz * document. 1261151539Ssuz */ 1262151539Ssuz ifidlen = in6_if2idlen(ifp); 1263151539Ssuz if (ifidlen < 0) { 1264151539Ssuz /* this should not happen, so we always log it. */ 1265151539Ssuz log(LOG_ERR, "prelist_update: IFID undefined (%s)\n", 1266151539Ssuz if_name(ifp)); 1267151539Ssuz goto end; 1268151539Ssuz } 1269151539Ssuz if (ifidlen + pr->ndpr_plen != 128) { 1270151539Ssuz nd6log((LOG_INFO, 1271151539Ssuz "prelist_update: invalid prefixlen " 1272151539Ssuz "%d for %s, ignored\n", 1273151539Ssuz pr->ndpr_plen, if_name(ifp))); 1274151539Ssuz goto end; 1275151539Ssuz } 1276151539Ssuz 1277151539Ssuz if ((ia6 = in6_ifadd(new, mcast)) != NULL) { 127878064Sume /* 127978064Sume * note that we should use pr (not new) for reference. 128078064Sume */ 128178064Sume pr->ndpr_refcnt++; 128278064Sume ia6->ia6_ndpr = pr; 128353541Sshin 128478064Sume /* 128578064Sume * RFC 3041 3.3 (2). 128678064Sume * When a new public address is created as described 128778064Sume * in RFC2462, also create a new temporary address. 128878064Sume * 128978064Sume * RFC 3041 3.5. 129078064Sume * When an interface connects to a new link, a new 129178064Sume * randomized interface identifier should be generated 129278064Sume * immediately together with a new set of temporary 129378064Sume * addresses. Thus, we specifiy 1 as the 2nd arg of 129478064Sume * in6_tmpifadd(). 129578064Sume */ 1296181803Sbz if (V_ip6_use_tempaddr) { 129778064Sume int e; 1298151539Ssuz if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) { 129978064Sume nd6log((LOG_NOTICE, "prelist_update: " 130078064Sume "failed to create a temporary " 130178064Sume "address, errno=%d\n", 130278064Sume e)); 130378064Sume } 130478064Sume } 130578064Sume 130678064Sume /* 130778064Sume * A newly added address might affect the status 130878064Sume * of other addresses, so we check and update it. 130978064Sume * XXX: what if address duplication happens? 131078064Sume */ 131178064Sume pfxlist_onlink_check(); 131278064Sume } else { 131378064Sume /* just set an error. do not bark here. */ 131478064Sume error = EADDRNOTAVAIL; /* XXX: might be unused. */ 131578064Sume } 131678064Sume } 131778064Sume 131853541Sshin end: 131953541Sshin splx(s); 132053541Sshin return error; 132153541Sshin} 132253541Sshin 132353541Sshin/* 132462587Sitojun * A supplement function used in the on-link detection below; 132562587Sitojun * detect if a given prefix has a (probably) reachable advertising router. 132662587Sitojun * XXX: lengthy function name... 132762587Sitojun */ 132878064Sumestatic struct nd_pfxrouter * 1329171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr) 133062587Sitojun{ 133162587Sitojun struct nd_pfxrouter *pfxrtr; 1332186119Sqingli struct llentry *ln; 1333186162Skmacy int canreach; 133462587Sitojun 1335186198Skmacy for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr != NULL; 133662587Sitojun pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { 1337186119Sqingli IF_AFDATA_LOCK(pfxrtr->router->ifp); 1338186162Skmacy ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp); 1339186162Skmacy IF_AFDATA_UNLOCK(pfxrtr->router->ifp); 1340186198Skmacy if (ln == NULL) 1341186198Skmacy continue; 1342186198Skmacy canreach = ND6_IS_LLINFO_PROBREACH(ln); 1343186198Skmacy LLE_RUNLOCK(ln); 1344186162Skmacy if (canreach) 1345186162Skmacy break; 134662587Sitojun } 1347120856Sume return (pfxrtr); 134862587Sitojun} 134962587Sitojun 135062587Sitojun/* 135153541Sshin * Check if each prefix in the prefix list has at least one available router 135278064Sume * that advertised the prefix (a router is "available" if its neighbor cache 135378064Sume * entry is reachable or probably reachable). 135462587Sitojun * If the check fails, the prefix may be off-link, because, for example, 135553541Sshin * we have moved from the network but the lifetime of the prefix has not 135678064Sume * expired yet. So we should not use the prefix if there is another prefix 135778064Sume * that has an available router. 135878064Sume * But, if there is no prefix that has an available router, we still regards 135978064Sume * all the prefixes as on-link. This is because we can't tell if all the 136053541Sshin * routers are simply dead or if we really moved from the network and there 136153541Sshin * is no router around us. 136253541Sshin */ 136362587Sitojunvoid 136453541Sshinpfxlist_onlink_check() 136553541Sshin{ 1366183550Szec INIT_VNET_INET6(curvnet); 136753541Sshin struct nd_prefix *pr; 136878064Sume struct in6_ifaddr *ifa; 1369151539Ssuz struct nd_defrouter *dr; 1370151539Ssuz struct nd_pfxrouter *pfxrtr = NULL; 137153541Sshin 137262587Sitojun /* 137362587Sitojun * Check if there is a prefix that has a reachable advertising 137462587Sitojun * router. 137562587Sitojun */ 1376181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 137778064Sume if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 137853541Sshin break; 137962587Sitojun } 138053541Sshin 1381151539Ssuz /* 1382151539Ssuz * If we have no such prefix, check whether we still have a router 1383151539Ssuz * that does not advertise any prefixes. 1384151539Ssuz */ 1385151465Ssuz if (pr == NULL) { 1386181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 1387151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 1388151539Ssuz struct nd_prefix *pr0; 1389151539Ssuz 1390181803Sbz for (pr0 = V_nd_prefix.lh_first; pr0; 1391151539Ssuz pr0 = pr0->ndpr_next) { 1392151539Ssuz if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) 1393151539Ssuz break; 1394151539Ssuz } 1395151539Ssuz if (pfxrtr != NULL) 1396151539Ssuz break; 1397151539Ssuz } 1398151539Ssuz } 1399181803Sbz if (pr != NULL || (TAILQ_FIRST(&V_nd_defrouter) && pfxrtr == NULL)) { 1400171260Sdelphij /* 1401151539Ssuz * There is at least one prefix that has a reachable router, 1402151539Ssuz * or at least a router which probably does not advertise 1403151539Ssuz * any prefixes. The latter would be the case when we move 1404151539Ssuz * to a new link where we have a router that does not provide 1405151539Ssuz * prefixes and we configure an address by hand. 1406171260Sdelphij * Detach prefixes which have no reachable advertising 1407171260Sdelphij * router, and attach other prefixes. 1408171260Sdelphij */ 1409181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 141078064Sume /* XXX: a link-local prefix should never be detached */ 141178064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 141278064Sume continue; 141378064Sume 141478064Sume /* 141578064Sume * we aren't interested in prefixes without the L bit 141678064Sume * set. 141778064Sume */ 141878064Sume if (pr->ndpr_raf_onlink == 0) 141978064Sume continue; 142078064Sume 142178064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 142278064Sume find_pfxlist_reachable_router(pr) == NULL) 142378064Sume pr->ndpr_stateflags |= NDPRF_DETACHED; 142478064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 142578064Sume find_pfxlist_reachable_router(pr) != 0) 142678064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 142753541Sshin } 142878064Sume } else { 142978064Sume /* there is no prefix that has a reachable router */ 1430181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 143178064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 143278064Sume continue; 143378064Sume 143478064Sume if (pr->ndpr_raf_onlink == 0) 143578064Sume continue; 143678064Sume 143778064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 143878064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 143953541Sshin } 144062587Sitojun } 144178064Sume 144278064Sume /* 144378064Sume * Remove each interface route associated with a (just) detached 144478064Sume * prefix, and reinstall the interface route for a (just) attached 144578064Sume * prefix. Note that all attempt of reinstallation does not 144678064Sume * necessarily success, when a same prefix is shared among multiple 144778064Sume * interfaces. Such cases will be handled in nd6_prefix_onlink, 144878064Sume * so we don't have to care about them. 144978064Sume */ 1450181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 145178064Sume int e; 1452165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 145378064Sume 145478064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 145578064Sume continue; 145678064Sume 145778064Sume if (pr->ndpr_raf_onlink == 0) 145878064Sume continue; 145978064Sume 146078064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 146178064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 146278064Sume if ((e = nd6_prefix_offlink(pr)) != 0) { 146378064Sume nd6log((LOG_ERR, 146478064Sume "pfxlist_onlink_check: failed to " 1465151479Ssuz "make %s/%d offlink, errno=%d\n", 1466165118Sbz ip6_sprintf(ip6buf, 1467165118Sbz &pr->ndpr_prefix.sin6_addr), 1468165118Sbz pr->ndpr_plen, e)); 146978064Sume } 147078064Sume } 147178064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 147278064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 147378064Sume pr->ndpr_raf_onlink) { 147478064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 147578064Sume nd6log((LOG_ERR, 147678064Sume "pfxlist_onlink_check: failed to " 1477151479Ssuz "make %s/%d onlink, errno=%d\n", 1478165118Sbz ip6_sprintf(ip6buf, 1479165118Sbz &pr->ndpr_prefix.sin6_addr), 1480165118Sbz pr->ndpr_plen, e)); 148178064Sume } 148278064Sume } 148378064Sume } 148478064Sume 148578064Sume /* 148678064Sume * Changes on the prefix status might affect address status as well. 148778064Sume * Make sure that all addresses derived from an attached prefix are 148878064Sume * attached, and that all addresses derived from a detached prefix are 148978064Sume * detached. Note, however, that a manually configured address should 149078064Sume * always be attached. 149178064Sume * The precise detection logic is same as the one for prefixes. 149278064Sume */ 1493181803Sbz for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) { 1494120941Sume if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) 149578064Sume continue; 149678064Sume 149778064Sume if (ifa->ia6_ndpr == NULL) { 149878064Sume /* 149978064Sume * This can happen when we first configure the address 150078064Sume * (i.e. the address exists, but the prefix does not). 150178064Sume * XXX: complicated relationships... 150278064Sume */ 150378064Sume continue; 150478064Sume } 150578064Sume 150678064Sume if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 150778064Sume break; 150878064Sume } 150978064Sume if (ifa) { 1510181803Sbz for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) { 151178064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 151278064Sume continue; 151378064Sume 151478064Sume if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 151578064Sume continue; 151678064Sume 1517151539Ssuz if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) { 1518151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1519151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1520151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1521151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1522151539Ssuz } 1523151539Ssuz } else { 152478064Sume ifa->ia6_flags |= IN6_IFF_DETACHED; 1525151539Ssuz } 152678064Sume } 152778064Sume } 152862587Sitojun else { 1529181803Sbz for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) { 153078064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 153178064Sume continue; 153278064Sume 1533151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1534151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1535151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1536151539Ssuz /* Do we need a delay in this case? */ 1537151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1538151539Ssuz } 153978064Sume } 154053541Sshin } 154153541Sshin} 154253541Sshin 154378064Sumeint 1544171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr) 154553541Sshin{ 1546183550Szec INIT_VNET_INET6(curvnet); 154778064Sume struct ifaddr *ifa; 154878064Sume struct ifnet *ifp = pr->ndpr_ifp; 154978064Sume struct sockaddr_in6 mask6; 155078064Sume struct nd_prefix *opr; 155178064Sume u_long rtflags; 155278064Sume int error = 0; 1553186119Sqingli struct radix_node_head *rnh; 155478064Sume struct rtentry *rt = NULL; 1555165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 1556186119Sqingli struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 155753541Sshin 155878064Sume /* sanity check */ 155978064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 156078064Sume nd6log((LOG_ERR, 156178064Sume "nd6_prefix_onlink: %s/%d is already on-link\n", 1562165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1563165118Sbz pr->ndpr_plen)); 1564151465Ssuz return (EEXIST); 156578064Sume } 156678064Sume 156753541Sshin /* 156878064Sume * Add the interface route associated with the prefix. Before 156978064Sume * installing the route, check if there's the same prefix on another 157078064Sume * interface, and the prefix has already installed the interface route. 157178064Sume * Although such a configuration is expected to be rare, we explicitly 157278064Sume * allow it. 157353541Sshin */ 1574181803Sbz for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 157578064Sume if (opr == pr) 157678064Sume continue; 157778064Sume 157878064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 157978064Sume continue; 158078064Sume 158178064Sume if (opr->ndpr_plen == pr->ndpr_plen && 158278064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1583120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) 1584120856Sume return (0); 158578064Sume } 158678064Sume 158778064Sume /* 1588120941Sume * We prefer link-local addresses as the associated interface address. 158978064Sume */ 159078064Sume /* search for a link-local addr */ 159178064Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 1592120941Sume IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); 159378064Sume if (ifa == NULL) { 159478064Sume /* XXX: freebsd does not have ifa_ifwithaf */ 1595120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 159678064Sume if (ifa->ifa_addr->sa_family == AF_INET6) 159778064Sume break; 159878064Sume } 159978064Sume /* should we care about ia6_flags? */ 160078064Sume } 160178064Sume if (ifa == NULL) { 160278064Sume /* 160378064Sume * This can still happen, when, for example, we receive an RA 160478064Sume * containing a prefix with the L bit set and the A bit clear, 160578064Sume * after removing all IPv6 addresses on the receiving 160678064Sume * interface. This should, of course, be rare though. 160778064Sume */ 160878064Sume nd6log((LOG_NOTICE, 160978064Sume "nd6_prefix_onlink: failed to find any ifaddr" 161078064Sume " to add route for a prefix(%s/%d) on %s\n", 1611165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 161278064Sume pr->ndpr_plen, if_name(ifp))); 1613120856Sume return (0); 161478064Sume } 161578064Sume 161678064Sume /* 161778064Sume * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 161878064Sume * ifa->ifa_rtrequest = nd6_rtrequest; 161978064Sume */ 162078064Sume bzero(&mask6, sizeof(mask6)); 162178064Sume mask6.sin6_len = sizeof(mask6); 162278064Sume mask6.sin6_addr = pr->ndpr_mask; 1623186119Sqingli rtflags = ifa->ifa_flags | RTF_UP; 162478064Sume error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, 1625120941Sume ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt); 162678064Sume if (error == 0) { 1627186119Sqingli if (rt != NULL) /* this should be non NULL, though */ { 1628186119Sqingli rnh = V_rt_tables[rt->rt_fibnum][AF_INET6]; 1629186119Sqingli RADIX_NODE_HEAD_LOCK(rnh); 1630186119Sqingli RT_LOCK(rt); 1631186119Sqingli if (!rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl)) { 1632186119Sqingli ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = 1633186119Sqingli rt->rt_ifp->if_type; 1634186119Sqingli ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = 1635186119Sqingli rt->rt_ifp->if_index; 1636186119Sqingli } 1637186119Sqingli RADIX_NODE_HEAD_UNLOCK(rnh); 163878064Sume nd6_rtmsg(RTM_ADD, rt); 1639186119Sqingli RT_UNLOCK(rt); 1640186119Sqingli } 164178064Sume pr->ndpr_stateflags |= NDPRF_ONLINK; 1642120941Sume } else { 1643165118Sbz char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN]; 164478064Sume nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" 164578064Sume " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " 164678064Sume "errno = %d\n", 1647165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 164878064Sume pr->ndpr_plen, if_name(ifp), 1649165118Sbz ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), 1650165118Sbz ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error)); 165178064Sume } 165278064Sume 1653120727Ssam if (rt != NULL) { 1654120727Ssam RT_LOCK(rt); 1655122334Ssam RT_REMREF(rt); 1656120727Ssam RT_UNLOCK(rt); 1657120727Ssam } 165878064Sume 1659120856Sume return (error); 166078064Sume} 166178064Sume 166278064Sumeint 1663171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr) 166478064Sume{ 1665183550Szec INIT_VNET_INET6(curvnet); 166678064Sume int error = 0; 166778064Sume struct ifnet *ifp = pr->ndpr_ifp; 166878064Sume struct nd_prefix *opr; 166978064Sume struct sockaddr_in6 sa6, mask6; 167078064Sume struct rtentry *rt = NULL; 1671165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 167278064Sume 167378064Sume /* sanity check */ 167478064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 167578064Sume nd6log((LOG_ERR, 167678064Sume "nd6_prefix_offlink: %s/%d is already off-link\n", 1677165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1678165118Sbz pr->ndpr_plen)); 1679120856Sume return (EEXIST); 168078064Sume } 168178064Sume 168253541Sshin bzero(&sa6, sizeof(sa6)); 168353541Sshin sa6.sin6_family = AF_INET6; 168453541Sshin sa6.sin6_len = sizeof(sa6); 168553541Sshin bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 1686120941Sume sizeof(struct in6_addr)); 168753541Sshin bzero(&mask6, sizeof(mask6)); 168853541Sshin mask6.sin6_family = AF_INET6; 168953541Sshin mask6.sin6_len = sizeof(sa6); 169053541Sshin bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 169178064Sume error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 1692120941Sume (struct sockaddr *)&mask6, 0, &rt); 169378064Sume if (error == 0) { 169478064Sume pr->ndpr_stateflags &= ~NDPRF_ONLINK; 169553541Sshin 169678064Sume /* report the route deletion to the routing socket. */ 169778064Sume if (rt != NULL) 169878064Sume nd6_rtmsg(RTM_DELETE, rt); 169953541Sshin 170078064Sume /* 170178064Sume * There might be the same prefix on another interface, 170278064Sume * the prefix which could not be on-link just because we have 170378064Sume * the interface route (see comments in nd6_prefix_onlink). 170478064Sume * If there's one, try to make the prefix on-link on the 170578064Sume * interface. 170678064Sume */ 1707181803Sbz for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 170878064Sume if (opr == pr) 170978064Sume continue; 171053541Sshin 171178064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 171278064Sume continue; 171353541Sshin 171478064Sume /* 171578064Sume * KAME specific: detached prefixes should not be 171678064Sume * on-link. 171778064Sume */ 171878064Sume if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 171978064Sume continue; 172078064Sume 172178064Sume if (opr->ndpr_plen == pr->ndpr_plen && 172278064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1723120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 172478064Sume int e; 172578064Sume 172678064Sume if ((e = nd6_prefix_onlink(opr)) != 0) { 172778064Sume nd6log((LOG_ERR, 172878064Sume "nd6_prefix_offlink: failed to " 172978064Sume "recover a prefix %s/%d from %s " 173078064Sume "to %s (errno = %d)\n", 1731165118Sbz ip6_sprintf(ip6buf, 1732165118Sbz &opr->ndpr_prefix.sin6_addr), 173378064Sume opr->ndpr_plen, if_name(ifp), 173478064Sume if_name(opr->ndpr_ifp), e)); 173578064Sume } 173678064Sume } 173778064Sume } 1738120941Sume } else { 173978064Sume /* XXX: can we still set the NDPRF_ONLINK flag? */ 174078064Sume nd6log((LOG_ERR, 174178064Sume "nd6_prefix_offlink: failed to delete route: " 174278064Sume "%s/%d on %s (errno = %d)\n", 1743165118Sbz ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen, 1744165118Sbz if_name(ifp), error)); 174578064Sume } 174653541Sshin 1747120941Sume if (rt != NULL) { 1748108269Sru RTFREE(rt); 1749120941Sume } 175053541Sshin 1751120856Sume return (error); 175253541Sshin} 175353541Sshin 175453541Sshinstatic struct in6_ifaddr * 1755171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast) 175653541Sshin{ 1757183550Szec INIT_VNET_INET6(curvnet); 175878064Sume struct ifnet *ifp = pr->ndpr_ifp; 175953541Sshin struct ifaddr *ifa; 176078064Sume struct in6_aliasreq ifra; 176178064Sume struct in6_ifaddr *ia, *ib; 176278064Sume int error, plen0; 176353541Sshin struct in6_addr mask; 176478064Sume int prefixlen = pr->ndpr_plen; 1765151539Ssuz int updateflags; 1766165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 176753541Sshin 1768121168Sume in6_prefixlen2mask(&mask, prefixlen); 176953541Sshin 177078064Sume /* 177178064Sume * find a link-local address (will be interface ID). 177278064Sume * Is it really mandatory? Theoretically, a global or a site-local 177378064Sume * address can be configured without a link-local address, if we 177478064Sume * have a unique interface identifier... 177578064Sume * 177678064Sume * it is not mandatory to have a link-local address, we can generate 177778064Sume * interface identifier on the fly. we do this because: 177878064Sume * (1) it should be the easiest way to find interface identifier. 177978064Sume * (2) RFC2462 5.4 suggesting the use of the same interface identifier 178078064Sume * for multiple addresses on a single interface, and possible shortcut 178178064Sume * of DAD. we omitted DAD for this reason in the past. 1782120941Sume * (3) a user can prevent autoconfiguration of global address 178378064Sume * by removing link-local address by hand (this is partly because we 1784108533Sschweikh * don't have other way to control the use of IPv6 on an interface. 178578064Sume * this has been our design choice - cf. NRL's "ifconfig auto"). 178678064Sume * (4) it is easier to manage when an interface has addresses 178778064Sume * with the same interface identifier, than to have multiple addresses 178878064Sume * with different interface identifiers. 178978064Sume */ 1790120941Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ 179153541Sshin if (ifa) 179253541Sshin ib = (struct in6_ifaddr *)ifa; 179353541Sshin else 179453541Sshin return NULL; 179553541Sshin 179653541Sshin /* prefixlen + ifidlen must be equal to 128 */ 179778064Sume plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 179878064Sume if (prefixlen != plen0) { 179978064Sume nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 180078064Sume "(prefix=%d ifid=%d)\n", 180178064Sume if_name(ifp), prefixlen, 128 - plen0)); 180253541Sshin return NULL; 180353541Sshin } 180453541Sshin 180553541Sshin /* make ifaddr */ 180653541Sshin 180778064Sume bzero(&ifra, sizeof(ifra)); 180878064Sume /* 180978064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 181078064Sume * for safety. 181178064Sume */ 181278064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 181378064Sume ifra.ifra_addr.sin6_family = AF_INET6; 181478064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 181578064Sume /* prefix */ 1816151539Ssuz ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr; 181778064Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 181878064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 181978064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 182078064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 182153541Sshin 182253541Sshin /* interface ID */ 1823120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] |= 1824151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); 1825120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] |= 1826151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); 1827120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1828151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); 1829120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1830151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); 1831120941Sume 183278064Sume /* new prefix mask. */ 183378064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 183478064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 183578064Sume bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 1836120941Sume sizeof(ifra.ifra_prefixmask.sin6_addr)); 183753541Sshin 1838151539Ssuz /* lifetimes. */ 183978064Sume ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 184078064Sume ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 184153541Sshin 184278064Sume /* XXX: scope zone ID? */ 184353541Sshin 184478064Sume ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 1845151539Ssuz 1846171260Sdelphij /* 1847151539Ssuz * Make sure that we do not have this address already. This should 1848151539Ssuz * usually not happen, but we can still see this case, e.g., if we 1849151539Ssuz * have manually configured the exact address to be configured. 185078064Sume */ 1851151539Ssuz if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { 1852151539Ssuz /* this should be rare enough to make an explicit log */ 1853151539Ssuz log(LOG_INFO, "in6_ifadd: %s is already configured\n", 1854165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr)); 1855151539Ssuz return (NULL); 1856151539Ssuz } 185753541Sshin 185853541Sshin /* 1859151539Ssuz * Allocate ifaddr structure, link into chain, etc. 1860151539Ssuz * If we are going to create a new address upon receiving a multicasted 1861151539Ssuz * RA, we need to impose a random delay before starting DAD. 1862151539Ssuz * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] 186353541Sshin */ 1864151539Ssuz updateflags = 0; 1865151539Ssuz if (mcast) 1866151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1867151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { 186878064Sume nd6log((LOG_ERR, 186978064Sume "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 1870165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr), 1871165118Sbz if_name(ifp), error)); 1872120856Sume return (NULL); /* ifaddr must not have been allocated. */ 187353541Sshin } 187453541Sshin 187578064Sume ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 187653541Sshin 1877120941Sume return (ia); /* this is always non-NULL */ 187853541Sshin} 187953541Sshin 1880171259Sdelphij/* 1881171259Sdelphij * ia0 - corresponding public address 1882171259Sdelphij */ 188353541Sshinint 1884171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) 188553541Sshin{ 1886183550Szec INIT_VNET_INET6(curvnet); 188778064Sume struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 1888151539Ssuz struct in6_ifaddr *newia, *ia; 188978064Sume struct in6_aliasreq ifra; 189078064Sume int i, error; 189178064Sume int trylimit = 3; /* XXX: adhoc value */ 1892151539Ssuz int updateflags; 189378064Sume u_int32_t randid[2]; 189478064Sume time_t vltime0, pltime0; 189553541Sshin 189678064Sume bzero(&ifra, sizeof(ifra)); 189778064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 189878064Sume ifra.ifra_addr = ia0->ia_addr; 189978064Sume /* copy prefix mask */ 190078064Sume ifra.ifra_prefixmask = ia0->ia_prefixmask; 190178064Sume /* clear the old IFID */ 190278064Sume for (i = 0; i < 4; i++) { 1903120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[i] &= 1904120941Sume ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 190578064Sume } 190653541Sshin 190778064Sume again: 1908151539Ssuz if (in6_get_tmpifid(ifp, (u_int8_t *)randid, 1909151539Ssuz (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { 1910151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good " 1911151539Ssuz "random IFID\n")); 1912151539Ssuz return (EINVAL); 1913151539Ssuz } 1914120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1915120941Sume (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 1916120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1917120941Sume (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 191853541Sshin 1919171260Sdelphij /* 1920151539Ssuz * in6_get_tmpifid() quite likely provided a unique interface ID. 1921151539Ssuz * However, we may still have a chance to see collision, because 1922151539Ssuz * there may be a time lag between generation of the ID and generation 1923151539Ssuz * of the address. So, we'll do one more sanity check. 192478064Sume */ 1925181803Sbz for (ia = V_in6_ifaddr; ia; ia = ia->ia_next) { 1926151539Ssuz if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 1927151539Ssuz &ifra.ifra_addr.sin6_addr)) { 1928171260Sdelphij if (trylimit-- == 0) { 1929151539Ssuz /* 1930151539Ssuz * Give up. Something strange should have 1931151539Ssuz * happened. 1932151539Ssuz */ 1933151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " 1934151539Ssuz "find a unique random IFID\n")); 1935151539Ssuz return (EEXIST); 1936151539Ssuz } 1937151539Ssuz forcegen = 1; 1938151539Ssuz goto again; 193978064Sume } 194053541Sshin } 194153541Sshin 194278064Sume /* 194378064Sume * The Valid Lifetime is the lower of the Valid Lifetime of the 194478064Sume * public address or TEMP_VALID_LIFETIME. 194578064Sume * The Preferred Lifetime is the lower of the Preferred Lifetime 194678064Sume * of the public address or TEMP_PREFERRED_LIFETIME - 194778064Sume * DESYNC_FACTOR. 194878064Sume */ 1949151539Ssuz if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 195078064Sume vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 1951151539Ssuz (ia0->ia6_lifetime.ia6t_vltime - 1952151539Ssuz (time_second - ia0->ia6_updatetime)); 1953181803Sbz if (vltime0 > V_ip6_temp_valid_lifetime) 1954181803Sbz vltime0 = V_ip6_temp_valid_lifetime; 195578064Sume } else 1956181803Sbz vltime0 = V_ip6_temp_valid_lifetime; 1957151539Ssuz if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 195878064Sume pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 1959151539Ssuz (ia0->ia6_lifetime.ia6t_pltime - 1960151539Ssuz (time_second - ia0->ia6_updatetime)); 1961181803Sbz if (pltime0 > V_ip6_temp_preferred_lifetime - V_ip6_desync_factor){ 1962181803Sbz pltime0 = V_ip6_temp_preferred_lifetime - 1963181803Sbz V_ip6_desync_factor; 196478064Sume } 196578064Sume } else 1966181803Sbz pltime0 = V_ip6_temp_preferred_lifetime - V_ip6_desync_factor; 196778064Sume ifra.ifra_lifetime.ia6t_vltime = vltime0; 196878064Sume ifra.ifra_lifetime.ia6t_pltime = pltime0; 196953541Sshin 197078064Sume /* 197178064Sume * A temporary address is created only if this calculated Preferred 197278064Sume * Lifetime is greater than REGEN_ADVANCE time units. 197378064Sume */ 1974181803Sbz if (ifra.ifra_lifetime.ia6t_pltime <= V_ip6_temp_regen_advance) 1975120856Sume return (0); 197653541Sshin 197778064Sume /* XXX: scope zone ID? */ 197878064Sume 197978064Sume ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 198078064Sume 198178064Sume /* allocate ifaddr structure, link into chain, etc. */ 1982151539Ssuz updateflags = 0; 1983151539Ssuz if (delay) 1984151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1985151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) 1986120856Sume return (error); 198778064Sume 198878064Sume newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 198978064Sume if (newia == NULL) { /* XXX: can it happen? */ 199078064Sume nd6log((LOG_ERR, 199178064Sume "in6_tmpifadd: ifa update succeeded, but we got " 199278064Sume "no ifaddr\n")); 1993120856Sume return (EINVAL); /* XXX */ 199453541Sshin } 199578064Sume newia->ia6_ndpr = ia0->ia6_ndpr; 199678064Sume newia->ia6_ndpr->ndpr_refcnt++; 199753541Sshin 199878407Sume /* 199978407Sume * A newly added address might affect the status of other addresses. 200078407Sume * XXX: when the temporary address is generated with a new public 200178407Sume * address, the onlink check is redundant. However, it would be safe 200278407Sume * to do the check explicitly everywhere a new address is generated, 200378407Sume * and, in fact, we surely need the check when we create a new 200478407Sume * temporary address due to deprecation of an old temporary address. 200578407Sume */ 200678407Sume pfxlist_onlink_check(); 200778407Sume 2008120856Sume return (0); 2009120941Sume} 201053541Sshin 2011151539Ssuzstatic int 201253541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr) 201353541Sshin{ 201453541Sshin if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 201553541Sshin ndpr->ndpr_preferred = 0; 201653541Sshin else 201753541Sshin ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; 201853541Sshin if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 201953541Sshin ndpr->ndpr_expire = 0; 202053541Sshin else 202153541Sshin ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; 202253541Sshin 202353541Sshin return 0; 202453541Sshin} 202553541Sshin 202653541Sshinstatic void 202778064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 202853541Sshin{ 202978064Sume /* init ia6t_expire */ 203078064Sume if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 203178064Sume lt6->ia6t_expire = 0; 203278064Sume else { 203378064Sume lt6->ia6t_expire = time_second; 203478064Sume lt6->ia6t_expire += lt6->ia6t_vltime; 203553541Sshin } 203662587Sitojun 203753541Sshin /* init ia6t_preferred */ 203853541Sshin if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 203953541Sshin lt6->ia6t_preferred = 0; 204053541Sshin else { 204153541Sshin lt6->ia6t_preferred = time_second; 204253541Sshin lt6->ia6t_preferred += lt6->ia6t_pltime; 204353541Sshin } 204453541Sshin} 204553541Sshin 204653541Sshin/* 204753541Sshin * Delete all the routing table entries that use the specified gateway. 204853541Sshin * XXX: this function causes search through all entries of routing table, so 204953541Sshin * it shouldn't be called when acting as a router. 205053541Sshin */ 205153541Sshinvoid 2052171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp) 205353541Sshin{ 2054183550Szec INIT_VNET_NET(curvnet); 2055181803Sbz struct radix_node_head *rnh = V_rt_tables[0][AF_INET6]; 205653541Sshin int s = splnet(); 205753541Sshin 205853541Sshin /* We'll care only link-local addresses */ 205953541Sshin if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { 206053541Sshin splx(s); 206153541Sshin return; 206253541Sshin } 206353541Sshin 2064108250Shsu RADIX_NODE_HEAD_LOCK(rnh); 206553541Sshin rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 2066108250Shsu RADIX_NODE_HEAD_UNLOCK(rnh); 206753541Sshin splx(s); 206853541Sshin} 206953541Sshin 207053541Sshinstatic int 2071171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg) 207253541Sshin{ 207353541Sshin#define SIN6(s) ((struct sockaddr_in6 *)s) 207453541Sshin struct rtentry *rt = (struct rtentry *)rn; 207553541Sshin struct in6_addr *gate = (struct in6_addr *)arg; 207653541Sshin 207753541Sshin if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 2078120856Sume return (0); 207953541Sshin 2080120941Sume if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) { 2081120856Sume return (0); 2082120941Sume } 208353541Sshin 208453541Sshin /* 208578064Sume * Do not delete a static route. 208678064Sume * XXX: this seems to be a bit ad-hoc. Should we consider the 208778064Sume * 'cloned' bit instead? 208878064Sume */ 208978064Sume if ((rt->rt_flags & RTF_STATIC) != 0) 2090120856Sume return (0); 209178064Sume 209278064Sume /* 209353541Sshin * We delete only host route. This means, in particular, we don't 209453541Sshin * delete default route. 209553541Sshin */ 209653541Sshin if ((rt->rt_flags & RTF_HOST) == 0) 2097120856Sume return (0); 209853541Sshin 2099120941Sume return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 2100120941Sume rt_mask(rt), rt->rt_flags, 0)); 210153541Sshin#undef SIN6 210253541Sshin} 210362587Sitojun 210462587Sitojunint 2105171259Sdelphijnd6_setdefaultiface(int ifindex) 210662587Sitojun{ 2107183550Szec INIT_VNET_NET(curvnet); 2108183550Szec INIT_VNET_INET6(curvnet); 210962587Sitojun int error = 0; 211062587Sitojun 2111181803Sbz if (ifindex < 0 || V_if_index < ifindex) 2112120856Sume return (EINVAL); 2113151539Ssuz if (ifindex != 0 && !ifnet_byindex(ifindex)) 2114151539Ssuz return (EINVAL); 211562587Sitojun 2116181803Sbz if (V_nd6_defifindex != ifindex) { 2117181803Sbz V_nd6_defifindex = ifindex; 2118181803Sbz if (V_nd6_defifindex > 0) 2119181803Sbz V_nd6_defifp = ifnet_byindex(V_nd6_defifindex); 212062587Sitojun else 2121181803Sbz V_nd6_defifp = NULL; 212262587Sitojun 212362587Sitojun /* 212462587Sitojun * Our current implementation assumes one-to-one maping between 212562587Sitojun * interfaces and links, so it would be natural to use the 212662587Sitojun * default interface as the default link. 212762587Sitojun */ 2128181803Sbz scope6_setdefault(V_nd6_defifp); 212962587Sitojun } 213062587Sitojun 2131120856Sume return (error); 213262587Sitojun} 2133