nd6_rtr.c revision 171259
162587Sitojun/* $FreeBSD: head/sys/netinet6/nd6_rtr.c 171259 2007-07-05 16:23:49Z delphij $ */ 278064Sume/* $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $ */ 362587Sitojun 4139826Simp/*- 553541Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 653541Sshin * All rights reserved. 753541Sshin * 853541Sshin * Redistribution and use in source and binary forms, with or without 953541Sshin * modification, are permitted provided that the following conditions 1053541Sshin * are met: 1153541Sshin * 1. Redistributions of source code must retain the above copyright 1253541Sshin * notice, this list of conditions and the following disclaimer. 1353541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1453541Sshin * notice, this list of conditions and the following disclaimer in the 1553541Sshin * documentation and/or other materials provided with the distribution. 1653541Sshin * 3. Neither the name of the project nor the names of its contributors 1753541Sshin * may be used to endorse or promote products derived from this software 1853541Sshin * without specific prior written permission. 1953541Sshin * 2053541Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2153541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2253541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2353541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2453541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2553541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2653541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2753541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2853541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2953541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3053541Sshin * SUCH DAMAGE. 3153541Sshin */ 3253541Sshin 3362587Sitojun#include "opt_inet.h" 3462587Sitojun#include "opt_inet6.h" 3562587Sitojun 3653541Sshin#include <sys/param.h> 3753541Sshin#include <sys/systm.h> 3853541Sshin#include <sys/malloc.h> 3953541Sshin#include <sys/mbuf.h> 4053541Sshin#include <sys/socket.h> 4153541Sshin#include <sys/sockio.h> 4253541Sshin#include <sys/time.h> 4378064Sume#include <sys/kernel.h> 4453541Sshin#include <sys/errno.h> 4553541Sshin#include <sys/syslog.h> 4678064Sume#include <sys/queue.h> 4753541Sshin 4853541Sshin#include <net/if.h> 4953541Sshin#include <net/if_types.h> 5053541Sshin#include <net/if_dl.h> 5153541Sshin#include <net/route.h> 5253541Sshin#include <net/radix.h> 5353541Sshin 5453541Sshin#include <netinet/in.h> 5553541Sshin#include <netinet6/in6_var.h> 5678064Sume#include <netinet6/in6_ifattach.h> 5762587Sitojun#include <netinet/ip6.h> 5853541Sshin#include <netinet6/ip6_var.h> 5953541Sshin#include <netinet6/nd6.h> 6062587Sitojun#include <netinet/icmp6.h> 6162587Sitojun#include <netinet6/scope6_var.h> 6253541Sshin 6362587Sitojun#define SDL(s) ((struct sockaddr_dl *)s) 6453541Sshin 65151539Ssuzstatic int rtpref __P((struct nd_defrouter *)); 6662587Sitojunstatic struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *)); 67151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *, 68151539Ssuz struct mbuf *, int)); 69151539Ssuzstatic struct in6_ifaddr *in6_ifadd __P((struct nd_prefixctl *, int)); 7062587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, 7178064Sume struct nd_defrouter *)); 7262587Sitojunstatic void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *)); 7362587Sitojunstatic void pfxrtr_del __P((struct nd_pfxrouter *)); 7462587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router 7578064Sume __P((struct nd_prefix *)); 76151539Ssuzstatic void defrouter_delreq __P((struct nd_defrouter *)); 7778064Sumestatic void nd6_rtmsg __P((int, struct rtentry *)); 7853541Sshin 79151539Ssuzstatic int in6_init_prefix_ltimes __P((struct nd_prefix *)); 80120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *, 81120941Sume struct in6_addrlifetime *)); 8253541Sshin 8362587Sitojunstatic int rt6_deleteroute __P((struct radix_node *, void *)); 8453541Sshin 8562587Sitojunextern int nd6_recalc_reachtm_interval; 8653541Sshin 8778064Sumestatic struct ifnet *nd6_defifp; 8862587Sitojunint nd6_defifindex; 8962587Sitojun 9078064Sumeint ip6_use_tempaddr = 0; 9178064Sume 9278064Sumeint ip6_desync_factor; 9378064Sumeu_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME; 9478064Sumeu_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME; 9553541Sshin/* 9678064Sume * shorter lifetimes for debugging purposes. 9778064Sumeint ip6_temp_preferred_lifetime = 800; 9878064Sumestatic int ip6_temp_valid_lifetime = 1800; 9978064Sume*/ 10078064Sumeint ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE; 10178064Sume 102151539Ssuz/* RTPREF_MEDIUM has to be 0! */ 103151539Ssuz#define RTPREF_HIGH 1 104151539Ssuz#define RTPREF_MEDIUM 0 105151539Ssuz#define RTPREF_LOW (-1) 106151539Ssuz#define RTPREF_RESERVED (-2) 107151539Ssuz#define RTPREF_INVALID (-3) /* internal */ 108151539Ssuz 10978064Sume/* 11053541Sshin * Receive Router Solicitation Message - just for routers. 11153541Sshin * Router solicitation/advertisement is mostly managed by userland program 11253541Sshin * (rtadvd) so here we have no function like nd6_ra_output(). 11353541Sshin * 11453541Sshin * Based on RFC 2461 11553541Sshin */ 11653541Sshinvoid 117171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len) 11853541Sshin{ 11953541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 12053541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 12162587Sitojun struct nd_router_solicit *nd_rs; 12253541Sshin struct in6_addr saddr6 = ip6->ip6_src; 12353541Sshin char *lladdr = NULL; 12453541Sshin int lladdrlen = 0; 12553541Sshin union nd_opts ndopts; 126165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 12753541Sshin 12853541Sshin /* If I'm not a router, ignore it. */ 12953541Sshin if (ip6_accept_rtadv != 0 || ip6_forwarding != 1) 13062587Sitojun goto freeit; 13153541Sshin 13253541Sshin /* Sanity checks */ 13353541Sshin if (ip6->ip6_hlim != 255) { 13478064Sume nd6log((LOG_ERR, 13578064Sume "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 136165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 137165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 13878064Sume goto bad; 13953541Sshin } 14053541Sshin 14153541Sshin /* 14253541Sshin * Don't update the neighbor cache, if src = ::. 14353541Sshin * This indicates that the src has no IP address assigned yet. 14453541Sshin */ 14553541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 14662587Sitojun goto freeit; 14762587Sitojun 14862587Sitojun#ifndef PULLDOWN_TEST 14962587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 15062587Sitojun nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 15162587Sitojun#else 15262587Sitojun IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 15362587Sitojun if (nd_rs == NULL) { 15462587Sitojun icmp6stat.icp6s_tooshort++; 15553541Sshin return; 15662587Sitojun } 15762587Sitojun#endif 15853541Sshin 15953541Sshin icmp6len -= sizeof(*nd_rs); 16053541Sshin nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 16153541Sshin if (nd6_options(&ndopts) < 0) { 16278064Sume nd6log((LOG_INFO, 16378064Sume "nd6_rs_input: invalid ND option, ignored\n")); 16478064Sume /* nd6_options have incremented stats */ 16562587Sitojun goto freeit; 16653541Sshin } 16753541Sshin 16853541Sshin if (ndopts.nd_opts_src_lladdr) { 16953541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 17053541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 17153541Sshin } 17253541Sshin 17353541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 17478064Sume nd6log((LOG_INFO, 17553541Sshin "nd6_rs_input: lladdrlen mismatch for %s " 17653541Sshin "(if %d, RS packet %d)\n", 177165118Sbz ip6_sprintf(ip6bufs, &saddr6), 178120941Sume ifp->if_addrlen, lladdrlen - 2)); 17978064Sume goto bad; 18053541Sshin } 18153541Sshin 18253541Sshin nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 18362587Sitojun 18462587Sitojun freeit: 18562587Sitojun m_freem(m); 18678064Sume return; 18778064Sume 18878064Sume bad: 18978064Sume icmp6stat.icp6s_badrs++; 19078064Sume m_freem(m); 19153541Sshin} 19253541Sshin 19353541Sshin/* 19453541Sshin * Receive Router Advertisement Message. 19553541Sshin * 19653541Sshin * Based on RFC 2461 19753541Sshin * TODO: on-link bit on prefix information 19853541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 19953541Sshin */ 20053541Sshinvoid 201171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len) 20253541Sshin{ 20353541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 204121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 20553541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 20662587Sitojun struct nd_router_advert *nd_ra; 20753541Sshin struct in6_addr saddr6 = ip6->ip6_src; 208151539Ssuz int mcast = 0; 20953541Sshin union nd_opts ndopts; 21053541Sshin struct nd_defrouter *dr; 211165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 21253541Sshin 213118498Sume /* 214118498Sume * We only accept RAs only when 215118498Sume * the system-wide variable allows the acceptance, and 216118498Sume * per-interface variable allows RAs on the receiving interface. 217118498Sume */ 21853541Sshin if (ip6_accept_rtadv == 0) 21962587Sitojun goto freeit; 220118498Sume if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 221118498Sume goto freeit; 22253541Sshin 22353541Sshin if (ip6->ip6_hlim != 255) { 22478064Sume nd6log((LOG_ERR, 22578064Sume "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 226165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 227165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 22878064Sume goto bad; 22953541Sshin } 23053541Sshin 23153541Sshin if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 23278064Sume nd6log((LOG_ERR, 23353541Sshin "nd6_ra_input: src %s is not link-local\n", 234165118Sbz ip6_sprintf(ip6bufs, &saddr6))); 23578064Sume goto bad; 23662587Sitojun } 23762587Sitojun 23862587Sitojun#ifndef PULLDOWN_TEST 23962587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 24062587Sitojun nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); 24162587Sitojun#else 24262587Sitojun IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); 24362587Sitojun if (nd_ra == NULL) { 24462587Sitojun icmp6stat.icp6s_tooshort++; 24553541Sshin return; 24653541Sshin } 24762587Sitojun#endif 24853541Sshin 24953541Sshin icmp6len -= sizeof(*nd_ra); 25053541Sshin nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 25153541Sshin if (nd6_options(&ndopts) < 0) { 25278064Sume nd6log((LOG_INFO, 25378064Sume "nd6_ra_input: invalid ND option, ignored\n")); 25478064Sume /* nd6_options have incremented stats */ 25562587Sitojun goto freeit; 25653541Sshin } 25753541Sshin 25853541Sshin { 25953541Sshin struct nd_defrouter dr0; 26053541Sshin u_int32_t advreachable = nd_ra->nd_ra_reachable; 26153541Sshin 262151539Ssuz /* remember if this is a multicasted advertisement */ 263151539Ssuz if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 264151539Ssuz mcast = 1; 265151539Ssuz 266151539Ssuz bzero(&dr0, sizeof(dr0)); 26753541Sshin dr0.rtaddr = saddr6; 26853541Sshin dr0.flags = nd_ra->nd_ra_flags_reserved; 269156871Ssuz dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 27053541Sshin dr0.expire = time_second + dr0.rtlifetime; 27153541Sshin dr0.ifp = ifp; 27253541Sshin /* unspecified or not? (RFC 2461 6.3.4) */ 27353541Sshin if (advreachable) { 27490868Smike advreachable = ntohl(advreachable); 27553541Sshin if (advreachable <= MAX_REACHABLE_TIME && 27653541Sshin ndi->basereachable != advreachable) { 27753541Sshin ndi->basereachable = advreachable; 27853541Sshin ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 27953541Sshin ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */ 28053541Sshin } 28153541Sshin } 28253541Sshin if (nd_ra->nd_ra_retransmit) 28353541Sshin ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 28453541Sshin if (nd_ra->nd_ra_curhoplimit) 28553541Sshin ndi->chlim = nd_ra->nd_ra_curhoplimit; 28653541Sshin dr = defrtrlist_update(&dr0); 28753541Sshin } 28853541Sshin 28953541Sshin /* 29053541Sshin * prefix 29153541Sshin */ 29253541Sshin if (ndopts.nd_opts_pi) { 29353541Sshin struct nd_opt_hdr *pt; 29478064Sume struct nd_opt_prefix_info *pi = NULL; 295151539Ssuz struct nd_prefixctl pr; 29653541Sshin 29753541Sshin for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 29853541Sshin pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 29953541Sshin pt = (struct nd_opt_hdr *)((caddr_t)pt + 30053541Sshin (pt->nd_opt_len << 3))) { 30153541Sshin if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 30253541Sshin continue; 30353541Sshin pi = (struct nd_opt_prefix_info *)pt; 30453541Sshin 30553541Sshin if (pi->nd_opt_pi_len != 4) { 30678064Sume nd6log((LOG_INFO, 30778064Sume "nd6_ra_input: invalid option " 30878064Sume "len %d for prefix information option, " 30978064Sume "ignored\n", pi->nd_opt_pi_len)); 31053541Sshin continue; 31153541Sshin } 31253541Sshin 31353541Sshin if (128 < pi->nd_opt_pi_prefix_len) { 31478064Sume nd6log((LOG_INFO, 31578064Sume "nd6_ra_input: invalid prefix " 31678064Sume "len %d for prefix information option, " 31778064Sume "ignored\n", pi->nd_opt_pi_prefix_len)); 31853541Sshin continue; 31953541Sshin } 32053541Sshin 32153541Sshin if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 32253541Sshin || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 32378064Sume nd6log((LOG_INFO, 32478064Sume "nd6_ra_input: invalid prefix " 32578064Sume "%s, ignored\n", 326165118Sbz ip6_sprintf(ip6bufs, 327165118Sbz &pi->nd_opt_pi_prefix))); 32853541Sshin continue; 32953541Sshin } 33053541Sshin 33153541Sshin bzero(&pr, sizeof(pr)); 33253541Sshin pr.ndpr_prefix.sin6_family = AF_INET6; 33353541Sshin pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 33453541Sshin pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 33553541Sshin pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 33653541Sshin 33753541Sshin pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 338120941Sume ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 33953541Sshin pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 340120941Sume ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 34153541Sshin pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 34253541Sshin pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 343120941Sume pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); 344151539Ssuz (void)prelist_update(&pr, dr, m, mcast); 34553541Sshin } 34653541Sshin } 34753541Sshin 34853541Sshin /* 34953541Sshin * MTU 35053541Sshin */ 35153541Sshin if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 352121283Sume u_long mtu; 353121283Sume u_long maxmtu; 35453541Sshin 355121283Sume mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 356120941Sume 35753541Sshin /* lower bound */ 35853541Sshin if (mtu < IPV6_MMTU) { 35978064Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " 360121283Sume "mtu=%lu sent from %s, ignoring\n", 361165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src))); 36253541Sshin goto skip; 36353541Sshin } 36453541Sshin 36553541Sshin /* upper bound */ 366121283Sume maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu) 367121283Sume ? ndi->maxmtu : ifp->if_mtu; 368121283Sume if (mtu <= maxmtu) { 369121283Sume int change = (ndi->linkmtu != mtu); 37053541Sshin 371121283Sume ndi->linkmtu = mtu; 372121283Sume if (change) /* in6_maxmtu may change */ 373121283Sume in6_setmaxmtu(); 37453541Sshin } else { 375121283Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " 376121283Sume "mtu=%lu sent from %s; " 377121283Sume "exceeds maxmtu %lu, ignoring\n", 378165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu)); 37953541Sshin } 38053541Sshin } 38153541Sshin 38253541Sshin skip: 383120941Sume 38453541Sshin /* 38595023Ssuz * Source link layer address 38653541Sshin */ 38753541Sshin { 38853541Sshin char *lladdr = NULL; 38953541Sshin int lladdrlen = 0; 390120941Sume 39153541Sshin if (ndopts.nd_opts_src_lladdr) { 39253541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 39353541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 39453541Sshin } 39553541Sshin 39653541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 39778064Sume nd6log((LOG_INFO, 39853541Sshin "nd6_ra_input: lladdrlen mismatch for %s " 399165118Sbz "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6), 400120941Sume ifp->if_addrlen, lladdrlen - 2)); 40178064Sume goto bad; 40253541Sshin } 40353541Sshin 404120941Sume nd6_cache_lladdr(ifp, &saddr6, lladdr, 405120941Sume lladdrlen, ND_ROUTER_ADVERT, 0); 40662587Sitojun 40762587Sitojun /* 40862587Sitojun * Installing a link-layer address might change the state of the 40962587Sitojun * router's neighbor cache, which might also affect our on-link 41062587Sitojun * detection of adveritsed prefixes. 41162587Sitojun */ 41262587Sitojun pfxlist_onlink_check(); 41353541Sshin } 41462587Sitojun 41578064Sume freeit: 41662587Sitojun m_freem(m); 41778064Sume return; 41878064Sume 41978064Sume bad: 42078064Sume icmp6stat.icp6s_badra++; 42178064Sume m_freem(m); 42253541Sshin} 42353541Sshin 42453541Sshin/* 42553541Sshin * default router list proccessing sub routines 42653541Sshin */ 42762587Sitojun 42862587Sitojun/* tell the change to user processes watching the routing socket. */ 42962587Sitojunstatic void 430171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt) 43162587Sitojun{ 43262587Sitojun struct rt_addrinfo info; 43362587Sitojun 43462587Sitojun bzero((caddr_t)&info, sizeof(info)); 43562587Sitojun info.rti_info[RTAX_DST] = rt_key(rt); 43662587Sitojun info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 43762587Sitojun info.rti_info[RTAX_NETMASK] = rt_mask(rt); 438151539Ssuz if (rt->rt_ifp) { 439151539Ssuz info.rti_info[RTAX_IFP] = 440151539Ssuz TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 441151539Ssuz info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 442151539Ssuz } 44362587Sitojun 44462587Sitojun rt_missmsg(cmd, &info, rt->rt_flags, 0); 44562587Sitojun} 44662587Sitojun 44753541Sshinvoid 448171259Sdelphijdefrouter_addreq(struct nd_defrouter *new) 44953541Sshin{ 45053541Sshin struct sockaddr_in6 def, mask, gate; 45162587Sitojun struct rtentry *newrt = NULL; 452151539Ssuz int s; 453151539Ssuz int error; 45453541Sshin 455128397Sluigi bzero(&def, sizeof(def)); 456128397Sluigi bzero(&mask, sizeof(mask)); 457128397Sluigi bzero(&gate, sizeof(gate)); 45853541Sshin 459120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 460120941Sume sizeof(struct sockaddr_in6); 461151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 46253541Sshin gate.sin6_addr = new->rtaddr; 46353541Sshin 464151539Ssuz s = splnet(); 465151539Ssuz error = rtrequest(RTM_ADD, (struct sockaddr *)&def, 466120941Sume (struct sockaddr *)&gate, (struct sockaddr *)&mask, 467120941Sume RTF_GATEWAY, &newrt); 46862587Sitojun if (newrt) { 469120727Ssam RT_LOCK(newrt); 47078064Sume nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 471122334Ssam RT_REMREF(newrt); 472120727Ssam RT_UNLOCK(newrt); 47362587Sitojun } 474151539Ssuz if (error == 0) 475151539Ssuz new->installed = 1; 476151539Ssuz splx(s); 47753541Sshin return; 47853541Sshin} 47953541Sshin 48053541Sshinstruct nd_defrouter * 481171259Sdelphijdefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) 48253541Sshin{ 48353541Sshin struct nd_defrouter *dr; 48453541Sshin 48562587Sitojun for (dr = TAILQ_FIRST(&nd_defrouter); dr; 48662587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 48753541Sshin if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 488120856Sume return (dr); 48962587Sitojun } 49053541Sshin 491120856Sume return (NULL); /* search failed */ 49253541Sshin} 49353541Sshin 494151539Ssuz/* 495151539Ssuz * Remove the default route for a given router. 496151539Ssuz * This is just a subroutine function for defrouter_select(), and should 497151539Ssuz * not be called from anywhere else. 498151539Ssuz */ 499151539Ssuzstatic void 500171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr) 50153541Sshin{ 50253541Sshin struct sockaddr_in6 def, mask, gate; 50362587Sitojun struct rtentry *oldrt = NULL; 50453541Sshin 505128397Sluigi bzero(&def, sizeof(def)); 506128397Sluigi bzero(&mask, sizeof(mask)); 507128397Sluigi bzero(&gate, sizeof(gate)); 50853541Sshin 509120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 510120941Sume sizeof(struct sockaddr_in6); 511151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 51253541Sshin gate.sin6_addr = dr->rtaddr; 51353541Sshin 51453541Sshin rtrequest(RTM_DELETE, (struct sockaddr *)&def, 515120941Sume (struct sockaddr *)&gate, 516120941Sume (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); 51762587Sitojun if (oldrt) { 51878064Sume nd6_rtmsg(RTM_DELETE, oldrt); 519108269Sru RTFREE(oldrt); 52062587Sitojun } 52153541Sshin 522151539Ssuz dr->installed = 0; 52353541Sshin} 52453541Sshin 525151539Ssuz/* 526151539Ssuz * remove all default routes from default router list 527151539Ssuz */ 52853541Sshinvoid 529171259Sdelphijdefrouter_reset(void) 530151539Ssuz{ 531151539Ssuz struct nd_defrouter *dr; 532151539Ssuz 533151539Ssuz for (dr = TAILQ_FIRST(&nd_defrouter); dr; 534151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) 535151539Ssuz defrouter_delreq(dr); 536151539Ssuz 537151539Ssuz /* 538151539Ssuz * XXX should we also nuke any default routers in the kernel, by 539151539Ssuz * going through them by rtalloc1()? 540151539Ssuz */ 541151539Ssuz} 542151539Ssuz 543151539Ssuzvoid 544171259Sdelphijdefrtrlist_del(struct nd_defrouter *dr) 54553541Sshin{ 54653541Sshin struct nd_defrouter *deldr = NULL; 54753541Sshin struct nd_prefix *pr; 54853541Sshin 54953541Sshin /* 55053541Sshin * Flush all the routing table entries that use the router 55153541Sshin * as a next hop. 55253541Sshin */ 553120941Sume if (!ip6_forwarding && ip6_accept_rtadv) /* XXX: better condition? */ 55453541Sshin rt6_flush(&dr->rtaddr, dr->ifp); 55553541Sshin 556151539Ssuz if (dr->installed) { 557151539Ssuz deldr = dr; 558151539Ssuz defrouter_delreq(dr); 559151539Ssuz } 56062587Sitojun TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 56153541Sshin 56253541Sshin /* 56353541Sshin * Also delete all the pointers to the router in each prefix lists. 56453541Sshin */ 56562587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 56653541Sshin struct nd_pfxrouter *pfxrtr; 56753541Sshin if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 56853541Sshin pfxrtr_del(pfxrtr); 56953541Sshin } 57053541Sshin pfxlist_onlink_check(); 57153541Sshin 57253541Sshin /* 57362587Sitojun * If the router is the primary one, choose a new one. 57462587Sitojun * Note that defrouter_select() will remove the current gateway 57562587Sitojun * from the routing table. 57653541Sshin */ 57753541Sshin if (deldr) 57862587Sitojun defrouter_select(); 57962587Sitojun 58053541Sshin free(dr, M_IP6NDP); 58153541Sshin} 58253541Sshin 58362587Sitojun/* 584151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and 585151539Ssuz * draft-ietf-ipngwg-router-selection: 586151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred. 587151539Ssuz * If we have more than one (probably) reachable router, prefer ones 588151539Ssuz * with the highest router preference. 58962587Sitojun * 2) When no routers on the list are known to be reachable or 59062587Sitojun * probably reachable, routers SHOULD be selected in a round-robin 591151539Ssuz * fashion, regardless of router preference values. 59262587Sitojun * 3) If the Default Router List is empty, assume that all 59362587Sitojun * destinations are on-link. 594151539Ssuz * 595151539Ssuz * We assume nd_defrouter is sorted by router preference value. 596151539Ssuz * Since the code below covers both with and without router preference cases, 597151539Ssuz * we do not need to classify the cases by ifdef. 598151539Ssuz * 599151539Ssuz * At this moment, we do not try to install more than one default router, 600151539Ssuz * even when the multipath routing is available, because we're not sure about 601151539Ssuz * the benefits for stub hosts comparing to the risk of making the code 602151539Ssuz * complicated and the possibility of introducing bugs. 60362587Sitojun */ 60462587Sitojunvoid 605171259Sdelphijdefrouter_select(void) 60662587Sitojun{ 60762587Sitojun int s = splnet(); 608151539Ssuz struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; 60962587Sitojun struct rtentry *rt = NULL; 61062587Sitojun struct llinfo_nd6 *ln = NULL; 61162587Sitojun 61262587Sitojun /* 613151539Ssuz * This function should be called only when acting as an autoconfigured 614151539Ssuz * host. Although the remaining part of this function is not effective 615151539Ssuz * if the node is not an autoconfigured host, we explicitly exclude 616151539Ssuz * such cases here for safety. 617151539Ssuz */ 618151539Ssuz if (ip6_forwarding || !ip6_accept_rtadv) { 619151539Ssuz nd6log((LOG_WARNING, 620151539Ssuz "defrouter_select: called unexpectedly (forwarding=%d, " 621151539Ssuz "accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv)); 622151539Ssuz splx(s); 623151539Ssuz return; 624151539Ssuz } 625151539Ssuz 626151539Ssuz /* 627151539Ssuz * Let's handle easy case (3) first: 628151539Ssuz * If default router list is empty, there's nothing to be done. 629151539Ssuz */ 630151539Ssuz if (!TAILQ_FIRST(&nd_defrouter)) { 631151539Ssuz splx(s); 632151539Ssuz return; 633151539Ssuz } 634151539Ssuz 635151539Ssuz /* 63662587Sitojun * Search for a (probably) reachable router from the list. 637151539Ssuz * We just pick up the first reachable one (if any), assuming that 638151539Ssuz * the ordering rule of the list described in defrtrlist_update(). 63962587Sitojun */ 64062587Sitojun for (dr = TAILQ_FIRST(&nd_defrouter); dr; 64162587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 642151539Ssuz if (selected_dr == NULL && 643151539Ssuz (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && 64462587Sitojun (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 64562587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) { 646151539Ssuz selected_dr = dr; 64762587Sitojun } 64862587Sitojun 649151539Ssuz if (dr->installed && installed_dr == NULL) 650151539Ssuz installed_dr = dr; 651151539Ssuz else if (dr->installed && installed_dr) { 652151539Ssuz /* this should not happen. warn for diagnosis. */ 653151539Ssuz log(LOG_ERR, "defrouter_select: more than one router" 654151539Ssuz " is installed\n"); 65562587Sitojun } 65662587Sitojun } 657151539Ssuz /* 658151539Ssuz * If none of the default routers was found to be reachable, 659151539Ssuz * round-robin the list regardless of preference. 660151539Ssuz * Otherwise, if we have an installed router, check if the selected 661151539Ssuz * (reachable) router should really be preferred to the installed one. 662151539Ssuz * We only prefer the new router when the old one is not reachable 663151539Ssuz * or when the new one has a really higher preference value. 664151539Ssuz */ 665151539Ssuz if (selected_dr == NULL) { 666151539Ssuz if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry)) 667151539Ssuz selected_dr = TAILQ_FIRST(&nd_defrouter); 668151539Ssuz else 669151539Ssuz selected_dr = TAILQ_NEXT(installed_dr, dr_entry); 670151539Ssuz } else if (installed_dr && 671151539Ssuz (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && 672151539Ssuz (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 673151539Ssuz ND6_IS_LLINFO_PROBREACH(ln) && 674151539Ssuz rtpref(selected_dr) <= rtpref(installed_dr)) { 675151539Ssuz selected_dr = installed_dr; 676151539Ssuz } 67762587Sitojun 678151539Ssuz /* 679151539Ssuz * If the selected router is different than the installed one, 680151539Ssuz * remove the installed router and install the selected one. 681151539Ssuz * Note that the selected router is never NULL here. 682151539Ssuz */ 683151539Ssuz if (installed_dr != selected_dr) { 684151539Ssuz if (installed_dr) 685151539Ssuz defrouter_delreq(installed_dr); 686151539Ssuz defrouter_addreq(selected_dr); 687151539Ssuz } 688151539Ssuz 68962587Sitojun splx(s); 69062587Sitojun return; 69162587Sitojun} 69262587Sitojun 693151539Ssuz/* 694151539Ssuz * for default router selection 695151539Ssuz * regards router-preference field as a 2-bit signed integer 696151539Ssuz */ 697151539Ssuzstatic int 698151539Ssuzrtpref(struct nd_defrouter *dr) 699151539Ssuz{ 700151539Ssuz switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) { 701151539Ssuz case ND_RA_FLAG_RTPREF_HIGH: 702151539Ssuz return (RTPREF_HIGH); 703151539Ssuz case ND_RA_FLAG_RTPREF_MEDIUM: 704156871Ssuz case ND_RA_FLAG_RTPREF_RSV: 705151539Ssuz return (RTPREF_MEDIUM); 706151539Ssuz case ND_RA_FLAG_RTPREF_LOW: 707151539Ssuz return (RTPREF_LOW); 708151539Ssuz default: 709151539Ssuz /* 710151539Ssuz * This case should never happen. If it did, it would mean a 711151539Ssuz * serious bug of kernel internal. We thus always bark here. 712151539Ssuz * Or, can we even panic? 713151539Ssuz */ 714151539Ssuz log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags); 715151539Ssuz return (RTPREF_INVALID); 716151539Ssuz } 717151539Ssuz /* NOTREACHED */ 718151539Ssuz} 719151539Ssuz 72053541Sshinstatic struct nd_defrouter * 721171259Sdelphijdefrtrlist_update(struct nd_defrouter *new) 72253541Sshin{ 72353541Sshin struct nd_defrouter *dr, *n; 72453541Sshin int s = splnet(); 72553541Sshin 72653541Sshin if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 72753541Sshin /* entry exists */ 72853541Sshin if (new->rtlifetime == 0) { 72953541Sshin defrtrlist_del(dr); 73053541Sshin dr = NULL; 73153541Sshin } else { 732151539Ssuz int oldpref = rtpref(dr); 733151539Ssuz 73453541Sshin /* override */ 73553541Sshin dr->flags = new->flags; /* xxx flag check */ 73653541Sshin dr->rtlifetime = new->rtlifetime; 73753541Sshin dr->expire = new->expire; 738151539Ssuz 739151539Ssuz /* 740151539Ssuz * If the preference does not change, there's no need 741151539Ssuz * to sort the entries. 742151539Ssuz */ 743151539Ssuz if (rtpref(new) == oldpref) { 744151539Ssuz splx(s); 745151539Ssuz return (dr); 746151539Ssuz } 747151539Ssuz 748151539Ssuz /* 749151539Ssuz * preferred router may be changed, so relocate 750151539Ssuz * this router. 751151539Ssuz * XXX: calling TAILQ_REMOVE directly is a bad manner. 752151539Ssuz * However, since defrtrlist_del() has many side 753151539Ssuz * effects, we intentionally do so here. 754151539Ssuz * defrouter_select() below will handle routing 755151539Ssuz * changes later. 756151539Ssuz */ 757151539Ssuz TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 758151539Ssuz n = dr; 759151539Ssuz goto insert; 76053541Sshin } 76153541Sshin splx(s); 762120856Sume return (dr); 76353541Sshin } 76453541Sshin 76553541Sshin /* entry does not exist */ 76653541Sshin if (new->rtlifetime == 0) { 76753541Sshin splx(s); 768120856Sume return (NULL); 76953541Sshin } 77053541Sshin 77153541Sshin n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 77253541Sshin if (n == NULL) { 77353541Sshin splx(s); 774120856Sume return (NULL); 77553541Sshin } 77653541Sshin bzero(n, sizeof(*n)); 77753541Sshin *n = *new; 77862587Sitojun 779151539Ssuzinsert: 78062587Sitojun /* 781151539Ssuz * Insert the new router in the Default Router List; 782151539Ssuz * The Default Router List should be in the descending order 783151539Ssuz * of router-preferece. Routers with the same preference are 784151539Ssuz * sorted in the arriving time order. 78562587Sitojun */ 786151539Ssuz 787151539Ssuz /* insert at the end of the group */ 788151539Ssuz for (dr = TAILQ_FIRST(&nd_defrouter); dr; 789151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 790151539Ssuz if (rtpref(n) > rtpref(dr)) 791151539Ssuz break; 792151539Ssuz } 793151539Ssuz if (dr) 794151539Ssuz TAILQ_INSERT_BEFORE(dr, n, dr_entry); 795151539Ssuz else 796151539Ssuz TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry); 797151539Ssuz 798151539Ssuz defrouter_select(); 799151539Ssuz 80053541Sshin splx(s); 801120941Sume 802120856Sume return (n); 80353541Sshin} 80453541Sshin 80553541Sshinstatic struct nd_pfxrouter * 806171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) 80753541Sshin{ 80853541Sshin struct nd_pfxrouter *search; 809120941Sume 81062587Sitojun for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { 81153541Sshin if (search->router == dr) 81253541Sshin break; 81353541Sshin } 81453541Sshin 815120856Sume return (search); 81653541Sshin} 81753541Sshin 81853541Sshinstatic void 819171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) 82053541Sshin{ 82153541Sshin struct nd_pfxrouter *new; 82253541Sshin 82353541Sshin new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 82453541Sshin if (new == NULL) 82553541Sshin return; 82653541Sshin bzero(new, sizeof(*new)); 82753541Sshin new->router = dr; 82853541Sshin 82953541Sshin LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 83053541Sshin 83153541Sshin pfxlist_onlink_check(); 83253541Sshin} 83353541Sshin 83453541Sshinstatic void 835171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr) 83653541Sshin{ 83753541Sshin LIST_REMOVE(pfr, pfr_entry); 83853541Sshin free(pfr, M_IP6NDP); 83953541Sshin} 84053541Sshin 84178064Sumestruct nd_prefix * 842171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key) 84353541Sshin{ 84453541Sshin struct nd_prefix *search; 84553541Sshin 84662587Sitojun for (search = nd_prefix.lh_first; search; search = search->ndpr_next) { 847151539Ssuz if (key->ndpr_ifp == search->ndpr_ifp && 848151539Ssuz key->ndpr_plen == search->ndpr_plen && 849151539Ssuz in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr, 850151539Ssuz &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) { 85153541Sshin break; 85253541Sshin } 85353541Sshin } 85453541Sshin 855120856Sume return (search); 85653541Sshin} 85753541Sshin 85878064Sumeint 859171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr, 860171259Sdelphij struct nd_prefix **newp) 86153541Sshin{ 86278064Sume struct nd_prefix *new = NULL; 863151539Ssuz int error = 0; 86453541Sshin int i, s; 865165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 86653541Sshin 86753541Sshin new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 86853541Sshin if (new == NULL) 869120941Sume return(ENOMEM); 87053541Sshin bzero(new, sizeof(*new)); 871151539Ssuz new->ndpr_ifp = pr->ndpr_ifp; 872151539Ssuz new->ndpr_prefix = pr->ndpr_prefix; 873151539Ssuz new->ndpr_plen = pr->ndpr_plen; 874151539Ssuz new->ndpr_vltime = pr->ndpr_vltime; 875151539Ssuz new->ndpr_pltime = pr->ndpr_pltime; 876151539Ssuz new->ndpr_flags = pr->ndpr_flags; 877151539Ssuz if ((error = in6_init_prefix_ltimes(new)) != 0) { 878151539Ssuz free(new, M_IP6NDP); 879151539Ssuz return(error); 880151539Ssuz } 881151539Ssuz new->ndpr_lastupdate = time_second; 88278064Sume if (newp != NULL) 88378064Sume *newp = new; 88453541Sshin 885120941Sume /* initialization */ 88653541Sshin LIST_INIT(&new->ndpr_advrtrs); 88753541Sshin in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 88853541Sshin /* make prefix in the canonical form */ 88953541Sshin for (i = 0; i < 4; i++) 89053541Sshin new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 891120941Sume new->ndpr_mask.s6_addr32[i]; 89253541Sshin 89353541Sshin s = splnet(); 89453541Sshin /* link ndpr_entry to nd_prefix list */ 89553541Sshin LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry); 89653541Sshin splx(s); 89753541Sshin 89878064Sume /* ND_OPT_PI_FLAG_ONLINK processing */ 89978064Sume if (new->ndpr_raf_onlink) { 90078064Sume int e; 90178064Sume 90278064Sume if ((e = nd6_prefix_onlink(new)) != 0) { 90378064Sume nd6log((LOG_ERR, "nd6_prelist_add: failed to make " 90478064Sume "the prefix %s/%d on-link on %s (errno=%d)\n", 905165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 90678064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 90778064Sume /* proceed anyway. XXX: is it correct? */ 90878064Sume } 90978064Sume } 91078064Sume 911120941Sume if (dr) 91253541Sshin pfxrtr_add(new, dr); 91353541Sshin 91453541Sshin return 0; 91553541Sshin} 91653541Sshin 91753541Sshinvoid 918171259Sdelphijprelist_remove(struct nd_prefix *pr) 91953541Sshin{ 92053541Sshin struct nd_pfxrouter *pfr, *next; 92178064Sume int e, s; 922165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 92353541Sshin 92478064Sume /* make sure to invalidate the prefix until it is really freed. */ 92578064Sume pr->ndpr_vltime = 0; 92678064Sume pr->ndpr_pltime = 0; 927151539Ssuz 92878064Sume /* 92978064Sume * Though these flags are now meaningless, we'd rather keep the value 930151479Ssuz * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users 931151479Ssuz * when executing "ndp -p". 93278064Sume */ 933151479Ssuz 93478064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && 93578064Sume (e = nd6_prefix_offlink(pr)) != 0) { 93678064Sume nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " 93778064Sume "on %s, errno=%d\n", 938165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 93978064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 94078064Sume /* what should we do? */ 94178064Sume } 94278064Sume 94378064Sume if (pr->ndpr_refcnt > 0) 94478064Sume return; /* notice here? */ 94578064Sume 94653541Sshin s = splnet(); 94778064Sume 94853541Sshin /* unlink ndpr_entry from nd_prefix list */ 94953541Sshin LIST_REMOVE(pr, ndpr_entry); 95053541Sshin 95153541Sshin /* free list of routers that adversed the prefix */ 95262587Sitojun for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { 95362587Sitojun next = pfr->pfr_next; 95453541Sshin 95553541Sshin free(pfr, M_IP6NDP); 95653541Sshin } 95778064Sume splx(s); 95878064Sume 95953541Sshin free(pr, M_IP6NDP); 96053541Sshin 96153541Sshin pfxlist_onlink_check(); 96253541Sshin} 96353541Sshin 964171259Sdelphij/* 965171259Sdelphij * dr - may be NULL 966171259Sdelphij */ 967171259Sdelphij 968151539Ssuzstatic int 969171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, 970171259Sdelphij struct mbuf *m, int mcast) 97153541Sshin{ 97278064Sume struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 97378064Sume struct ifaddr *ifa; 97478064Sume struct ifnet *ifp = new->ndpr_ifp; 97553541Sshin struct nd_prefix *pr; 97653541Sshin int s = splnet(); 97753541Sshin int error = 0; 97878064Sume int newprefix = 0; 97953541Sshin int auth; 98078064Sume struct in6_addrlifetime lt6_tmp; 981165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 98253541Sshin 98353541Sshin auth = 0; 98453541Sshin if (m) { 98553541Sshin /* 98653541Sshin * Authenticity for NA consists authentication for 98753541Sshin * both IP header and IP datagrams, doesn't it ? 98853541Sshin */ 98953541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 990120941Sume auth = ((m->m_flags & M_AUTHIPHDR) && 991120941Sume (m->m_flags & M_AUTHIPDGM)); 99253541Sshin#endif 99353541Sshin } 99453541Sshin 99578064Sume if ((pr = nd6_prefix_lookup(new)) != NULL) { 99678064Sume /* 99778064Sume * nd6_prefix_lookup() ensures that pr and new have the same 99878064Sume * prefix on a same interface. 99978064Sume */ 100053541Sshin 100153541Sshin /* 100278064Sume * Update prefix information. Note that the on-link (L) bit 100378064Sume * and the autonomous (A) bit should NOT be changed from 1 100478064Sume * to 0. 100553541Sshin */ 100678064Sume if (new->ndpr_raf_onlink == 1) 100778064Sume pr->ndpr_raf_onlink = 1; 100878064Sume if (new->ndpr_raf_auto == 1) 100978064Sume pr->ndpr_raf_auto = 1; 101078064Sume if (new->ndpr_raf_onlink) { 101178064Sume pr->ndpr_vltime = new->ndpr_vltime; 101278064Sume pr->ndpr_pltime = new->ndpr_pltime; 1013151539Ssuz (void)in6_init_prefix_ltimes(pr); /* XXX error case? */ 1014151539Ssuz pr->ndpr_lastupdate = time_second; 101578064Sume } 101653541Sshin 101778064Sume if (new->ndpr_raf_onlink && 101878064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 101978064Sume int e; 102053541Sshin 102178064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 102278064Sume nd6log((LOG_ERR, 102378064Sume "prelist_update: failed to make " 102478064Sume "the prefix %s/%d on-link on %s " 102578064Sume "(errno=%d)\n", 1026165118Sbz ip6_sprintf(ip6buf, 1027165118Sbz &pr->ndpr_prefix.sin6_addr), 102878064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 102978064Sume /* proceed anyway. XXX: is it correct? */ 103053541Sshin } 103178064Sume } 103253541Sshin 103378064Sume if (dr && pfxrtr_lookup(pr, dr) == NULL) 103478064Sume pfxrtr_add(pr, dr); 103578064Sume } else { 103678064Sume struct nd_prefix *newpr = NULL; 103753541Sshin 103878064Sume newprefix = 1; 103953541Sshin 104078064Sume if (new->ndpr_vltime == 0) 104178064Sume goto end; 104278064Sume if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 104378064Sume goto end; 104453541Sshin 104578064Sume error = nd6_prelist_add(new, dr, &newpr); 104678064Sume if (error != 0 || newpr == NULL) { 104778064Sume nd6log((LOG_NOTICE, "prelist_update: " 104878064Sume "nd6_prelist_add failed for %s/%d on %s " 104978064Sume "errno=%d, returnpr=%p\n", 1050165118Sbz ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr), 1051120941Sume new->ndpr_plen, if_name(new->ndpr_ifp), 1052120941Sume error, newpr)); 105378064Sume goto end; /* we should just give up in this case. */ 105478064Sume } 105553541Sshin 105678064Sume /* 105778064Sume * XXX: from the ND point of view, we can ignore a prefix 105878064Sume * with the on-link bit being zero. However, we need a 105978064Sume * prefix structure for references from autoconfigured 1060120941Sume * addresses. Thus, we explicitly make sure that the prefix 106178064Sume * itself expires now. 106278064Sume */ 106378064Sume if (newpr->ndpr_raf_onlink == 0) { 106478064Sume newpr->ndpr_vltime = 0; 106578064Sume newpr->ndpr_pltime = 0; 106678064Sume in6_init_prefix_ltimes(newpr); 106753541Sshin } 106853541Sshin 106978064Sume pr = newpr; 107078064Sume } 107153541Sshin 107278064Sume /* 107378064Sume * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 107478064Sume * Note that pr must be non NULL at this point. 107578064Sume */ 107662587Sitojun 107778064Sume /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 107878064Sume if (!new->ndpr_raf_auto) 1079151539Ssuz goto end; 108062587Sitojun 108178064Sume /* 108278064Sume * 5.5.3 (b). the link-local prefix should have been ignored in 108378064Sume * nd6_ra_input. 108478064Sume */ 108562587Sitojun 1086151539Ssuz /* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */ 1087151539Ssuz if (new->ndpr_pltime > new->ndpr_vltime) { 1088151539Ssuz error = EINVAL; /* XXX: won't be used */ 1089151539Ssuz goto end; 1090151539Ssuz } 109162587Sitojun 109278064Sume /* 1093151539Ssuz * 5.5.3 (d). If the prefix advertised is not equal to the prefix of 1094151539Ssuz * an address configured by stateless autoconfiguration already in the 1095151539Ssuz * list of addresses associated with the interface, and the Valid 1096151539Ssuz * Lifetime is not 0, form an address. We first check if we have 1097151539Ssuz * a matching prefix. 1098151539Ssuz * Note: we apply a clarification in rfc2462bis-02 here. We only 1099151539Ssuz * consider autoconfigured addresses while RFC2462 simply said 1100151539Ssuz * "address". 110178064Sume */ 1102120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 110378064Sume struct in6_ifaddr *ifa6; 1104151539Ssuz u_int32_t remaininglifetime; 110553541Sshin 110678064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 110778064Sume continue; 110853541Sshin 110978064Sume ifa6 = (struct in6_ifaddr *)ifa; 111053541Sshin 111153541Sshin /* 1112151539Ssuz * We only consider autoconfigured addresses as per rfc2462bis. 1113151539Ssuz */ 1114151539Ssuz if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF)) 1115151539Ssuz continue; 1116151539Ssuz 1117151539Ssuz /* 111878064Sume * Spec is not clear here, but I believe we should concentrate 111978064Sume * on unicast (i.e. not anycast) addresses. 112078064Sume * XXX: other ia6_flags? detached or duplicated? 112153541Sshin */ 112278064Sume if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 112378064Sume continue; 1124120941Sume 1125151539Ssuz /* 1126151539Ssuz * Ignore the address if it is not associated with a prefix 1127151539Ssuz * or is associated with a prefix that is different from this 1128151539Ssuz * one. (pr is never NULL here) 1129151539Ssuz */ 1130151539Ssuz if (ifa6->ia6_ndpr != pr) 113178064Sume continue; 113253541Sshin 113378064Sume if (ia6_match == NULL) /* remember the first one */ 113478064Sume ia6_match = ifa6; 113578064Sume 113678064Sume /* 113778064Sume * An already autoconfigured address matched. Now that we 113878064Sume * are sure there is at least one matched address, we can 113978064Sume * proceed to 5.5.3. (e): update the lifetimes according to the 114078064Sume * "two hours" rule and the privacy extension. 1141151539Ssuz * We apply some clarifications in rfc2462bis: 1142151539Ssuz * - use remaininglifetime instead of storedlifetime as a 1143151539Ssuz * variable name 1144151539Ssuz * - remove the dead code in the "two-hour" rule 114578064Sume */ 114678064Sume#define TWOHOUR (120*60) 114778064Sume lt6_tmp = ifa6->ia6_lifetime; 114878064Sume 1149112678Sume if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 1150151539Ssuz remaininglifetime = ND6_INFINITE_LIFETIME; 1151151539Ssuz else if (time_second - ifa6->ia6_updatetime > 1152151539Ssuz lt6_tmp.ia6t_vltime) { 1153151539Ssuz /* 1154151539Ssuz * The case of "invalid" address. We should usually 1155151539Ssuz * not see this case. 1156151539Ssuz */ 1157151539Ssuz remaininglifetime = 0; 1158151539Ssuz } else 1159151539Ssuz remaininglifetime = lt6_tmp.ia6t_vltime - 1160151539Ssuz (time_second - ifa6->ia6_updatetime); 116178064Sume 1162112678Sume /* when not updating, keep the current stored lifetime. */ 1163151539Ssuz lt6_tmp.ia6t_vltime = remaininglifetime; 1164112678Sume 116578064Sume if (TWOHOUR < new->ndpr_vltime || 1166151539Ssuz remaininglifetime < new->ndpr_vltime) { 116778064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 1168151539Ssuz } else if (remaininglifetime <= TWOHOUR) { 116978064Sume if (auth) { 117078064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 117178064Sume } 117278064Sume } else { 117378064Sume /* 117478064Sume * new->ndpr_vltime <= TWOHOUR && 1175151539Ssuz * TWOHOUR < remaininglifetime 117678064Sume */ 117778064Sume lt6_tmp.ia6t_vltime = TWOHOUR; 117853541Sshin } 117953541Sshin 118078064Sume /* The 2 hour rule is not imposed for preferred lifetime. */ 118178064Sume lt6_tmp.ia6t_pltime = new->ndpr_pltime; 118253541Sshin 118378064Sume in6_init_address_ltimes(pr, <6_tmp); 118453541Sshin 1185151539Ssuz /* 1186151539Ssuz * We need to treat lifetimes for temporary addresses 1187151539Ssuz * differently, according to 1188151539Ssuz * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1); 1189151539Ssuz * we only update the lifetimes when they are in the maximum 1190151539Ssuz * intervals. 1191151539Ssuz */ 1192151539Ssuz if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 1193151539Ssuz u_int32_t maxvltime, maxpltime; 1194151539Ssuz 1195151539Ssuz if (ip6_temp_valid_lifetime > 1196151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1197151539Ssuz ip6_desync_factor)) { 1198151539Ssuz maxvltime = ip6_temp_valid_lifetime - 1199151539Ssuz (time_second - ifa6->ia6_createtime) - 1200151539Ssuz ip6_desync_factor; 1201151539Ssuz } else 1202151539Ssuz maxvltime = 0; 1203151539Ssuz if (ip6_temp_preferred_lifetime > 1204151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1205151539Ssuz ip6_desync_factor)) { 1206151539Ssuz maxpltime = ip6_temp_preferred_lifetime - 1207151539Ssuz (time_second - ifa6->ia6_createtime) - 1208151539Ssuz ip6_desync_factor; 1209151539Ssuz } else 1210151539Ssuz maxpltime = 0; 1211151539Ssuz 1212151539Ssuz if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME || 1213151539Ssuz lt6_tmp.ia6t_vltime > maxvltime) { 1214151539Ssuz lt6_tmp.ia6t_vltime = maxvltime; 121578064Sume } 1216151539Ssuz if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || 1217151539Ssuz lt6_tmp.ia6t_pltime > maxpltime) { 1218151539Ssuz lt6_tmp.ia6t_pltime = maxpltime; 121978064Sume } 122078064Sume } 122178064Sume ifa6->ia6_lifetime = lt6_tmp; 1222151539Ssuz ifa6->ia6_updatetime = time_second; 122353541Sshin } 122478064Sume if (ia6_match == NULL && new->ndpr_vltime) { 1225151539Ssuz int ifidlen; 1226151539Ssuz 122778064Sume /* 1228151539Ssuz * 5.5.3 (d) (continued) 122978064Sume * No address matched and the valid lifetime is non-zero. 123078064Sume * Create a new address. 123178064Sume */ 1232151539Ssuz 1233151539Ssuz /* 1234151539Ssuz * Prefix Length check: 1235151539Ssuz * If the sum of the prefix length and interface identifier 1236151539Ssuz * length does not equal 128 bits, the Prefix Information 1237151539Ssuz * option MUST be ignored. The length of the interface 1238151539Ssuz * identifier is defined in a separate link-type specific 1239151539Ssuz * document. 1240151539Ssuz */ 1241151539Ssuz ifidlen = in6_if2idlen(ifp); 1242151539Ssuz if (ifidlen < 0) { 1243151539Ssuz /* this should not happen, so we always log it. */ 1244151539Ssuz log(LOG_ERR, "prelist_update: IFID undefined (%s)\n", 1245151539Ssuz if_name(ifp)); 1246151539Ssuz goto end; 1247151539Ssuz } 1248151539Ssuz if (ifidlen + pr->ndpr_plen != 128) { 1249151539Ssuz nd6log((LOG_INFO, 1250151539Ssuz "prelist_update: invalid prefixlen " 1251151539Ssuz "%d for %s, ignored\n", 1252151539Ssuz pr->ndpr_plen, if_name(ifp))); 1253151539Ssuz goto end; 1254151539Ssuz } 1255151539Ssuz 1256151539Ssuz if ((ia6 = in6_ifadd(new, mcast)) != NULL) { 125778064Sume /* 125878064Sume * note that we should use pr (not new) for reference. 125978064Sume */ 126078064Sume pr->ndpr_refcnt++; 126178064Sume ia6->ia6_ndpr = pr; 126253541Sshin 126378064Sume /* 126478064Sume * RFC 3041 3.3 (2). 126578064Sume * When a new public address is created as described 126678064Sume * in RFC2462, also create a new temporary address. 126778064Sume * 126878064Sume * RFC 3041 3.5. 126978064Sume * When an interface connects to a new link, a new 127078064Sume * randomized interface identifier should be generated 127178064Sume * immediately together with a new set of temporary 127278064Sume * addresses. Thus, we specifiy 1 as the 2nd arg of 127378064Sume * in6_tmpifadd(). 127478064Sume */ 127578064Sume if (ip6_use_tempaddr) { 127678064Sume int e; 1277151539Ssuz if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) { 127878064Sume nd6log((LOG_NOTICE, "prelist_update: " 127978064Sume "failed to create a temporary " 128078064Sume "address, errno=%d\n", 128178064Sume e)); 128278064Sume } 128378064Sume } 128478064Sume 128578064Sume /* 128678064Sume * A newly added address might affect the status 128778064Sume * of other addresses, so we check and update it. 128878064Sume * XXX: what if address duplication happens? 128978064Sume */ 129078064Sume pfxlist_onlink_check(); 129178064Sume } else { 129278064Sume /* just set an error. do not bark here. */ 129378064Sume error = EADDRNOTAVAIL; /* XXX: might be unused. */ 129478064Sume } 129578064Sume } 129678064Sume 129753541Sshin end: 129853541Sshin splx(s); 129953541Sshin return error; 130053541Sshin} 130153541Sshin 130253541Sshin/* 130362587Sitojun * A supplement function used in the on-link detection below; 130462587Sitojun * detect if a given prefix has a (probably) reachable advertising router. 130562587Sitojun * XXX: lengthy function name... 130662587Sitojun */ 130778064Sumestatic struct nd_pfxrouter * 1308171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr) 130962587Sitojun{ 131062587Sitojun struct nd_pfxrouter *pfxrtr; 131162587Sitojun struct rtentry *rt; 131262587Sitojun struct llinfo_nd6 *ln; 131362587Sitojun 131462587Sitojun for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr; 131562587Sitojun pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { 131662587Sitojun if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0, 1317120941Sume pfxrtr->router->ifp)) && 131862587Sitojun (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 131962587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) 132062587Sitojun break; /* found */ 132162587Sitojun } 132262587Sitojun 1323120856Sume return (pfxrtr); 132462587Sitojun} 132562587Sitojun 132662587Sitojun/* 132753541Sshin * Check if each prefix in the prefix list has at least one available router 132878064Sume * that advertised the prefix (a router is "available" if its neighbor cache 132978064Sume * entry is reachable or probably reachable). 133062587Sitojun * If the check fails, the prefix may be off-link, because, for example, 133153541Sshin * we have moved from the network but the lifetime of the prefix has not 133278064Sume * expired yet. So we should not use the prefix if there is another prefix 133378064Sume * that has an available router. 133478064Sume * But, if there is no prefix that has an available router, we still regards 133578064Sume * all the prefixes as on-link. This is because we can't tell if all the 133653541Sshin * routers are simply dead or if we really moved from the network and there 133753541Sshin * is no router around us. 133853541Sshin */ 133962587Sitojunvoid 134053541Sshinpfxlist_onlink_check() 134153541Sshin{ 134253541Sshin struct nd_prefix *pr; 134378064Sume struct in6_ifaddr *ifa; 1344151539Ssuz struct nd_defrouter *dr; 1345151539Ssuz struct nd_pfxrouter *pfxrtr = NULL; 134653541Sshin 134762587Sitojun /* 134862587Sitojun * Check if there is a prefix that has a reachable advertising 134962587Sitojun * router. 135062587Sitojun */ 135162587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 135278064Sume if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 135353541Sshin break; 135462587Sitojun } 135553541Sshin 1356151539Ssuz /* 1357151539Ssuz * If we have no such prefix, check whether we still have a router 1358151539Ssuz * that does not advertise any prefixes. 1359151539Ssuz */ 1360151465Ssuz if (pr == NULL) { 1361151539Ssuz for (dr = TAILQ_FIRST(&nd_defrouter); dr; 1362151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 1363151539Ssuz struct nd_prefix *pr0; 1364151539Ssuz 1365151539Ssuz for (pr0 = nd_prefix.lh_first; pr0; 1366151539Ssuz pr0 = pr0->ndpr_next) { 1367151539Ssuz if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) 1368151539Ssuz break; 1369151539Ssuz } 1370151539Ssuz if (pfxrtr != NULL) 1371151539Ssuz break; 1372151539Ssuz } 1373151539Ssuz } 1374151539Ssuz if (pr != NULL || (TAILQ_FIRST(&nd_defrouter) && pfxrtr == NULL)) { 1375151539Ssuz /* 1376151539Ssuz * There is at least one prefix that has a reachable router, 1377151539Ssuz * or at least a router which probably does not advertise 1378151539Ssuz * any prefixes. The latter would be the case when we move 1379151539Ssuz * to a new link where we have a router that does not provide 1380151539Ssuz * prefixes and we configure an address by hand. 1381151539Ssuz * Detach prefixes which have no reachable advertising 1382151539Ssuz * router, and attach other prefixes. 1383151539Ssuz */ 138462587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 138578064Sume /* XXX: a link-local prefix should never be detached */ 138678064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 138778064Sume continue; 138878064Sume 138978064Sume /* 139078064Sume * we aren't interested in prefixes without the L bit 139178064Sume * set. 139278064Sume */ 139378064Sume if (pr->ndpr_raf_onlink == 0) 139478064Sume continue; 139578064Sume 139678064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 139778064Sume find_pfxlist_reachable_router(pr) == NULL) 139878064Sume pr->ndpr_stateflags |= NDPRF_DETACHED; 139978064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 140078064Sume find_pfxlist_reachable_router(pr) != 0) 140178064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 140253541Sshin } 140378064Sume } else { 140478064Sume /* there is no prefix that has a reachable router */ 140562587Sitojun for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 140678064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 140778064Sume continue; 140878064Sume 140978064Sume if (pr->ndpr_raf_onlink == 0) 141078064Sume continue; 141178064Sume 141278064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 141378064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 141453541Sshin } 141562587Sitojun } 141678064Sume 141778064Sume /* 141878064Sume * Remove each interface route associated with a (just) detached 141978064Sume * prefix, and reinstall the interface route for a (just) attached 142078064Sume * prefix. Note that all attempt of reinstallation does not 142178064Sume * necessarily success, when a same prefix is shared among multiple 142278064Sume * interfaces. Such cases will be handled in nd6_prefix_onlink, 142378064Sume * so we don't have to care about them. 142478064Sume */ 142578064Sume for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 142678064Sume int e; 1427165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 142878064Sume 142978064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 143078064Sume continue; 143178064Sume 143278064Sume if (pr->ndpr_raf_onlink == 0) 143378064Sume continue; 143478064Sume 143578064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 143678064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 143778064Sume if ((e = nd6_prefix_offlink(pr)) != 0) { 143878064Sume nd6log((LOG_ERR, 143978064Sume "pfxlist_onlink_check: failed to " 1440151479Ssuz "make %s/%d offlink, errno=%d\n", 1441165118Sbz ip6_sprintf(ip6buf, 1442165118Sbz &pr->ndpr_prefix.sin6_addr), 1443165118Sbz pr->ndpr_plen, e)); 144478064Sume } 144578064Sume } 144678064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 144778064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 144878064Sume pr->ndpr_raf_onlink) { 144978064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 145078064Sume nd6log((LOG_ERR, 145178064Sume "pfxlist_onlink_check: failed to " 1452151479Ssuz "make %s/%d onlink, errno=%d\n", 1453165118Sbz ip6_sprintf(ip6buf, 1454165118Sbz &pr->ndpr_prefix.sin6_addr), 1455165118Sbz pr->ndpr_plen, e)); 145678064Sume } 145778064Sume } 145878064Sume } 145978064Sume 146078064Sume /* 146178064Sume * Changes on the prefix status might affect address status as well. 146278064Sume * Make sure that all addresses derived from an attached prefix are 146378064Sume * attached, and that all addresses derived from a detached prefix are 146478064Sume * detached. Note, however, that a manually configured address should 146578064Sume * always be attached. 146678064Sume * The precise detection logic is same as the one for prefixes. 146778064Sume */ 146878064Sume for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 1469120941Sume if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) 147078064Sume continue; 147178064Sume 147278064Sume if (ifa->ia6_ndpr == NULL) { 147378064Sume /* 147478064Sume * This can happen when we first configure the address 147578064Sume * (i.e. the address exists, but the prefix does not). 147678064Sume * XXX: complicated relationships... 147778064Sume */ 147878064Sume continue; 147978064Sume } 148078064Sume 148178064Sume if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 148278064Sume break; 148378064Sume } 148478064Sume if (ifa) { 148578064Sume for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 148678064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 148778064Sume continue; 148878064Sume 148978064Sume if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 149078064Sume continue; 149178064Sume 1492151539Ssuz if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) { 1493151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1494151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1495151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1496151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1497151539Ssuz } 1498151539Ssuz } else { 149978064Sume ifa->ia6_flags |= IN6_IFF_DETACHED; 1500151539Ssuz } 150178064Sume } 150278064Sume } 150362587Sitojun else { 150478064Sume for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 150578064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 150678064Sume continue; 150778064Sume 1508151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1509151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1510151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1511151539Ssuz /* Do we need a delay in this case? */ 1512151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1513151539Ssuz } 151478064Sume } 151553541Sshin } 151653541Sshin} 151753541Sshin 151878064Sumeint 1519171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr) 152053541Sshin{ 152178064Sume struct ifaddr *ifa; 152278064Sume struct ifnet *ifp = pr->ndpr_ifp; 152378064Sume struct sockaddr_in6 mask6; 152478064Sume struct nd_prefix *opr; 152578064Sume u_long rtflags; 152678064Sume int error = 0; 152778064Sume struct rtentry *rt = NULL; 1528165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 152953541Sshin 153078064Sume /* sanity check */ 153178064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 153278064Sume nd6log((LOG_ERR, 153378064Sume "nd6_prefix_onlink: %s/%d is already on-link\n", 1534165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1535165118Sbz pr->ndpr_plen)); 1536151465Ssuz return (EEXIST); 153778064Sume } 153878064Sume 153953541Sshin /* 154078064Sume * Add the interface route associated with the prefix. Before 154178064Sume * installing the route, check if there's the same prefix on another 154278064Sume * interface, and the prefix has already installed the interface route. 154378064Sume * Although such a configuration is expected to be rare, we explicitly 154478064Sume * allow it. 154553541Sshin */ 154678064Sume for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 154778064Sume if (opr == pr) 154878064Sume continue; 154978064Sume 155078064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 155178064Sume continue; 155278064Sume 155378064Sume if (opr->ndpr_plen == pr->ndpr_plen && 155478064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1555120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) 1556120856Sume return (0); 155778064Sume } 155878064Sume 155978064Sume /* 1560120941Sume * We prefer link-local addresses as the associated interface address. 156178064Sume */ 156278064Sume /* search for a link-local addr */ 156378064Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 1564120941Sume IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); 156578064Sume if (ifa == NULL) { 156678064Sume /* XXX: freebsd does not have ifa_ifwithaf */ 1567120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 156878064Sume if (ifa->ifa_addr->sa_family == AF_INET6) 156978064Sume break; 157078064Sume } 157178064Sume /* should we care about ia6_flags? */ 157278064Sume } 157378064Sume if (ifa == NULL) { 157478064Sume /* 157578064Sume * This can still happen, when, for example, we receive an RA 157678064Sume * containing a prefix with the L bit set and the A bit clear, 157778064Sume * after removing all IPv6 addresses on the receiving 157878064Sume * interface. This should, of course, be rare though. 157978064Sume */ 158078064Sume nd6log((LOG_NOTICE, 158178064Sume "nd6_prefix_onlink: failed to find any ifaddr" 158278064Sume " to add route for a prefix(%s/%d) on %s\n", 1583165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 158478064Sume pr->ndpr_plen, if_name(ifp))); 1585120856Sume return (0); 158678064Sume } 158778064Sume 158878064Sume /* 158978064Sume * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 159078064Sume * ifa->ifa_rtrequest = nd6_rtrequest; 159178064Sume */ 159278064Sume bzero(&mask6, sizeof(mask6)); 159378064Sume mask6.sin6_len = sizeof(mask6); 159478064Sume mask6.sin6_addr = pr->ndpr_mask; 159578064Sume rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP; 159678064Sume if (nd6_need_cache(ifp)) { 159778064Sume /* explicitly set in case ifa_flags does not set the flag. */ 159878064Sume rtflags |= RTF_CLONING; 159978064Sume } else { 160078064Sume /* 160178064Sume * explicitly clear the cloning bit in case ifa_flags sets it. 160278064Sume */ 160378064Sume rtflags &= ~RTF_CLONING; 160478064Sume } 160578064Sume error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, 1606120941Sume ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt); 160778064Sume if (error == 0) { 160878064Sume if (rt != NULL) /* this should be non NULL, though */ 160978064Sume nd6_rtmsg(RTM_ADD, rt); 161078064Sume pr->ndpr_stateflags |= NDPRF_ONLINK; 1611120941Sume } else { 1612165118Sbz char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN]; 161378064Sume nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" 161478064Sume " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " 161578064Sume "errno = %d\n", 1616165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 161778064Sume pr->ndpr_plen, if_name(ifp), 1618165118Sbz ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), 1619165118Sbz ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error)); 162078064Sume } 162178064Sume 1622120727Ssam if (rt != NULL) { 1623120727Ssam RT_LOCK(rt); 1624122334Ssam RT_REMREF(rt); 1625120727Ssam RT_UNLOCK(rt); 1626120727Ssam } 162778064Sume 1628120856Sume return (error); 162978064Sume} 163078064Sume 163178064Sumeint 1632171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr) 163378064Sume{ 163478064Sume int error = 0; 163578064Sume struct ifnet *ifp = pr->ndpr_ifp; 163678064Sume struct nd_prefix *opr; 163778064Sume struct sockaddr_in6 sa6, mask6; 163878064Sume struct rtentry *rt = NULL; 1639165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 164078064Sume 164178064Sume /* sanity check */ 164278064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 164378064Sume nd6log((LOG_ERR, 164478064Sume "nd6_prefix_offlink: %s/%d is already off-link\n", 1645165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1646165118Sbz pr->ndpr_plen)); 1647120856Sume return (EEXIST); 164878064Sume } 164978064Sume 165053541Sshin bzero(&sa6, sizeof(sa6)); 165153541Sshin sa6.sin6_family = AF_INET6; 165253541Sshin sa6.sin6_len = sizeof(sa6); 165353541Sshin bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 1654120941Sume sizeof(struct in6_addr)); 165553541Sshin bzero(&mask6, sizeof(mask6)); 165653541Sshin mask6.sin6_family = AF_INET6; 165753541Sshin mask6.sin6_len = sizeof(sa6); 165853541Sshin bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 165978064Sume error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 1660120941Sume (struct sockaddr *)&mask6, 0, &rt); 166178064Sume if (error == 0) { 166278064Sume pr->ndpr_stateflags &= ~NDPRF_ONLINK; 166353541Sshin 166478064Sume /* report the route deletion to the routing socket. */ 166578064Sume if (rt != NULL) 166678064Sume nd6_rtmsg(RTM_DELETE, rt); 166753541Sshin 166878064Sume /* 166978064Sume * There might be the same prefix on another interface, 167078064Sume * the prefix which could not be on-link just because we have 167178064Sume * the interface route (see comments in nd6_prefix_onlink). 167278064Sume * If there's one, try to make the prefix on-link on the 167378064Sume * interface. 167478064Sume */ 167578064Sume for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 167678064Sume if (opr == pr) 167778064Sume continue; 167853541Sshin 167978064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 168078064Sume continue; 168153541Sshin 168278064Sume /* 168378064Sume * KAME specific: detached prefixes should not be 168478064Sume * on-link. 168578064Sume */ 168678064Sume if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 168778064Sume continue; 168878064Sume 168978064Sume if (opr->ndpr_plen == pr->ndpr_plen && 169078064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1691120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 169278064Sume int e; 169378064Sume 169478064Sume if ((e = nd6_prefix_onlink(opr)) != 0) { 169578064Sume nd6log((LOG_ERR, 169678064Sume "nd6_prefix_offlink: failed to " 169778064Sume "recover a prefix %s/%d from %s " 169878064Sume "to %s (errno = %d)\n", 1699165118Sbz ip6_sprintf(ip6buf, 1700165118Sbz &opr->ndpr_prefix.sin6_addr), 170178064Sume opr->ndpr_plen, if_name(ifp), 170278064Sume if_name(opr->ndpr_ifp), e)); 170378064Sume } 170478064Sume } 170578064Sume } 1706120941Sume } else { 170778064Sume /* XXX: can we still set the NDPRF_ONLINK flag? */ 170878064Sume nd6log((LOG_ERR, 170978064Sume "nd6_prefix_offlink: failed to delete route: " 171078064Sume "%s/%d on %s (errno = %d)\n", 1711165118Sbz ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen, 1712165118Sbz if_name(ifp), error)); 171378064Sume } 171453541Sshin 1715120941Sume if (rt != NULL) { 1716108269Sru RTFREE(rt); 1717120941Sume } 171853541Sshin 1719120856Sume return (error); 172053541Sshin} 172153541Sshin 172253541Sshinstatic struct in6_ifaddr * 1723171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast) 172453541Sshin{ 172578064Sume struct ifnet *ifp = pr->ndpr_ifp; 172653541Sshin struct ifaddr *ifa; 172778064Sume struct in6_aliasreq ifra; 172878064Sume struct in6_ifaddr *ia, *ib; 172978064Sume int error, plen0; 173053541Sshin struct in6_addr mask; 173178064Sume int prefixlen = pr->ndpr_plen; 1732151539Ssuz int updateflags; 1733165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 173453541Sshin 1735121168Sume in6_prefixlen2mask(&mask, prefixlen); 173653541Sshin 173778064Sume /* 173878064Sume * find a link-local address (will be interface ID). 173978064Sume * Is it really mandatory? Theoretically, a global or a site-local 174078064Sume * address can be configured without a link-local address, if we 174178064Sume * have a unique interface identifier... 174278064Sume * 174378064Sume * it is not mandatory to have a link-local address, we can generate 174478064Sume * interface identifier on the fly. we do this because: 174578064Sume * (1) it should be the easiest way to find interface identifier. 174678064Sume * (2) RFC2462 5.4 suggesting the use of the same interface identifier 174778064Sume * for multiple addresses on a single interface, and possible shortcut 174878064Sume * of DAD. we omitted DAD for this reason in the past. 1749120941Sume * (3) a user can prevent autoconfiguration of global address 175078064Sume * by removing link-local address by hand (this is partly because we 1751108533Sschweikh * don't have other way to control the use of IPv6 on an interface. 175278064Sume * this has been our design choice - cf. NRL's "ifconfig auto"). 175378064Sume * (4) it is easier to manage when an interface has addresses 175478064Sume * with the same interface identifier, than to have multiple addresses 175578064Sume * with different interface identifiers. 175678064Sume */ 1757120941Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ 175853541Sshin if (ifa) 175953541Sshin ib = (struct in6_ifaddr *)ifa; 176053541Sshin else 176153541Sshin return NULL; 176253541Sshin 176353541Sshin /* prefixlen + ifidlen must be equal to 128 */ 176478064Sume plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 176578064Sume if (prefixlen != plen0) { 176678064Sume nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 176778064Sume "(prefix=%d ifid=%d)\n", 176878064Sume if_name(ifp), prefixlen, 128 - plen0)); 176953541Sshin return NULL; 177053541Sshin } 177153541Sshin 177253541Sshin /* make ifaddr */ 177353541Sshin 177478064Sume bzero(&ifra, sizeof(ifra)); 177578064Sume /* 177678064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 177778064Sume * for safety. 177878064Sume */ 177978064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 178078064Sume ifra.ifra_addr.sin6_family = AF_INET6; 178178064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 178278064Sume /* prefix */ 1783151539Ssuz ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr; 178478064Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 178578064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 178678064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 178778064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 178853541Sshin 178953541Sshin /* interface ID */ 1790120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] |= 1791151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); 1792120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] |= 1793151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); 1794120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1795151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); 1796120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1797151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); 1798120941Sume 179978064Sume /* new prefix mask. */ 180078064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 180178064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 180278064Sume bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 1803120941Sume sizeof(ifra.ifra_prefixmask.sin6_addr)); 180453541Sshin 1805151539Ssuz /* lifetimes. */ 180678064Sume ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 180778064Sume ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 180853541Sshin 180978064Sume /* XXX: scope zone ID? */ 181053541Sshin 181178064Sume ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 1812151539Ssuz 1813151539Ssuz /* 1814151539Ssuz * Make sure that we do not have this address already. This should 1815151539Ssuz * usually not happen, but we can still see this case, e.g., if we 1816151539Ssuz * have manually configured the exact address to be configured. 181778064Sume */ 1818151539Ssuz if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { 1819151539Ssuz /* this should be rare enough to make an explicit log */ 1820151539Ssuz log(LOG_INFO, "in6_ifadd: %s is already configured\n", 1821165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr)); 1822151539Ssuz return (NULL); 1823151539Ssuz } 182453541Sshin 182553541Sshin /* 1826151539Ssuz * Allocate ifaddr structure, link into chain, etc. 1827151539Ssuz * If we are going to create a new address upon receiving a multicasted 1828151539Ssuz * RA, we need to impose a random delay before starting DAD. 1829151539Ssuz * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] 183053541Sshin */ 1831151539Ssuz updateflags = 0; 1832151539Ssuz if (mcast) 1833151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1834151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { 183578064Sume nd6log((LOG_ERR, 183678064Sume "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 1837165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr), 1838165118Sbz if_name(ifp), error)); 1839120856Sume return (NULL); /* ifaddr must not have been allocated. */ 184053541Sshin } 184153541Sshin 184278064Sume ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 184353541Sshin 1844120941Sume return (ia); /* this is always non-NULL */ 184553541Sshin} 184653541Sshin 1847171259Sdelphij/* 1848171259Sdelphij * ia0 - corresponding public address 1849171259Sdelphij */ 185053541Sshinint 1851171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) 185253541Sshin{ 185378064Sume struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 1854151539Ssuz struct in6_ifaddr *newia, *ia; 185578064Sume struct in6_aliasreq ifra; 185678064Sume int i, error; 185778064Sume int trylimit = 3; /* XXX: adhoc value */ 1858151539Ssuz int updateflags; 185978064Sume u_int32_t randid[2]; 186078064Sume time_t vltime0, pltime0; 186153541Sshin 186278064Sume bzero(&ifra, sizeof(ifra)); 186378064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 186478064Sume ifra.ifra_addr = ia0->ia_addr; 186578064Sume /* copy prefix mask */ 186678064Sume ifra.ifra_prefixmask = ia0->ia_prefixmask; 186778064Sume /* clear the old IFID */ 186878064Sume for (i = 0; i < 4; i++) { 1869120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[i] &= 1870120941Sume ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 187178064Sume } 187253541Sshin 187378064Sume again: 1874151539Ssuz if (in6_get_tmpifid(ifp, (u_int8_t *)randid, 1875151539Ssuz (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { 1876151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good " 1877151539Ssuz "random IFID\n")); 1878151539Ssuz return (EINVAL); 1879151539Ssuz } 1880120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1881120941Sume (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 1882120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1883120941Sume (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 188453541Sshin 1885151539Ssuz /* 1886151539Ssuz * in6_get_tmpifid() quite likely provided a unique interface ID. 1887151539Ssuz * However, we may still have a chance to see collision, because 1888151539Ssuz * there may be a time lag between generation of the ID and generation 1889151539Ssuz * of the address. So, we'll do one more sanity check. 189078064Sume */ 1891151539Ssuz for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 1892151539Ssuz if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 1893151539Ssuz &ifra.ifra_addr.sin6_addr)) { 1894151539Ssuz if (trylimit-- == 0) { 1895151539Ssuz /* 1896151539Ssuz * Give up. Something strange should have 1897151539Ssuz * happened. 1898151539Ssuz */ 1899151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " 1900151539Ssuz "find a unique random IFID\n")); 1901151539Ssuz return (EEXIST); 1902151539Ssuz } 1903151539Ssuz forcegen = 1; 1904151539Ssuz goto again; 190578064Sume } 190653541Sshin } 190753541Sshin 190878064Sume /* 190978064Sume * The Valid Lifetime is the lower of the Valid Lifetime of the 191078064Sume * public address or TEMP_VALID_LIFETIME. 191178064Sume * The Preferred Lifetime is the lower of the Preferred Lifetime 191278064Sume * of the public address or TEMP_PREFERRED_LIFETIME - 191378064Sume * DESYNC_FACTOR. 191478064Sume */ 1915151539Ssuz if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 191678064Sume vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 1917151539Ssuz (ia0->ia6_lifetime.ia6t_vltime - 1918151539Ssuz (time_second - ia0->ia6_updatetime)); 191978064Sume if (vltime0 > ip6_temp_valid_lifetime) 192078064Sume vltime0 = ip6_temp_valid_lifetime; 192178064Sume } else 192278064Sume vltime0 = ip6_temp_valid_lifetime; 1923151539Ssuz if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 192478064Sume pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 1925151539Ssuz (ia0->ia6_lifetime.ia6t_pltime - 1926151539Ssuz (time_second - ia0->ia6_updatetime)); 192778064Sume if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){ 192878064Sume pltime0 = ip6_temp_preferred_lifetime - 1929120941Sume ip6_desync_factor; 193078064Sume } 193178064Sume } else 193278064Sume pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor; 193378064Sume ifra.ifra_lifetime.ia6t_vltime = vltime0; 193478064Sume ifra.ifra_lifetime.ia6t_pltime = pltime0; 193553541Sshin 193678064Sume /* 193778064Sume * A temporary address is created only if this calculated Preferred 193878064Sume * Lifetime is greater than REGEN_ADVANCE time units. 193978064Sume */ 194078064Sume if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance) 1941120856Sume return (0); 194253541Sshin 194378064Sume /* XXX: scope zone ID? */ 194478064Sume 194578064Sume ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 194678064Sume 194778064Sume /* allocate ifaddr structure, link into chain, etc. */ 1948151539Ssuz updateflags = 0; 1949151539Ssuz if (delay) 1950151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1951151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) 1952120856Sume return (error); 195378064Sume 195478064Sume newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 195578064Sume if (newia == NULL) { /* XXX: can it happen? */ 195678064Sume nd6log((LOG_ERR, 195778064Sume "in6_tmpifadd: ifa update succeeded, but we got " 195878064Sume "no ifaddr\n")); 1959120856Sume return (EINVAL); /* XXX */ 196053541Sshin } 196178064Sume newia->ia6_ndpr = ia0->ia6_ndpr; 196278064Sume newia->ia6_ndpr->ndpr_refcnt++; 196353541Sshin 196478407Sume /* 196578407Sume * A newly added address might affect the status of other addresses. 196678407Sume * XXX: when the temporary address is generated with a new public 196778407Sume * address, the onlink check is redundant. However, it would be safe 196878407Sume * to do the check explicitly everywhere a new address is generated, 196978407Sume * and, in fact, we surely need the check when we create a new 197078407Sume * temporary address due to deprecation of an old temporary address. 197178407Sume */ 197278407Sume pfxlist_onlink_check(); 197378407Sume 1974120856Sume return (0); 1975120941Sume} 197653541Sshin 1977151539Ssuzstatic int 197853541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr) 197953541Sshin{ 198053541Sshin if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 198153541Sshin ndpr->ndpr_preferred = 0; 198253541Sshin else 198353541Sshin ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; 198453541Sshin if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 198553541Sshin ndpr->ndpr_expire = 0; 198653541Sshin else 198753541Sshin ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; 198853541Sshin 198953541Sshin return 0; 199053541Sshin} 199153541Sshin 199253541Sshinstatic void 199378064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 199453541Sshin{ 199578064Sume /* init ia6t_expire */ 199678064Sume if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 199778064Sume lt6->ia6t_expire = 0; 199878064Sume else { 199978064Sume lt6->ia6t_expire = time_second; 200078064Sume lt6->ia6t_expire += lt6->ia6t_vltime; 200153541Sshin } 200262587Sitojun 200353541Sshin /* init ia6t_preferred */ 200453541Sshin if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 200553541Sshin lt6->ia6t_preferred = 0; 200653541Sshin else { 200753541Sshin lt6->ia6t_preferred = time_second; 200853541Sshin lt6->ia6t_preferred += lt6->ia6t_pltime; 200953541Sshin } 201053541Sshin} 201153541Sshin 201253541Sshin/* 201353541Sshin * Delete all the routing table entries that use the specified gateway. 201453541Sshin * XXX: this function causes search through all entries of routing table, so 201553541Sshin * it shouldn't be called when acting as a router. 201653541Sshin */ 201753541Sshinvoid 2018171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp) 201953541Sshin{ 202053541Sshin struct radix_node_head *rnh = rt_tables[AF_INET6]; 202153541Sshin int s = splnet(); 202253541Sshin 202353541Sshin /* We'll care only link-local addresses */ 202453541Sshin if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { 202553541Sshin splx(s); 202653541Sshin return; 202753541Sshin } 202853541Sshin 2029108250Shsu RADIX_NODE_HEAD_LOCK(rnh); 203053541Sshin rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 2031108250Shsu RADIX_NODE_HEAD_UNLOCK(rnh); 203253541Sshin splx(s); 203353541Sshin} 203453541Sshin 203553541Sshinstatic int 2036171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg) 203753541Sshin{ 203853541Sshin#define SIN6(s) ((struct sockaddr_in6 *)s) 203953541Sshin struct rtentry *rt = (struct rtentry *)rn; 204053541Sshin struct in6_addr *gate = (struct in6_addr *)arg; 204153541Sshin 204253541Sshin if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 2043120856Sume return (0); 204453541Sshin 2045120941Sume if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) { 2046120856Sume return (0); 2047120941Sume } 204853541Sshin 204953541Sshin /* 205078064Sume * Do not delete a static route. 205178064Sume * XXX: this seems to be a bit ad-hoc. Should we consider the 205278064Sume * 'cloned' bit instead? 205378064Sume */ 205478064Sume if ((rt->rt_flags & RTF_STATIC) != 0) 2055120856Sume return (0); 205678064Sume 205778064Sume /* 205853541Sshin * We delete only host route. This means, in particular, we don't 205953541Sshin * delete default route. 206053541Sshin */ 206153541Sshin if ((rt->rt_flags & RTF_HOST) == 0) 2062120856Sume return (0); 206353541Sshin 2064120941Sume return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 2065120941Sume rt_mask(rt), rt->rt_flags, 0)); 206653541Sshin#undef SIN6 206753541Sshin} 206862587Sitojun 206962587Sitojunint 2070171259Sdelphijnd6_setdefaultiface(int ifindex) 207162587Sitojun{ 207262587Sitojun int error = 0; 207362587Sitojun 207462587Sitojun if (ifindex < 0 || if_index < ifindex) 2075120856Sume return (EINVAL); 2076151539Ssuz if (ifindex != 0 && !ifnet_byindex(ifindex)) 2077151539Ssuz return (EINVAL); 207862587Sitojun 207962587Sitojun if (nd6_defifindex != ifindex) { 208062587Sitojun nd6_defifindex = ifindex; 208162587Sitojun if (nd6_defifindex > 0) 208283130Sjlemon nd6_defifp = ifnet_byindex(nd6_defifindex); 208362587Sitojun else 208462587Sitojun nd6_defifp = NULL; 208562587Sitojun 208662587Sitojun /* 208762587Sitojun * Our current implementation assumes one-to-one maping between 208862587Sitojun * interfaces and links, so it would be natural to use the 208962587Sitojun * default interface as the default link. 209062587Sitojun */ 209162587Sitojun scope6_setdefault(nd6_defifp); 209262587Sitojun } 209362587Sitojun 2094120856Sume return (error); 209562587Sitojun} 2096