nd6_rtr.c revision 175162
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 175162 2008-01-08 19:08:58Z obrien $"); 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> 4653541Sshin#include <sys/errno.h> 4753541Sshin#include <sys/syslog.h> 4878064Sume#include <sys/queue.h> 4953541Sshin 5053541Sshin#include <net/if.h> 5153541Sshin#include <net/if_types.h> 5253541Sshin#include <net/if_dl.h> 5353541Sshin#include <net/route.h> 5453541Sshin#include <net/radix.h> 5553541Sshin 5653541Sshin#include <netinet/in.h> 5753541Sshin#include <netinet6/in6_var.h> 5878064Sume#include <netinet6/in6_ifattach.h> 5962587Sitojun#include <netinet/ip6.h> 6053541Sshin#include <netinet6/ip6_var.h> 6153541Sshin#include <netinet6/nd6.h> 6262587Sitojun#include <netinet/icmp6.h> 6362587Sitojun#include <netinet6/scope6_var.h> 6453541Sshin 6562587Sitojun#define SDL(s) ((struct sockaddr_dl *)s) 6653541Sshin 67175162Sobrienstatic int rtpref(struct nd_defrouter *); 68175162Sobrienstatic struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); 69151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *, 70151539Ssuz struct mbuf *, int)); 71175162Sobrienstatic struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int); 7262587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, 7378064Sume struct nd_defrouter *)); 74175162Sobrienstatic void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *); 75175162Sobrienstatic void pfxrtr_del(struct nd_pfxrouter *); 7662587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router 77175162Sobrien(struct nd_prefix *); 78175162Sobrienstatic void defrouter_delreq(struct nd_defrouter *); 79175162Sobrienstatic void nd6_rtmsg(int, struct rtentry *); 8053541Sshin 81175162Sobrienstatic int in6_init_prefix_ltimes(struct nd_prefix *); 82120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *, 83120941Sume struct in6_addrlifetime *)); 8453541Sshin 85175162Sobrienstatic int rt6_deleteroute(struct radix_node *, void *); 8653541Sshin 8762587Sitojunextern int nd6_recalc_reachtm_interval; 8853541Sshin 8978064Sumestatic struct ifnet *nd6_defifp; 9062587Sitojunint nd6_defifindex; 9162587Sitojun 9278064Sumeint ip6_use_tempaddr = 0; 9378064Sume 9478064Sumeint ip6_desync_factor; 9578064Sumeu_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME; 9678064Sumeu_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME; 9753541Sshin/* 9878064Sume * shorter lifetimes for debugging purposes. 9978064Sumeint ip6_temp_preferred_lifetime = 800; 10078064Sumestatic int ip6_temp_valid_lifetime = 1800; 10178064Sume*/ 10278064Sumeint ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE; 10378064Sume 104151539Ssuz/* RTPREF_MEDIUM has to be 0! */ 105151539Ssuz#define RTPREF_HIGH 1 106151539Ssuz#define RTPREF_MEDIUM 0 107151539Ssuz#define RTPREF_LOW (-1) 108151539Ssuz#define RTPREF_RESERVED (-2) 109151539Ssuz#define RTPREF_INVALID (-3) /* internal */ 110151539Ssuz 11178064Sume/* 11253541Sshin * Receive Router Solicitation Message - just for routers. 11353541Sshin * Router solicitation/advertisement is mostly managed by userland program 11453541Sshin * (rtadvd) so here we have no function like nd6_ra_output(). 11553541Sshin * 11653541Sshin * Based on RFC 2461 11753541Sshin */ 11853541Sshinvoid 119171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len) 12053541Sshin{ 12153541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 12253541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 12362587Sitojun struct nd_router_solicit *nd_rs; 12453541Sshin struct in6_addr saddr6 = ip6->ip6_src; 12553541Sshin char *lladdr = NULL; 12653541Sshin int lladdrlen = 0; 12753541Sshin union nd_opts ndopts; 128165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 12953541Sshin 13053541Sshin /* If I'm not a router, ignore it. */ 13153541Sshin if (ip6_accept_rtadv != 0 || ip6_forwarding != 1) 13262587Sitojun goto freeit; 13353541Sshin 13453541Sshin /* Sanity checks */ 13553541Sshin if (ip6->ip6_hlim != 255) { 13678064Sume nd6log((LOG_ERR, 13778064Sume "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 138165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 139165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 14078064Sume goto bad; 14153541Sshin } 14253541Sshin 14353541Sshin /* 14453541Sshin * Don't update the neighbor cache, if src = ::. 14553541Sshin * This indicates that the src has no IP address assigned yet. 14653541Sshin */ 14753541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 14862587Sitojun goto freeit; 14962587Sitojun 15062587Sitojun#ifndef PULLDOWN_TEST 15162587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 15262587Sitojun nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 15362587Sitojun#else 15462587Sitojun IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 15562587Sitojun if (nd_rs == NULL) { 15662587Sitojun icmp6stat.icp6s_tooshort++; 15753541Sshin return; 15862587Sitojun } 15962587Sitojun#endif 16053541Sshin 16153541Sshin icmp6len -= sizeof(*nd_rs); 16253541Sshin nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 16353541Sshin if (nd6_options(&ndopts) < 0) { 16478064Sume nd6log((LOG_INFO, 16578064Sume "nd6_rs_input: invalid ND option, ignored\n")); 16678064Sume /* nd6_options have incremented stats */ 16762587Sitojun goto freeit; 16853541Sshin } 16953541Sshin 17053541Sshin if (ndopts.nd_opts_src_lladdr) { 17153541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 17253541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 17353541Sshin } 17453541Sshin 17553541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 17678064Sume nd6log((LOG_INFO, 17753541Sshin "nd6_rs_input: lladdrlen mismatch for %s " 17853541Sshin "(if %d, RS packet %d)\n", 179165118Sbz ip6_sprintf(ip6bufs, &saddr6), 180120941Sume ifp->if_addrlen, lladdrlen - 2)); 18178064Sume goto bad; 18253541Sshin } 18353541Sshin 18453541Sshin nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 18562587Sitojun 18662587Sitojun freeit: 18762587Sitojun m_freem(m); 18878064Sume return; 18978064Sume 19078064Sume bad: 19178064Sume icmp6stat.icp6s_badrs++; 19278064Sume m_freem(m); 19353541Sshin} 19453541Sshin 19553541Sshin/* 19653541Sshin * Receive Router Advertisement Message. 19753541Sshin * 19853541Sshin * Based on RFC 2461 19953541Sshin * TODO: on-link bit on prefix information 20053541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 20153541Sshin */ 20253541Sshinvoid 203171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len) 20453541Sshin{ 20553541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 206121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 20753541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 20862587Sitojun struct nd_router_advert *nd_ra; 20953541Sshin struct in6_addr saddr6 = ip6->ip6_src; 210151539Ssuz int mcast = 0; 21153541Sshin union nd_opts ndopts; 21253541Sshin struct nd_defrouter *dr; 213165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 21453541Sshin 215118498Sume /* 216118498Sume * We only accept RAs only when 217118498Sume * the system-wide variable allows the acceptance, and 218118498Sume * per-interface variable allows RAs on the receiving interface. 219118498Sume */ 22053541Sshin if (ip6_accept_rtadv == 0) 22162587Sitojun goto freeit; 222118498Sume if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 223118498Sume goto freeit; 22453541Sshin 22553541Sshin if (ip6->ip6_hlim != 255) { 22678064Sume nd6log((LOG_ERR, 22778064Sume "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 228165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 229165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 23078064Sume goto bad; 23153541Sshin } 23253541Sshin 23353541Sshin if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 23478064Sume nd6log((LOG_ERR, 23553541Sshin "nd6_ra_input: src %s is not link-local\n", 236165118Sbz ip6_sprintf(ip6bufs, &saddr6))); 23778064Sume goto bad; 23862587Sitojun } 23962587Sitojun 24062587Sitojun#ifndef PULLDOWN_TEST 24162587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 24262587Sitojun nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); 24362587Sitojun#else 24462587Sitojun IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); 24562587Sitojun if (nd_ra == NULL) { 24662587Sitojun icmp6stat.icp6s_tooshort++; 24753541Sshin return; 24853541Sshin } 24962587Sitojun#endif 25053541Sshin 25153541Sshin icmp6len -= sizeof(*nd_ra); 25253541Sshin nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 25353541Sshin if (nd6_options(&ndopts) < 0) { 25478064Sume nd6log((LOG_INFO, 25578064Sume "nd6_ra_input: invalid ND option, ignored\n")); 25678064Sume /* nd6_options have incremented stats */ 25762587Sitojun goto freeit; 25853541Sshin } 25953541Sshin 26053541Sshin { 26153541Sshin struct nd_defrouter dr0; 26253541Sshin u_int32_t advreachable = nd_ra->nd_ra_reachable; 26353541Sshin 264151539Ssuz /* remember if this is a multicasted advertisement */ 265151539Ssuz if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 266151539Ssuz mcast = 1; 267151539Ssuz 268151539Ssuz bzero(&dr0, sizeof(dr0)); 26953541Sshin dr0.rtaddr = saddr6; 27053541Sshin dr0.flags = nd_ra->nd_ra_flags_reserved; 271156871Ssuz dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 27253541Sshin dr0.expire = time_second + dr0.rtlifetime; 27353541Sshin dr0.ifp = ifp; 27453541Sshin /* unspecified or not? (RFC 2461 6.3.4) */ 27553541Sshin if (advreachable) { 27690868Smike advreachable = ntohl(advreachable); 27753541Sshin if (advreachable <= MAX_REACHABLE_TIME && 27853541Sshin ndi->basereachable != advreachable) { 27953541Sshin ndi->basereachable = advreachable; 28053541Sshin ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 28153541Sshin ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */ 28253541Sshin } 28353541Sshin } 28453541Sshin if (nd_ra->nd_ra_retransmit) 28553541Sshin ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 28653541Sshin if (nd_ra->nd_ra_curhoplimit) 28753541Sshin ndi->chlim = nd_ra->nd_ra_curhoplimit; 28853541Sshin dr = defrtrlist_update(&dr0); 28953541Sshin } 29053541Sshin 29153541Sshin /* 29253541Sshin * prefix 29353541Sshin */ 29453541Sshin if (ndopts.nd_opts_pi) { 29553541Sshin struct nd_opt_hdr *pt; 29678064Sume struct nd_opt_prefix_info *pi = NULL; 297151539Ssuz struct nd_prefixctl pr; 29853541Sshin 29953541Sshin for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 30053541Sshin pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 30153541Sshin pt = (struct nd_opt_hdr *)((caddr_t)pt + 30253541Sshin (pt->nd_opt_len << 3))) { 30353541Sshin if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 30453541Sshin continue; 30553541Sshin pi = (struct nd_opt_prefix_info *)pt; 30653541Sshin 30753541Sshin if (pi->nd_opt_pi_len != 4) { 30878064Sume nd6log((LOG_INFO, 30978064Sume "nd6_ra_input: invalid option " 31078064Sume "len %d for prefix information option, " 31178064Sume "ignored\n", pi->nd_opt_pi_len)); 31253541Sshin continue; 31353541Sshin } 31453541Sshin 31553541Sshin if (128 < pi->nd_opt_pi_prefix_len) { 31678064Sume nd6log((LOG_INFO, 31778064Sume "nd6_ra_input: invalid prefix " 31878064Sume "len %d for prefix information option, " 31978064Sume "ignored\n", pi->nd_opt_pi_prefix_len)); 32053541Sshin continue; 32153541Sshin } 32253541Sshin 32353541Sshin if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 32453541Sshin || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 32578064Sume nd6log((LOG_INFO, 32678064Sume "nd6_ra_input: invalid prefix " 32778064Sume "%s, ignored\n", 328165118Sbz ip6_sprintf(ip6bufs, 329165118Sbz &pi->nd_opt_pi_prefix))); 33053541Sshin continue; 33153541Sshin } 33253541Sshin 33353541Sshin bzero(&pr, sizeof(pr)); 33453541Sshin pr.ndpr_prefix.sin6_family = AF_INET6; 33553541Sshin pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 33653541Sshin pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 33753541Sshin pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 33853541Sshin 33953541Sshin pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 340120941Sume ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 34153541Sshin pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 342120941Sume ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 34353541Sshin pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 34453541Sshin pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 345120941Sume pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); 346151539Ssuz (void)prelist_update(&pr, dr, m, mcast); 34753541Sshin } 34853541Sshin } 34953541Sshin 35053541Sshin /* 35153541Sshin * MTU 35253541Sshin */ 35353541Sshin if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 354121283Sume u_long mtu; 355121283Sume u_long maxmtu; 35653541Sshin 357121283Sume mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 358120941Sume 35953541Sshin /* lower bound */ 36053541Sshin if (mtu < IPV6_MMTU) { 36178064Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " 362121283Sume "mtu=%lu sent from %s, ignoring\n", 363165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src))); 36453541Sshin goto skip; 36553541Sshin } 36653541Sshin 36753541Sshin /* upper bound */ 368121283Sume maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu) 369121283Sume ? ndi->maxmtu : ifp->if_mtu; 370121283Sume if (mtu <= maxmtu) { 371121283Sume int change = (ndi->linkmtu != mtu); 37253541Sshin 373121283Sume ndi->linkmtu = mtu; 374121283Sume if (change) /* in6_maxmtu may change */ 375121283Sume in6_setmaxmtu(); 37653541Sshin } else { 377121283Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " 378121283Sume "mtu=%lu sent from %s; " 379121283Sume "exceeds maxmtu %lu, ignoring\n", 380165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu)); 38153541Sshin } 38253541Sshin } 38353541Sshin 38453541Sshin skip: 385120941Sume 38653541Sshin /* 38795023Ssuz * Source link layer address 38853541Sshin */ 38953541Sshin { 39053541Sshin char *lladdr = NULL; 39153541Sshin int lladdrlen = 0; 392120941Sume 39353541Sshin if (ndopts.nd_opts_src_lladdr) { 39453541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 39553541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 39653541Sshin } 39753541Sshin 39853541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 39978064Sume nd6log((LOG_INFO, 40053541Sshin "nd6_ra_input: lladdrlen mismatch for %s " 401165118Sbz "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6), 402120941Sume ifp->if_addrlen, lladdrlen - 2)); 40378064Sume goto bad; 40453541Sshin } 40553541Sshin 406120941Sume nd6_cache_lladdr(ifp, &saddr6, lladdr, 407120941Sume lladdrlen, ND_ROUTER_ADVERT, 0); 40862587Sitojun 40962587Sitojun /* 41062587Sitojun * Installing a link-layer address might change the state of the 41162587Sitojun * router's neighbor cache, which might also affect our on-link 41262587Sitojun * detection of adveritsed prefixes. 41362587Sitojun */ 41462587Sitojun pfxlist_onlink_check(); 41553541Sshin } 41662587Sitojun 41778064Sume freeit: 41862587Sitojun m_freem(m); 41978064Sume return; 42078064Sume 42178064Sume bad: 42278064Sume icmp6stat.icp6s_badra++; 42378064Sume m_freem(m); 42453541Sshin} 42553541Sshin 42653541Sshin/* 42753541Sshin * default router list proccessing sub routines 42853541Sshin */ 42962587Sitojun 43062587Sitojun/* tell the change to user processes watching the routing socket. */ 43162587Sitojunstatic void 432171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt) 43362587Sitojun{ 43462587Sitojun struct rt_addrinfo info; 43562587Sitojun 43662587Sitojun bzero((caddr_t)&info, sizeof(info)); 43762587Sitojun info.rti_info[RTAX_DST] = rt_key(rt); 43862587Sitojun info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 43962587Sitojun info.rti_info[RTAX_NETMASK] = rt_mask(rt); 440151539Ssuz if (rt->rt_ifp) { 441151539Ssuz info.rti_info[RTAX_IFP] = 442151539Ssuz TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 443151539Ssuz info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 444151539Ssuz } 44562587Sitojun 44662587Sitojun rt_missmsg(cmd, &info, rt->rt_flags, 0); 44762587Sitojun} 44862587Sitojun 44953541Sshinvoid 450171259Sdelphijdefrouter_addreq(struct nd_defrouter *new) 45153541Sshin{ 45253541Sshin struct sockaddr_in6 def, mask, gate; 45362587Sitojun struct rtentry *newrt = NULL; 454151539Ssuz int s; 455151539Ssuz int error; 45653541Sshin 457128397Sluigi bzero(&def, sizeof(def)); 458128397Sluigi bzero(&mask, sizeof(mask)); 459128397Sluigi bzero(&gate, sizeof(gate)); 46053541Sshin 461120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 462120941Sume sizeof(struct sockaddr_in6); 463151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 46453541Sshin gate.sin6_addr = new->rtaddr; 46553541Sshin 466151539Ssuz s = splnet(); 467151539Ssuz error = rtrequest(RTM_ADD, (struct sockaddr *)&def, 468120941Sume (struct sockaddr *)&gate, (struct sockaddr *)&mask, 469120941Sume RTF_GATEWAY, &newrt); 47062587Sitojun if (newrt) { 471120727Ssam RT_LOCK(newrt); 47278064Sume nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 473122334Ssam RT_REMREF(newrt); 474120727Ssam RT_UNLOCK(newrt); 47562587Sitojun } 476151539Ssuz if (error == 0) 477151539Ssuz new->installed = 1; 478151539Ssuz splx(s); 47953541Sshin return; 48053541Sshin} 48153541Sshin 48253541Sshinstruct nd_defrouter * 483171259Sdelphijdefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) 48453541Sshin{ 48553541Sshin struct nd_defrouter *dr; 48653541Sshin 48762587Sitojun for (dr = TAILQ_FIRST(&nd_defrouter); dr; 48862587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 48953541Sshin if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 490120856Sume return (dr); 49162587Sitojun } 49253541Sshin 493120856Sume return (NULL); /* search failed */ 49453541Sshin} 49553541Sshin 496151539Ssuz/* 497151539Ssuz * Remove the default route for a given router. 498151539Ssuz * This is just a subroutine function for defrouter_select(), and should 499151539Ssuz * not be called from anywhere else. 500151539Ssuz */ 501151539Ssuzstatic void 502171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr) 50353541Sshin{ 50453541Sshin struct sockaddr_in6 def, mask, gate; 50562587Sitojun struct rtentry *oldrt = NULL; 50653541Sshin 507128397Sluigi bzero(&def, sizeof(def)); 508128397Sluigi bzero(&mask, sizeof(mask)); 509128397Sluigi bzero(&gate, sizeof(gate)); 51053541Sshin 511120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 512120941Sume sizeof(struct sockaddr_in6); 513151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 51453541Sshin gate.sin6_addr = dr->rtaddr; 51553541Sshin 51653541Sshin rtrequest(RTM_DELETE, (struct sockaddr *)&def, 517120941Sume (struct sockaddr *)&gate, 518120941Sume (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); 51962587Sitojun if (oldrt) { 52078064Sume nd6_rtmsg(RTM_DELETE, oldrt); 521108269Sru RTFREE(oldrt); 52262587Sitojun } 52353541Sshin 524151539Ssuz dr->installed = 0; 52553541Sshin} 52653541Sshin 527151539Ssuz/* 528151539Ssuz * remove all default routes from default router list 529151539Ssuz */ 53053541Sshinvoid 531171259Sdelphijdefrouter_reset(void) 532151539Ssuz{ 533151539Ssuz struct nd_defrouter *dr; 534151539Ssuz 535151539Ssuz for (dr = TAILQ_FIRST(&nd_defrouter); dr; 536151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) 537151539Ssuz defrouter_delreq(dr); 538151539Ssuz 539151539Ssuz /* 540151539Ssuz * XXX should we also nuke any default routers in the kernel, by 541151539Ssuz * going through them by rtalloc1()? 542151539Ssuz */ 543151539Ssuz} 544151539Ssuz 545151539Ssuzvoid 546171259Sdelphijdefrtrlist_del(struct nd_defrouter *dr) 54753541Sshin{ 54853541Sshin struct nd_defrouter *deldr = NULL; 54953541Sshin struct nd_prefix *pr; 55053541Sshin 55153541Sshin /* 55253541Sshin * Flush all the routing table entries that use the router 55353541Sshin * as a next hop. 55453541Sshin */ 555120941Sume if (!ip6_forwarding && ip6_accept_rtadv) /* XXX: better condition? */ 55653541Sshin rt6_flush(&dr->rtaddr, dr->ifp); 55753541Sshin 558151539Ssuz if (dr->installed) { 559151539Ssuz deldr = dr; 560151539Ssuz defrouter_delreq(dr); 561151539Ssuz } 56262587Sitojun TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 56353541Sshin 56453541Sshin /* 56553541Sshin * Also delete all the pointers to the router in each prefix lists. 56653541Sshin */ 56762587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 56853541Sshin struct nd_pfxrouter *pfxrtr; 56953541Sshin if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 57053541Sshin pfxrtr_del(pfxrtr); 57153541Sshin } 57253541Sshin pfxlist_onlink_check(); 57353541Sshin 57453541Sshin /* 57562587Sitojun * If the router is the primary one, choose a new one. 57662587Sitojun * Note that defrouter_select() will remove the current gateway 57762587Sitojun * from the routing table. 57853541Sshin */ 57953541Sshin if (deldr) 58062587Sitojun defrouter_select(); 58162587Sitojun 58253541Sshin free(dr, M_IP6NDP); 58353541Sshin} 58453541Sshin 58562587Sitojun/* 586151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and 587151539Ssuz * draft-ietf-ipngwg-router-selection: 588151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred. 589151539Ssuz * If we have more than one (probably) reachable router, prefer ones 590151539Ssuz * with the highest router preference. 59162587Sitojun * 2) When no routers on the list are known to be reachable or 59262587Sitojun * probably reachable, routers SHOULD be selected in a round-robin 593151539Ssuz * fashion, regardless of router preference values. 59462587Sitojun * 3) If the Default Router List is empty, assume that all 59562587Sitojun * destinations are on-link. 596151539Ssuz * 597151539Ssuz * We assume nd_defrouter is sorted by router preference value. 598151539Ssuz * Since the code below covers both with and without router preference cases, 599151539Ssuz * we do not need to classify the cases by ifdef. 600151539Ssuz * 601151539Ssuz * At this moment, we do not try to install more than one default router, 602151539Ssuz * even when the multipath routing is available, because we're not sure about 603151539Ssuz * the benefits for stub hosts comparing to the risk of making the code 604151539Ssuz * complicated and the possibility of introducing bugs. 60562587Sitojun */ 60662587Sitojunvoid 607171259Sdelphijdefrouter_select(void) 60862587Sitojun{ 60962587Sitojun int s = splnet(); 610151539Ssuz struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; 61162587Sitojun struct rtentry *rt = NULL; 61262587Sitojun struct llinfo_nd6 *ln = NULL; 61362587Sitojun 61462587Sitojun /* 615151539Ssuz * This function should be called only when acting as an autoconfigured 616151539Ssuz * host. Although the remaining part of this function is not effective 617151539Ssuz * if the node is not an autoconfigured host, we explicitly exclude 618151539Ssuz * such cases here for safety. 619151539Ssuz */ 620151539Ssuz if (ip6_forwarding || !ip6_accept_rtadv) { 621151539Ssuz nd6log((LOG_WARNING, 622151539Ssuz "defrouter_select: called unexpectedly (forwarding=%d, " 623151539Ssuz "accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv)); 624151539Ssuz splx(s); 625151539Ssuz return; 626151539Ssuz } 627151539Ssuz 628151539Ssuz /* 629151539Ssuz * Let's handle easy case (3) first: 630151539Ssuz * If default router list is empty, there's nothing to be done. 631151539Ssuz */ 632151539Ssuz if (!TAILQ_FIRST(&nd_defrouter)) { 633151539Ssuz splx(s); 634151539Ssuz return; 635151539Ssuz } 636151539Ssuz 637151539Ssuz /* 63862587Sitojun * Search for a (probably) reachable router from the list. 639151539Ssuz * We just pick up the first reachable one (if any), assuming that 640151539Ssuz * the ordering rule of the list described in defrtrlist_update(). 64162587Sitojun */ 64262587Sitojun for (dr = TAILQ_FIRST(&nd_defrouter); dr; 64362587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 644151539Ssuz if (selected_dr == NULL && 645151539Ssuz (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && 64662587Sitojun (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 64762587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) { 648151539Ssuz selected_dr = dr; 64962587Sitojun } 65062587Sitojun 651151539Ssuz if (dr->installed && installed_dr == NULL) 652151539Ssuz installed_dr = dr; 653151539Ssuz else if (dr->installed && installed_dr) { 654151539Ssuz /* this should not happen. warn for diagnosis. */ 655151539Ssuz log(LOG_ERR, "defrouter_select: more than one router" 656151539Ssuz " is installed\n"); 65762587Sitojun } 65862587Sitojun } 659151539Ssuz /* 660151539Ssuz * If none of the default routers was found to be reachable, 661151539Ssuz * round-robin the list regardless of preference. 662151539Ssuz * Otherwise, if we have an installed router, check if the selected 663151539Ssuz * (reachable) router should really be preferred to the installed one. 664151539Ssuz * We only prefer the new router when the old one is not reachable 665151539Ssuz * or when the new one has a really higher preference value. 666151539Ssuz */ 667151539Ssuz if (selected_dr == NULL) { 668151539Ssuz if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry)) 669151539Ssuz selected_dr = TAILQ_FIRST(&nd_defrouter); 670151539Ssuz else 671151539Ssuz selected_dr = TAILQ_NEXT(installed_dr, dr_entry); 672151539Ssuz } else if (installed_dr && 673151539Ssuz (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && 674151539Ssuz (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 675151539Ssuz ND6_IS_LLINFO_PROBREACH(ln) && 676151539Ssuz rtpref(selected_dr) <= rtpref(installed_dr)) { 677151539Ssuz selected_dr = installed_dr; 678151539Ssuz } 67962587Sitojun 680151539Ssuz /* 681151539Ssuz * If the selected router is different than the installed one, 682151539Ssuz * remove the installed router and install the selected one. 683151539Ssuz * Note that the selected router is never NULL here. 684151539Ssuz */ 685151539Ssuz if (installed_dr != selected_dr) { 686151539Ssuz if (installed_dr) 687151539Ssuz defrouter_delreq(installed_dr); 688151539Ssuz defrouter_addreq(selected_dr); 689151539Ssuz } 690151539Ssuz 69162587Sitojun splx(s); 69262587Sitojun return; 69362587Sitojun} 69462587Sitojun 695151539Ssuz/* 696151539Ssuz * for default router selection 697151539Ssuz * regards router-preference field as a 2-bit signed integer 698151539Ssuz */ 699151539Ssuzstatic int 700151539Ssuzrtpref(struct nd_defrouter *dr) 701151539Ssuz{ 702151539Ssuz switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) { 703151539Ssuz case ND_RA_FLAG_RTPREF_HIGH: 704151539Ssuz return (RTPREF_HIGH); 705151539Ssuz case ND_RA_FLAG_RTPREF_MEDIUM: 706156871Ssuz case ND_RA_FLAG_RTPREF_RSV: 707151539Ssuz return (RTPREF_MEDIUM); 708151539Ssuz case ND_RA_FLAG_RTPREF_LOW: 709151539Ssuz return (RTPREF_LOW); 710151539Ssuz default: 711151539Ssuz /* 712151539Ssuz * This case should never happen. If it did, it would mean a 713151539Ssuz * serious bug of kernel internal. We thus always bark here. 714151539Ssuz * Or, can we even panic? 715151539Ssuz */ 716151539Ssuz log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags); 717151539Ssuz return (RTPREF_INVALID); 718151539Ssuz } 719151539Ssuz /* NOTREACHED */ 720151539Ssuz} 721151539Ssuz 72253541Sshinstatic struct nd_defrouter * 723171259Sdelphijdefrtrlist_update(struct nd_defrouter *new) 72453541Sshin{ 72553541Sshin struct nd_defrouter *dr, *n; 72653541Sshin int s = splnet(); 72753541Sshin 72853541Sshin if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 72953541Sshin /* entry exists */ 73053541Sshin if (new->rtlifetime == 0) { 73153541Sshin defrtrlist_del(dr); 73253541Sshin dr = NULL; 73353541Sshin } else { 734151539Ssuz int oldpref = rtpref(dr); 735151539Ssuz 73653541Sshin /* override */ 73753541Sshin dr->flags = new->flags; /* xxx flag check */ 73853541Sshin dr->rtlifetime = new->rtlifetime; 73953541Sshin dr->expire = new->expire; 740151539Ssuz 741151539Ssuz /* 742151539Ssuz * If the preference does not change, there's no need 743151539Ssuz * to sort the entries. 744151539Ssuz */ 745151539Ssuz if (rtpref(new) == oldpref) { 746151539Ssuz splx(s); 747151539Ssuz return (dr); 748151539Ssuz } 749151539Ssuz 750151539Ssuz /* 751151539Ssuz * preferred router may be changed, so relocate 752151539Ssuz * this router. 753151539Ssuz * XXX: calling TAILQ_REMOVE directly is a bad manner. 754151539Ssuz * However, since defrtrlist_del() has many side 755151539Ssuz * effects, we intentionally do so here. 756151539Ssuz * defrouter_select() below will handle routing 757151539Ssuz * changes later. 758151539Ssuz */ 759151539Ssuz TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 760151539Ssuz n = dr; 761151539Ssuz goto insert; 76253541Sshin } 76353541Sshin splx(s); 764120856Sume return (dr); 76553541Sshin } 76653541Sshin 76753541Sshin /* entry does not exist */ 76853541Sshin if (new->rtlifetime == 0) { 76953541Sshin splx(s); 770120856Sume return (NULL); 77153541Sshin } 77253541Sshin 77353541Sshin n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 77453541Sshin if (n == NULL) { 77553541Sshin splx(s); 776120856Sume return (NULL); 77753541Sshin } 77853541Sshin bzero(n, sizeof(*n)); 77953541Sshin *n = *new; 78062587Sitojun 781151539Ssuzinsert: 78262587Sitojun /* 783151539Ssuz * Insert the new router in the Default Router List; 784151539Ssuz * The Default Router List should be in the descending order 785151539Ssuz * of router-preferece. Routers with the same preference are 786151539Ssuz * sorted in the arriving time order. 78762587Sitojun */ 788151539Ssuz 789151539Ssuz /* insert at the end of the group */ 790151539Ssuz for (dr = TAILQ_FIRST(&nd_defrouter); dr; 791151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 792151539Ssuz if (rtpref(n) > rtpref(dr)) 793151539Ssuz break; 794151539Ssuz } 795151539Ssuz if (dr) 796151539Ssuz TAILQ_INSERT_BEFORE(dr, n, dr_entry); 797151539Ssuz else 798151539Ssuz TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry); 799151539Ssuz 800151539Ssuz defrouter_select(); 801151539Ssuz 80253541Sshin splx(s); 803120941Sume 804120856Sume return (n); 80553541Sshin} 80653541Sshin 80753541Sshinstatic struct nd_pfxrouter * 808171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) 80953541Sshin{ 81053541Sshin struct nd_pfxrouter *search; 811120941Sume 81262587Sitojun for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { 81353541Sshin if (search->router == dr) 81453541Sshin break; 81553541Sshin } 81653541Sshin 817120856Sume return (search); 81853541Sshin} 81953541Sshin 82053541Sshinstatic void 821171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) 82253541Sshin{ 82353541Sshin struct nd_pfxrouter *new; 82453541Sshin 82553541Sshin new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 82653541Sshin if (new == NULL) 82753541Sshin return; 82853541Sshin bzero(new, sizeof(*new)); 82953541Sshin new->router = dr; 83053541Sshin 83153541Sshin LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 83253541Sshin 83353541Sshin pfxlist_onlink_check(); 83453541Sshin} 83553541Sshin 83653541Sshinstatic void 837171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr) 83853541Sshin{ 83953541Sshin LIST_REMOVE(pfr, pfr_entry); 84053541Sshin free(pfr, M_IP6NDP); 84153541Sshin} 84253541Sshin 84378064Sumestruct nd_prefix * 844171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key) 84553541Sshin{ 84653541Sshin struct nd_prefix *search; 84753541Sshin 84862587Sitojun for (search = nd_prefix.lh_first; search; search = search->ndpr_next) { 849151539Ssuz if (key->ndpr_ifp == search->ndpr_ifp && 850151539Ssuz key->ndpr_plen == search->ndpr_plen && 851151539Ssuz in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr, 852151539Ssuz &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) { 85353541Sshin break; 85453541Sshin } 85553541Sshin } 85653541Sshin 857120856Sume return (search); 85853541Sshin} 85953541Sshin 86078064Sumeint 861171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr, 862171259Sdelphij struct nd_prefix **newp) 86353541Sshin{ 86478064Sume struct nd_prefix *new = NULL; 865151539Ssuz int error = 0; 86653541Sshin int i, s; 867165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 86853541Sshin 86953541Sshin new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 87053541Sshin if (new == NULL) 871120941Sume return(ENOMEM); 87253541Sshin bzero(new, sizeof(*new)); 873151539Ssuz new->ndpr_ifp = pr->ndpr_ifp; 874151539Ssuz new->ndpr_prefix = pr->ndpr_prefix; 875151539Ssuz new->ndpr_plen = pr->ndpr_plen; 876151539Ssuz new->ndpr_vltime = pr->ndpr_vltime; 877151539Ssuz new->ndpr_pltime = pr->ndpr_pltime; 878151539Ssuz new->ndpr_flags = pr->ndpr_flags; 879151539Ssuz if ((error = in6_init_prefix_ltimes(new)) != 0) { 880151539Ssuz free(new, M_IP6NDP); 881151539Ssuz return(error); 882151539Ssuz } 883151539Ssuz new->ndpr_lastupdate = time_second; 88478064Sume if (newp != NULL) 88578064Sume *newp = new; 88653541Sshin 887120941Sume /* initialization */ 88853541Sshin LIST_INIT(&new->ndpr_advrtrs); 88953541Sshin in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 89053541Sshin /* make prefix in the canonical form */ 89153541Sshin for (i = 0; i < 4; i++) 89253541Sshin new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 893120941Sume new->ndpr_mask.s6_addr32[i]; 89453541Sshin 89553541Sshin s = splnet(); 89653541Sshin /* link ndpr_entry to nd_prefix list */ 89753541Sshin LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry); 89853541Sshin splx(s); 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; 92378064Sume int e, s; 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 s = splnet(); 94978064Sume 95053541Sshin /* unlink ndpr_entry from nd_prefix list */ 95153541Sshin LIST_REMOVE(pr, ndpr_entry); 95253541Sshin 95353541Sshin /* free list of routers that adversed the prefix */ 95462587Sitojun for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { 95562587Sitojun next = pfr->pfr_next; 95653541Sshin 95753541Sshin free(pfr, M_IP6NDP); 95853541Sshin } 95978064Sume splx(s); 96078064Sume 96153541Sshin free(pr, M_IP6NDP); 96253541Sshin 96353541Sshin pfxlist_onlink_check(); 96453541Sshin} 96553541Sshin 966171259Sdelphij/* 967171259Sdelphij * dr - may be NULL 968171259Sdelphij */ 969171259Sdelphij 970151539Ssuzstatic int 971171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, 972171259Sdelphij struct mbuf *m, int mcast) 97353541Sshin{ 97478064Sume struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 97578064Sume struct ifaddr *ifa; 97678064Sume struct ifnet *ifp = new->ndpr_ifp; 97753541Sshin struct nd_prefix *pr; 97853541Sshin int s = splnet(); 97953541Sshin int error = 0; 98078064Sume int newprefix = 0; 98153541Sshin int auth; 98278064Sume struct in6_addrlifetime lt6_tmp; 983165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 98453541Sshin 98553541Sshin auth = 0; 98653541Sshin if (m) { 98753541Sshin /* 98853541Sshin * Authenticity for NA consists authentication for 98953541Sshin * both IP header and IP datagrams, doesn't it ? 99053541Sshin */ 99153541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 992120941Sume auth = ((m->m_flags & M_AUTHIPHDR) && 993120941Sume (m->m_flags & M_AUTHIPDGM)); 99453541Sshin#endif 99553541Sshin } 99653541Sshin 99778064Sume if ((pr = nd6_prefix_lookup(new)) != NULL) { 99878064Sume /* 99978064Sume * nd6_prefix_lookup() ensures that pr and new have the same 100078064Sume * prefix on a same interface. 100178064Sume */ 100253541Sshin 100353541Sshin /* 100478064Sume * Update prefix information. Note that the on-link (L) bit 100578064Sume * and the autonomous (A) bit should NOT be changed from 1 100678064Sume * to 0. 100753541Sshin */ 100878064Sume if (new->ndpr_raf_onlink == 1) 100978064Sume pr->ndpr_raf_onlink = 1; 101078064Sume if (new->ndpr_raf_auto == 1) 101178064Sume pr->ndpr_raf_auto = 1; 101278064Sume if (new->ndpr_raf_onlink) { 101378064Sume pr->ndpr_vltime = new->ndpr_vltime; 101478064Sume pr->ndpr_pltime = new->ndpr_pltime; 1015151539Ssuz (void)in6_init_prefix_ltimes(pr); /* XXX error case? */ 1016151539Ssuz pr->ndpr_lastupdate = time_second; 101778064Sume } 101853541Sshin 101978064Sume if (new->ndpr_raf_onlink && 102078064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 102178064Sume int e; 102253541Sshin 102378064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 102478064Sume nd6log((LOG_ERR, 102578064Sume "prelist_update: failed to make " 102678064Sume "the prefix %s/%d on-link on %s " 102778064Sume "(errno=%d)\n", 1028165118Sbz ip6_sprintf(ip6buf, 1029165118Sbz &pr->ndpr_prefix.sin6_addr), 103078064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 103178064Sume /* proceed anyway. XXX: is it correct? */ 103253541Sshin } 103378064Sume } 103453541Sshin 103578064Sume if (dr && pfxrtr_lookup(pr, dr) == NULL) 103678064Sume pfxrtr_add(pr, dr); 103778064Sume } else { 103878064Sume struct nd_prefix *newpr = NULL; 103953541Sshin 104078064Sume newprefix = 1; 104153541Sshin 104278064Sume if (new->ndpr_vltime == 0) 104378064Sume goto end; 104478064Sume if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 104578064Sume goto end; 104653541Sshin 104778064Sume error = nd6_prelist_add(new, dr, &newpr); 104878064Sume if (error != 0 || newpr == NULL) { 104978064Sume nd6log((LOG_NOTICE, "prelist_update: " 105078064Sume "nd6_prelist_add failed for %s/%d on %s " 105178064Sume "errno=%d, returnpr=%p\n", 1052165118Sbz ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr), 1053120941Sume new->ndpr_plen, if_name(new->ndpr_ifp), 1054120941Sume error, newpr)); 105578064Sume goto end; /* we should just give up in this case. */ 105678064Sume } 105753541Sshin 105878064Sume /* 105978064Sume * XXX: from the ND point of view, we can ignore a prefix 106078064Sume * with the on-link bit being zero. However, we need a 106178064Sume * prefix structure for references from autoconfigured 1062120941Sume * addresses. Thus, we explicitly make sure that the prefix 106378064Sume * itself expires now. 106478064Sume */ 106578064Sume if (newpr->ndpr_raf_onlink == 0) { 106678064Sume newpr->ndpr_vltime = 0; 106778064Sume newpr->ndpr_pltime = 0; 106878064Sume in6_init_prefix_ltimes(newpr); 106953541Sshin } 107053541Sshin 107178064Sume pr = newpr; 107278064Sume } 107353541Sshin 107478064Sume /* 107578064Sume * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 107678064Sume * Note that pr must be non NULL at this point. 107778064Sume */ 107862587Sitojun 107978064Sume /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 108078064Sume if (!new->ndpr_raf_auto) 1081151539Ssuz goto end; 108262587Sitojun 108378064Sume /* 108478064Sume * 5.5.3 (b). the link-local prefix should have been ignored in 108578064Sume * nd6_ra_input. 108678064Sume */ 108762587Sitojun 1088151539Ssuz /* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */ 1089151539Ssuz if (new->ndpr_pltime > new->ndpr_vltime) { 1090151539Ssuz error = EINVAL; /* XXX: won't be used */ 1091151539Ssuz goto end; 1092151539Ssuz } 109362587Sitojun 1094171260Sdelphij /* 1095151539Ssuz * 5.5.3 (d). If the prefix advertised is not equal to the prefix of 1096151539Ssuz * an address configured by stateless autoconfiguration already in the 1097151539Ssuz * list of addresses associated with the interface, and the Valid 1098151539Ssuz * Lifetime is not 0, form an address. We first check if we have 1099151539Ssuz * a matching prefix. 1100151539Ssuz * Note: we apply a clarification in rfc2462bis-02 here. We only 1101151539Ssuz * consider autoconfigured addresses while RFC2462 simply said 1102151539Ssuz * "address". 110378064Sume */ 1104120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 110578064Sume struct in6_ifaddr *ifa6; 1106151539Ssuz u_int32_t remaininglifetime; 110753541Sshin 110878064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 110978064Sume continue; 111053541Sshin 111178064Sume ifa6 = (struct in6_ifaddr *)ifa; 111253541Sshin 111353541Sshin /* 1114151539Ssuz * We only consider autoconfigured addresses as per rfc2462bis. 1115151539Ssuz */ 1116151539Ssuz if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF)) 1117151539Ssuz continue; 1118151539Ssuz 1119151539Ssuz /* 112078064Sume * Spec is not clear here, but I believe we should concentrate 112178064Sume * on unicast (i.e. not anycast) addresses. 112278064Sume * XXX: other ia6_flags? detached or duplicated? 112353541Sshin */ 112478064Sume if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 112578064Sume continue; 1126120941Sume 1127151539Ssuz /* 1128151539Ssuz * Ignore the address if it is not associated with a prefix 1129151539Ssuz * or is associated with a prefix that is different from this 1130151539Ssuz * one. (pr is never NULL here) 1131151539Ssuz */ 1132151539Ssuz if (ifa6->ia6_ndpr != pr) 113378064Sume continue; 113453541Sshin 113578064Sume if (ia6_match == NULL) /* remember the first one */ 113678064Sume ia6_match = ifa6; 113778064Sume 113878064Sume /* 113978064Sume * An already autoconfigured address matched. Now that we 114078064Sume * are sure there is at least one matched address, we can 114178064Sume * proceed to 5.5.3. (e): update the lifetimes according to the 114278064Sume * "two hours" rule and the privacy extension. 1143151539Ssuz * We apply some clarifications in rfc2462bis: 1144151539Ssuz * - use remaininglifetime instead of storedlifetime as a 1145151539Ssuz * variable name 1146151539Ssuz * - remove the dead code in the "two-hour" rule 114778064Sume */ 114878064Sume#define TWOHOUR (120*60) 114978064Sume lt6_tmp = ifa6->ia6_lifetime; 115078064Sume 1151112678Sume if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 1152151539Ssuz remaininglifetime = ND6_INFINITE_LIFETIME; 1153151539Ssuz else if (time_second - ifa6->ia6_updatetime > 1154151539Ssuz lt6_tmp.ia6t_vltime) { 1155151539Ssuz /* 1156151539Ssuz * The case of "invalid" address. We should usually 1157151539Ssuz * not see this case. 1158151539Ssuz */ 1159151539Ssuz remaininglifetime = 0; 1160151539Ssuz } else 1161151539Ssuz remaininglifetime = lt6_tmp.ia6t_vltime - 1162151539Ssuz (time_second - ifa6->ia6_updatetime); 116378064Sume 1164112678Sume /* when not updating, keep the current stored lifetime. */ 1165151539Ssuz lt6_tmp.ia6t_vltime = remaininglifetime; 1166112678Sume 116778064Sume if (TWOHOUR < new->ndpr_vltime || 1168151539Ssuz remaininglifetime < new->ndpr_vltime) { 116978064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 1170151539Ssuz } else if (remaininglifetime <= TWOHOUR) { 117178064Sume if (auth) { 117278064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 117378064Sume } 117478064Sume } else { 117578064Sume /* 117678064Sume * new->ndpr_vltime <= TWOHOUR && 1177151539Ssuz * TWOHOUR < remaininglifetime 117878064Sume */ 117978064Sume lt6_tmp.ia6t_vltime = TWOHOUR; 118053541Sshin } 118153541Sshin 118278064Sume /* The 2 hour rule is not imposed for preferred lifetime. */ 118378064Sume lt6_tmp.ia6t_pltime = new->ndpr_pltime; 118453541Sshin 118578064Sume in6_init_address_ltimes(pr, <6_tmp); 118653541Sshin 1187171260Sdelphij /* 1188151539Ssuz * We need to treat lifetimes for temporary addresses 1189151539Ssuz * differently, according to 1190151539Ssuz * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1); 1191151539Ssuz * we only update the lifetimes when they are in the maximum 1192151539Ssuz * intervals. 1193171260Sdelphij */ 1194171260Sdelphij if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 1195151539Ssuz u_int32_t maxvltime, maxpltime; 1196151539Ssuz 1197151539Ssuz if (ip6_temp_valid_lifetime > 1198151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1199151539Ssuz ip6_desync_factor)) { 1200151539Ssuz maxvltime = ip6_temp_valid_lifetime - 1201151539Ssuz (time_second - ifa6->ia6_createtime) - 1202151539Ssuz ip6_desync_factor; 1203151539Ssuz } else 1204151539Ssuz maxvltime = 0; 1205151539Ssuz if (ip6_temp_preferred_lifetime > 1206151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1207151539Ssuz ip6_desync_factor)) { 1208151539Ssuz maxpltime = ip6_temp_preferred_lifetime - 1209151539Ssuz (time_second - ifa6->ia6_createtime) - 1210151539Ssuz ip6_desync_factor; 1211151539Ssuz } else 1212151539Ssuz maxpltime = 0; 1213151539Ssuz 1214151539Ssuz if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME || 1215151539Ssuz lt6_tmp.ia6t_vltime > maxvltime) { 1216151539Ssuz lt6_tmp.ia6t_vltime = maxvltime; 121778064Sume } 1218151539Ssuz if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || 1219151539Ssuz lt6_tmp.ia6t_pltime > maxpltime) { 1220151539Ssuz lt6_tmp.ia6t_pltime = maxpltime; 122178064Sume } 122278064Sume } 122378064Sume ifa6->ia6_lifetime = lt6_tmp; 1224151539Ssuz ifa6->ia6_updatetime = time_second; 122553541Sshin } 122678064Sume if (ia6_match == NULL && new->ndpr_vltime) { 1227151539Ssuz int ifidlen; 1228151539Ssuz 122978064Sume /* 1230151539Ssuz * 5.5.3 (d) (continued) 123178064Sume * No address matched and the valid lifetime is non-zero. 123278064Sume * Create a new address. 123378064Sume */ 1234151539Ssuz 1235151539Ssuz /* 1236151539Ssuz * Prefix Length check: 1237151539Ssuz * If the sum of the prefix length and interface identifier 1238151539Ssuz * length does not equal 128 bits, the Prefix Information 1239151539Ssuz * option MUST be ignored. The length of the interface 1240151539Ssuz * identifier is defined in a separate link-type specific 1241151539Ssuz * document. 1242151539Ssuz */ 1243151539Ssuz ifidlen = in6_if2idlen(ifp); 1244151539Ssuz if (ifidlen < 0) { 1245151539Ssuz /* this should not happen, so we always log it. */ 1246151539Ssuz log(LOG_ERR, "prelist_update: IFID undefined (%s)\n", 1247151539Ssuz if_name(ifp)); 1248151539Ssuz goto end; 1249151539Ssuz } 1250151539Ssuz if (ifidlen + pr->ndpr_plen != 128) { 1251151539Ssuz nd6log((LOG_INFO, 1252151539Ssuz "prelist_update: invalid prefixlen " 1253151539Ssuz "%d for %s, ignored\n", 1254151539Ssuz pr->ndpr_plen, if_name(ifp))); 1255151539Ssuz goto end; 1256151539Ssuz } 1257151539Ssuz 1258151539Ssuz if ((ia6 = in6_ifadd(new, mcast)) != NULL) { 125978064Sume /* 126078064Sume * note that we should use pr (not new) for reference. 126178064Sume */ 126278064Sume pr->ndpr_refcnt++; 126378064Sume ia6->ia6_ndpr = pr; 126453541Sshin 126578064Sume /* 126678064Sume * RFC 3041 3.3 (2). 126778064Sume * When a new public address is created as described 126878064Sume * in RFC2462, also create a new temporary address. 126978064Sume * 127078064Sume * RFC 3041 3.5. 127178064Sume * When an interface connects to a new link, a new 127278064Sume * randomized interface identifier should be generated 127378064Sume * immediately together with a new set of temporary 127478064Sume * addresses. Thus, we specifiy 1 as the 2nd arg of 127578064Sume * in6_tmpifadd(). 127678064Sume */ 127778064Sume if (ip6_use_tempaddr) { 127878064Sume int e; 1279151539Ssuz if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) { 128078064Sume nd6log((LOG_NOTICE, "prelist_update: " 128178064Sume "failed to create a temporary " 128278064Sume "address, errno=%d\n", 128378064Sume e)); 128478064Sume } 128578064Sume } 128678064Sume 128778064Sume /* 128878064Sume * A newly added address might affect the status 128978064Sume * of other addresses, so we check and update it. 129078064Sume * XXX: what if address duplication happens? 129178064Sume */ 129278064Sume pfxlist_onlink_check(); 129378064Sume } else { 129478064Sume /* just set an error. do not bark here. */ 129578064Sume error = EADDRNOTAVAIL; /* XXX: might be unused. */ 129678064Sume } 129778064Sume } 129878064Sume 129953541Sshin end: 130053541Sshin splx(s); 130153541Sshin return error; 130253541Sshin} 130353541Sshin 130453541Sshin/* 130562587Sitojun * A supplement function used in the on-link detection below; 130662587Sitojun * detect if a given prefix has a (probably) reachable advertising router. 130762587Sitojun * XXX: lengthy function name... 130862587Sitojun */ 130978064Sumestatic struct nd_pfxrouter * 1310171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr) 131162587Sitojun{ 131262587Sitojun struct nd_pfxrouter *pfxrtr; 131362587Sitojun struct rtentry *rt; 131462587Sitojun struct llinfo_nd6 *ln; 131562587Sitojun 131662587Sitojun for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr; 131762587Sitojun pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { 131862587Sitojun if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0, 1319120941Sume pfxrtr->router->ifp)) && 132062587Sitojun (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 132162587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) 132262587Sitojun break; /* found */ 132362587Sitojun } 132462587Sitojun 1325120856Sume return (pfxrtr); 132662587Sitojun} 132762587Sitojun 132862587Sitojun/* 132953541Sshin * Check if each prefix in the prefix list has at least one available router 133078064Sume * that advertised the prefix (a router is "available" if its neighbor cache 133178064Sume * entry is reachable or probably reachable). 133262587Sitojun * If the check fails, the prefix may be off-link, because, for example, 133353541Sshin * we have moved from the network but the lifetime of the prefix has not 133478064Sume * expired yet. So we should not use the prefix if there is another prefix 133578064Sume * that has an available router. 133678064Sume * But, if there is no prefix that has an available router, we still regards 133778064Sume * all the prefixes as on-link. This is because we can't tell if all the 133853541Sshin * routers are simply dead or if we really moved from the network and there 133953541Sshin * is no router around us. 134053541Sshin */ 134162587Sitojunvoid 134253541Sshinpfxlist_onlink_check() 134353541Sshin{ 134453541Sshin struct nd_prefix *pr; 134578064Sume struct in6_ifaddr *ifa; 1346151539Ssuz struct nd_defrouter *dr; 1347151539Ssuz struct nd_pfxrouter *pfxrtr = NULL; 134853541Sshin 134962587Sitojun /* 135062587Sitojun * Check if there is a prefix that has a reachable advertising 135162587Sitojun * router. 135262587Sitojun */ 135362587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 135478064Sume if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 135553541Sshin break; 135662587Sitojun } 135753541Sshin 1358151539Ssuz /* 1359151539Ssuz * If we have no such prefix, check whether we still have a router 1360151539Ssuz * that does not advertise any prefixes. 1361151539Ssuz */ 1362151465Ssuz if (pr == NULL) { 1363151539Ssuz for (dr = TAILQ_FIRST(&nd_defrouter); dr; 1364151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 1365151539Ssuz struct nd_prefix *pr0; 1366151539Ssuz 1367151539Ssuz for (pr0 = nd_prefix.lh_first; pr0; 1368151539Ssuz pr0 = pr0->ndpr_next) { 1369151539Ssuz if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) 1370151539Ssuz break; 1371151539Ssuz } 1372151539Ssuz if (pfxrtr != NULL) 1373151539Ssuz break; 1374151539Ssuz } 1375151539Ssuz } 1376151539Ssuz if (pr != NULL || (TAILQ_FIRST(&nd_defrouter) && pfxrtr == NULL)) { 1377171260Sdelphij /* 1378151539Ssuz * There is at least one prefix that has a reachable router, 1379151539Ssuz * or at least a router which probably does not advertise 1380151539Ssuz * any prefixes. The latter would be the case when we move 1381151539Ssuz * to a new link where we have a router that does not provide 1382151539Ssuz * prefixes and we configure an address by hand. 1383171260Sdelphij * Detach prefixes which have no reachable advertising 1384171260Sdelphij * router, and attach other prefixes. 1385171260Sdelphij */ 138662587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 138778064Sume /* XXX: a link-local prefix should never be detached */ 138878064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 138978064Sume continue; 139078064Sume 139178064Sume /* 139278064Sume * we aren't interested in prefixes without the L bit 139378064Sume * set. 139478064Sume */ 139578064Sume if (pr->ndpr_raf_onlink == 0) 139678064Sume continue; 139778064Sume 139878064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 139978064Sume find_pfxlist_reachable_router(pr) == NULL) 140078064Sume pr->ndpr_stateflags |= NDPRF_DETACHED; 140178064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 140278064Sume find_pfxlist_reachable_router(pr) != 0) 140378064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 140453541Sshin } 140578064Sume } else { 140678064Sume /* there is no prefix that has a reachable router */ 140762587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 140878064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 140978064Sume continue; 141078064Sume 141178064Sume if (pr->ndpr_raf_onlink == 0) 141278064Sume continue; 141378064Sume 141478064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 141578064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 141653541Sshin } 141762587Sitojun } 141878064Sume 141978064Sume /* 142078064Sume * Remove each interface route associated with a (just) detached 142178064Sume * prefix, and reinstall the interface route for a (just) attached 142278064Sume * prefix. Note that all attempt of reinstallation does not 142378064Sume * necessarily success, when a same prefix is shared among multiple 142478064Sume * interfaces. Such cases will be handled in nd6_prefix_onlink, 142578064Sume * so we don't have to care about them. 142678064Sume */ 142778064Sume for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 142878064Sume int e; 1429165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 143078064Sume 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_ONLINK) != 0) { 143978064Sume if ((e = nd6_prefix_offlink(pr)) != 0) { 144078064Sume nd6log((LOG_ERR, 144178064Sume "pfxlist_onlink_check: failed to " 1442151479Ssuz "make %s/%d offlink, errno=%d\n", 1443165118Sbz ip6_sprintf(ip6buf, 1444165118Sbz &pr->ndpr_prefix.sin6_addr), 1445165118Sbz pr->ndpr_plen, e)); 144678064Sume } 144778064Sume } 144878064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 144978064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 145078064Sume pr->ndpr_raf_onlink) { 145178064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 145278064Sume nd6log((LOG_ERR, 145378064Sume "pfxlist_onlink_check: failed to " 1454151479Ssuz "make %s/%d onlink, errno=%d\n", 1455165118Sbz ip6_sprintf(ip6buf, 1456165118Sbz &pr->ndpr_prefix.sin6_addr), 1457165118Sbz pr->ndpr_plen, e)); 145878064Sume } 145978064Sume } 146078064Sume } 146178064Sume 146278064Sume /* 146378064Sume * Changes on the prefix status might affect address status as well. 146478064Sume * Make sure that all addresses derived from an attached prefix are 146578064Sume * attached, and that all addresses derived from a detached prefix are 146678064Sume * detached. Note, however, that a manually configured address should 146778064Sume * always be attached. 146878064Sume * The precise detection logic is same as the one for prefixes. 146978064Sume */ 147078064Sume for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 1471120941Sume if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) 147278064Sume continue; 147378064Sume 147478064Sume if (ifa->ia6_ndpr == NULL) { 147578064Sume /* 147678064Sume * This can happen when we first configure the address 147778064Sume * (i.e. the address exists, but the prefix does not). 147878064Sume * XXX: complicated relationships... 147978064Sume */ 148078064Sume continue; 148178064Sume } 148278064Sume 148378064Sume if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 148478064Sume break; 148578064Sume } 148678064Sume if (ifa) { 148778064Sume for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 148878064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 148978064Sume continue; 149078064Sume 149178064Sume if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 149278064Sume continue; 149378064Sume 1494151539Ssuz if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) { 1495151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1496151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1497151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1498151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1499151539Ssuz } 1500151539Ssuz } else { 150178064Sume ifa->ia6_flags |= IN6_IFF_DETACHED; 1502151539Ssuz } 150378064Sume } 150478064Sume } 150562587Sitojun else { 150678064Sume for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 150778064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 150878064Sume continue; 150978064Sume 1510151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1511151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1512151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1513151539Ssuz /* Do we need a delay in this case? */ 1514151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1515151539Ssuz } 151678064Sume } 151753541Sshin } 151853541Sshin} 151953541Sshin 152078064Sumeint 1521171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr) 152253541Sshin{ 152378064Sume struct ifaddr *ifa; 152478064Sume struct ifnet *ifp = pr->ndpr_ifp; 152578064Sume struct sockaddr_in6 mask6; 152678064Sume struct nd_prefix *opr; 152778064Sume u_long rtflags; 152878064Sume int error = 0; 152978064Sume struct rtentry *rt = NULL; 1530165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 153153541Sshin 153278064Sume /* sanity check */ 153378064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 153478064Sume nd6log((LOG_ERR, 153578064Sume "nd6_prefix_onlink: %s/%d is already on-link\n", 1536165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1537165118Sbz pr->ndpr_plen)); 1538151465Ssuz return (EEXIST); 153978064Sume } 154078064Sume 154153541Sshin /* 154278064Sume * Add the interface route associated with the prefix. Before 154378064Sume * installing the route, check if there's the same prefix on another 154478064Sume * interface, and the prefix has already installed the interface route. 154578064Sume * Although such a configuration is expected to be rare, we explicitly 154678064Sume * allow it. 154753541Sshin */ 154878064Sume for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 154978064Sume if (opr == pr) 155078064Sume continue; 155178064Sume 155278064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 155378064Sume continue; 155478064Sume 155578064Sume if (opr->ndpr_plen == pr->ndpr_plen && 155678064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1557120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) 1558120856Sume return (0); 155978064Sume } 156078064Sume 156178064Sume /* 1562120941Sume * We prefer link-local addresses as the associated interface address. 156378064Sume */ 156478064Sume /* search for a link-local addr */ 156578064Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 1566120941Sume IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); 156778064Sume if (ifa == NULL) { 156878064Sume /* XXX: freebsd does not have ifa_ifwithaf */ 1569120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 157078064Sume if (ifa->ifa_addr->sa_family == AF_INET6) 157178064Sume break; 157278064Sume } 157378064Sume /* should we care about ia6_flags? */ 157478064Sume } 157578064Sume if (ifa == NULL) { 157678064Sume /* 157778064Sume * This can still happen, when, for example, we receive an RA 157878064Sume * containing a prefix with the L bit set and the A bit clear, 157978064Sume * after removing all IPv6 addresses on the receiving 158078064Sume * interface. This should, of course, be rare though. 158178064Sume */ 158278064Sume nd6log((LOG_NOTICE, 158378064Sume "nd6_prefix_onlink: failed to find any ifaddr" 158478064Sume " to add route for a prefix(%s/%d) on %s\n", 1585165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 158678064Sume pr->ndpr_plen, if_name(ifp))); 1587120856Sume return (0); 158878064Sume } 158978064Sume 159078064Sume /* 159178064Sume * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 159278064Sume * ifa->ifa_rtrequest = nd6_rtrequest; 159378064Sume */ 159478064Sume bzero(&mask6, sizeof(mask6)); 159578064Sume mask6.sin6_len = sizeof(mask6); 159678064Sume mask6.sin6_addr = pr->ndpr_mask; 159778064Sume rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP; 159878064Sume if (nd6_need_cache(ifp)) { 159978064Sume /* explicitly set in case ifa_flags does not set the flag. */ 160078064Sume rtflags |= RTF_CLONING; 160178064Sume } else { 160278064Sume /* 160378064Sume * explicitly clear the cloning bit in case ifa_flags sets it. 160478064Sume */ 160578064Sume rtflags &= ~RTF_CLONING; 160678064Sume } 160778064Sume error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, 1608120941Sume ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt); 160978064Sume if (error == 0) { 161078064Sume if (rt != NULL) /* this should be non NULL, though */ 161178064Sume nd6_rtmsg(RTM_ADD, rt); 161278064Sume pr->ndpr_stateflags |= NDPRF_ONLINK; 1613120941Sume } else { 1614165118Sbz char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN]; 161578064Sume nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" 161678064Sume " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " 161778064Sume "errno = %d\n", 1618165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 161978064Sume pr->ndpr_plen, if_name(ifp), 1620165118Sbz ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), 1621165118Sbz ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error)); 162278064Sume } 162378064Sume 1624120727Ssam if (rt != NULL) { 1625120727Ssam RT_LOCK(rt); 1626122334Ssam RT_REMREF(rt); 1627120727Ssam RT_UNLOCK(rt); 1628120727Ssam } 162978064Sume 1630120856Sume return (error); 163178064Sume} 163278064Sume 163378064Sumeint 1634171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr) 163578064Sume{ 163678064Sume int error = 0; 163778064Sume struct ifnet *ifp = pr->ndpr_ifp; 163878064Sume struct nd_prefix *opr; 163978064Sume struct sockaddr_in6 sa6, mask6; 164078064Sume struct rtentry *rt = NULL; 1641165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 164278064Sume 164378064Sume /* sanity check */ 164478064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 164578064Sume nd6log((LOG_ERR, 164678064Sume "nd6_prefix_offlink: %s/%d is already off-link\n", 1647165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1648165118Sbz pr->ndpr_plen)); 1649120856Sume return (EEXIST); 165078064Sume } 165178064Sume 165253541Sshin bzero(&sa6, sizeof(sa6)); 165353541Sshin sa6.sin6_family = AF_INET6; 165453541Sshin sa6.sin6_len = sizeof(sa6); 165553541Sshin bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 1656120941Sume sizeof(struct in6_addr)); 165753541Sshin bzero(&mask6, sizeof(mask6)); 165853541Sshin mask6.sin6_family = AF_INET6; 165953541Sshin mask6.sin6_len = sizeof(sa6); 166053541Sshin bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 166178064Sume error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 1662120941Sume (struct sockaddr *)&mask6, 0, &rt); 166378064Sume if (error == 0) { 166478064Sume pr->ndpr_stateflags &= ~NDPRF_ONLINK; 166553541Sshin 166678064Sume /* report the route deletion to the routing socket. */ 166778064Sume if (rt != NULL) 166878064Sume nd6_rtmsg(RTM_DELETE, rt); 166953541Sshin 167078064Sume /* 167178064Sume * There might be the same prefix on another interface, 167278064Sume * the prefix which could not be on-link just because we have 167378064Sume * the interface route (see comments in nd6_prefix_onlink). 167478064Sume * If there's one, try to make the prefix on-link on the 167578064Sume * interface. 167678064Sume */ 167778064Sume for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 167878064Sume if (opr == pr) 167978064Sume continue; 168053541Sshin 168178064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 168278064Sume continue; 168353541Sshin 168478064Sume /* 168578064Sume * KAME specific: detached prefixes should not be 168678064Sume * on-link. 168778064Sume */ 168878064Sume if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 168978064Sume continue; 169078064Sume 169178064Sume if (opr->ndpr_plen == pr->ndpr_plen && 169278064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1693120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 169478064Sume int e; 169578064Sume 169678064Sume if ((e = nd6_prefix_onlink(opr)) != 0) { 169778064Sume nd6log((LOG_ERR, 169878064Sume "nd6_prefix_offlink: failed to " 169978064Sume "recover a prefix %s/%d from %s " 170078064Sume "to %s (errno = %d)\n", 1701165118Sbz ip6_sprintf(ip6buf, 1702165118Sbz &opr->ndpr_prefix.sin6_addr), 170378064Sume opr->ndpr_plen, if_name(ifp), 170478064Sume if_name(opr->ndpr_ifp), e)); 170578064Sume } 170678064Sume } 170778064Sume } 1708120941Sume } else { 170978064Sume /* XXX: can we still set the NDPRF_ONLINK flag? */ 171078064Sume nd6log((LOG_ERR, 171178064Sume "nd6_prefix_offlink: failed to delete route: " 171278064Sume "%s/%d on %s (errno = %d)\n", 1713165118Sbz ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen, 1714165118Sbz if_name(ifp), error)); 171578064Sume } 171653541Sshin 1717120941Sume if (rt != NULL) { 1718108269Sru RTFREE(rt); 1719120941Sume } 172053541Sshin 1721120856Sume return (error); 172253541Sshin} 172353541Sshin 172453541Sshinstatic struct in6_ifaddr * 1725171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast) 172653541Sshin{ 172778064Sume struct ifnet *ifp = pr->ndpr_ifp; 172853541Sshin struct ifaddr *ifa; 172978064Sume struct in6_aliasreq ifra; 173078064Sume struct in6_ifaddr *ia, *ib; 173178064Sume int error, plen0; 173253541Sshin struct in6_addr mask; 173378064Sume int prefixlen = pr->ndpr_plen; 1734151539Ssuz int updateflags; 1735165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 173653541Sshin 1737121168Sume in6_prefixlen2mask(&mask, prefixlen); 173853541Sshin 173978064Sume /* 174078064Sume * find a link-local address (will be interface ID). 174178064Sume * Is it really mandatory? Theoretically, a global or a site-local 174278064Sume * address can be configured without a link-local address, if we 174378064Sume * have a unique interface identifier... 174478064Sume * 174578064Sume * it is not mandatory to have a link-local address, we can generate 174678064Sume * interface identifier on the fly. we do this because: 174778064Sume * (1) it should be the easiest way to find interface identifier. 174878064Sume * (2) RFC2462 5.4 suggesting the use of the same interface identifier 174978064Sume * for multiple addresses on a single interface, and possible shortcut 175078064Sume * of DAD. we omitted DAD for this reason in the past. 1751120941Sume * (3) a user can prevent autoconfiguration of global address 175278064Sume * by removing link-local address by hand (this is partly because we 1753108533Sschweikh * don't have other way to control the use of IPv6 on an interface. 175478064Sume * this has been our design choice - cf. NRL's "ifconfig auto"). 175578064Sume * (4) it is easier to manage when an interface has addresses 175678064Sume * with the same interface identifier, than to have multiple addresses 175778064Sume * with different interface identifiers. 175878064Sume */ 1759120941Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ 176053541Sshin if (ifa) 176153541Sshin ib = (struct in6_ifaddr *)ifa; 176253541Sshin else 176353541Sshin return NULL; 176453541Sshin 176553541Sshin /* prefixlen + ifidlen must be equal to 128 */ 176678064Sume plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 176778064Sume if (prefixlen != plen0) { 176878064Sume nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 176978064Sume "(prefix=%d ifid=%d)\n", 177078064Sume if_name(ifp), prefixlen, 128 - plen0)); 177153541Sshin return NULL; 177253541Sshin } 177353541Sshin 177453541Sshin /* make ifaddr */ 177553541Sshin 177678064Sume bzero(&ifra, sizeof(ifra)); 177778064Sume /* 177878064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 177978064Sume * for safety. 178078064Sume */ 178178064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 178278064Sume ifra.ifra_addr.sin6_family = AF_INET6; 178378064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 178478064Sume /* prefix */ 1785151539Ssuz ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr; 178678064Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 178778064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 178878064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 178978064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 179053541Sshin 179153541Sshin /* interface ID */ 1792120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] |= 1793151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); 1794120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] |= 1795151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); 1796120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1797151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); 1798120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1799151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); 1800120941Sume 180178064Sume /* new prefix mask. */ 180278064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 180378064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 180478064Sume bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 1805120941Sume sizeof(ifra.ifra_prefixmask.sin6_addr)); 180653541Sshin 1807151539Ssuz /* lifetimes. */ 180878064Sume ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 180978064Sume ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 181053541Sshin 181178064Sume /* XXX: scope zone ID? */ 181253541Sshin 181378064Sume ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 1814151539Ssuz 1815171260Sdelphij /* 1816151539Ssuz * Make sure that we do not have this address already. This should 1817151539Ssuz * usually not happen, but we can still see this case, e.g., if we 1818151539Ssuz * have manually configured the exact address to be configured. 181978064Sume */ 1820151539Ssuz if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { 1821151539Ssuz /* this should be rare enough to make an explicit log */ 1822151539Ssuz log(LOG_INFO, "in6_ifadd: %s is already configured\n", 1823165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr)); 1824151539Ssuz return (NULL); 1825151539Ssuz } 182653541Sshin 182753541Sshin /* 1828151539Ssuz * Allocate ifaddr structure, link into chain, etc. 1829151539Ssuz * If we are going to create a new address upon receiving a multicasted 1830151539Ssuz * RA, we need to impose a random delay before starting DAD. 1831151539Ssuz * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] 183253541Sshin */ 1833151539Ssuz updateflags = 0; 1834151539Ssuz if (mcast) 1835151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1836151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { 183778064Sume nd6log((LOG_ERR, 183878064Sume "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 1839165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr), 1840165118Sbz if_name(ifp), error)); 1841120856Sume return (NULL); /* ifaddr must not have been allocated. */ 184253541Sshin } 184353541Sshin 184478064Sume ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 184553541Sshin 1846120941Sume return (ia); /* this is always non-NULL */ 184753541Sshin} 184853541Sshin 1849171259Sdelphij/* 1850171259Sdelphij * ia0 - corresponding public address 1851171259Sdelphij */ 185253541Sshinint 1853171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) 185453541Sshin{ 185578064Sume struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 1856151539Ssuz struct in6_ifaddr *newia, *ia; 185778064Sume struct in6_aliasreq ifra; 185878064Sume int i, error; 185978064Sume int trylimit = 3; /* XXX: adhoc value */ 1860151539Ssuz int updateflags; 186178064Sume u_int32_t randid[2]; 186278064Sume time_t vltime0, pltime0; 186353541Sshin 186478064Sume bzero(&ifra, sizeof(ifra)); 186578064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 186678064Sume ifra.ifra_addr = ia0->ia_addr; 186778064Sume /* copy prefix mask */ 186878064Sume ifra.ifra_prefixmask = ia0->ia_prefixmask; 186978064Sume /* clear the old IFID */ 187078064Sume for (i = 0; i < 4; i++) { 1871120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[i] &= 1872120941Sume ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 187378064Sume } 187453541Sshin 187578064Sume again: 1876151539Ssuz if (in6_get_tmpifid(ifp, (u_int8_t *)randid, 1877151539Ssuz (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { 1878151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good " 1879151539Ssuz "random IFID\n")); 1880151539Ssuz return (EINVAL); 1881151539Ssuz } 1882120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1883120941Sume (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 1884120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1885120941Sume (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 188653541Sshin 1887171260Sdelphij /* 1888151539Ssuz * in6_get_tmpifid() quite likely provided a unique interface ID. 1889151539Ssuz * However, we may still have a chance to see collision, because 1890151539Ssuz * there may be a time lag between generation of the ID and generation 1891151539Ssuz * of the address. So, we'll do one more sanity check. 189278064Sume */ 1893151539Ssuz for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 1894151539Ssuz if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 1895151539Ssuz &ifra.ifra_addr.sin6_addr)) { 1896171260Sdelphij if (trylimit-- == 0) { 1897151539Ssuz /* 1898151539Ssuz * Give up. Something strange should have 1899151539Ssuz * happened. 1900151539Ssuz */ 1901151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " 1902151539Ssuz "find a unique random IFID\n")); 1903151539Ssuz return (EEXIST); 1904151539Ssuz } 1905151539Ssuz forcegen = 1; 1906151539Ssuz goto again; 190778064Sume } 190853541Sshin } 190953541Sshin 191078064Sume /* 191178064Sume * The Valid Lifetime is the lower of the Valid Lifetime of the 191278064Sume * public address or TEMP_VALID_LIFETIME. 191378064Sume * The Preferred Lifetime is the lower of the Preferred Lifetime 191478064Sume * of the public address or TEMP_PREFERRED_LIFETIME - 191578064Sume * DESYNC_FACTOR. 191678064Sume */ 1917151539Ssuz if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 191878064Sume vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 1919151539Ssuz (ia0->ia6_lifetime.ia6t_vltime - 1920151539Ssuz (time_second - ia0->ia6_updatetime)); 192178064Sume if (vltime0 > ip6_temp_valid_lifetime) 192278064Sume vltime0 = ip6_temp_valid_lifetime; 192378064Sume } else 192478064Sume vltime0 = ip6_temp_valid_lifetime; 1925151539Ssuz if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 192678064Sume pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 1927151539Ssuz (ia0->ia6_lifetime.ia6t_pltime - 1928151539Ssuz (time_second - ia0->ia6_updatetime)); 192978064Sume if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){ 193078064Sume pltime0 = ip6_temp_preferred_lifetime - 1931120941Sume ip6_desync_factor; 193278064Sume } 193378064Sume } else 193478064Sume pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor; 193578064Sume ifra.ifra_lifetime.ia6t_vltime = vltime0; 193678064Sume ifra.ifra_lifetime.ia6t_pltime = pltime0; 193753541Sshin 193878064Sume /* 193978064Sume * A temporary address is created only if this calculated Preferred 194078064Sume * Lifetime is greater than REGEN_ADVANCE time units. 194178064Sume */ 194278064Sume if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance) 1943120856Sume return (0); 194453541Sshin 194578064Sume /* XXX: scope zone ID? */ 194678064Sume 194778064Sume ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 194878064Sume 194978064Sume /* allocate ifaddr structure, link into chain, etc. */ 1950151539Ssuz updateflags = 0; 1951151539Ssuz if (delay) 1952151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1953151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) 1954120856Sume return (error); 195578064Sume 195678064Sume newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 195778064Sume if (newia == NULL) { /* XXX: can it happen? */ 195878064Sume nd6log((LOG_ERR, 195978064Sume "in6_tmpifadd: ifa update succeeded, but we got " 196078064Sume "no ifaddr\n")); 1961120856Sume return (EINVAL); /* XXX */ 196253541Sshin } 196378064Sume newia->ia6_ndpr = ia0->ia6_ndpr; 196478064Sume newia->ia6_ndpr->ndpr_refcnt++; 196553541Sshin 196678407Sume /* 196778407Sume * A newly added address might affect the status of other addresses. 196878407Sume * XXX: when the temporary address is generated with a new public 196978407Sume * address, the onlink check is redundant. However, it would be safe 197078407Sume * to do the check explicitly everywhere a new address is generated, 197178407Sume * and, in fact, we surely need the check when we create a new 197278407Sume * temporary address due to deprecation of an old temporary address. 197378407Sume */ 197478407Sume pfxlist_onlink_check(); 197578407Sume 1976120856Sume return (0); 1977120941Sume} 197853541Sshin 1979151539Ssuzstatic int 198053541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr) 198153541Sshin{ 198253541Sshin if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 198353541Sshin ndpr->ndpr_preferred = 0; 198453541Sshin else 198553541Sshin ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; 198653541Sshin if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 198753541Sshin ndpr->ndpr_expire = 0; 198853541Sshin else 198953541Sshin ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; 199053541Sshin 199153541Sshin return 0; 199253541Sshin} 199353541Sshin 199453541Sshinstatic void 199578064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 199653541Sshin{ 199778064Sume /* init ia6t_expire */ 199878064Sume if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 199978064Sume lt6->ia6t_expire = 0; 200078064Sume else { 200178064Sume lt6->ia6t_expire = time_second; 200278064Sume lt6->ia6t_expire += lt6->ia6t_vltime; 200353541Sshin } 200462587Sitojun 200553541Sshin /* init ia6t_preferred */ 200653541Sshin if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 200753541Sshin lt6->ia6t_preferred = 0; 200853541Sshin else { 200953541Sshin lt6->ia6t_preferred = time_second; 201053541Sshin lt6->ia6t_preferred += lt6->ia6t_pltime; 201153541Sshin } 201253541Sshin} 201353541Sshin 201453541Sshin/* 201553541Sshin * Delete all the routing table entries that use the specified gateway. 201653541Sshin * XXX: this function causes search through all entries of routing table, so 201753541Sshin * it shouldn't be called when acting as a router. 201853541Sshin */ 201953541Sshinvoid 2020171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp) 202153541Sshin{ 202253541Sshin struct radix_node_head *rnh = rt_tables[AF_INET6]; 202353541Sshin int s = splnet(); 202453541Sshin 202553541Sshin /* We'll care only link-local addresses */ 202653541Sshin if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { 202753541Sshin splx(s); 202853541Sshin return; 202953541Sshin } 203053541Sshin 2031108250Shsu RADIX_NODE_HEAD_LOCK(rnh); 203253541Sshin rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 2033108250Shsu RADIX_NODE_HEAD_UNLOCK(rnh); 203453541Sshin splx(s); 203553541Sshin} 203653541Sshin 203753541Sshinstatic int 2038171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg) 203953541Sshin{ 204053541Sshin#define SIN6(s) ((struct sockaddr_in6 *)s) 204153541Sshin struct rtentry *rt = (struct rtentry *)rn; 204253541Sshin struct in6_addr *gate = (struct in6_addr *)arg; 204353541Sshin 204453541Sshin if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 2045120856Sume return (0); 204653541Sshin 2047120941Sume if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) { 2048120856Sume return (0); 2049120941Sume } 205053541Sshin 205153541Sshin /* 205278064Sume * Do not delete a static route. 205378064Sume * XXX: this seems to be a bit ad-hoc. Should we consider the 205478064Sume * 'cloned' bit instead? 205578064Sume */ 205678064Sume if ((rt->rt_flags & RTF_STATIC) != 0) 2057120856Sume return (0); 205878064Sume 205978064Sume /* 206053541Sshin * We delete only host route. This means, in particular, we don't 206153541Sshin * delete default route. 206253541Sshin */ 206353541Sshin if ((rt->rt_flags & RTF_HOST) == 0) 2064120856Sume return (0); 206553541Sshin 2066120941Sume return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 2067120941Sume rt_mask(rt), rt->rt_flags, 0)); 206853541Sshin#undef SIN6 206953541Sshin} 207062587Sitojun 207162587Sitojunint 2072171259Sdelphijnd6_setdefaultiface(int ifindex) 207362587Sitojun{ 207462587Sitojun int error = 0; 207562587Sitojun 207662587Sitojun if (ifindex < 0 || if_index < ifindex) 2077120856Sume return (EINVAL); 2078151539Ssuz if (ifindex != 0 && !ifnet_byindex(ifindex)) 2079151539Ssuz return (EINVAL); 208062587Sitojun 208162587Sitojun if (nd6_defifindex != ifindex) { 208262587Sitojun nd6_defifindex = ifindex; 208362587Sitojun if (nd6_defifindex > 0) 208483130Sjlemon nd6_defifp = ifnet_byindex(nd6_defifindex); 208562587Sitojun else 208662587Sitojun nd6_defifp = NULL; 208762587Sitojun 208862587Sitojun /* 208962587Sitojun * Our current implementation assumes one-to-one maping between 209062587Sitojun * interfaces and links, so it would be natural to use the 209162587Sitojun * default interface as the default link. 209262587Sitojun */ 209362587Sitojun scope6_setdefault(nd6_defifp); 209462587Sitojun } 209562587Sitojun 2096120856Sume return (error); 209762587Sitojun} 2098