nd6_rtr.c revision 181803
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 181803 2008-08-17 23:27:27Z bz $"); 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> 49181803Sbz#include <sys/vimage.h> 5053541Sshin 5153541Sshin#include <net/if.h> 5253541Sshin#include <net/if_types.h> 5353541Sshin#include <net/if_dl.h> 5453541Sshin#include <net/route.h> 5553541Sshin#include <net/radix.h> 5653541Sshin 5753541Sshin#include <netinet/in.h> 5853541Sshin#include <netinet6/in6_var.h> 5978064Sume#include <netinet6/in6_ifattach.h> 6062587Sitojun#include <netinet/ip6.h> 6153541Sshin#include <netinet6/ip6_var.h> 6253541Sshin#include <netinet6/nd6.h> 6362587Sitojun#include <netinet/icmp6.h> 6462587Sitojun#include <netinet6/scope6_var.h> 6553541Sshin 6662587Sitojun#define SDL(s) ((struct sockaddr_dl *)s) 6753541Sshin 68175162Sobrienstatic int rtpref(struct nd_defrouter *); 69175162Sobrienstatic struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); 70151539Ssuzstatic int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *, 71151539Ssuz struct mbuf *, int)); 72175162Sobrienstatic struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int); 7362587Sitojunstatic struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, 7478064Sume struct nd_defrouter *)); 75175162Sobrienstatic void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *); 76175162Sobrienstatic void pfxrtr_del(struct nd_pfxrouter *); 7762587Sitojunstatic struct nd_pfxrouter *find_pfxlist_reachable_router 78175162Sobrien(struct nd_prefix *); 79175162Sobrienstatic void defrouter_delreq(struct nd_defrouter *); 80175162Sobrienstatic void nd6_rtmsg(int, struct rtentry *); 8153541Sshin 82175162Sobrienstatic int in6_init_prefix_ltimes(struct nd_prefix *); 83120941Sumestatic void in6_init_address_ltimes __P((struct nd_prefix *, 84120941Sume struct in6_addrlifetime *)); 8553541Sshin 86175162Sobrienstatic int rt6_deleteroute(struct radix_node *, void *); 8753541Sshin 8862587Sitojunextern int nd6_recalc_reachtm_interval; 8953541Sshin 9078064Sumestatic struct ifnet *nd6_defifp; 9162587Sitojunint nd6_defifindex; 9262587Sitojun 9378064Sumeint ip6_use_tempaddr = 0; 9478064Sume 9578064Sumeint ip6_desync_factor; 9678064Sumeu_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME; 9778064Sumeu_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME; 9853541Sshin/* 9978064Sume * shorter lifetimes for debugging purposes. 10078064Sumeint ip6_temp_preferred_lifetime = 800; 10178064Sumestatic int ip6_temp_valid_lifetime = 1800; 10278064Sume*/ 10378064Sumeint ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE; 10478064Sume 105151539Ssuz/* RTPREF_MEDIUM has to be 0! */ 106151539Ssuz#define RTPREF_HIGH 1 107151539Ssuz#define RTPREF_MEDIUM 0 108151539Ssuz#define RTPREF_LOW (-1) 109151539Ssuz#define RTPREF_RESERVED (-2) 110151539Ssuz#define RTPREF_INVALID (-3) /* internal */ 111151539Ssuz 11278064Sume/* 11353541Sshin * Receive Router Solicitation Message - just for routers. 11453541Sshin * Router solicitation/advertisement is mostly managed by userland program 11553541Sshin * (rtadvd) so here we have no function like nd6_ra_output(). 11653541Sshin * 11753541Sshin * Based on RFC 2461 11853541Sshin */ 11953541Sshinvoid 120171259Sdelphijnd6_rs_input(struct mbuf *m, int off, int icmp6len) 12153541Sshin{ 12253541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 12353541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 12462587Sitojun struct nd_router_solicit *nd_rs; 12553541Sshin struct in6_addr saddr6 = ip6->ip6_src; 12653541Sshin char *lladdr = NULL; 12753541Sshin int lladdrlen = 0; 12853541Sshin union nd_opts ndopts; 129165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 13053541Sshin 13153541Sshin /* If I'm not a router, ignore it. */ 132181803Sbz if (V_ip6_accept_rtadv != 0 || V_ip6_forwarding != 1) 13362587Sitojun goto freeit; 13453541Sshin 13553541Sshin /* Sanity checks */ 13653541Sshin if (ip6->ip6_hlim != 255) { 13778064Sume nd6log((LOG_ERR, 13878064Sume "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 139165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 140165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 14178064Sume goto bad; 14253541Sshin } 14353541Sshin 14453541Sshin /* 14553541Sshin * Don't update the neighbor cache, if src = ::. 14653541Sshin * This indicates that the src has no IP address assigned yet. 14753541Sshin */ 14853541Sshin if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 14962587Sitojun goto freeit; 15062587Sitojun 15162587Sitojun#ifndef PULLDOWN_TEST 15262587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 15362587Sitojun nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 15462587Sitojun#else 15562587Sitojun IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 15662587Sitojun if (nd_rs == NULL) { 157181803Sbz V_icmp6stat.icp6s_tooshort++; 15853541Sshin return; 15962587Sitojun } 16062587Sitojun#endif 16153541Sshin 16253541Sshin icmp6len -= sizeof(*nd_rs); 16353541Sshin nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 16453541Sshin if (nd6_options(&ndopts) < 0) { 16578064Sume nd6log((LOG_INFO, 16678064Sume "nd6_rs_input: invalid ND option, ignored\n")); 16778064Sume /* nd6_options have incremented stats */ 16862587Sitojun goto freeit; 16953541Sshin } 17053541Sshin 17153541Sshin if (ndopts.nd_opts_src_lladdr) { 17253541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 17353541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 17453541Sshin } 17553541Sshin 17653541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 17778064Sume nd6log((LOG_INFO, 17853541Sshin "nd6_rs_input: lladdrlen mismatch for %s " 17953541Sshin "(if %d, RS packet %d)\n", 180165118Sbz ip6_sprintf(ip6bufs, &saddr6), 181120941Sume ifp->if_addrlen, lladdrlen - 2)); 18278064Sume goto bad; 18353541Sshin } 18453541Sshin 18553541Sshin nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 18662587Sitojun 18762587Sitojun freeit: 18862587Sitojun m_freem(m); 18978064Sume return; 19078064Sume 19178064Sume bad: 192181803Sbz V_icmp6stat.icp6s_badrs++; 19378064Sume m_freem(m); 19453541Sshin} 19553541Sshin 19653541Sshin/* 19753541Sshin * Receive Router Advertisement Message. 19853541Sshin * 19953541Sshin * Based on RFC 2461 20053541Sshin * TODO: on-link bit on prefix information 20153541Sshin * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 20253541Sshin */ 20353541Sshinvoid 204171259Sdelphijnd6_ra_input(struct mbuf *m, int off, int icmp6len) 20553541Sshin{ 20653541Sshin struct ifnet *ifp = m->m_pkthdr.rcvif; 207121161Sume struct nd_ifinfo *ndi = ND_IFINFO(ifp); 20853541Sshin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 20962587Sitojun struct nd_router_advert *nd_ra; 21053541Sshin struct in6_addr saddr6 = ip6->ip6_src; 211151539Ssuz int mcast = 0; 21253541Sshin union nd_opts ndopts; 21353541Sshin struct nd_defrouter *dr; 214165118Sbz char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 21553541Sshin 216118498Sume /* 217118498Sume * We only accept RAs only when 218118498Sume * the system-wide variable allows the acceptance, and 219118498Sume * per-interface variable allows RAs on the receiving interface. 220118498Sume */ 221181803Sbz if (V_ip6_accept_rtadv == 0) 22262587Sitojun goto freeit; 223118498Sume if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 224118498Sume goto freeit; 22553541Sshin 22653541Sshin if (ip6->ip6_hlim != 255) { 22778064Sume nd6log((LOG_ERR, 22878064Sume "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 229165118Sbz ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 230165118Sbz ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 23178064Sume goto bad; 23253541Sshin } 23353541Sshin 23453541Sshin if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 23578064Sume nd6log((LOG_ERR, 23653541Sshin "nd6_ra_input: src %s is not link-local\n", 237165118Sbz ip6_sprintf(ip6bufs, &saddr6))); 23878064Sume goto bad; 23962587Sitojun } 24062587Sitojun 24162587Sitojun#ifndef PULLDOWN_TEST 24262587Sitojun IP6_EXTHDR_CHECK(m, off, icmp6len,); 24362587Sitojun nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); 24462587Sitojun#else 24562587Sitojun IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); 24662587Sitojun if (nd_ra == NULL) { 247181803Sbz V_icmp6stat.icp6s_tooshort++; 24853541Sshin return; 24953541Sshin } 25062587Sitojun#endif 25153541Sshin 25253541Sshin icmp6len -= sizeof(*nd_ra); 25353541Sshin nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 25453541Sshin if (nd6_options(&ndopts) < 0) { 25578064Sume nd6log((LOG_INFO, 25678064Sume "nd6_ra_input: invalid ND option, ignored\n")); 25778064Sume /* nd6_options have incremented stats */ 25862587Sitojun goto freeit; 25953541Sshin } 26053541Sshin 26153541Sshin { 26253541Sshin struct nd_defrouter dr0; 26353541Sshin u_int32_t advreachable = nd_ra->nd_ra_reachable; 26453541Sshin 265151539Ssuz /* remember if this is a multicasted advertisement */ 266151539Ssuz if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 267151539Ssuz mcast = 1; 268151539Ssuz 269151539Ssuz bzero(&dr0, sizeof(dr0)); 27053541Sshin dr0.rtaddr = saddr6; 27153541Sshin dr0.flags = nd_ra->nd_ra_flags_reserved; 272156871Ssuz dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 27353541Sshin dr0.expire = time_second + dr0.rtlifetime; 27453541Sshin dr0.ifp = ifp; 27553541Sshin /* unspecified or not? (RFC 2461 6.3.4) */ 27653541Sshin if (advreachable) { 27790868Smike advreachable = ntohl(advreachable); 27853541Sshin if (advreachable <= MAX_REACHABLE_TIME && 27953541Sshin ndi->basereachable != advreachable) { 28053541Sshin ndi->basereachable = advreachable; 28153541Sshin ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 282181803Sbz ndi->recalctm = V_nd6_recalc_reachtm_interval; /* reset */ 28353541Sshin } 28453541Sshin } 28553541Sshin if (nd_ra->nd_ra_retransmit) 28653541Sshin ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 28753541Sshin if (nd_ra->nd_ra_curhoplimit) 28853541Sshin ndi->chlim = nd_ra->nd_ra_curhoplimit; 28953541Sshin dr = defrtrlist_update(&dr0); 29053541Sshin } 29153541Sshin 29253541Sshin /* 29353541Sshin * prefix 29453541Sshin */ 29553541Sshin if (ndopts.nd_opts_pi) { 29653541Sshin struct nd_opt_hdr *pt; 29778064Sume struct nd_opt_prefix_info *pi = NULL; 298151539Ssuz struct nd_prefixctl pr; 29953541Sshin 30053541Sshin for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 30153541Sshin pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 30253541Sshin pt = (struct nd_opt_hdr *)((caddr_t)pt + 30353541Sshin (pt->nd_opt_len << 3))) { 30453541Sshin if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 30553541Sshin continue; 30653541Sshin pi = (struct nd_opt_prefix_info *)pt; 30753541Sshin 30853541Sshin if (pi->nd_opt_pi_len != 4) { 30978064Sume nd6log((LOG_INFO, 31078064Sume "nd6_ra_input: invalid option " 31178064Sume "len %d for prefix information option, " 31278064Sume "ignored\n", pi->nd_opt_pi_len)); 31353541Sshin continue; 31453541Sshin } 31553541Sshin 31653541Sshin if (128 < pi->nd_opt_pi_prefix_len) { 31778064Sume nd6log((LOG_INFO, 31878064Sume "nd6_ra_input: invalid prefix " 31978064Sume "len %d for prefix information option, " 32078064Sume "ignored\n", pi->nd_opt_pi_prefix_len)); 32153541Sshin continue; 32253541Sshin } 32353541Sshin 32453541Sshin if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 32553541Sshin || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 32678064Sume nd6log((LOG_INFO, 32778064Sume "nd6_ra_input: invalid prefix " 32878064Sume "%s, ignored\n", 329165118Sbz ip6_sprintf(ip6bufs, 330165118Sbz &pi->nd_opt_pi_prefix))); 33153541Sshin continue; 33253541Sshin } 33353541Sshin 33453541Sshin bzero(&pr, sizeof(pr)); 33553541Sshin pr.ndpr_prefix.sin6_family = AF_INET6; 33653541Sshin pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 33753541Sshin pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 33853541Sshin pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 33953541Sshin 34053541Sshin pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 341120941Sume ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 34253541Sshin pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 343120941Sume ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 34453541Sshin pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 34553541Sshin pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 346120941Sume pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); 347151539Ssuz (void)prelist_update(&pr, dr, m, mcast); 34853541Sshin } 34953541Sshin } 35053541Sshin 35153541Sshin /* 35253541Sshin * MTU 35353541Sshin */ 35453541Sshin if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 355121283Sume u_long mtu; 356121283Sume u_long maxmtu; 35753541Sshin 358121283Sume mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 359120941Sume 36053541Sshin /* lower bound */ 36153541Sshin if (mtu < IPV6_MMTU) { 36278064Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " 363121283Sume "mtu=%lu sent from %s, ignoring\n", 364165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src))); 36553541Sshin goto skip; 36653541Sshin } 36753541Sshin 36853541Sshin /* upper bound */ 369121283Sume maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu) 370121283Sume ? ndi->maxmtu : ifp->if_mtu; 371121283Sume if (mtu <= maxmtu) { 372121283Sume int change = (ndi->linkmtu != mtu); 37353541Sshin 374121283Sume ndi->linkmtu = mtu; 375121283Sume if (change) /* in6_maxmtu may change */ 376121283Sume in6_setmaxmtu(); 37753541Sshin } else { 378121283Sume nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " 379121283Sume "mtu=%lu sent from %s; " 380121283Sume "exceeds maxmtu %lu, ignoring\n", 381165118Sbz mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu)); 38253541Sshin } 38353541Sshin } 38453541Sshin 38553541Sshin skip: 386120941Sume 38753541Sshin /* 38895023Ssuz * Source link layer address 38953541Sshin */ 39053541Sshin { 39153541Sshin char *lladdr = NULL; 39253541Sshin int lladdrlen = 0; 393120941Sume 39453541Sshin if (ndopts.nd_opts_src_lladdr) { 39553541Sshin lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 39653541Sshin lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 39753541Sshin } 39853541Sshin 39953541Sshin if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 40078064Sume nd6log((LOG_INFO, 40153541Sshin "nd6_ra_input: lladdrlen mismatch for %s " 402165118Sbz "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6), 403120941Sume ifp->if_addrlen, lladdrlen - 2)); 40478064Sume goto bad; 40553541Sshin } 40653541Sshin 407120941Sume nd6_cache_lladdr(ifp, &saddr6, lladdr, 408120941Sume lladdrlen, ND_ROUTER_ADVERT, 0); 40962587Sitojun 41062587Sitojun /* 41162587Sitojun * Installing a link-layer address might change the state of the 41262587Sitojun * router's neighbor cache, which might also affect our on-link 41362587Sitojun * detection of adveritsed prefixes. 41462587Sitojun */ 41562587Sitojun pfxlist_onlink_check(); 41653541Sshin } 41762587Sitojun 41878064Sume freeit: 41962587Sitojun m_freem(m); 42078064Sume return; 42178064Sume 42278064Sume bad: 423181803Sbz V_icmp6stat.icp6s_badra++; 42478064Sume m_freem(m); 42553541Sshin} 42653541Sshin 42753541Sshin/* 42853541Sshin * default router list proccessing sub routines 42953541Sshin */ 43062587Sitojun 43162587Sitojun/* tell the change to user processes watching the routing socket. */ 43262587Sitojunstatic void 433171259Sdelphijnd6_rtmsg(int cmd, struct rtentry *rt) 43462587Sitojun{ 43562587Sitojun struct rt_addrinfo info; 43662587Sitojun 43762587Sitojun bzero((caddr_t)&info, sizeof(info)); 43862587Sitojun info.rti_info[RTAX_DST] = rt_key(rt); 43962587Sitojun info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 44062587Sitojun info.rti_info[RTAX_NETMASK] = rt_mask(rt); 441151539Ssuz if (rt->rt_ifp) { 442151539Ssuz info.rti_info[RTAX_IFP] = 443151539Ssuz TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 444151539Ssuz info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 445151539Ssuz } 44662587Sitojun 44762587Sitojun rt_missmsg(cmd, &info, rt->rt_flags, 0); 44862587Sitojun} 44962587Sitojun 45053541Sshinvoid 451171259Sdelphijdefrouter_addreq(struct nd_defrouter *new) 45253541Sshin{ 45353541Sshin struct sockaddr_in6 def, mask, gate; 45462587Sitojun struct rtentry *newrt = NULL; 455151539Ssuz int s; 456151539Ssuz int error; 45753541Sshin 458128397Sluigi bzero(&def, sizeof(def)); 459128397Sluigi bzero(&mask, sizeof(mask)); 460128397Sluigi bzero(&gate, sizeof(gate)); 46153541Sshin 462120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 463120941Sume sizeof(struct sockaddr_in6); 464151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 46553541Sshin gate.sin6_addr = new->rtaddr; 46653541Sshin 467151539Ssuz s = splnet(); 468151539Ssuz error = rtrequest(RTM_ADD, (struct sockaddr *)&def, 469120941Sume (struct sockaddr *)&gate, (struct sockaddr *)&mask, 470120941Sume RTF_GATEWAY, &newrt); 47162587Sitojun if (newrt) { 472120727Ssam RT_LOCK(newrt); 47378064Sume nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 474122334Ssam RT_REMREF(newrt); 475120727Ssam RT_UNLOCK(newrt); 47662587Sitojun } 477151539Ssuz if (error == 0) 478151539Ssuz new->installed = 1; 479151539Ssuz splx(s); 48053541Sshin return; 48153541Sshin} 48253541Sshin 48353541Sshinstruct nd_defrouter * 484171259Sdelphijdefrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) 48553541Sshin{ 48653541Sshin struct nd_defrouter *dr; 48753541Sshin 488181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 48962587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 49053541Sshin if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 491120856Sume return (dr); 49262587Sitojun } 49353541Sshin 494120856Sume return (NULL); /* search failed */ 49553541Sshin} 49653541Sshin 497151539Ssuz/* 498151539Ssuz * Remove the default route for a given router. 499151539Ssuz * This is just a subroutine function for defrouter_select(), and should 500151539Ssuz * not be called from anywhere else. 501151539Ssuz */ 502151539Ssuzstatic void 503171259Sdelphijdefrouter_delreq(struct nd_defrouter *dr) 50453541Sshin{ 50553541Sshin struct sockaddr_in6 def, mask, gate; 50662587Sitojun struct rtentry *oldrt = NULL; 50753541Sshin 508128397Sluigi bzero(&def, sizeof(def)); 509128397Sluigi bzero(&mask, sizeof(mask)); 510128397Sluigi bzero(&gate, sizeof(gate)); 51153541Sshin 512120941Sume def.sin6_len = mask.sin6_len = gate.sin6_len = 513120941Sume sizeof(struct sockaddr_in6); 514151539Ssuz def.sin6_family = gate.sin6_family = AF_INET6; 51553541Sshin gate.sin6_addr = dr->rtaddr; 51653541Sshin 51753541Sshin rtrequest(RTM_DELETE, (struct sockaddr *)&def, 518120941Sume (struct sockaddr *)&gate, 519120941Sume (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); 52062587Sitojun if (oldrt) { 52178064Sume nd6_rtmsg(RTM_DELETE, oldrt); 522108269Sru RTFREE(oldrt); 52362587Sitojun } 52453541Sshin 525151539Ssuz dr->installed = 0; 52653541Sshin} 52753541Sshin 528151539Ssuz/* 529151539Ssuz * remove all default routes from default router list 530151539Ssuz */ 53153541Sshinvoid 532171259Sdelphijdefrouter_reset(void) 533151539Ssuz{ 534151539Ssuz struct nd_defrouter *dr; 535151539Ssuz 536181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 537151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) 538151539Ssuz defrouter_delreq(dr); 539151539Ssuz 540151539Ssuz /* 541151539Ssuz * XXX should we also nuke any default routers in the kernel, by 542151539Ssuz * going through them by rtalloc1()? 543151539Ssuz */ 544151539Ssuz} 545151539Ssuz 546151539Ssuzvoid 547171259Sdelphijdefrtrlist_del(struct nd_defrouter *dr) 54853541Sshin{ 54953541Sshin struct nd_defrouter *deldr = NULL; 55053541Sshin struct nd_prefix *pr; 55153541Sshin 55253541Sshin /* 55353541Sshin * Flush all the routing table entries that use the router 55453541Sshin * as a next hop. 55553541Sshin */ 556181803Sbz if (!V_ip6_forwarding && V_ip6_accept_rtadv) /* XXX: better condition? */ 55753541Sshin rt6_flush(&dr->rtaddr, dr->ifp); 55853541Sshin 559151539Ssuz if (dr->installed) { 560151539Ssuz deldr = dr; 561151539Ssuz defrouter_delreq(dr); 562151539Ssuz } 563181803Sbz TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 56453541Sshin 56553541Sshin /* 56653541Sshin * Also delete all the pointers to the router in each prefix lists. 56753541Sshin */ 568181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 56953541Sshin struct nd_pfxrouter *pfxrtr; 57053541Sshin if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 57153541Sshin pfxrtr_del(pfxrtr); 57253541Sshin } 57353541Sshin pfxlist_onlink_check(); 57453541Sshin 57553541Sshin /* 57662587Sitojun * If the router is the primary one, choose a new one. 57762587Sitojun * Note that defrouter_select() will remove the current gateway 57862587Sitojun * from the routing table. 57953541Sshin */ 58053541Sshin if (deldr) 58162587Sitojun defrouter_select(); 58262587Sitojun 58353541Sshin free(dr, M_IP6NDP); 58453541Sshin} 58553541Sshin 58662587Sitojun/* 587151539Ssuz * Default Router Selection according to Section 6.3.6 of RFC 2461 and 588151539Ssuz * draft-ietf-ipngwg-router-selection: 589151539Ssuz * 1) Routers that are reachable or probably reachable should be preferred. 590151539Ssuz * If we have more than one (probably) reachable router, prefer ones 591151539Ssuz * with the highest router preference. 59262587Sitojun * 2) When no routers on the list are known to be reachable or 59362587Sitojun * probably reachable, routers SHOULD be selected in a round-robin 594151539Ssuz * fashion, regardless of router preference values. 59562587Sitojun * 3) If the Default Router List is empty, assume that all 59662587Sitojun * destinations are on-link. 597151539Ssuz * 598151539Ssuz * We assume nd_defrouter is sorted by router preference value. 599151539Ssuz * Since the code below covers both with and without router preference cases, 600151539Ssuz * we do not need to classify the cases by ifdef. 601151539Ssuz * 602151539Ssuz * At this moment, we do not try to install more than one default router, 603151539Ssuz * even when the multipath routing is available, because we're not sure about 604151539Ssuz * the benefits for stub hosts comparing to the risk of making the code 605151539Ssuz * complicated and the possibility of introducing bugs. 60662587Sitojun */ 60762587Sitojunvoid 608171259Sdelphijdefrouter_select(void) 60962587Sitojun{ 61062587Sitojun int s = splnet(); 611151539Ssuz struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; 61262587Sitojun struct rtentry *rt = NULL; 61362587Sitojun struct llinfo_nd6 *ln = NULL; 61462587Sitojun 61562587Sitojun /* 616151539Ssuz * This function should be called only when acting as an autoconfigured 617151539Ssuz * host. Although the remaining part of this function is not effective 618151539Ssuz * if the node is not an autoconfigured host, we explicitly exclude 619151539Ssuz * such cases here for safety. 620151539Ssuz */ 621181803Sbz if (V_ip6_forwarding || !V_ip6_accept_rtadv) { 622151539Ssuz nd6log((LOG_WARNING, 623151539Ssuz "defrouter_select: called unexpectedly (forwarding=%d, " 624181803Sbz "accept_rtadv=%d)\n", V_ip6_forwarding, V_ip6_accept_rtadv)); 625151539Ssuz splx(s); 626151539Ssuz return; 627151539Ssuz } 628151539Ssuz 629151539Ssuz /* 630151539Ssuz * Let's handle easy case (3) first: 631151539Ssuz * If default router list is empty, there's nothing to be done. 632151539Ssuz */ 633181803Sbz if (!TAILQ_FIRST(&V_nd_defrouter)) { 634151539Ssuz splx(s); 635151539Ssuz return; 636151539Ssuz } 637151539Ssuz 638151539Ssuz /* 63962587Sitojun * Search for a (probably) reachable router from the list. 640151539Ssuz * We just pick up the first reachable one (if any), assuming that 641151539Ssuz * the ordering rule of the list described in defrtrlist_update(). 64262587Sitojun */ 643181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 64462587Sitojun dr = TAILQ_NEXT(dr, dr_entry)) { 645151539Ssuz if (selected_dr == NULL && 646151539Ssuz (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && 64762587Sitojun (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 64862587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) { 649151539Ssuz selected_dr = dr; 65062587Sitojun } 65162587Sitojun 652151539Ssuz if (dr->installed && installed_dr == NULL) 653151539Ssuz installed_dr = dr; 654151539Ssuz else if (dr->installed && installed_dr) { 655151539Ssuz /* this should not happen. warn for diagnosis. */ 656151539Ssuz log(LOG_ERR, "defrouter_select: more than one router" 657151539Ssuz " is installed\n"); 65862587Sitojun } 65962587Sitojun } 660151539Ssuz /* 661151539Ssuz * If none of the default routers was found to be reachable, 662151539Ssuz * round-robin the list regardless of preference. 663151539Ssuz * Otherwise, if we have an installed router, check if the selected 664151539Ssuz * (reachable) router should really be preferred to the installed one. 665151539Ssuz * We only prefer the new router when the old one is not reachable 666151539Ssuz * or when the new one has a really higher preference value. 667151539Ssuz */ 668151539Ssuz if (selected_dr == NULL) { 669151539Ssuz if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry)) 670181803Sbz selected_dr = TAILQ_FIRST(&V_nd_defrouter); 671151539Ssuz else 672151539Ssuz selected_dr = TAILQ_NEXT(installed_dr, dr_entry); 673151539Ssuz } else if (installed_dr && 674151539Ssuz (rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && 675151539Ssuz (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 676151539Ssuz ND6_IS_LLINFO_PROBREACH(ln) && 677151539Ssuz rtpref(selected_dr) <= rtpref(installed_dr)) { 678151539Ssuz selected_dr = installed_dr; 679151539Ssuz } 68062587Sitojun 681151539Ssuz /* 682151539Ssuz * If the selected router is different than the installed one, 683151539Ssuz * remove the installed router and install the selected one. 684151539Ssuz * Note that the selected router is never NULL here. 685151539Ssuz */ 686151539Ssuz if (installed_dr != selected_dr) { 687151539Ssuz if (installed_dr) 688151539Ssuz defrouter_delreq(installed_dr); 689151539Ssuz defrouter_addreq(selected_dr); 690151539Ssuz } 691151539Ssuz 69262587Sitojun splx(s); 69362587Sitojun return; 69462587Sitojun} 69562587Sitojun 696151539Ssuz/* 697151539Ssuz * for default router selection 698151539Ssuz * regards router-preference field as a 2-bit signed integer 699151539Ssuz */ 700151539Ssuzstatic int 701151539Ssuzrtpref(struct nd_defrouter *dr) 702151539Ssuz{ 703151539Ssuz switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) { 704151539Ssuz case ND_RA_FLAG_RTPREF_HIGH: 705151539Ssuz return (RTPREF_HIGH); 706151539Ssuz case ND_RA_FLAG_RTPREF_MEDIUM: 707156871Ssuz case ND_RA_FLAG_RTPREF_RSV: 708151539Ssuz return (RTPREF_MEDIUM); 709151539Ssuz case ND_RA_FLAG_RTPREF_LOW: 710151539Ssuz return (RTPREF_LOW); 711151539Ssuz default: 712151539Ssuz /* 713151539Ssuz * This case should never happen. If it did, it would mean a 714151539Ssuz * serious bug of kernel internal. We thus always bark here. 715151539Ssuz * Or, can we even panic? 716151539Ssuz */ 717151539Ssuz log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags); 718151539Ssuz return (RTPREF_INVALID); 719151539Ssuz } 720151539Ssuz /* NOTREACHED */ 721151539Ssuz} 722151539Ssuz 72353541Sshinstatic struct nd_defrouter * 724171259Sdelphijdefrtrlist_update(struct nd_defrouter *new) 72553541Sshin{ 72653541Sshin struct nd_defrouter *dr, *n; 72753541Sshin int s = splnet(); 72853541Sshin 72953541Sshin if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 73053541Sshin /* entry exists */ 73153541Sshin if (new->rtlifetime == 0) { 73253541Sshin defrtrlist_del(dr); 73353541Sshin dr = NULL; 73453541Sshin } else { 735151539Ssuz int oldpref = rtpref(dr); 736151539Ssuz 73753541Sshin /* override */ 73853541Sshin dr->flags = new->flags; /* xxx flag check */ 73953541Sshin dr->rtlifetime = new->rtlifetime; 74053541Sshin dr->expire = new->expire; 741151539Ssuz 742151539Ssuz /* 743151539Ssuz * If the preference does not change, there's no need 744151539Ssuz * to sort the entries. 745151539Ssuz */ 746151539Ssuz if (rtpref(new) == oldpref) { 747151539Ssuz splx(s); 748151539Ssuz return (dr); 749151539Ssuz } 750151539Ssuz 751151539Ssuz /* 752151539Ssuz * preferred router may be changed, so relocate 753151539Ssuz * this router. 754151539Ssuz * XXX: calling TAILQ_REMOVE directly is a bad manner. 755151539Ssuz * However, since defrtrlist_del() has many side 756151539Ssuz * effects, we intentionally do so here. 757151539Ssuz * defrouter_select() below will handle routing 758151539Ssuz * changes later. 759151539Ssuz */ 760181803Sbz TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 761151539Ssuz n = dr; 762151539Ssuz goto insert; 76353541Sshin } 76453541Sshin splx(s); 765120856Sume return (dr); 76653541Sshin } 76753541Sshin 76853541Sshin /* entry does not exist */ 76953541Sshin if (new->rtlifetime == 0) { 77053541Sshin splx(s); 771120856Sume return (NULL); 77253541Sshin } 77353541Sshin 77453541Sshin n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 77553541Sshin if (n == NULL) { 77653541Sshin splx(s); 777120856Sume return (NULL); 77853541Sshin } 77953541Sshin bzero(n, sizeof(*n)); 78053541Sshin *n = *new; 78162587Sitojun 782151539Ssuzinsert: 78362587Sitojun /* 784151539Ssuz * Insert the new router in the Default Router List; 785151539Ssuz * The Default Router List should be in the descending order 786151539Ssuz * of router-preferece. Routers with the same preference are 787151539Ssuz * sorted in the arriving time order. 78862587Sitojun */ 789151539Ssuz 790151539Ssuz /* insert at the end of the group */ 791181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 792151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 793151539Ssuz if (rtpref(n) > rtpref(dr)) 794151539Ssuz break; 795151539Ssuz } 796151539Ssuz if (dr) 797151539Ssuz TAILQ_INSERT_BEFORE(dr, n, dr_entry); 798151539Ssuz else 799181803Sbz TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry); 800151539Ssuz 801151539Ssuz defrouter_select(); 802151539Ssuz 80353541Sshin splx(s); 804120941Sume 805120856Sume return (n); 80653541Sshin} 80753541Sshin 80853541Sshinstatic struct nd_pfxrouter * 809171259Sdelphijpfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) 81053541Sshin{ 81153541Sshin struct nd_pfxrouter *search; 812120941Sume 81362587Sitojun for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { 81453541Sshin if (search->router == dr) 81553541Sshin break; 81653541Sshin } 81753541Sshin 818120856Sume return (search); 81953541Sshin} 82053541Sshin 82153541Sshinstatic void 822171259Sdelphijpfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) 82353541Sshin{ 82453541Sshin struct nd_pfxrouter *new; 82553541Sshin 82653541Sshin new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 82753541Sshin if (new == NULL) 82853541Sshin return; 82953541Sshin bzero(new, sizeof(*new)); 83053541Sshin new->router = dr; 83153541Sshin 83253541Sshin LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 83353541Sshin 83453541Sshin pfxlist_onlink_check(); 83553541Sshin} 83653541Sshin 83753541Sshinstatic void 838171259Sdelphijpfxrtr_del(struct nd_pfxrouter *pfr) 83953541Sshin{ 84053541Sshin LIST_REMOVE(pfr, pfr_entry); 84153541Sshin free(pfr, M_IP6NDP); 84253541Sshin} 84353541Sshin 84478064Sumestruct nd_prefix * 845171259Sdelphijnd6_prefix_lookup(struct nd_prefixctl *key) 84653541Sshin{ 84753541Sshin struct nd_prefix *search; 84853541Sshin 849181803Sbz for (search = V_nd_prefix.lh_first; search; search = search->ndpr_next) { 850151539Ssuz if (key->ndpr_ifp == search->ndpr_ifp && 851151539Ssuz key->ndpr_plen == search->ndpr_plen && 852151539Ssuz in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr, 853151539Ssuz &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) { 85453541Sshin break; 85553541Sshin } 85653541Sshin } 85753541Sshin 858120856Sume return (search); 85953541Sshin} 86053541Sshin 86178064Sumeint 862171259Sdelphijnd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr, 863171259Sdelphij struct nd_prefix **newp) 86453541Sshin{ 86578064Sume struct nd_prefix *new = NULL; 866151539Ssuz int error = 0; 86753541Sshin int i, s; 868165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 86953541Sshin 87053541Sshin new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 87153541Sshin if (new == NULL) 872120941Sume return(ENOMEM); 87353541Sshin bzero(new, sizeof(*new)); 874151539Ssuz new->ndpr_ifp = pr->ndpr_ifp; 875151539Ssuz new->ndpr_prefix = pr->ndpr_prefix; 876151539Ssuz new->ndpr_plen = pr->ndpr_plen; 877151539Ssuz new->ndpr_vltime = pr->ndpr_vltime; 878151539Ssuz new->ndpr_pltime = pr->ndpr_pltime; 879151539Ssuz new->ndpr_flags = pr->ndpr_flags; 880151539Ssuz if ((error = in6_init_prefix_ltimes(new)) != 0) { 881151539Ssuz free(new, M_IP6NDP); 882151539Ssuz return(error); 883151539Ssuz } 884151539Ssuz new->ndpr_lastupdate = time_second; 88578064Sume if (newp != NULL) 88678064Sume *newp = new; 88753541Sshin 888120941Sume /* initialization */ 88953541Sshin LIST_INIT(&new->ndpr_advrtrs); 89053541Sshin in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 89153541Sshin /* make prefix in the canonical form */ 89253541Sshin for (i = 0; i < 4; i++) 89353541Sshin new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 894120941Sume new->ndpr_mask.s6_addr32[i]; 89553541Sshin 89653541Sshin s = splnet(); 89753541Sshin /* link ndpr_entry to nd_prefix list */ 898181803Sbz LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry); 89953541Sshin splx(s); 90053541Sshin 90178064Sume /* ND_OPT_PI_FLAG_ONLINK processing */ 90278064Sume if (new->ndpr_raf_onlink) { 90378064Sume int e; 90478064Sume 90578064Sume if ((e = nd6_prefix_onlink(new)) != 0) { 90678064Sume nd6log((LOG_ERR, "nd6_prelist_add: failed to make " 90778064Sume "the prefix %s/%d on-link on %s (errno=%d)\n", 908165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 90978064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 91078064Sume /* proceed anyway. XXX: is it correct? */ 91178064Sume } 91278064Sume } 91378064Sume 914120941Sume if (dr) 91553541Sshin pfxrtr_add(new, dr); 91653541Sshin 91753541Sshin return 0; 91853541Sshin} 91953541Sshin 92053541Sshinvoid 921171259Sdelphijprelist_remove(struct nd_prefix *pr) 92253541Sshin{ 92353541Sshin struct nd_pfxrouter *pfr, *next; 92478064Sume int e, s; 925165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 92653541Sshin 92778064Sume /* make sure to invalidate the prefix until it is really freed. */ 92878064Sume pr->ndpr_vltime = 0; 92978064Sume pr->ndpr_pltime = 0; 930151539Ssuz 93178064Sume /* 93278064Sume * Though these flags are now meaningless, we'd rather keep the value 933151479Ssuz * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users 934151479Ssuz * when executing "ndp -p". 93578064Sume */ 936151479Ssuz 93778064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && 93878064Sume (e = nd6_prefix_offlink(pr)) != 0) { 93978064Sume nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " 94078064Sume "on %s, errno=%d\n", 941165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 94278064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 94378064Sume /* what should we do? */ 94478064Sume } 94578064Sume 94678064Sume if (pr->ndpr_refcnt > 0) 94778064Sume return; /* notice here? */ 94878064Sume 94953541Sshin s = splnet(); 95078064Sume 95153541Sshin /* unlink ndpr_entry from nd_prefix list */ 95253541Sshin LIST_REMOVE(pr, ndpr_entry); 95353541Sshin 95453541Sshin /* free list of routers that adversed the prefix */ 95562587Sitojun for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { 95662587Sitojun next = pfr->pfr_next; 95753541Sshin 95853541Sshin free(pfr, M_IP6NDP); 95953541Sshin } 96078064Sume splx(s); 96178064Sume 96253541Sshin free(pr, M_IP6NDP); 96353541Sshin 96453541Sshin pfxlist_onlink_check(); 96553541Sshin} 96653541Sshin 967171259Sdelphij/* 968171259Sdelphij * dr - may be NULL 969171259Sdelphij */ 970171259Sdelphij 971151539Ssuzstatic int 972171259Sdelphijprelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, 973171259Sdelphij struct mbuf *m, int mcast) 97453541Sshin{ 97578064Sume struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 97678064Sume struct ifaddr *ifa; 97778064Sume struct ifnet *ifp = new->ndpr_ifp; 97853541Sshin struct nd_prefix *pr; 97953541Sshin int s = splnet(); 98053541Sshin int error = 0; 98178064Sume int newprefix = 0; 98253541Sshin int auth; 98378064Sume struct in6_addrlifetime lt6_tmp; 984165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 98553541Sshin 98653541Sshin auth = 0; 98753541Sshin if (m) { 98853541Sshin /* 98953541Sshin * Authenticity for NA consists authentication for 99053541Sshin * both IP header and IP datagrams, doesn't it ? 99153541Sshin */ 99253541Sshin#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 993120941Sume auth = ((m->m_flags & M_AUTHIPHDR) && 994120941Sume (m->m_flags & M_AUTHIPDGM)); 99553541Sshin#endif 99653541Sshin } 99753541Sshin 99878064Sume if ((pr = nd6_prefix_lookup(new)) != NULL) { 99978064Sume /* 100078064Sume * nd6_prefix_lookup() ensures that pr and new have the same 100178064Sume * prefix on a same interface. 100278064Sume */ 100353541Sshin 100453541Sshin /* 100578064Sume * Update prefix information. Note that the on-link (L) bit 100678064Sume * and the autonomous (A) bit should NOT be changed from 1 100778064Sume * to 0. 100853541Sshin */ 100978064Sume if (new->ndpr_raf_onlink == 1) 101078064Sume pr->ndpr_raf_onlink = 1; 101178064Sume if (new->ndpr_raf_auto == 1) 101278064Sume pr->ndpr_raf_auto = 1; 101378064Sume if (new->ndpr_raf_onlink) { 101478064Sume pr->ndpr_vltime = new->ndpr_vltime; 101578064Sume pr->ndpr_pltime = new->ndpr_pltime; 1016151539Ssuz (void)in6_init_prefix_ltimes(pr); /* XXX error case? */ 1017151539Ssuz pr->ndpr_lastupdate = time_second; 101878064Sume } 101953541Sshin 102078064Sume if (new->ndpr_raf_onlink && 102178064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 102278064Sume int e; 102353541Sshin 102478064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 102578064Sume nd6log((LOG_ERR, 102678064Sume "prelist_update: failed to make " 102778064Sume "the prefix %s/%d on-link on %s " 102878064Sume "(errno=%d)\n", 1029165118Sbz ip6_sprintf(ip6buf, 1030165118Sbz &pr->ndpr_prefix.sin6_addr), 103178064Sume pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 103278064Sume /* proceed anyway. XXX: is it correct? */ 103353541Sshin } 103478064Sume } 103553541Sshin 103678064Sume if (dr && pfxrtr_lookup(pr, dr) == NULL) 103778064Sume pfxrtr_add(pr, dr); 103878064Sume } else { 103978064Sume struct nd_prefix *newpr = NULL; 104053541Sshin 104178064Sume newprefix = 1; 104253541Sshin 104378064Sume if (new->ndpr_vltime == 0) 104478064Sume goto end; 104578064Sume if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 104678064Sume goto end; 104753541Sshin 104878064Sume error = nd6_prelist_add(new, dr, &newpr); 104978064Sume if (error != 0 || newpr == NULL) { 105078064Sume nd6log((LOG_NOTICE, "prelist_update: " 105178064Sume "nd6_prelist_add failed for %s/%d on %s " 105278064Sume "errno=%d, returnpr=%p\n", 1053165118Sbz ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr), 1054120941Sume new->ndpr_plen, if_name(new->ndpr_ifp), 1055120941Sume error, newpr)); 105678064Sume goto end; /* we should just give up in this case. */ 105778064Sume } 105853541Sshin 105978064Sume /* 106078064Sume * XXX: from the ND point of view, we can ignore a prefix 106178064Sume * with the on-link bit being zero. However, we need a 106278064Sume * prefix structure for references from autoconfigured 1063120941Sume * addresses. Thus, we explicitly make sure that the prefix 106478064Sume * itself expires now. 106578064Sume */ 106678064Sume if (newpr->ndpr_raf_onlink == 0) { 106778064Sume newpr->ndpr_vltime = 0; 106878064Sume newpr->ndpr_pltime = 0; 106978064Sume in6_init_prefix_ltimes(newpr); 107053541Sshin } 107153541Sshin 107278064Sume pr = newpr; 107378064Sume } 107453541Sshin 107578064Sume /* 107678064Sume * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 107778064Sume * Note that pr must be non NULL at this point. 107878064Sume */ 107962587Sitojun 108078064Sume /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 108178064Sume if (!new->ndpr_raf_auto) 1082151539Ssuz goto end; 108362587Sitojun 108478064Sume /* 108578064Sume * 5.5.3 (b). the link-local prefix should have been ignored in 108678064Sume * nd6_ra_input. 108778064Sume */ 108862587Sitojun 1089151539Ssuz /* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */ 1090151539Ssuz if (new->ndpr_pltime > new->ndpr_vltime) { 1091151539Ssuz error = EINVAL; /* XXX: won't be used */ 1092151539Ssuz goto end; 1093151539Ssuz } 109462587Sitojun 1095171260Sdelphij /* 1096151539Ssuz * 5.5.3 (d). If the prefix advertised is not equal to the prefix of 1097151539Ssuz * an address configured by stateless autoconfiguration already in the 1098151539Ssuz * list of addresses associated with the interface, and the Valid 1099151539Ssuz * Lifetime is not 0, form an address. We first check if we have 1100151539Ssuz * a matching prefix. 1101151539Ssuz * Note: we apply a clarification in rfc2462bis-02 here. We only 1102151539Ssuz * consider autoconfigured addresses while RFC2462 simply said 1103151539Ssuz * "address". 110478064Sume */ 1105120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 110678064Sume struct in6_ifaddr *ifa6; 1107151539Ssuz u_int32_t remaininglifetime; 110853541Sshin 110978064Sume if (ifa->ifa_addr->sa_family != AF_INET6) 111078064Sume continue; 111153541Sshin 111278064Sume ifa6 = (struct in6_ifaddr *)ifa; 111353541Sshin 111453541Sshin /* 1115151539Ssuz * We only consider autoconfigured addresses as per rfc2462bis. 1116151539Ssuz */ 1117151539Ssuz if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF)) 1118151539Ssuz continue; 1119151539Ssuz 1120151539Ssuz /* 112178064Sume * Spec is not clear here, but I believe we should concentrate 112278064Sume * on unicast (i.e. not anycast) addresses. 112378064Sume * XXX: other ia6_flags? detached or duplicated? 112453541Sshin */ 112578064Sume if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 112678064Sume continue; 1127120941Sume 1128151539Ssuz /* 1129151539Ssuz * Ignore the address if it is not associated with a prefix 1130151539Ssuz * or is associated with a prefix that is different from this 1131151539Ssuz * one. (pr is never NULL here) 1132151539Ssuz */ 1133151539Ssuz if (ifa6->ia6_ndpr != pr) 113478064Sume continue; 113553541Sshin 113678064Sume if (ia6_match == NULL) /* remember the first one */ 113778064Sume ia6_match = ifa6; 113878064Sume 113978064Sume /* 114078064Sume * An already autoconfigured address matched. Now that we 114178064Sume * are sure there is at least one matched address, we can 114278064Sume * proceed to 5.5.3. (e): update the lifetimes according to the 114378064Sume * "two hours" rule and the privacy extension. 1144151539Ssuz * We apply some clarifications in rfc2462bis: 1145151539Ssuz * - use remaininglifetime instead of storedlifetime as a 1146151539Ssuz * variable name 1147151539Ssuz * - remove the dead code in the "two-hour" rule 114878064Sume */ 114978064Sume#define TWOHOUR (120*60) 115078064Sume lt6_tmp = ifa6->ia6_lifetime; 115178064Sume 1152112678Sume if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 1153151539Ssuz remaininglifetime = ND6_INFINITE_LIFETIME; 1154151539Ssuz else if (time_second - ifa6->ia6_updatetime > 1155151539Ssuz lt6_tmp.ia6t_vltime) { 1156151539Ssuz /* 1157151539Ssuz * The case of "invalid" address. We should usually 1158151539Ssuz * not see this case. 1159151539Ssuz */ 1160151539Ssuz remaininglifetime = 0; 1161151539Ssuz } else 1162151539Ssuz remaininglifetime = lt6_tmp.ia6t_vltime - 1163151539Ssuz (time_second - ifa6->ia6_updatetime); 116478064Sume 1165112678Sume /* when not updating, keep the current stored lifetime. */ 1166151539Ssuz lt6_tmp.ia6t_vltime = remaininglifetime; 1167112678Sume 116878064Sume if (TWOHOUR < new->ndpr_vltime || 1169151539Ssuz remaininglifetime < new->ndpr_vltime) { 117078064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 1171151539Ssuz } else if (remaininglifetime <= TWOHOUR) { 117278064Sume if (auth) { 117378064Sume lt6_tmp.ia6t_vltime = new->ndpr_vltime; 117478064Sume } 117578064Sume } else { 117678064Sume /* 117778064Sume * new->ndpr_vltime <= TWOHOUR && 1178151539Ssuz * TWOHOUR < remaininglifetime 117978064Sume */ 118078064Sume lt6_tmp.ia6t_vltime = TWOHOUR; 118153541Sshin } 118253541Sshin 118378064Sume /* The 2 hour rule is not imposed for preferred lifetime. */ 118478064Sume lt6_tmp.ia6t_pltime = new->ndpr_pltime; 118553541Sshin 118678064Sume in6_init_address_ltimes(pr, <6_tmp); 118753541Sshin 1188171260Sdelphij /* 1189151539Ssuz * We need to treat lifetimes for temporary addresses 1190151539Ssuz * differently, according to 1191151539Ssuz * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1); 1192151539Ssuz * we only update the lifetimes when they are in the maximum 1193151539Ssuz * intervals. 1194171260Sdelphij */ 1195171260Sdelphij if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 1196151539Ssuz u_int32_t maxvltime, maxpltime; 1197151539Ssuz 1198181803Sbz if (V_ip6_temp_valid_lifetime > 1199151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1200181803Sbz V_ip6_desync_factor)) { 1201181803Sbz maxvltime = V_ip6_temp_valid_lifetime - 1202151539Ssuz (time_second - ifa6->ia6_createtime) - 1203181803Sbz V_ip6_desync_factor; 1204151539Ssuz } else 1205151539Ssuz maxvltime = 0; 1206181803Sbz if (V_ip6_temp_preferred_lifetime > 1207151539Ssuz (u_int32_t)((time_second - ifa6->ia6_createtime) + 1208181803Sbz V_ip6_desync_factor)) { 1209181803Sbz maxpltime = V_ip6_temp_preferred_lifetime - 1210151539Ssuz (time_second - ifa6->ia6_createtime) - 1211181803Sbz V_ip6_desync_factor; 1212151539Ssuz } else 1213151539Ssuz maxpltime = 0; 1214151539Ssuz 1215151539Ssuz if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME || 1216151539Ssuz lt6_tmp.ia6t_vltime > maxvltime) { 1217151539Ssuz lt6_tmp.ia6t_vltime = maxvltime; 121878064Sume } 1219151539Ssuz if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || 1220151539Ssuz lt6_tmp.ia6t_pltime > maxpltime) { 1221151539Ssuz lt6_tmp.ia6t_pltime = maxpltime; 122278064Sume } 122378064Sume } 122478064Sume ifa6->ia6_lifetime = lt6_tmp; 1225151539Ssuz ifa6->ia6_updatetime = time_second; 122653541Sshin } 122778064Sume if (ia6_match == NULL && new->ndpr_vltime) { 1228151539Ssuz int ifidlen; 1229151539Ssuz 123078064Sume /* 1231151539Ssuz * 5.5.3 (d) (continued) 123278064Sume * No address matched and the valid lifetime is non-zero. 123378064Sume * Create a new address. 123478064Sume */ 1235151539Ssuz 1236151539Ssuz /* 1237151539Ssuz * Prefix Length check: 1238151539Ssuz * If the sum of the prefix length and interface identifier 1239151539Ssuz * length does not equal 128 bits, the Prefix Information 1240151539Ssuz * option MUST be ignored. The length of the interface 1241151539Ssuz * identifier is defined in a separate link-type specific 1242151539Ssuz * document. 1243151539Ssuz */ 1244151539Ssuz ifidlen = in6_if2idlen(ifp); 1245151539Ssuz if (ifidlen < 0) { 1246151539Ssuz /* this should not happen, so we always log it. */ 1247151539Ssuz log(LOG_ERR, "prelist_update: IFID undefined (%s)\n", 1248151539Ssuz if_name(ifp)); 1249151539Ssuz goto end; 1250151539Ssuz } 1251151539Ssuz if (ifidlen + pr->ndpr_plen != 128) { 1252151539Ssuz nd6log((LOG_INFO, 1253151539Ssuz "prelist_update: invalid prefixlen " 1254151539Ssuz "%d for %s, ignored\n", 1255151539Ssuz pr->ndpr_plen, if_name(ifp))); 1256151539Ssuz goto end; 1257151539Ssuz } 1258151539Ssuz 1259151539Ssuz if ((ia6 = in6_ifadd(new, mcast)) != NULL) { 126078064Sume /* 126178064Sume * note that we should use pr (not new) for reference. 126278064Sume */ 126378064Sume pr->ndpr_refcnt++; 126478064Sume ia6->ia6_ndpr = pr; 126553541Sshin 126678064Sume /* 126778064Sume * RFC 3041 3.3 (2). 126878064Sume * When a new public address is created as described 126978064Sume * in RFC2462, also create a new temporary address. 127078064Sume * 127178064Sume * RFC 3041 3.5. 127278064Sume * When an interface connects to a new link, a new 127378064Sume * randomized interface identifier should be generated 127478064Sume * immediately together with a new set of temporary 127578064Sume * addresses. Thus, we specifiy 1 as the 2nd arg of 127678064Sume * in6_tmpifadd(). 127778064Sume */ 1278181803Sbz if (V_ip6_use_tempaddr) { 127978064Sume int e; 1280151539Ssuz if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) { 128178064Sume nd6log((LOG_NOTICE, "prelist_update: " 128278064Sume "failed to create a temporary " 128378064Sume "address, errno=%d\n", 128478064Sume e)); 128578064Sume } 128678064Sume } 128778064Sume 128878064Sume /* 128978064Sume * A newly added address might affect the status 129078064Sume * of other addresses, so we check and update it. 129178064Sume * XXX: what if address duplication happens? 129278064Sume */ 129378064Sume pfxlist_onlink_check(); 129478064Sume } else { 129578064Sume /* just set an error. do not bark here. */ 129678064Sume error = EADDRNOTAVAIL; /* XXX: might be unused. */ 129778064Sume } 129878064Sume } 129978064Sume 130053541Sshin end: 130153541Sshin splx(s); 130253541Sshin return error; 130353541Sshin} 130453541Sshin 130553541Sshin/* 130662587Sitojun * A supplement function used in the on-link detection below; 130762587Sitojun * detect if a given prefix has a (probably) reachable advertising router. 130862587Sitojun * XXX: lengthy function name... 130962587Sitojun */ 131078064Sumestatic struct nd_pfxrouter * 1311171259Sdelphijfind_pfxlist_reachable_router(struct nd_prefix *pr) 131262587Sitojun{ 131362587Sitojun struct nd_pfxrouter *pfxrtr; 131462587Sitojun struct rtentry *rt; 131562587Sitojun struct llinfo_nd6 *ln; 131662587Sitojun 131762587Sitojun for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr; 131862587Sitojun pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { 131962587Sitojun if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0, 1320120941Sume pfxrtr->router->ifp)) && 132162587Sitojun (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 132262587Sitojun ND6_IS_LLINFO_PROBREACH(ln)) 132362587Sitojun break; /* found */ 132462587Sitojun } 132562587Sitojun 1326120856Sume return (pfxrtr); 132762587Sitojun} 132862587Sitojun 132962587Sitojun/* 133053541Sshin * Check if each prefix in the prefix list has at least one available router 133178064Sume * that advertised the prefix (a router is "available" if its neighbor cache 133278064Sume * entry is reachable or probably reachable). 133362587Sitojun * If the check fails, the prefix may be off-link, because, for example, 133453541Sshin * we have moved from the network but the lifetime of the prefix has not 133578064Sume * expired yet. So we should not use the prefix if there is another prefix 133678064Sume * that has an available router. 133778064Sume * But, if there is no prefix that has an available router, we still regards 133878064Sume * all the prefixes as on-link. This is because we can't tell if all the 133953541Sshin * routers are simply dead or if we really moved from the network and there 134053541Sshin * is no router around us. 134153541Sshin */ 134262587Sitojunvoid 134353541Sshinpfxlist_onlink_check() 134453541Sshin{ 134553541Sshin struct nd_prefix *pr; 134678064Sume struct in6_ifaddr *ifa; 1347151539Ssuz struct nd_defrouter *dr; 1348151539Ssuz struct nd_pfxrouter *pfxrtr = NULL; 134953541Sshin 135062587Sitojun /* 135162587Sitojun * Check if there is a prefix that has a reachable advertising 135262587Sitojun * router. 135362587Sitojun */ 1354181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 135578064Sume if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 135653541Sshin break; 135762587Sitojun } 135853541Sshin 1359151539Ssuz /* 1360151539Ssuz * If we have no such prefix, check whether we still have a router 1361151539Ssuz * that does not advertise any prefixes. 1362151539Ssuz */ 1363151465Ssuz if (pr == NULL) { 1364181803Sbz for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 1365151539Ssuz dr = TAILQ_NEXT(dr, dr_entry)) { 1366151539Ssuz struct nd_prefix *pr0; 1367151539Ssuz 1368181803Sbz for (pr0 = V_nd_prefix.lh_first; pr0; 1369151539Ssuz pr0 = pr0->ndpr_next) { 1370151539Ssuz if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) 1371151539Ssuz break; 1372151539Ssuz } 1373151539Ssuz if (pfxrtr != NULL) 1374151539Ssuz break; 1375151539Ssuz } 1376151539Ssuz } 1377181803Sbz if (pr != NULL || (TAILQ_FIRST(&V_nd_defrouter) && pfxrtr == NULL)) { 1378171260Sdelphij /* 1379151539Ssuz * There is at least one prefix that has a reachable router, 1380151539Ssuz * or at least a router which probably does not advertise 1381151539Ssuz * any prefixes. The latter would be the case when we move 1382151539Ssuz * to a new link where we have a router that does not provide 1383151539Ssuz * prefixes and we configure an address by hand. 1384171260Sdelphij * Detach prefixes which have no reachable advertising 1385171260Sdelphij * router, and attach other prefixes. 1386171260Sdelphij */ 1387181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 138878064Sume /* XXX: a link-local prefix should never be detached */ 138978064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 139078064Sume continue; 139178064Sume 139278064Sume /* 139378064Sume * we aren't interested in prefixes without the L bit 139478064Sume * set. 139578064Sume */ 139678064Sume if (pr->ndpr_raf_onlink == 0) 139778064Sume continue; 139878064Sume 139978064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 140078064Sume find_pfxlist_reachable_router(pr) == NULL) 140178064Sume pr->ndpr_stateflags |= NDPRF_DETACHED; 140278064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 140378064Sume find_pfxlist_reachable_router(pr) != 0) 140478064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 140553541Sshin } 140678064Sume } else { 140778064Sume /* there is no prefix that has a reachable router */ 1408181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 140978064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 141078064Sume continue; 141178064Sume 141278064Sume if (pr->ndpr_raf_onlink == 0) 141378064Sume continue; 141478064Sume 141578064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 141678064Sume pr->ndpr_stateflags &= ~NDPRF_DETACHED; 141753541Sshin } 141862587Sitojun } 141978064Sume 142078064Sume /* 142178064Sume * Remove each interface route associated with a (just) detached 142278064Sume * prefix, and reinstall the interface route for a (just) attached 142378064Sume * prefix. Note that all attempt of reinstallation does not 142478064Sume * necessarily success, when a same prefix is shared among multiple 142578064Sume * interfaces. Such cases will be handled in nd6_prefix_onlink, 142678064Sume * so we don't have to care about them. 142778064Sume */ 1428181803Sbz for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 142978064Sume int e; 1430165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 143178064Sume 143278064Sume if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 143378064Sume continue; 143478064Sume 143578064Sume if (pr->ndpr_raf_onlink == 0) 143678064Sume continue; 143778064Sume 143878064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 143978064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 144078064Sume if ((e = nd6_prefix_offlink(pr)) != 0) { 144178064Sume nd6log((LOG_ERR, 144278064Sume "pfxlist_onlink_check: failed to " 1443151479Ssuz "make %s/%d offlink, errno=%d\n", 1444165118Sbz ip6_sprintf(ip6buf, 1445165118Sbz &pr->ndpr_prefix.sin6_addr), 1446165118Sbz pr->ndpr_plen, e)); 144778064Sume } 144878064Sume } 144978064Sume if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 145078064Sume (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 145178064Sume pr->ndpr_raf_onlink) { 145278064Sume if ((e = nd6_prefix_onlink(pr)) != 0) { 145378064Sume nd6log((LOG_ERR, 145478064Sume "pfxlist_onlink_check: failed to " 1455151479Ssuz "make %s/%d onlink, errno=%d\n", 1456165118Sbz ip6_sprintf(ip6buf, 1457165118Sbz &pr->ndpr_prefix.sin6_addr), 1458165118Sbz pr->ndpr_plen, e)); 145978064Sume } 146078064Sume } 146178064Sume } 146278064Sume 146378064Sume /* 146478064Sume * Changes on the prefix status might affect address status as well. 146578064Sume * Make sure that all addresses derived from an attached prefix are 146678064Sume * attached, and that all addresses derived from a detached prefix are 146778064Sume * detached. Note, however, that a manually configured address should 146878064Sume * always be attached. 146978064Sume * The precise detection logic is same as the one for prefixes. 147078064Sume */ 1471181803Sbz for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) { 1472120941Sume if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) 147378064Sume continue; 147478064Sume 147578064Sume if (ifa->ia6_ndpr == NULL) { 147678064Sume /* 147778064Sume * This can happen when we first configure the address 147878064Sume * (i.e. the address exists, but the prefix does not). 147978064Sume * XXX: complicated relationships... 148078064Sume */ 148178064Sume continue; 148278064Sume } 148378064Sume 148478064Sume if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 148578064Sume break; 148678064Sume } 148778064Sume if (ifa) { 1488181803Sbz for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) { 148978064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 149078064Sume continue; 149178064Sume 149278064Sume if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 149378064Sume continue; 149478064Sume 1495151539Ssuz if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) { 1496151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1497151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1498151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1499151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1500151539Ssuz } 1501151539Ssuz } else { 150278064Sume ifa->ia6_flags |= IN6_IFF_DETACHED; 1503151539Ssuz } 150478064Sume } 150578064Sume } 150662587Sitojun else { 1507181803Sbz for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) { 150878064Sume if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 150978064Sume continue; 151078064Sume 1511151539Ssuz if (ifa->ia6_flags & IN6_IFF_DETACHED) { 1512151539Ssuz ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1513151539Ssuz ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1514151539Ssuz /* Do we need a delay in this case? */ 1515151539Ssuz nd6_dad_start((struct ifaddr *)ifa, 0); 1516151539Ssuz } 151778064Sume } 151853541Sshin } 151953541Sshin} 152053541Sshin 152178064Sumeint 1522171259Sdelphijnd6_prefix_onlink(struct nd_prefix *pr) 152353541Sshin{ 152478064Sume struct ifaddr *ifa; 152578064Sume struct ifnet *ifp = pr->ndpr_ifp; 152678064Sume struct sockaddr_in6 mask6; 152778064Sume struct nd_prefix *opr; 152878064Sume u_long rtflags; 152978064Sume int error = 0; 153078064Sume struct rtentry *rt = NULL; 1531165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 153253541Sshin 153378064Sume /* sanity check */ 153478064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 153578064Sume nd6log((LOG_ERR, 153678064Sume "nd6_prefix_onlink: %s/%d is already on-link\n", 1537165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1538165118Sbz pr->ndpr_plen)); 1539151465Ssuz return (EEXIST); 154078064Sume } 154178064Sume 154253541Sshin /* 154378064Sume * Add the interface route associated with the prefix. Before 154478064Sume * installing the route, check if there's the same prefix on another 154578064Sume * interface, and the prefix has already installed the interface route. 154678064Sume * Although such a configuration is expected to be rare, we explicitly 154778064Sume * allow it. 154853541Sshin */ 1549181803Sbz for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 155078064Sume if (opr == pr) 155178064Sume continue; 155278064Sume 155378064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 155478064Sume continue; 155578064Sume 155678064Sume if (opr->ndpr_plen == pr->ndpr_plen && 155778064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1558120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) 1559120856Sume return (0); 156078064Sume } 156178064Sume 156278064Sume /* 1563120941Sume * We prefer link-local addresses as the associated interface address. 156478064Sume */ 156578064Sume /* search for a link-local addr */ 156678064Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 1567120941Sume IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); 156878064Sume if (ifa == NULL) { 156978064Sume /* XXX: freebsd does not have ifa_ifwithaf */ 1570120941Sume TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 157178064Sume if (ifa->ifa_addr->sa_family == AF_INET6) 157278064Sume break; 157378064Sume } 157478064Sume /* should we care about ia6_flags? */ 157578064Sume } 157678064Sume if (ifa == NULL) { 157778064Sume /* 157878064Sume * This can still happen, when, for example, we receive an RA 157978064Sume * containing a prefix with the L bit set and the A bit clear, 158078064Sume * after removing all IPv6 addresses on the receiving 158178064Sume * interface. This should, of course, be rare though. 158278064Sume */ 158378064Sume nd6log((LOG_NOTICE, 158478064Sume "nd6_prefix_onlink: failed to find any ifaddr" 158578064Sume " to add route for a prefix(%s/%d) on %s\n", 1586165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 158778064Sume pr->ndpr_plen, if_name(ifp))); 1588120856Sume return (0); 158978064Sume } 159078064Sume 159178064Sume /* 159278064Sume * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 159378064Sume * ifa->ifa_rtrequest = nd6_rtrequest; 159478064Sume */ 159578064Sume bzero(&mask6, sizeof(mask6)); 159678064Sume mask6.sin6_len = sizeof(mask6); 159778064Sume mask6.sin6_addr = pr->ndpr_mask; 159878064Sume rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP; 159978064Sume if (nd6_need_cache(ifp)) { 160078064Sume /* explicitly set in case ifa_flags does not set the flag. */ 160178064Sume rtflags |= RTF_CLONING; 160278064Sume } else { 160378064Sume /* 160478064Sume * explicitly clear the cloning bit in case ifa_flags sets it. 160578064Sume */ 160678064Sume rtflags &= ~RTF_CLONING; 160778064Sume } 160878064Sume error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, 1609120941Sume ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt); 161078064Sume if (error == 0) { 161178064Sume if (rt != NULL) /* this should be non NULL, though */ 161278064Sume nd6_rtmsg(RTM_ADD, rt); 161378064Sume pr->ndpr_stateflags |= NDPRF_ONLINK; 1614120941Sume } else { 1615165118Sbz char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN]; 161678064Sume nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" 161778064Sume " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " 161878064Sume "errno = %d\n", 1619165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 162078064Sume pr->ndpr_plen, if_name(ifp), 1621165118Sbz ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), 1622165118Sbz ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error)); 162378064Sume } 162478064Sume 1625120727Ssam if (rt != NULL) { 1626120727Ssam RT_LOCK(rt); 1627122334Ssam RT_REMREF(rt); 1628120727Ssam RT_UNLOCK(rt); 1629120727Ssam } 163078064Sume 1631120856Sume return (error); 163278064Sume} 163378064Sume 163478064Sumeint 1635171259Sdelphijnd6_prefix_offlink(struct nd_prefix *pr) 163678064Sume{ 163778064Sume int error = 0; 163878064Sume struct ifnet *ifp = pr->ndpr_ifp; 163978064Sume struct nd_prefix *opr; 164078064Sume struct sockaddr_in6 sa6, mask6; 164178064Sume struct rtentry *rt = NULL; 1642165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 164378064Sume 164478064Sume /* sanity check */ 164578064Sume if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 164678064Sume nd6log((LOG_ERR, 164778064Sume "nd6_prefix_offlink: %s/%d is already off-link\n", 1648165118Sbz ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 1649165118Sbz pr->ndpr_plen)); 1650120856Sume return (EEXIST); 165178064Sume } 165278064Sume 165353541Sshin bzero(&sa6, sizeof(sa6)); 165453541Sshin sa6.sin6_family = AF_INET6; 165553541Sshin sa6.sin6_len = sizeof(sa6); 165653541Sshin bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 1657120941Sume sizeof(struct in6_addr)); 165853541Sshin bzero(&mask6, sizeof(mask6)); 165953541Sshin mask6.sin6_family = AF_INET6; 166053541Sshin mask6.sin6_len = sizeof(sa6); 166153541Sshin bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 166278064Sume error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 1663120941Sume (struct sockaddr *)&mask6, 0, &rt); 166478064Sume if (error == 0) { 166578064Sume pr->ndpr_stateflags &= ~NDPRF_ONLINK; 166653541Sshin 166778064Sume /* report the route deletion to the routing socket. */ 166878064Sume if (rt != NULL) 166978064Sume nd6_rtmsg(RTM_DELETE, rt); 167053541Sshin 167178064Sume /* 167278064Sume * There might be the same prefix on another interface, 167378064Sume * the prefix which could not be on-link just because we have 167478064Sume * the interface route (see comments in nd6_prefix_onlink). 167578064Sume * If there's one, try to make the prefix on-link on the 167678064Sume * interface. 167778064Sume */ 1678181803Sbz for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 167978064Sume if (opr == pr) 168078064Sume continue; 168153541Sshin 168278064Sume if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 168378064Sume continue; 168453541Sshin 168578064Sume /* 168678064Sume * KAME specific: detached prefixes should not be 168778064Sume * on-link. 168878064Sume */ 168978064Sume if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 169078064Sume continue; 169178064Sume 169278064Sume if (opr->ndpr_plen == pr->ndpr_plen && 169378064Sume in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 1694120941Sume &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 169578064Sume int e; 169678064Sume 169778064Sume if ((e = nd6_prefix_onlink(opr)) != 0) { 169878064Sume nd6log((LOG_ERR, 169978064Sume "nd6_prefix_offlink: failed to " 170078064Sume "recover a prefix %s/%d from %s " 170178064Sume "to %s (errno = %d)\n", 1702165118Sbz ip6_sprintf(ip6buf, 1703165118Sbz &opr->ndpr_prefix.sin6_addr), 170478064Sume opr->ndpr_plen, if_name(ifp), 170578064Sume if_name(opr->ndpr_ifp), e)); 170678064Sume } 170778064Sume } 170878064Sume } 1709120941Sume } else { 171078064Sume /* XXX: can we still set the NDPRF_ONLINK flag? */ 171178064Sume nd6log((LOG_ERR, 171278064Sume "nd6_prefix_offlink: failed to delete route: " 171378064Sume "%s/%d on %s (errno = %d)\n", 1714165118Sbz ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen, 1715165118Sbz if_name(ifp), error)); 171678064Sume } 171753541Sshin 1718120941Sume if (rt != NULL) { 1719108269Sru RTFREE(rt); 1720120941Sume } 172153541Sshin 1722120856Sume return (error); 172353541Sshin} 172453541Sshin 172553541Sshinstatic struct in6_ifaddr * 1726171259Sdelphijin6_ifadd(struct nd_prefixctl *pr, int mcast) 172753541Sshin{ 172878064Sume struct ifnet *ifp = pr->ndpr_ifp; 172953541Sshin struct ifaddr *ifa; 173078064Sume struct in6_aliasreq ifra; 173178064Sume struct in6_ifaddr *ia, *ib; 173278064Sume int error, plen0; 173353541Sshin struct in6_addr mask; 173478064Sume int prefixlen = pr->ndpr_plen; 1735151539Ssuz int updateflags; 1736165118Sbz char ip6buf[INET6_ADDRSTRLEN]; 173753541Sshin 1738121168Sume in6_prefixlen2mask(&mask, prefixlen); 173953541Sshin 174078064Sume /* 174178064Sume * find a link-local address (will be interface ID). 174278064Sume * Is it really mandatory? Theoretically, a global or a site-local 174378064Sume * address can be configured without a link-local address, if we 174478064Sume * have a unique interface identifier... 174578064Sume * 174678064Sume * it is not mandatory to have a link-local address, we can generate 174778064Sume * interface identifier on the fly. we do this because: 174878064Sume * (1) it should be the easiest way to find interface identifier. 174978064Sume * (2) RFC2462 5.4 suggesting the use of the same interface identifier 175078064Sume * for multiple addresses on a single interface, and possible shortcut 175178064Sume * of DAD. we omitted DAD for this reason in the past. 1752120941Sume * (3) a user can prevent autoconfiguration of global address 175378064Sume * by removing link-local address by hand (this is partly because we 1754108533Sschweikh * don't have other way to control the use of IPv6 on an interface. 175578064Sume * this has been our design choice - cf. NRL's "ifconfig auto"). 175678064Sume * (4) it is easier to manage when an interface has addresses 175778064Sume * with the same interface identifier, than to have multiple addresses 175878064Sume * with different interface identifiers. 175978064Sume */ 1760120941Sume ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ 176153541Sshin if (ifa) 176253541Sshin ib = (struct in6_ifaddr *)ifa; 176353541Sshin else 176453541Sshin return NULL; 176553541Sshin 176653541Sshin /* prefixlen + ifidlen must be equal to 128 */ 176778064Sume plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 176878064Sume if (prefixlen != plen0) { 176978064Sume nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 177078064Sume "(prefix=%d ifid=%d)\n", 177178064Sume if_name(ifp), prefixlen, 128 - plen0)); 177253541Sshin return NULL; 177353541Sshin } 177453541Sshin 177553541Sshin /* make ifaddr */ 177653541Sshin 177778064Sume bzero(&ifra, sizeof(ifra)); 177878064Sume /* 177978064Sume * in6_update_ifa() does not use ifra_name, but we accurately set it 178078064Sume * for safety. 178178064Sume */ 178278064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 178378064Sume ifra.ifra_addr.sin6_family = AF_INET6; 178478064Sume ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 178578064Sume /* prefix */ 1786151539Ssuz ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr; 178778064Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 178878064Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 178978064Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 179078064Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 179153541Sshin 179253541Sshin /* interface ID */ 1793120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[0] |= 1794151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); 1795120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[1] |= 1796151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); 1797120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1798151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); 1799120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1800151539Ssuz (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); 1801120941Sume 180278064Sume /* new prefix mask. */ 180378064Sume ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 180478064Sume ifra.ifra_prefixmask.sin6_family = AF_INET6; 180578064Sume bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 1806120941Sume sizeof(ifra.ifra_prefixmask.sin6_addr)); 180753541Sshin 1808151539Ssuz /* lifetimes. */ 180978064Sume ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 181078064Sume ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 181153541Sshin 181278064Sume /* XXX: scope zone ID? */ 181353541Sshin 181478064Sume ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 1815151539Ssuz 1816171260Sdelphij /* 1817151539Ssuz * Make sure that we do not have this address already. This should 1818151539Ssuz * usually not happen, but we can still see this case, e.g., if we 1819151539Ssuz * have manually configured the exact address to be configured. 182078064Sume */ 1821151539Ssuz if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { 1822151539Ssuz /* this should be rare enough to make an explicit log */ 1823151539Ssuz log(LOG_INFO, "in6_ifadd: %s is already configured\n", 1824165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr)); 1825151539Ssuz return (NULL); 1826151539Ssuz } 182753541Sshin 182853541Sshin /* 1829151539Ssuz * Allocate ifaddr structure, link into chain, etc. 1830151539Ssuz * If we are going to create a new address upon receiving a multicasted 1831151539Ssuz * RA, we need to impose a random delay before starting DAD. 1832151539Ssuz * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] 183353541Sshin */ 1834151539Ssuz updateflags = 0; 1835151539Ssuz if (mcast) 1836151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1837151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { 183878064Sume nd6log((LOG_ERR, 183978064Sume "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 1840165118Sbz ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr), 1841165118Sbz if_name(ifp), error)); 1842120856Sume return (NULL); /* ifaddr must not have been allocated. */ 184353541Sshin } 184453541Sshin 184578064Sume ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 184653541Sshin 1847120941Sume return (ia); /* this is always non-NULL */ 184853541Sshin} 184953541Sshin 1850171259Sdelphij/* 1851171259Sdelphij * ia0 - corresponding public address 1852171259Sdelphij */ 185353541Sshinint 1854171259Sdelphijin6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) 185553541Sshin{ 185678064Sume struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 1857151539Ssuz struct in6_ifaddr *newia, *ia; 185878064Sume struct in6_aliasreq ifra; 185978064Sume int i, error; 186078064Sume int trylimit = 3; /* XXX: adhoc value */ 1861151539Ssuz int updateflags; 186278064Sume u_int32_t randid[2]; 186378064Sume time_t vltime0, pltime0; 186453541Sshin 186578064Sume bzero(&ifra, sizeof(ifra)); 186678064Sume strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 186778064Sume ifra.ifra_addr = ia0->ia_addr; 186878064Sume /* copy prefix mask */ 186978064Sume ifra.ifra_prefixmask = ia0->ia_prefixmask; 187078064Sume /* clear the old IFID */ 187178064Sume for (i = 0; i < 4; i++) { 1872120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[i] &= 1873120941Sume ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 187478064Sume } 187553541Sshin 187678064Sume again: 1877151539Ssuz if (in6_get_tmpifid(ifp, (u_int8_t *)randid, 1878151539Ssuz (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { 1879151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good " 1880151539Ssuz "random IFID\n")); 1881151539Ssuz return (EINVAL); 1882151539Ssuz } 1883120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1884120941Sume (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 1885120941Sume ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1886120941Sume (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 188753541Sshin 1888171260Sdelphij /* 1889151539Ssuz * in6_get_tmpifid() quite likely provided a unique interface ID. 1890151539Ssuz * However, we may still have a chance to see collision, because 1891151539Ssuz * there may be a time lag between generation of the ID and generation 1892151539Ssuz * of the address. So, we'll do one more sanity check. 189378064Sume */ 1894181803Sbz for (ia = V_in6_ifaddr; ia; ia = ia->ia_next) { 1895151539Ssuz if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 1896151539Ssuz &ifra.ifra_addr.sin6_addr)) { 1897171260Sdelphij if (trylimit-- == 0) { 1898151539Ssuz /* 1899151539Ssuz * Give up. Something strange should have 1900151539Ssuz * happened. 1901151539Ssuz */ 1902151539Ssuz nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " 1903151539Ssuz "find a unique random IFID\n")); 1904151539Ssuz return (EEXIST); 1905151539Ssuz } 1906151539Ssuz forcegen = 1; 1907151539Ssuz goto again; 190878064Sume } 190953541Sshin } 191053541Sshin 191178064Sume /* 191278064Sume * The Valid Lifetime is the lower of the Valid Lifetime of the 191378064Sume * public address or TEMP_VALID_LIFETIME. 191478064Sume * The Preferred Lifetime is the lower of the Preferred Lifetime 191578064Sume * of the public address or TEMP_PREFERRED_LIFETIME - 191678064Sume * DESYNC_FACTOR. 191778064Sume */ 1918151539Ssuz if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 191978064Sume vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 1920151539Ssuz (ia0->ia6_lifetime.ia6t_vltime - 1921151539Ssuz (time_second - ia0->ia6_updatetime)); 1922181803Sbz if (vltime0 > V_ip6_temp_valid_lifetime) 1923181803Sbz vltime0 = V_ip6_temp_valid_lifetime; 192478064Sume } else 1925181803Sbz vltime0 = V_ip6_temp_valid_lifetime; 1926151539Ssuz if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 192778064Sume pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 1928151539Ssuz (ia0->ia6_lifetime.ia6t_pltime - 1929151539Ssuz (time_second - ia0->ia6_updatetime)); 1930181803Sbz if (pltime0 > V_ip6_temp_preferred_lifetime - V_ip6_desync_factor){ 1931181803Sbz pltime0 = V_ip6_temp_preferred_lifetime - 1932181803Sbz V_ip6_desync_factor; 193378064Sume } 193478064Sume } else 1935181803Sbz pltime0 = V_ip6_temp_preferred_lifetime - V_ip6_desync_factor; 193678064Sume ifra.ifra_lifetime.ia6t_vltime = vltime0; 193778064Sume ifra.ifra_lifetime.ia6t_pltime = pltime0; 193853541Sshin 193978064Sume /* 194078064Sume * A temporary address is created only if this calculated Preferred 194178064Sume * Lifetime is greater than REGEN_ADVANCE time units. 194278064Sume */ 1943181803Sbz if (ifra.ifra_lifetime.ia6t_pltime <= V_ip6_temp_regen_advance) 1944120856Sume return (0); 194553541Sshin 194678064Sume /* XXX: scope zone ID? */ 194778064Sume 194878064Sume ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 194978064Sume 195078064Sume /* allocate ifaddr structure, link into chain, etc. */ 1951151539Ssuz updateflags = 0; 1952151539Ssuz if (delay) 1953151539Ssuz updateflags |= IN6_IFAUPDATE_DADDELAY; 1954151539Ssuz if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) 1955120856Sume return (error); 195678064Sume 195778064Sume newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 195878064Sume if (newia == NULL) { /* XXX: can it happen? */ 195978064Sume nd6log((LOG_ERR, 196078064Sume "in6_tmpifadd: ifa update succeeded, but we got " 196178064Sume "no ifaddr\n")); 1962120856Sume return (EINVAL); /* XXX */ 196353541Sshin } 196478064Sume newia->ia6_ndpr = ia0->ia6_ndpr; 196578064Sume newia->ia6_ndpr->ndpr_refcnt++; 196653541Sshin 196778407Sume /* 196878407Sume * A newly added address might affect the status of other addresses. 196978407Sume * XXX: when the temporary address is generated with a new public 197078407Sume * address, the onlink check is redundant. However, it would be safe 197178407Sume * to do the check explicitly everywhere a new address is generated, 197278407Sume * and, in fact, we surely need the check when we create a new 197378407Sume * temporary address due to deprecation of an old temporary address. 197478407Sume */ 197578407Sume pfxlist_onlink_check(); 197678407Sume 1977120856Sume return (0); 1978120941Sume} 197953541Sshin 1980151539Ssuzstatic int 198153541Sshinin6_init_prefix_ltimes(struct nd_prefix *ndpr) 198253541Sshin{ 198353541Sshin if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 198453541Sshin ndpr->ndpr_preferred = 0; 198553541Sshin else 198653541Sshin ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; 198753541Sshin if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 198853541Sshin ndpr->ndpr_expire = 0; 198953541Sshin else 199053541Sshin ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; 199153541Sshin 199253541Sshin return 0; 199353541Sshin} 199453541Sshin 199553541Sshinstatic void 199678064Sumein6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 199753541Sshin{ 199878064Sume /* init ia6t_expire */ 199978064Sume if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 200078064Sume lt6->ia6t_expire = 0; 200178064Sume else { 200278064Sume lt6->ia6t_expire = time_second; 200378064Sume lt6->ia6t_expire += lt6->ia6t_vltime; 200453541Sshin } 200562587Sitojun 200653541Sshin /* init ia6t_preferred */ 200753541Sshin if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 200853541Sshin lt6->ia6t_preferred = 0; 200953541Sshin else { 201053541Sshin lt6->ia6t_preferred = time_second; 201153541Sshin lt6->ia6t_preferred += lt6->ia6t_pltime; 201253541Sshin } 201353541Sshin} 201453541Sshin 201553541Sshin/* 201653541Sshin * Delete all the routing table entries that use the specified gateway. 201753541Sshin * XXX: this function causes search through all entries of routing table, so 201853541Sshin * it shouldn't be called when acting as a router. 201953541Sshin */ 202053541Sshinvoid 2021171259Sdelphijrt6_flush(struct in6_addr *gateway, struct ifnet *ifp) 202253541Sshin{ 2023178888Sjulian 2024181803Sbz struct radix_node_head *rnh = V_rt_tables[0][AF_INET6]; 202553541Sshin int s = splnet(); 202653541Sshin 202753541Sshin /* We'll care only link-local addresses */ 202853541Sshin if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { 202953541Sshin splx(s); 203053541Sshin return; 203153541Sshin } 203253541Sshin 2033108250Shsu RADIX_NODE_HEAD_LOCK(rnh); 203453541Sshin rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 2035108250Shsu RADIX_NODE_HEAD_UNLOCK(rnh); 203653541Sshin splx(s); 203753541Sshin} 203853541Sshin 203953541Sshinstatic int 2040171259Sdelphijrt6_deleteroute(struct radix_node *rn, void *arg) 204153541Sshin{ 204253541Sshin#define SIN6(s) ((struct sockaddr_in6 *)s) 204353541Sshin struct rtentry *rt = (struct rtentry *)rn; 204453541Sshin struct in6_addr *gate = (struct in6_addr *)arg; 204553541Sshin 204653541Sshin if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 2047120856Sume return (0); 204853541Sshin 2049120941Sume if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) { 2050120856Sume return (0); 2051120941Sume } 205253541Sshin 205353541Sshin /* 205478064Sume * Do not delete a static route. 205578064Sume * XXX: this seems to be a bit ad-hoc. Should we consider the 205678064Sume * 'cloned' bit instead? 205778064Sume */ 205878064Sume if ((rt->rt_flags & RTF_STATIC) != 0) 2059120856Sume return (0); 206078064Sume 206178064Sume /* 206253541Sshin * We delete only host route. This means, in particular, we don't 206353541Sshin * delete default route. 206453541Sshin */ 206553541Sshin if ((rt->rt_flags & RTF_HOST) == 0) 2066120856Sume return (0); 206753541Sshin 2068120941Sume return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 2069120941Sume rt_mask(rt), rt->rt_flags, 0)); 207053541Sshin#undef SIN6 207153541Sshin} 207262587Sitojun 207362587Sitojunint 2074171259Sdelphijnd6_setdefaultiface(int ifindex) 207562587Sitojun{ 207662587Sitojun int error = 0; 207762587Sitojun 2078181803Sbz if (ifindex < 0 || V_if_index < ifindex) 2079120856Sume return (EINVAL); 2080151539Ssuz if (ifindex != 0 && !ifnet_byindex(ifindex)) 2081151539Ssuz return (EINVAL); 208262587Sitojun 2083181803Sbz if (V_nd6_defifindex != ifindex) { 2084181803Sbz V_nd6_defifindex = ifindex; 2085181803Sbz if (V_nd6_defifindex > 0) 2086181803Sbz V_nd6_defifp = ifnet_byindex(V_nd6_defifindex); 208762587Sitojun else 2088181803Sbz V_nd6_defifp = NULL; 208962587Sitojun 209062587Sitojun /* 209162587Sitojun * Our current implementation assumes one-to-one maping between 209262587Sitojun * interfaces and links, so it would be natural to use the 209362587Sitojun * default interface as the default link. 209462587Sitojun */ 2095181803Sbz scope6_setdefault(V_nd6_defifp); 209662587Sitojun } 209762587Sitojun 2098120856Sume return (error); 209962587Sitojun} 2100