1686cdd19SJun-ichiro itojun Hagino /* $FreeBSD$ */ 233841545SHajimu UMEMOTO /* $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $ */ 3686cdd19SJun-ichiro itojun Hagino 4caf43b02SWarner Losh /*- 582cd038dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 682cd038dSYoshinobu Inoue * All rights reserved. 782cd038dSYoshinobu Inoue * 882cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 982cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 1082cd038dSYoshinobu Inoue * are met: 1182cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 1282cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1382cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1482cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1582cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1682cd038dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1782cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 1882cd038dSYoshinobu Inoue * without specific prior written permission. 1982cd038dSYoshinobu Inoue * 2082cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2182cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2282cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2382cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2482cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2582cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2682cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2782cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2882cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2982cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3082cd038dSYoshinobu Inoue * SUCH DAMAGE. 3182cd038dSYoshinobu Inoue */ 3282cd038dSYoshinobu Inoue 33686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h" 34686cdd19SJun-ichiro itojun Hagino #include "opt_inet6.h" 35686cdd19SJun-ichiro itojun Hagino 3682cd038dSYoshinobu Inoue #include <sys/param.h> 3782cd038dSYoshinobu Inoue #include <sys/systm.h> 3882cd038dSYoshinobu Inoue #include <sys/malloc.h> 3982cd038dSYoshinobu Inoue #include <sys/mbuf.h> 4082cd038dSYoshinobu Inoue #include <sys/socket.h> 4182cd038dSYoshinobu Inoue #include <sys/sockio.h> 4282cd038dSYoshinobu Inoue #include <sys/time.h> 4333841545SHajimu UMEMOTO #include <sys/kernel.h> 4482cd038dSYoshinobu Inoue #include <sys/errno.h> 4582cd038dSYoshinobu Inoue #include <sys/syslog.h> 4633841545SHajimu UMEMOTO #include <sys/queue.h> 4782cd038dSYoshinobu Inoue 4882cd038dSYoshinobu Inoue #include <net/if.h> 4982cd038dSYoshinobu Inoue #include <net/if_types.h> 5082cd038dSYoshinobu Inoue #include <net/if_dl.h> 5182cd038dSYoshinobu Inoue #include <net/route.h> 5282cd038dSYoshinobu Inoue #include <net/radix.h> 5382cd038dSYoshinobu Inoue 5482cd038dSYoshinobu Inoue #include <netinet/in.h> 5582cd038dSYoshinobu Inoue #include <netinet6/in6_var.h> 5633841545SHajimu UMEMOTO #include <netinet6/in6_ifattach.h> 57686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 5882cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 5982cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 60686cdd19SJun-ichiro itojun Hagino #include <netinet/icmp6.h> 61686cdd19SJun-ichiro itojun Hagino #include <netinet6/scope6_var.h> 6282cd038dSYoshinobu Inoue 6382cd038dSYoshinobu Inoue #include <net/net_osdep.h> 6482cd038dSYoshinobu Inoue 6582cd038dSYoshinobu Inoue #define SDL(s) ((struct sockaddr_dl *)s) 6682cd038dSYoshinobu Inoue 6782cd038dSYoshinobu Inoue static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *)); 6833841545SHajimu UMEMOTO static struct in6_ifaddr *in6_ifadd __P((struct nd_prefix *, 6933841545SHajimu UMEMOTO struct in6_addr *)); 7082cd038dSYoshinobu Inoue static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, 7182cd038dSYoshinobu Inoue struct nd_defrouter *)); 7282cd038dSYoshinobu Inoue static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *)); 7382cd038dSYoshinobu Inoue static void pfxrtr_del __P((struct nd_pfxrouter *)); 74686cdd19SJun-ichiro itojun Hagino static struct nd_pfxrouter *find_pfxlist_reachable_router 75686cdd19SJun-ichiro itojun Hagino __P((struct nd_prefix *)); 76686cdd19SJun-ichiro itojun Hagino static void defrouter_addifreq __P((struct ifnet *)); 7733841545SHajimu UMEMOTO static void nd6_rtmsg __P((int, struct rtentry *)); 7882cd038dSYoshinobu Inoue 7907eb2995SHajimu UMEMOTO static void in6_init_address_ltimes __P((struct nd_prefix *, 8007eb2995SHajimu UMEMOTO struct in6_addrlifetime *)); 8182cd038dSYoshinobu Inoue 8282cd038dSYoshinobu Inoue static int rt6_deleteroute __P((struct radix_node *, void *)); 8382cd038dSYoshinobu Inoue 8482cd038dSYoshinobu Inoue extern int nd6_recalc_reachtm_interval; 8582cd038dSYoshinobu Inoue 8633841545SHajimu UMEMOTO static struct ifnet *nd6_defifp; 87686cdd19SJun-ichiro itojun Hagino int nd6_defifindex; 88686cdd19SJun-ichiro itojun Hagino 8933841545SHajimu UMEMOTO int ip6_use_tempaddr = 0; 9033841545SHajimu UMEMOTO 9133841545SHajimu UMEMOTO int ip6_desync_factor; 9233841545SHajimu UMEMOTO u_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME; 9333841545SHajimu UMEMOTO u_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME; 9433841545SHajimu UMEMOTO /* 9533841545SHajimu UMEMOTO * shorter lifetimes for debugging purposes. 9633841545SHajimu UMEMOTO int ip6_temp_preferred_lifetime = 800; 9733841545SHajimu UMEMOTO static int ip6_temp_valid_lifetime = 1800; 9833841545SHajimu UMEMOTO */ 9933841545SHajimu UMEMOTO int ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE; 10033841545SHajimu UMEMOTO 10182cd038dSYoshinobu Inoue /* 10282cd038dSYoshinobu Inoue * Receive Router Solicitation Message - just for routers. 10382cd038dSYoshinobu Inoue * Router solicitation/advertisement is mostly managed by userland program 10482cd038dSYoshinobu Inoue * (rtadvd) so here we have no function like nd6_ra_output(). 10582cd038dSYoshinobu Inoue * 10682cd038dSYoshinobu Inoue * Based on RFC 2461 10782cd038dSYoshinobu Inoue */ 10882cd038dSYoshinobu Inoue void 10982cd038dSYoshinobu Inoue nd6_rs_input(m, off, icmp6len) 11082cd038dSYoshinobu Inoue struct mbuf *m; 11182cd038dSYoshinobu Inoue int off, icmp6len; 11282cd038dSYoshinobu Inoue { 11382cd038dSYoshinobu Inoue struct ifnet *ifp = m->m_pkthdr.rcvif; 11482cd038dSYoshinobu Inoue struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 115686cdd19SJun-ichiro itojun Hagino struct nd_router_solicit *nd_rs; 11682cd038dSYoshinobu Inoue struct in6_addr saddr6 = ip6->ip6_src; 11782cd038dSYoshinobu Inoue char *lladdr = NULL; 11882cd038dSYoshinobu Inoue int lladdrlen = 0; 11982cd038dSYoshinobu Inoue union nd_opts ndopts; 12082cd038dSYoshinobu Inoue 12182cd038dSYoshinobu Inoue /* If I'm not a router, ignore it. */ 12282cd038dSYoshinobu Inoue if (ip6_accept_rtadv != 0 || ip6_forwarding != 1) 123686cdd19SJun-ichiro itojun Hagino goto freeit; 12482cd038dSYoshinobu Inoue 12582cd038dSYoshinobu Inoue /* Sanity checks */ 12682cd038dSYoshinobu Inoue if (ip6->ip6_hlim != 255) { 12733841545SHajimu UMEMOTO nd6log((LOG_ERR, 12833841545SHajimu UMEMOTO "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 12933841545SHajimu UMEMOTO ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), 13033841545SHajimu UMEMOTO ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); 13133841545SHajimu UMEMOTO goto bad; 13282cd038dSYoshinobu Inoue } 13382cd038dSYoshinobu Inoue 13482cd038dSYoshinobu Inoue /* 13582cd038dSYoshinobu Inoue * Don't update the neighbor cache, if src = ::. 13682cd038dSYoshinobu Inoue * This indicates that the src has no IP address assigned yet. 13782cd038dSYoshinobu Inoue */ 13882cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 139686cdd19SJun-ichiro itojun Hagino goto freeit; 140686cdd19SJun-ichiro itojun Hagino 141686cdd19SJun-ichiro itojun Hagino #ifndef PULLDOWN_TEST 142686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_CHECK(m, off, icmp6len,); 143686cdd19SJun-ichiro itojun Hagino nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 144686cdd19SJun-ichiro itojun Hagino #else 145686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 146686cdd19SJun-ichiro itojun Hagino if (nd_rs == NULL) { 147686cdd19SJun-ichiro itojun Hagino icmp6stat.icp6s_tooshort++; 14882cd038dSYoshinobu Inoue return; 149686cdd19SJun-ichiro itojun Hagino } 150686cdd19SJun-ichiro itojun Hagino #endif 15182cd038dSYoshinobu Inoue 15282cd038dSYoshinobu Inoue icmp6len -= sizeof(*nd_rs); 15382cd038dSYoshinobu Inoue nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 15482cd038dSYoshinobu Inoue if (nd6_options(&ndopts) < 0) { 15533841545SHajimu UMEMOTO nd6log((LOG_INFO, 15633841545SHajimu UMEMOTO "nd6_rs_input: invalid ND option, ignored\n")); 15733841545SHajimu UMEMOTO /* nd6_options have incremented stats */ 158686cdd19SJun-ichiro itojun Hagino goto freeit; 15982cd038dSYoshinobu Inoue } 16082cd038dSYoshinobu Inoue 16182cd038dSYoshinobu Inoue if (ndopts.nd_opts_src_lladdr) { 16282cd038dSYoshinobu Inoue lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 16382cd038dSYoshinobu Inoue lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 16482cd038dSYoshinobu Inoue } 16582cd038dSYoshinobu Inoue 16682cd038dSYoshinobu Inoue if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 16733841545SHajimu UMEMOTO nd6log((LOG_INFO, 16882cd038dSYoshinobu Inoue "nd6_rs_input: lladdrlen mismatch for %s " 16982cd038dSYoshinobu Inoue "(if %d, RS packet %d)\n", 17007eb2995SHajimu UMEMOTO ip6_sprintf(&saddr6), 17107eb2995SHajimu UMEMOTO ifp->if_addrlen, lladdrlen - 2)); 17233841545SHajimu UMEMOTO goto bad; 17382cd038dSYoshinobu Inoue } 17482cd038dSYoshinobu Inoue 17582cd038dSYoshinobu Inoue nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 176686cdd19SJun-ichiro itojun Hagino 177686cdd19SJun-ichiro itojun Hagino freeit: 178686cdd19SJun-ichiro itojun Hagino m_freem(m); 17933841545SHajimu UMEMOTO return; 18033841545SHajimu UMEMOTO 18133841545SHajimu UMEMOTO bad: 18233841545SHajimu UMEMOTO icmp6stat.icp6s_badrs++; 18333841545SHajimu UMEMOTO m_freem(m); 18482cd038dSYoshinobu Inoue } 18582cd038dSYoshinobu Inoue 18682cd038dSYoshinobu Inoue /* 18782cd038dSYoshinobu Inoue * Receive Router Advertisement Message. 18882cd038dSYoshinobu Inoue * 18982cd038dSYoshinobu Inoue * Based on RFC 2461 19082cd038dSYoshinobu Inoue * TODO: on-link bit on prefix information 19182cd038dSYoshinobu Inoue * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 19282cd038dSYoshinobu Inoue */ 19382cd038dSYoshinobu Inoue void 19482cd038dSYoshinobu Inoue nd6_ra_input(m, off, icmp6len) 19582cd038dSYoshinobu Inoue struct mbuf *m; 19682cd038dSYoshinobu Inoue int off, icmp6len; 19782cd038dSYoshinobu Inoue { 19882cd038dSYoshinobu Inoue struct ifnet *ifp = m->m_pkthdr.rcvif; 19931b1bfe1SHajimu UMEMOTO struct nd_ifinfo *ndi = ND_IFINFO(ifp); 20082cd038dSYoshinobu Inoue struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 201686cdd19SJun-ichiro itojun Hagino struct nd_router_advert *nd_ra; 20282cd038dSYoshinobu Inoue struct in6_addr saddr6 = ip6->ip6_src; 20382cd038dSYoshinobu Inoue union nd_opts ndopts; 20482cd038dSYoshinobu Inoue struct nd_defrouter *dr; 20582cd038dSYoshinobu Inoue 20607cf047dSHajimu UMEMOTO /* 20707cf047dSHajimu UMEMOTO * We only accept RAs only when 20807cf047dSHajimu UMEMOTO * the system-wide variable allows the acceptance, and 20907cf047dSHajimu UMEMOTO * per-interface variable allows RAs on the receiving interface. 21007cf047dSHajimu UMEMOTO */ 21182cd038dSYoshinobu Inoue if (ip6_accept_rtadv == 0) 212686cdd19SJun-ichiro itojun Hagino goto freeit; 21307cf047dSHajimu UMEMOTO if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 21407cf047dSHajimu UMEMOTO goto freeit; 21582cd038dSYoshinobu Inoue 21682cd038dSYoshinobu Inoue if (ip6->ip6_hlim != 255) { 21733841545SHajimu UMEMOTO nd6log((LOG_ERR, 21833841545SHajimu UMEMOTO "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 21933841545SHajimu UMEMOTO ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), 22033841545SHajimu UMEMOTO ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); 22133841545SHajimu UMEMOTO goto bad; 22282cd038dSYoshinobu Inoue } 22382cd038dSYoshinobu Inoue 22482cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 22533841545SHajimu UMEMOTO nd6log((LOG_ERR, 22682cd038dSYoshinobu Inoue "nd6_ra_input: src %s is not link-local\n", 22733841545SHajimu UMEMOTO ip6_sprintf(&saddr6))); 22833841545SHajimu UMEMOTO goto bad; 229686cdd19SJun-ichiro itojun Hagino } 230686cdd19SJun-ichiro itojun Hagino 231686cdd19SJun-ichiro itojun Hagino #ifndef PULLDOWN_TEST 232686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_CHECK(m, off, icmp6len,); 233686cdd19SJun-ichiro itojun Hagino nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); 234686cdd19SJun-ichiro itojun Hagino #else 235686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); 236686cdd19SJun-ichiro itojun Hagino if (nd_ra == NULL) { 237686cdd19SJun-ichiro itojun Hagino icmp6stat.icp6s_tooshort++; 23882cd038dSYoshinobu Inoue return; 23982cd038dSYoshinobu Inoue } 240686cdd19SJun-ichiro itojun Hagino #endif 24182cd038dSYoshinobu Inoue 24282cd038dSYoshinobu Inoue icmp6len -= sizeof(*nd_ra); 24382cd038dSYoshinobu Inoue nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 24482cd038dSYoshinobu Inoue if (nd6_options(&ndopts) < 0) { 24533841545SHajimu UMEMOTO nd6log((LOG_INFO, 24633841545SHajimu UMEMOTO "nd6_ra_input: invalid ND option, ignored\n")); 24733841545SHajimu UMEMOTO /* nd6_options have incremented stats */ 248686cdd19SJun-ichiro itojun Hagino goto freeit; 24982cd038dSYoshinobu Inoue } 25082cd038dSYoshinobu Inoue 25182cd038dSYoshinobu Inoue { 25282cd038dSYoshinobu Inoue struct nd_defrouter dr0; 25382cd038dSYoshinobu Inoue u_int32_t advreachable = nd_ra->nd_ra_reachable; 25482cd038dSYoshinobu Inoue 25582cd038dSYoshinobu Inoue dr0.rtaddr = saddr6; 25682cd038dSYoshinobu Inoue dr0.flags = nd_ra->nd_ra_flags_reserved; 25782cd038dSYoshinobu Inoue dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 25882cd038dSYoshinobu Inoue dr0.expire = time_second + dr0.rtlifetime; 25982cd038dSYoshinobu Inoue dr0.ifp = ifp; 26082cd038dSYoshinobu Inoue /* unspecified or not? (RFC 2461 6.3.4) */ 26182cd038dSYoshinobu Inoue if (advreachable) { 262fd8e4ebcSMike Barcroft advreachable = ntohl(advreachable); 26382cd038dSYoshinobu Inoue if (advreachable <= MAX_REACHABLE_TIME && 26482cd038dSYoshinobu Inoue ndi->basereachable != advreachable) { 26582cd038dSYoshinobu Inoue ndi->basereachable = advreachable; 26682cd038dSYoshinobu Inoue ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 26782cd038dSYoshinobu Inoue ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */ 26882cd038dSYoshinobu Inoue } 26982cd038dSYoshinobu Inoue } 27082cd038dSYoshinobu Inoue if (nd_ra->nd_ra_retransmit) 27182cd038dSYoshinobu Inoue ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 27282cd038dSYoshinobu Inoue if (nd_ra->nd_ra_curhoplimit) 27382cd038dSYoshinobu Inoue ndi->chlim = nd_ra->nd_ra_curhoplimit; 27482cd038dSYoshinobu Inoue dr = defrtrlist_update(&dr0); 27582cd038dSYoshinobu Inoue } 27682cd038dSYoshinobu Inoue 27782cd038dSYoshinobu Inoue /* 27882cd038dSYoshinobu Inoue * prefix 27982cd038dSYoshinobu Inoue */ 28082cd038dSYoshinobu Inoue if (ndopts.nd_opts_pi) { 28182cd038dSYoshinobu Inoue struct nd_opt_hdr *pt; 28233841545SHajimu UMEMOTO struct nd_opt_prefix_info *pi = NULL; 28382cd038dSYoshinobu Inoue struct nd_prefix pr; 28482cd038dSYoshinobu Inoue 28582cd038dSYoshinobu Inoue for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 28682cd038dSYoshinobu Inoue pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 28782cd038dSYoshinobu Inoue pt = (struct nd_opt_hdr *)((caddr_t)pt + 28882cd038dSYoshinobu Inoue (pt->nd_opt_len << 3))) { 28982cd038dSYoshinobu Inoue if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 29082cd038dSYoshinobu Inoue continue; 29182cd038dSYoshinobu Inoue pi = (struct nd_opt_prefix_info *)pt; 29282cd038dSYoshinobu Inoue 29382cd038dSYoshinobu Inoue if (pi->nd_opt_pi_len != 4) { 29433841545SHajimu UMEMOTO nd6log((LOG_INFO, 29533841545SHajimu UMEMOTO "nd6_ra_input: invalid option " 29682cd038dSYoshinobu Inoue "len %d for prefix information option, " 29733841545SHajimu UMEMOTO "ignored\n", pi->nd_opt_pi_len)); 29882cd038dSYoshinobu Inoue continue; 29982cd038dSYoshinobu Inoue } 30082cd038dSYoshinobu Inoue 30182cd038dSYoshinobu Inoue if (128 < pi->nd_opt_pi_prefix_len) { 30233841545SHajimu UMEMOTO nd6log((LOG_INFO, 30333841545SHajimu UMEMOTO "nd6_ra_input: invalid prefix " 30482cd038dSYoshinobu Inoue "len %d for prefix information option, " 30533841545SHajimu UMEMOTO "ignored\n", pi->nd_opt_pi_prefix_len)); 30682cd038dSYoshinobu Inoue continue; 30782cd038dSYoshinobu Inoue } 30882cd038dSYoshinobu Inoue 30982cd038dSYoshinobu Inoue if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 31082cd038dSYoshinobu Inoue || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 31133841545SHajimu UMEMOTO nd6log((LOG_INFO, 31233841545SHajimu UMEMOTO "nd6_ra_input: invalid prefix " 31382cd038dSYoshinobu Inoue "%s, ignored\n", 31433841545SHajimu UMEMOTO ip6_sprintf(&pi->nd_opt_pi_prefix))); 31582cd038dSYoshinobu Inoue continue; 31682cd038dSYoshinobu Inoue } 31782cd038dSYoshinobu Inoue 31882cd038dSYoshinobu Inoue /* aggregatable unicast address, rfc2374 */ 31982cd038dSYoshinobu Inoue if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20 32082cd038dSYoshinobu Inoue && pi->nd_opt_pi_prefix_len != 64) { 32133841545SHajimu UMEMOTO nd6log((LOG_INFO, 32233841545SHajimu UMEMOTO "nd6_ra_input: invalid prefixlen " 32382cd038dSYoshinobu Inoue "%d for rfc2374 prefix %s, ignored\n", 32482cd038dSYoshinobu Inoue pi->nd_opt_pi_prefix_len, 32533841545SHajimu UMEMOTO ip6_sprintf(&pi->nd_opt_pi_prefix))); 32682cd038dSYoshinobu Inoue continue; 32782cd038dSYoshinobu Inoue } 32882cd038dSYoshinobu Inoue 32982cd038dSYoshinobu Inoue bzero(&pr, sizeof(pr)); 33082cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_family = AF_INET6; 33182cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 33282cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 33382cd038dSYoshinobu Inoue pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 33482cd038dSYoshinobu Inoue 33582cd038dSYoshinobu Inoue pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 33682cd038dSYoshinobu Inoue ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 33782cd038dSYoshinobu Inoue pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 33882cd038dSYoshinobu Inoue ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 33982cd038dSYoshinobu Inoue pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 34082cd038dSYoshinobu Inoue pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 34107eb2995SHajimu UMEMOTO pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); 34282cd038dSYoshinobu Inoue if (in6_init_prefix_ltimes(&pr)) 34382cd038dSYoshinobu Inoue continue; /* prefix lifetime init failed */ 34482cd038dSYoshinobu Inoue (void)prelist_update(&pr, dr, m); 34582cd038dSYoshinobu Inoue } 34682cd038dSYoshinobu Inoue } 34782cd038dSYoshinobu Inoue 34882cd038dSYoshinobu Inoue /* 34982cd038dSYoshinobu Inoue * MTU 35082cd038dSYoshinobu Inoue */ 35182cd038dSYoshinobu Inoue if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 35231b3783cSHajimu UMEMOTO u_long mtu; 35331b3783cSHajimu UMEMOTO u_long maxmtu; 35407eb2995SHajimu UMEMOTO 35531b3783cSHajimu UMEMOTO mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 35682cd038dSYoshinobu Inoue 35782cd038dSYoshinobu Inoue /* lower bound */ 35882cd038dSYoshinobu Inoue if (mtu < IPV6_MMTU) { 35933841545SHajimu UMEMOTO nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " 36031b3783cSHajimu UMEMOTO "mtu=%lu sent from %s, ignoring\n", 36133841545SHajimu UMEMOTO mtu, ip6_sprintf(&ip6->ip6_src))); 36282cd038dSYoshinobu Inoue goto skip; 36382cd038dSYoshinobu Inoue } 36482cd038dSYoshinobu Inoue 36582cd038dSYoshinobu Inoue /* upper bound */ 36631b3783cSHajimu UMEMOTO maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu) 36731b3783cSHajimu UMEMOTO ? ndi->maxmtu : ifp->if_mtu; 36831b3783cSHajimu UMEMOTO if (mtu <= maxmtu) { 36982cd038dSYoshinobu Inoue int change = (ndi->linkmtu != mtu); 37082cd038dSYoshinobu Inoue 37182cd038dSYoshinobu Inoue ndi->linkmtu = mtu; 37282cd038dSYoshinobu Inoue if (change) /* in6_maxmtu may change */ 37382cd038dSYoshinobu Inoue in6_setmaxmtu(); 37482cd038dSYoshinobu Inoue } else { 37533841545SHajimu UMEMOTO nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " 37631b3783cSHajimu UMEMOTO "mtu=%lu sent from %s; " 37731b3783cSHajimu UMEMOTO "exceeds maxmtu %lu, ignoring\n", 37831b3783cSHajimu UMEMOTO mtu, ip6_sprintf(&ip6->ip6_src), maxmtu)); 37982cd038dSYoshinobu Inoue } 38082cd038dSYoshinobu Inoue } 38182cd038dSYoshinobu Inoue 38282cd038dSYoshinobu Inoue skip: 38382cd038dSYoshinobu Inoue 38482cd038dSYoshinobu Inoue /* 38588ff5695SSUZUKI Shinsuke * Source link layer address 38682cd038dSYoshinobu Inoue */ 38782cd038dSYoshinobu Inoue { 38882cd038dSYoshinobu Inoue char *lladdr = NULL; 38982cd038dSYoshinobu Inoue int lladdrlen = 0; 39082cd038dSYoshinobu Inoue 39182cd038dSYoshinobu Inoue if (ndopts.nd_opts_src_lladdr) { 39282cd038dSYoshinobu Inoue lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 39382cd038dSYoshinobu Inoue lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 39482cd038dSYoshinobu Inoue } 39582cd038dSYoshinobu Inoue 39682cd038dSYoshinobu Inoue if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 39733841545SHajimu UMEMOTO nd6log((LOG_INFO, 39882cd038dSYoshinobu Inoue "nd6_ra_input: lladdrlen mismatch for %s " 39907eb2995SHajimu UMEMOTO "(if %d, RA packet %d)\n", ip6_sprintf(&saddr6), 40007eb2995SHajimu UMEMOTO ifp->if_addrlen, lladdrlen - 2)); 40133841545SHajimu UMEMOTO goto bad; 40282cd038dSYoshinobu Inoue } 40382cd038dSYoshinobu Inoue 40407eb2995SHajimu UMEMOTO nd6_cache_lladdr(ifp, &saddr6, lladdr, 40507eb2995SHajimu UMEMOTO lladdrlen, ND_ROUTER_ADVERT, 0); 406686cdd19SJun-ichiro itojun Hagino 407686cdd19SJun-ichiro itojun Hagino /* 408686cdd19SJun-ichiro itojun Hagino * Installing a link-layer address might change the state of the 409686cdd19SJun-ichiro itojun Hagino * router's neighbor cache, which might also affect our on-link 410686cdd19SJun-ichiro itojun Hagino * detection of adveritsed prefixes. 411686cdd19SJun-ichiro itojun Hagino */ 412686cdd19SJun-ichiro itojun Hagino pfxlist_onlink_check(); 41382cd038dSYoshinobu Inoue } 414686cdd19SJun-ichiro itojun Hagino 415686cdd19SJun-ichiro itojun Hagino freeit: 416686cdd19SJun-ichiro itojun Hagino m_freem(m); 41733841545SHajimu UMEMOTO return; 41833841545SHajimu UMEMOTO 41933841545SHajimu UMEMOTO bad: 42033841545SHajimu UMEMOTO icmp6stat.icp6s_badra++; 42133841545SHajimu UMEMOTO m_freem(m); 42282cd038dSYoshinobu Inoue } 42382cd038dSYoshinobu Inoue 42482cd038dSYoshinobu Inoue /* 42582cd038dSYoshinobu Inoue * default router list proccessing sub routines 42682cd038dSYoshinobu Inoue */ 427686cdd19SJun-ichiro itojun Hagino 428686cdd19SJun-ichiro itojun Hagino /* tell the change to user processes watching the routing socket. */ 429686cdd19SJun-ichiro itojun Hagino static void 43033841545SHajimu UMEMOTO nd6_rtmsg(cmd, rt) 431686cdd19SJun-ichiro itojun Hagino int cmd; 432686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 433686cdd19SJun-ichiro itojun Hagino { 434686cdd19SJun-ichiro itojun Hagino struct rt_addrinfo info; 435686cdd19SJun-ichiro itojun Hagino 436686cdd19SJun-ichiro itojun Hagino bzero((caddr_t)&info, sizeof(info)); 437686cdd19SJun-ichiro itojun Hagino info.rti_info[RTAX_DST] = rt_key(rt); 438686cdd19SJun-ichiro itojun Hagino info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 439686cdd19SJun-ichiro itojun Hagino info.rti_info[RTAX_NETMASK] = rt_mask(rt); 44033841545SHajimu UMEMOTO info.rti_info[RTAX_IFP] = 44133841545SHajimu UMEMOTO (struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist); 44233841545SHajimu UMEMOTO info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 443686cdd19SJun-ichiro itojun Hagino 444686cdd19SJun-ichiro itojun Hagino rt_missmsg(cmd, &info, rt->rt_flags, 0); 445686cdd19SJun-ichiro itojun Hagino } 446686cdd19SJun-ichiro itojun Hagino 44782cd038dSYoshinobu Inoue void 44882cd038dSYoshinobu Inoue defrouter_addreq(new) 44982cd038dSYoshinobu Inoue struct nd_defrouter *new; 45082cd038dSYoshinobu Inoue { 45182cd038dSYoshinobu Inoue struct sockaddr_in6 def, mask, gate; 452686cdd19SJun-ichiro itojun Hagino struct rtentry *newrt = NULL; 45382cd038dSYoshinobu Inoue 454056c7327SLuigi Rizzo bzero(&def, sizeof(def)); 455056c7327SLuigi Rizzo bzero(&mask, sizeof(mask)); 456056c7327SLuigi Rizzo bzero(&gate, sizeof(gate)); 45782cd038dSYoshinobu Inoue 45807eb2995SHajimu UMEMOTO def.sin6_len = mask.sin6_len = gate.sin6_len = 45907eb2995SHajimu UMEMOTO sizeof(struct sockaddr_in6); 46082cd038dSYoshinobu Inoue def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6; 46182cd038dSYoshinobu Inoue gate.sin6_addr = new->rtaddr; 46282cd038dSYoshinobu Inoue 46382cd038dSYoshinobu Inoue (void)rtrequest(RTM_ADD, (struct sockaddr *)&def, 46482cd038dSYoshinobu Inoue (struct sockaddr *)&gate, (struct sockaddr *)&mask, 465686cdd19SJun-ichiro itojun Hagino RTF_GATEWAY, &newrt); 466686cdd19SJun-ichiro itojun Hagino if (newrt) { 467d1dd20beSSam Leffler RT_LOCK(newrt); 46833841545SHajimu UMEMOTO nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 4697138d65cSSam Leffler RT_REMREF(newrt); 470d1dd20beSSam Leffler RT_UNLOCK(newrt); 471686cdd19SJun-ichiro itojun Hagino } 47282cd038dSYoshinobu Inoue return; 47382cd038dSYoshinobu Inoue } 47482cd038dSYoshinobu Inoue 475686cdd19SJun-ichiro itojun Hagino /* Add a route to a given interface as default */ 476686cdd19SJun-ichiro itojun Hagino void 477686cdd19SJun-ichiro itojun Hagino defrouter_addifreq(ifp) 478686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 479686cdd19SJun-ichiro itojun Hagino { 480686cdd19SJun-ichiro itojun Hagino struct sockaddr_in6 def, mask; 481686cdd19SJun-ichiro itojun Hagino struct ifaddr *ifa; 482686cdd19SJun-ichiro itojun Hagino struct rtentry *newrt = NULL; 483686cdd19SJun-ichiro itojun Hagino int error, flags; 484686cdd19SJun-ichiro itojun Hagino 485686cdd19SJun-ichiro itojun Hagino bzero(&def, sizeof(def)); 486686cdd19SJun-ichiro itojun Hagino bzero(&mask, sizeof(mask)); 487686cdd19SJun-ichiro itojun Hagino 488686cdd19SJun-ichiro itojun Hagino def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6); 489686cdd19SJun-ichiro itojun Hagino def.sin6_family = mask.sin6_family = AF_INET6; 490686cdd19SJun-ichiro itojun Hagino 491686cdd19SJun-ichiro itojun Hagino /* 492686cdd19SJun-ichiro itojun Hagino * Search for an ifaddr beloging to the specified interface. 493686cdd19SJun-ichiro itojun Hagino * XXX: An IPv6 address are required to be assigned on the interface. 494686cdd19SJun-ichiro itojun Hagino */ 495686cdd19SJun-ichiro itojun Hagino if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) { 49633841545SHajimu UMEMOTO nd6log((LOG_ERR, /* better error? */ 497686cdd19SJun-ichiro itojun Hagino "defrouter_addifreq: failed to find an ifaddr " 498686cdd19SJun-ichiro itojun Hagino "to install a route to interface %s\n", 49933841545SHajimu UMEMOTO if_name(ifp))); 500686cdd19SJun-ichiro itojun Hagino return; 501686cdd19SJun-ichiro itojun Hagino } 502686cdd19SJun-ichiro itojun Hagino 503686cdd19SJun-ichiro itojun Hagino flags = ifa->ifa_flags; 50433841545SHajimu UMEMOTO error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr, 50533841545SHajimu UMEMOTO (struct sockaddr *)&mask, flags, &newrt); 50633841545SHajimu UMEMOTO if (error != 0) { 50733841545SHajimu UMEMOTO nd6log((LOG_ERR, 508686cdd19SJun-ichiro itojun Hagino "defrouter_addifreq: failed to install a route to " 509686cdd19SJun-ichiro itojun Hagino "interface %s (errno = %d)\n", 51033841545SHajimu UMEMOTO if_name(ifp), error)); 511686cdd19SJun-ichiro itojun Hagino } else { 512686cdd19SJun-ichiro itojun Hagino if (newrt) { 513d1dd20beSSam Leffler RT_LOCK(newrt); 51433841545SHajimu UMEMOTO nd6_rtmsg(RTM_ADD, newrt); 5157138d65cSSam Leffler RT_REMREF(newrt); 516d1dd20beSSam Leffler RT_UNLOCK(newrt); 517686cdd19SJun-ichiro itojun Hagino } 518686cdd19SJun-ichiro itojun Hagino } 519686cdd19SJun-ichiro itojun Hagino } 520686cdd19SJun-ichiro itojun Hagino 52182cd038dSYoshinobu Inoue struct nd_defrouter * 52282cd038dSYoshinobu Inoue defrouter_lookup(addr, ifp) 52382cd038dSYoshinobu Inoue struct in6_addr *addr; 52482cd038dSYoshinobu Inoue struct ifnet *ifp; 52582cd038dSYoshinobu Inoue { 52682cd038dSYoshinobu Inoue struct nd_defrouter *dr; 52782cd038dSYoshinobu Inoue 528686cdd19SJun-ichiro itojun Hagino for (dr = TAILQ_FIRST(&nd_defrouter); dr; 529686cdd19SJun-ichiro itojun Hagino dr = TAILQ_NEXT(dr, dr_entry)) { 53082cd038dSYoshinobu Inoue if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 53182cd038dSYoshinobu Inoue return (dr); 532686cdd19SJun-ichiro itojun Hagino } 53382cd038dSYoshinobu Inoue 53482cd038dSYoshinobu Inoue return (NULL); /* search failed */ 53582cd038dSYoshinobu Inoue } 53682cd038dSYoshinobu Inoue 53782cd038dSYoshinobu Inoue void 53882cd038dSYoshinobu Inoue defrouter_delreq(dr, dofree) 53982cd038dSYoshinobu Inoue struct nd_defrouter *dr; 54082cd038dSYoshinobu Inoue int dofree; 54182cd038dSYoshinobu Inoue { 54282cd038dSYoshinobu Inoue struct sockaddr_in6 def, mask, gate; 543686cdd19SJun-ichiro itojun Hagino struct rtentry *oldrt = NULL; 54482cd038dSYoshinobu Inoue 545056c7327SLuigi Rizzo bzero(&def, sizeof(def)); 546056c7327SLuigi Rizzo bzero(&mask, sizeof(mask)); 547056c7327SLuigi Rizzo bzero(&gate, sizeof(gate)); 54882cd038dSYoshinobu Inoue 54907eb2995SHajimu UMEMOTO def.sin6_len = mask.sin6_len = gate.sin6_len = 55007eb2995SHajimu UMEMOTO sizeof(struct sockaddr_in6); 55182cd038dSYoshinobu Inoue def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6; 55282cd038dSYoshinobu Inoue gate.sin6_addr = dr->rtaddr; 55382cd038dSYoshinobu Inoue 55482cd038dSYoshinobu Inoue rtrequest(RTM_DELETE, (struct sockaddr *)&def, 55582cd038dSYoshinobu Inoue (struct sockaddr *)&gate, 55607eb2995SHajimu UMEMOTO (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); 557686cdd19SJun-ichiro itojun Hagino if (oldrt) { 55833841545SHajimu UMEMOTO nd6_rtmsg(RTM_DELETE, oldrt); 55971eba915SRuslan Ermilov RTFREE(oldrt); 56020220070SJun-ichiro itojun Hagino } 56182cd038dSYoshinobu Inoue 562686cdd19SJun-ichiro itojun Hagino if (dofree) /* XXX: necessary? */ 56382cd038dSYoshinobu Inoue free(dr, M_IP6NDP); 56482cd038dSYoshinobu Inoue } 56582cd038dSYoshinobu Inoue 56682cd038dSYoshinobu Inoue void 56782cd038dSYoshinobu Inoue defrtrlist_del(dr) 56882cd038dSYoshinobu Inoue struct nd_defrouter *dr; 56982cd038dSYoshinobu Inoue { 57082cd038dSYoshinobu Inoue struct nd_defrouter *deldr = NULL; 57182cd038dSYoshinobu Inoue struct nd_prefix *pr; 57282cd038dSYoshinobu Inoue 57382cd038dSYoshinobu Inoue /* 57482cd038dSYoshinobu Inoue * Flush all the routing table entries that use the router 57582cd038dSYoshinobu Inoue * as a next hop. 57682cd038dSYoshinobu Inoue */ 57707eb2995SHajimu UMEMOTO if (!ip6_forwarding && ip6_accept_rtadv) /* XXX: better condition? */ 57882cd038dSYoshinobu Inoue rt6_flush(&dr->rtaddr, dr->ifp); 57982cd038dSYoshinobu Inoue 580686cdd19SJun-ichiro itojun Hagino if (dr == TAILQ_FIRST(&nd_defrouter)) 58182cd038dSYoshinobu Inoue deldr = dr; /* The router is primary. */ 58282cd038dSYoshinobu Inoue 583686cdd19SJun-ichiro itojun Hagino TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 58482cd038dSYoshinobu Inoue 58582cd038dSYoshinobu Inoue /* 58682cd038dSYoshinobu Inoue * Also delete all the pointers to the router in each prefix lists. 58782cd038dSYoshinobu Inoue */ 588686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 58982cd038dSYoshinobu Inoue struct nd_pfxrouter *pfxrtr; 59082cd038dSYoshinobu Inoue if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 59182cd038dSYoshinobu Inoue pfxrtr_del(pfxrtr); 59282cd038dSYoshinobu Inoue } 59382cd038dSYoshinobu Inoue pfxlist_onlink_check(); 59482cd038dSYoshinobu Inoue 59582cd038dSYoshinobu Inoue /* 596686cdd19SJun-ichiro itojun Hagino * If the router is the primary one, choose a new one. 597686cdd19SJun-ichiro itojun Hagino * Note that defrouter_select() will remove the current gateway 598686cdd19SJun-ichiro itojun Hagino * from the routing table. 59982cd038dSYoshinobu Inoue */ 60082cd038dSYoshinobu Inoue if (deldr) 601686cdd19SJun-ichiro itojun Hagino defrouter_select(); 602686cdd19SJun-ichiro itojun Hagino 60382cd038dSYoshinobu Inoue free(dr, M_IP6NDP); 60482cd038dSYoshinobu Inoue } 60582cd038dSYoshinobu Inoue 606686cdd19SJun-ichiro itojun Hagino /* 607686cdd19SJun-ichiro itojun Hagino * Default Router Selection according to Section 6.3.6 of RFC 2461: 608686cdd19SJun-ichiro itojun Hagino * 1) Routers that are reachable or probably reachable should be 609686cdd19SJun-ichiro itojun Hagino * preferred. 610686cdd19SJun-ichiro itojun Hagino * 2) When no routers on the list are known to be reachable or 611686cdd19SJun-ichiro itojun Hagino * probably reachable, routers SHOULD be selected in a round-robin 612686cdd19SJun-ichiro itojun Hagino * fashion. 613686cdd19SJun-ichiro itojun Hagino * 3) If the Default Router List is empty, assume that all 614686cdd19SJun-ichiro itojun Hagino * destinations are on-link. 615686cdd19SJun-ichiro itojun Hagino */ 616686cdd19SJun-ichiro itojun Hagino void 617686cdd19SJun-ichiro itojun Hagino defrouter_select() 618686cdd19SJun-ichiro itojun Hagino { 619686cdd19SJun-ichiro itojun Hagino int s = splnet(); 620686cdd19SJun-ichiro itojun Hagino struct nd_defrouter *dr, anydr; 621686cdd19SJun-ichiro itojun Hagino struct rtentry *rt = NULL; 622686cdd19SJun-ichiro itojun Hagino struct llinfo_nd6 *ln = NULL; 623686cdd19SJun-ichiro itojun Hagino 624686cdd19SJun-ichiro itojun Hagino /* 625686cdd19SJun-ichiro itojun Hagino * Search for a (probably) reachable router from the list. 626686cdd19SJun-ichiro itojun Hagino */ 627686cdd19SJun-ichiro itojun Hagino for (dr = TAILQ_FIRST(&nd_defrouter); dr; 628686cdd19SJun-ichiro itojun Hagino dr = TAILQ_NEXT(dr, dr_entry)) { 629686cdd19SJun-ichiro itojun Hagino if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && 630686cdd19SJun-ichiro itojun Hagino (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 631686cdd19SJun-ichiro itojun Hagino ND6_IS_LLINFO_PROBREACH(ln)) { 632686cdd19SJun-ichiro itojun Hagino /* Got it, and move it to the head */ 633686cdd19SJun-ichiro itojun Hagino TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 634686cdd19SJun-ichiro itojun Hagino TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry); 635686cdd19SJun-ichiro itojun Hagino break; 636686cdd19SJun-ichiro itojun Hagino } 637686cdd19SJun-ichiro itojun Hagino } 638686cdd19SJun-ichiro itojun Hagino 639686cdd19SJun-ichiro itojun Hagino if ((dr = TAILQ_FIRST(&nd_defrouter))) { 640686cdd19SJun-ichiro itojun Hagino /* 641686cdd19SJun-ichiro itojun Hagino * De-install the previous default gateway and install 642686cdd19SJun-ichiro itojun Hagino * a new one. 643686cdd19SJun-ichiro itojun Hagino * Note that if there is no reachable router in the list, 644686cdd19SJun-ichiro itojun Hagino * the head entry will be used anyway. 645686cdd19SJun-ichiro itojun Hagino * XXX: do we have to check the current routing table entry? 646686cdd19SJun-ichiro itojun Hagino */ 647686cdd19SJun-ichiro itojun Hagino bzero(&anydr, sizeof(anydr)); 648686cdd19SJun-ichiro itojun Hagino defrouter_delreq(&anydr, 0); 649686cdd19SJun-ichiro itojun Hagino defrouter_addreq(dr); 650686cdd19SJun-ichiro itojun Hagino } 651686cdd19SJun-ichiro itojun Hagino else { 652686cdd19SJun-ichiro itojun Hagino /* 653686cdd19SJun-ichiro itojun Hagino * The Default Router List is empty, so install the default 654686cdd19SJun-ichiro itojun Hagino * route to an inteface. 655686cdd19SJun-ichiro itojun Hagino * XXX: The specification does not say this mechanism should 656686cdd19SJun-ichiro itojun Hagino * be restricted to hosts, but this would be not useful 657686cdd19SJun-ichiro itojun Hagino * (even harmful) for routers. 658686cdd19SJun-ichiro itojun Hagino */ 659686cdd19SJun-ichiro itojun Hagino if (!ip6_forwarding) { 660686cdd19SJun-ichiro itojun Hagino /* 661686cdd19SJun-ichiro itojun Hagino * De-install the current default route 662686cdd19SJun-ichiro itojun Hagino * in advance. 663686cdd19SJun-ichiro itojun Hagino */ 664686cdd19SJun-ichiro itojun Hagino bzero(&anydr, sizeof(anydr)); 665686cdd19SJun-ichiro itojun Hagino defrouter_delreq(&anydr, 0); 666686cdd19SJun-ichiro itojun Hagino if (nd6_defifp) { 667686cdd19SJun-ichiro itojun Hagino /* 668686cdd19SJun-ichiro itojun Hagino * Install a route to the default interface 669686cdd19SJun-ichiro itojun Hagino * as default route. 67033841545SHajimu UMEMOTO * XXX: we enable this for host only, because 67133841545SHajimu UMEMOTO * this may override a default route installed 67233841545SHajimu UMEMOTO * a user process (e.g. routing daemon) in a 67333841545SHajimu UMEMOTO * router case. 674686cdd19SJun-ichiro itojun Hagino */ 675686cdd19SJun-ichiro itojun Hagino defrouter_addifreq(nd6_defifp); 67633841545SHajimu UMEMOTO } else { 67733841545SHajimu UMEMOTO nd6log((LOG_INFO, "defrouter_select: " 678686cdd19SJun-ichiro itojun Hagino "there's no default router and no default" 67933841545SHajimu UMEMOTO " interface\n")); 68033841545SHajimu UMEMOTO } 681686cdd19SJun-ichiro itojun Hagino } 682686cdd19SJun-ichiro itojun Hagino } 683686cdd19SJun-ichiro itojun Hagino 684686cdd19SJun-ichiro itojun Hagino splx(s); 685686cdd19SJun-ichiro itojun Hagino return; 686686cdd19SJun-ichiro itojun Hagino } 687686cdd19SJun-ichiro itojun Hagino 68882cd038dSYoshinobu Inoue static struct nd_defrouter * 68982cd038dSYoshinobu Inoue defrtrlist_update(new) 69082cd038dSYoshinobu Inoue struct nd_defrouter *new; 69182cd038dSYoshinobu Inoue { 69282cd038dSYoshinobu Inoue struct nd_defrouter *dr, *n; 69382cd038dSYoshinobu Inoue int s = splnet(); 69482cd038dSYoshinobu Inoue 69582cd038dSYoshinobu Inoue if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 69682cd038dSYoshinobu Inoue /* entry exists */ 69782cd038dSYoshinobu Inoue if (new->rtlifetime == 0) { 69882cd038dSYoshinobu Inoue defrtrlist_del(dr); 69982cd038dSYoshinobu Inoue dr = NULL; 70082cd038dSYoshinobu Inoue } else { 70182cd038dSYoshinobu Inoue /* override */ 70282cd038dSYoshinobu Inoue dr->flags = new->flags; /* xxx flag check */ 70382cd038dSYoshinobu Inoue dr->rtlifetime = new->rtlifetime; 70482cd038dSYoshinobu Inoue dr->expire = new->expire; 70582cd038dSYoshinobu Inoue } 70682cd038dSYoshinobu Inoue splx(s); 70782cd038dSYoshinobu Inoue return (dr); 70882cd038dSYoshinobu Inoue } 70982cd038dSYoshinobu Inoue 71082cd038dSYoshinobu Inoue /* entry does not exist */ 71182cd038dSYoshinobu Inoue if (new->rtlifetime == 0) { 71282cd038dSYoshinobu Inoue splx(s); 71382cd038dSYoshinobu Inoue return (NULL); 71482cd038dSYoshinobu Inoue } 71582cd038dSYoshinobu Inoue 71682cd038dSYoshinobu Inoue n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 71782cd038dSYoshinobu Inoue if (n == NULL) { 71882cd038dSYoshinobu Inoue splx(s); 71982cd038dSYoshinobu Inoue return (NULL); 72082cd038dSYoshinobu Inoue } 72182cd038dSYoshinobu Inoue bzero(n, sizeof(*n)); 72282cd038dSYoshinobu Inoue *n = *new; 723686cdd19SJun-ichiro itojun Hagino 724686cdd19SJun-ichiro itojun Hagino /* 725686cdd19SJun-ichiro itojun Hagino * Insert the new router at the end of the Default Router List. 726686cdd19SJun-ichiro itojun Hagino * If there is no other router, install it anyway. Otherwise, 727686cdd19SJun-ichiro itojun Hagino * just continue to use the current default router. 728686cdd19SJun-ichiro itojun Hagino */ 729686cdd19SJun-ichiro itojun Hagino TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry); 730686cdd19SJun-ichiro itojun Hagino if (TAILQ_FIRST(&nd_defrouter) == n) 731686cdd19SJun-ichiro itojun Hagino defrouter_select(); 73282cd038dSYoshinobu Inoue splx(s); 73382cd038dSYoshinobu Inoue 73482cd038dSYoshinobu Inoue return (n); 73582cd038dSYoshinobu Inoue } 73682cd038dSYoshinobu Inoue 73782cd038dSYoshinobu Inoue static struct nd_pfxrouter * 73882cd038dSYoshinobu Inoue pfxrtr_lookup(pr, dr) 73982cd038dSYoshinobu Inoue struct nd_prefix *pr; 74082cd038dSYoshinobu Inoue struct nd_defrouter *dr; 74182cd038dSYoshinobu Inoue { 74282cd038dSYoshinobu Inoue struct nd_pfxrouter *search; 74382cd038dSYoshinobu Inoue 744686cdd19SJun-ichiro itojun Hagino for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { 74582cd038dSYoshinobu Inoue if (search->router == dr) 74682cd038dSYoshinobu Inoue break; 74782cd038dSYoshinobu Inoue } 74882cd038dSYoshinobu Inoue 74982cd038dSYoshinobu Inoue return (search); 75082cd038dSYoshinobu Inoue } 75182cd038dSYoshinobu Inoue 75282cd038dSYoshinobu Inoue static void 75382cd038dSYoshinobu Inoue pfxrtr_add(pr, dr) 75482cd038dSYoshinobu Inoue struct nd_prefix *pr; 75582cd038dSYoshinobu Inoue struct nd_defrouter *dr; 75682cd038dSYoshinobu Inoue { 75782cd038dSYoshinobu Inoue struct nd_pfxrouter *new; 75882cd038dSYoshinobu Inoue 75982cd038dSYoshinobu Inoue new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 76082cd038dSYoshinobu Inoue if (new == NULL) 76182cd038dSYoshinobu Inoue return; 76282cd038dSYoshinobu Inoue bzero(new, sizeof(*new)); 76382cd038dSYoshinobu Inoue new->router = dr; 76482cd038dSYoshinobu Inoue 76582cd038dSYoshinobu Inoue LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 76682cd038dSYoshinobu Inoue 76782cd038dSYoshinobu Inoue pfxlist_onlink_check(); 76882cd038dSYoshinobu Inoue } 76982cd038dSYoshinobu Inoue 77082cd038dSYoshinobu Inoue static void 77182cd038dSYoshinobu Inoue pfxrtr_del(pfr) 77282cd038dSYoshinobu Inoue struct nd_pfxrouter *pfr; 77382cd038dSYoshinobu Inoue { 77482cd038dSYoshinobu Inoue LIST_REMOVE(pfr, pfr_entry); 77582cd038dSYoshinobu Inoue free(pfr, M_IP6NDP); 77682cd038dSYoshinobu Inoue } 77782cd038dSYoshinobu Inoue 77833841545SHajimu UMEMOTO struct nd_prefix * 77933841545SHajimu UMEMOTO nd6_prefix_lookup(pr) 78082cd038dSYoshinobu Inoue struct nd_prefix *pr; 78182cd038dSYoshinobu Inoue { 78282cd038dSYoshinobu Inoue struct nd_prefix *search; 78382cd038dSYoshinobu Inoue 784686cdd19SJun-ichiro itojun Hagino for (search = nd_prefix.lh_first; search; search = search->ndpr_next) { 78582cd038dSYoshinobu Inoue if (pr->ndpr_ifp == search->ndpr_ifp && 78682cd038dSYoshinobu Inoue pr->ndpr_plen == search->ndpr_plen && 78782cd038dSYoshinobu Inoue in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 78807eb2995SHajimu UMEMOTO &search->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 78982cd038dSYoshinobu Inoue break; 79082cd038dSYoshinobu Inoue } 79182cd038dSYoshinobu Inoue } 79282cd038dSYoshinobu Inoue 79382cd038dSYoshinobu Inoue return (search); 79482cd038dSYoshinobu Inoue } 79582cd038dSYoshinobu Inoue 79633841545SHajimu UMEMOTO int 79733841545SHajimu UMEMOTO nd6_prelist_add(pr, dr, newp) 79833841545SHajimu UMEMOTO struct nd_prefix *pr, **newp; 79982cd038dSYoshinobu Inoue struct nd_defrouter *dr; 80082cd038dSYoshinobu Inoue { 80133841545SHajimu UMEMOTO struct nd_prefix *new = NULL; 80282cd038dSYoshinobu Inoue int i, s; 80382cd038dSYoshinobu Inoue 80482cd038dSYoshinobu Inoue new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 80582cd038dSYoshinobu Inoue if (new == NULL) 80607eb2995SHajimu UMEMOTO return(ENOMEM); 80782cd038dSYoshinobu Inoue bzero(new, sizeof(*new)); 80882cd038dSYoshinobu Inoue *new = *pr; 80933841545SHajimu UMEMOTO if (newp != NULL) 81033841545SHajimu UMEMOTO *newp = new; 81182cd038dSYoshinobu Inoue 81207eb2995SHajimu UMEMOTO /* initialization */ 81382cd038dSYoshinobu Inoue LIST_INIT(&new->ndpr_advrtrs); 81482cd038dSYoshinobu Inoue in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 81582cd038dSYoshinobu Inoue /* make prefix in the canonical form */ 81682cd038dSYoshinobu Inoue for (i = 0; i < 4; i++) 81782cd038dSYoshinobu Inoue new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 81882cd038dSYoshinobu Inoue new->ndpr_mask.s6_addr32[i]; 81982cd038dSYoshinobu Inoue 82082cd038dSYoshinobu Inoue s = splnet(); 82182cd038dSYoshinobu Inoue /* link ndpr_entry to nd_prefix list */ 82282cd038dSYoshinobu Inoue LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry); 82382cd038dSYoshinobu Inoue splx(s); 82482cd038dSYoshinobu Inoue 82533841545SHajimu UMEMOTO /* ND_OPT_PI_FLAG_ONLINK processing */ 82633841545SHajimu UMEMOTO if (new->ndpr_raf_onlink) { 82733841545SHajimu UMEMOTO int e; 82833841545SHajimu UMEMOTO 82933841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(new)) != 0) { 83033841545SHajimu UMEMOTO nd6log((LOG_ERR, "nd6_prelist_add: failed to make " 83133841545SHajimu UMEMOTO "the prefix %s/%d on-link on %s (errno=%d)\n", 83233841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 83333841545SHajimu UMEMOTO pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 83433841545SHajimu UMEMOTO /* proceed anyway. XXX: is it correct? */ 83533841545SHajimu UMEMOTO } 83633841545SHajimu UMEMOTO } 83733841545SHajimu UMEMOTO 83807eb2995SHajimu UMEMOTO if (dr) 83982cd038dSYoshinobu Inoue pfxrtr_add(new, dr); 84082cd038dSYoshinobu Inoue 84182cd038dSYoshinobu Inoue return 0; 84282cd038dSYoshinobu Inoue } 84382cd038dSYoshinobu Inoue 84482cd038dSYoshinobu Inoue void 84582cd038dSYoshinobu Inoue prelist_remove(pr) 84682cd038dSYoshinobu Inoue struct nd_prefix *pr; 84782cd038dSYoshinobu Inoue { 84882cd038dSYoshinobu Inoue struct nd_pfxrouter *pfr, *next; 84933841545SHajimu UMEMOTO int e, s; 85033841545SHajimu UMEMOTO 85133841545SHajimu UMEMOTO /* make sure to invalidate the prefix until it is really freed. */ 85233841545SHajimu UMEMOTO pr->ndpr_vltime = 0; 85333841545SHajimu UMEMOTO pr->ndpr_pltime = 0; 85433841545SHajimu UMEMOTO /* 85533841545SHajimu UMEMOTO * Though these flags are now meaningless, we'd rather keep the value 8567aa59493SSUZUKI Shinsuke * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users 8577aa59493SSUZUKI Shinsuke * when executing "ndp -p". 85833841545SHajimu UMEMOTO */ 8597aa59493SSUZUKI Shinsuke 86033841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && 86133841545SHajimu UMEMOTO (e = nd6_prefix_offlink(pr)) != 0) { 86233841545SHajimu UMEMOTO nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " 86333841545SHajimu UMEMOTO "on %s, errno=%d\n", 86433841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 86533841545SHajimu UMEMOTO pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 86633841545SHajimu UMEMOTO /* what should we do? */ 86733841545SHajimu UMEMOTO } 86833841545SHajimu UMEMOTO 86933841545SHajimu UMEMOTO if (pr->ndpr_refcnt > 0) 87033841545SHajimu UMEMOTO return; /* notice here? */ 87182cd038dSYoshinobu Inoue 87282cd038dSYoshinobu Inoue s = splnet(); 87333841545SHajimu UMEMOTO 87482cd038dSYoshinobu Inoue /* unlink ndpr_entry from nd_prefix list */ 87582cd038dSYoshinobu Inoue LIST_REMOVE(pr, ndpr_entry); 87682cd038dSYoshinobu Inoue 87782cd038dSYoshinobu Inoue /* free list of routers that adversed the prefix */ 878686cdd19SJun-ichiro itojun Hagino for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { 879686cdd19SJun-ichiro itojun Hagino next = pfr->pfr_next; 88082cd038dSYoshinobu Inoue 88182cd038dSYoshinobu Inoue free(pfr, M_IP6NDP); 88282cd038dSYoshinobu Inoue } 88333841545SHajimu UMEMOTO splx(s); 88433841545SHajimu UMEMOTO 88582cd038dSYoshinobu Inoue free(pr, M_IP6NDP); 88682cd038dSYoshinobu Inoue 88782cd038dSYoshinobu Inoue pfxlist_onlink_check(); 88882cd038dSYoshinobu Inoue } 88982cd038dSYoshinobu Inoue 89082cd038dSYoshinobu Inoue int 89182cd038dSYoshinobu Inoue prelist_update(new, dr, m) 89282cd038dSYoshinobu Inoue struct nd_prefix *new; 89382cd038dSYoshinobu Inoue struct nd_defrouter *dr; /* may be NULL */ 89482cd038dSYoshinobu Inoue struct mbuf *m; 89582cd038dSYoshinobu Inoue { 89633841545SHajimu UMEMOTO struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 89733841545SHajimu UMEMOTO struct ifaddr *ifa; 89833841545SHajimu UMEMOTO struct ifnet *ifp = new->ndpr_ifp; 89982cd038dSYoshinobu Inoue struct nd_prefix *pr; 90082cd038dSYoshinobu Inoue int s = splnet(); 90182cd038dSYoshinobu Inoue int error = 0; 90233841545SHajimu UMEMOTO int newprefix = 0; 90382cd038dSYoshinobu Inoue int auth; 90433841545SHajimu UMEMOTO struct in6_addrlifetime lt6_tmp; 90582cd038dSYoshinobu Inoue 90682cd038dSYoshinobu Inoue auth = 0; 90782cd038dSYoshinobu Inoue if (m) { 90882cd038dSYoshinobu Inoue /* 90982cd038dSYoshinobu Inoue * Authenticity for NA consists authentication for 91082cd038dSYoshinobu Inoue * both IP header and IP datagrams, doesn't it ? 91182cd038dSYoshinobu Inoue */ 91282cd038dSYoshinobu Inoue #if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 91307eb2995SHajimu UMEMOTO auth = ((m->m_flags & M_AUTHIPHDR) && 91407eb2995SHajimu UMEMOTO (m->m_flags & M_AUTHIPDGM)); 91582cd038dSYoshinobu Inoue #endif 91682cd038dSYoshinobu Inoue } 91782cd038dSYoshinobu Inoue 91833841545SHajimu UMEMOTO if ((pr = nd6_prefix_lookup(new)) != NULL) { 91933841545SHajimu UMEMOTO /* 92033841545SHajimu UMEMOTO * nd6_prefix_lookup() ensures that pr and new have the same 92133841545SHajimu UMEMOTO * prefix on a same interface. 92233841545SHajimu UMEMOTO */ 92333841545SHajimu UMEMOTO 92433841545SHajimu UMEMOTO /* 92533841545SHajimu UMEMOTO * Update prefix information. Note that the on-link (L) bit 92633841545SHajimu UMEMOTO * and the autonomous (A) bit should NOT be changed from 1 92733841545SHajimu UMEMOTO * to 0. 92833841545SHajimu UMEMOTO */ 92933841545SHajimu UMEMOTO if (new->ndpr_raf_onlink == 1) 93033841545SHajimu UMEMOTO pr->ndpr_raf_onlink = 1; 93133841545SHajimu UMEMOTO if (new->ndpr_raf_auto == 1) 93233841545SHajimu UMEMOTO pr->ndpr_raf_auto = 1; 93333841545SHajimu UMEMOTO if (new->ndpr_raf_onlink) { 93482cd038dSYoshinobu Inoue pr->ndpr_vltime = new->ndpr_vltime; 93582cd038dSYoshinobu Inoue pr->ndpr_pltime = new->ndpr_pltime; 93682cd038dSYoshinobu Inoue pr->ndpr_preferred = new->ndpr_preferred; 93782cd038dSYoshinobu Inoue pr->ndpr_expire = new->ndpr_expire; 93882cd038dSYoshinobu Inoue } 93982cd038dSYoshinobu Inoue 94033841545SHajimu UMEMOTO if (new->ndpr_raf_onlink && 94133841545SHajimu UMEMOTO (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 94233841545SHajimu UMEMOTO int e; 94382cd038dSYoshinobu Inoue 94433841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(pr)) != 0) { 94533841545SHajimu UMEMOTO nd6log((LOG_ERR, 94633841545SHajimu UMEMOTO "prelist_update: failed to make " 94733841545SHajimu UMEMOTO "the prefix %s/%d on-link on %s " 94833841545SHajimu UMEMOTO "(errno=%d)\n", 94933841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 95033841545SHajimu UMEMOTO pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 95133841545SHajimu UMEMOTO /* proceed anyway. XXX: is it correct? */ 952686cdd19SJun-ichiro itojun Hagino } 95382cd038dSYoshinobu Inoue } 95482cd038dSYoshinobu Inoue 95582cd038dSYoshinobu Inoue if (dr && pfxrtr_lookup(pr, dr) == NULL) 95682cd038dSYoshinobu Inoue pfxrtr_add(pr, dr); 95782cd038dSYoshinobu Inoue } else { 95833841545SHajimu UMEMOTO struct nd_prefix *newpr = NULL; 95982cd038dSYoshinobu Inoue 96033841545SHajimu UMEMOTO newprefix = 1; 96133841545SHajimu UMEMOTO 96233841545SHajimu UMEMOTO if (new->ndpr_vltime == 0) 96333841545SHajimu UMEMOTO goto end; 96433841545SHajimu UMEMOTO if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 96533841545SHajimu UMEMOTO goto end; 96682cd038dSYoshinobu Inoue 96782cd038dSYoshinobu Inoue bzero(&new->ndpr_addr, sizeof(struct in6_addr)); 96882cd038dSYoshinobu Inoue 96933841545SHajimu UMEMOTO error = nd6_prelist_add(new, dr, &newpr); 97033841545SHajimu UMEMOTO if (error != 0 || newpr == NULL) { 97133841545SHajimu UMEMOTO nd6log((LOG_NOTICE, "prelist_update: " 97233841545SHajimu UMEMOTO "nd6_prelist_add failed for %s/%d on %s " 97333841545SHajimu UMEMOTO "errno=%d, returnpr=%p\n", 97433841545SHajimu UMEMOTO ip6_sprintf(&new->ndpr_prefix.sin6_addr), 97533841545SHajimu UMEMOTO new->ndpr_plen, if_name(new->ndpr_ifp), 97633841545SHajimu UMEMOTO error, newpr)); 97733841545SHajimu UMEMOTO goto end; /* we should just give up in this case. */ 97833841545SHajimu UMEMOTO } 97933841545SHajimu UMEMOTO 98082cd038dSYoshinobu Inoue /* 98133841545SHajimu UMEMOTO * XXX: from the ND point of view, we can ignore a prefix 98233841545SHajimu UMEMOTO * with the on-link bit being zero. However, we need a 98333841545SHajimu UMEMOTO * prefix structure for references from autoconfigured 98407eb2995SHajimu UMEMOTO * addresses. Thus, we explicitly make sure that the prefix 98533841545SHajimu UMEMOTO * itself expires now. 98682cd038dSYoshinobu Inoue */ 98733841545SHajimu UMEMOTO if (newpr->ndpr_raf_onlink == 0) { 98833841545SHajimu UMEMOTO newpr->ndpr_vltime = 0; 98933841545SHajimu UMEMOTO newpr->ndpr_pltime = 0; 99033841545SHajimu UMEMOTO in6_init_prefix_ltimes(newpr); 99133841545SHajimu UMEMOTO } 99233841545SHajimu UMEMOTO 99333841545SHajimu UMEMOTO pr = newpr; 99433841545SHajimu UMEMOTO } 99533841545SHajimu UMEMOTO 99633841545SHajimu UMEMOTO /* 99733841545SHajimu UMEMOTO * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 99833841545SHajimu UMEMOTO * Note that pr must be non NULL at this point. 99933841545SHajimu UMEMOTO */ 100033841545SHajimu UMEMOTO 100133841545SHajimu UMEMOTO /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 100282cd038dSYoshinobu Inoue if (!new->ndpr_raf_auto) 100333841545SHajimu UMEMOTO goto afteraddrconf; 100482cd038dSYoshinobu Inoue 100533841545SHajimu UMEMOTO /* 100633841545SHajimu UMEMOTO * 5.5.3 (b). the link-local prefix should have been ignored in 100733841545SHajimu UMEMOTO * nd6_ra_input. 100833841545SHajimu UMEMOTO */ 100933841545SHajimu UMEMOTO 101033841545SHajimu UMEMOTO /* 101133841545SHajimu UMEMOTO * 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. 101233841545SHajimu UMEMOTO * This should have been done in nd6_ra_input. 101333841545SHajimu UMEMOTO */ 101433841545SHajimu UMEMOTO 101533841545SHajimu UMEMOTO /* 101633841545SHajimu UMEMOTO * 5.5.3 (d). If the prefix advertised does not match the prefix of an 101733841545SHajimu UMEMOTO * address already in the list, and the Valid Lifetime is not 0, 101833841545SHajimu UMEMOTO * form an address. Note that even a manually configured address 101933841545SHajimu UMEMOTO * should reject autoconfiguration of a new address. 102033841545SHajimu UMEMOTO */ 102107eb2995SHajimu UMEMOTO TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 102233841545SHajimu UMEMOTO struct in6_ifaddr *ifa6; 102333841545SHajimu UMEMOTO int ifa_plen; 102433841545SHajimu UMEMOTO u_int32_t storedlifetime; 102533841545SHajimu UMEMOTO 102633841545SHajimu UMEMOTO if (ifa->ifa_addr->sa_family != AF_INET6) 102733841545SHajimu UMEMOTO continue; 102833841545SHajimu UMEMOTO 102933841545SHajimu UMEMOTO ifa6 = (struct in6_ifaddr *)ifa; 103033841545SHajimu UMEMOTO 103133841545SHajimu UMEMOTO /* 103233841545SHajimu UMEMOTO * Spec is not clear here, but I believe we should concentrate 103333841545SHajimu UMEMOTO * on unicast (i.e. not anycast) addresses. 103433841545SHajimu UMEMOTO * XXX: other ia6_flags? detached or duplicated? 103533841545SHajimu UMEMOTO */ 103633841545SHajimu UMEMOTO if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 103733841545SHajimu UMEMOTO continue; 103833841545SHajimu UMEMOTO 103933841545SHajimu UMEMOTO ifa_plen = in6_mask2len(&ifa6->ia_prefixmask.sin6_addr, NULL); 104033841545SHajimu UMEMOTO if (ifa_plen != new->ndpr_plen || 104133841545SHajimu UMEMOTO !in6_are_prefix_equal(&ifa6->ia_addr.sin6_addr, 104207eb2995SHajimu UMEMOTO &new->ndpr_prefix.sin6_addr, ifa_plen)) 104333841545SHajimu UMEMOTO continue; 104433841545SHajimu UMEMOTO 104533841545SHajimu UMEMOTO if (ia6_match == NULL) /* remember the first one */ 104633841545SHajimu UMEMOTO ia6_match = ifa6; 104733841545SHajimu UMEMOTO 104833841545SHajimu UMEMOTO if ((ifa6->ia6_flags & IN6_IFF_AUTOCONF) == 0) 104933841545SHajimu UMEMOTO continue; 105033841545SHajimu UMEMOTO 105133841545SHajimu UMEMOTO /* 105233841545SHajimu UMEMOTO * An already autoconfigured address matched. Now that we 105333841545SHajimu UMEMOTO * are sure there is at least one matched address, we can 105433841545SHajimu UMEMOTO * proceed to 5.5.3. (e): update the lifetimes according to the 105533841545SHajimu UMEMOTO * "two hours" rule and the privacy extension. 105633841545SHajimu UMEMOTO */ 105733841545SHajimu UMEMOTO #define TWOHOUR (120*60) 105833841545SHajimu UMEMOTO lt6_tmp = ifa6->ia6_lifetime; 105933841545SHajimu UMEMOTO 106011f3a6e2SHajimu UMEMOTO if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 106111f3a6e2SHajimu UMEMOTO storedlifetime = ND6_INFINITE_LIFETIME; 106211f3a6e2SHajimu UMEMOTO else if (IFA6_IS_INVALID(ifa6)) 106311f3a6e2SHajimu UMEMOTO storedlifetime = 0; 106411f3a6e2SHajimu UMEMOTO else 106511f3a6e2SHajimu UMEMOTO storedlifetime = lt6_tmp.ia6t_expire - time_second; 106611f3a6e2SHajimu UMEMOTO 106711f3a6e2SHajimu UMEMOTO /* when not updating, keep the current stored lifetime. */ 106811f3a6e2SHajimu UMEMOTO lt6_tmp.ia6t_vltime = storedlifetime; 106933841545SHajimu UMEMOTO 107033841545SHajimu UMEMOTO if (TWOHOUR < new->ndpr_vltime || 107133841545SHajimu UMEMOTO storedlifetime < new->ndpr_vltime) { 107233841545SHajimu UMEMOTO lt6_tmp.ia6t_vltime = new->ndpr_vltime; 10737aa59493SSUZUKI Shinsuke } else if (storedlifetime <= TWOHOUR) { 107433841545SHajimu UMEMOTO if (auth) { 107533841545SHajimu UMEMOTO lt6_tmp.ia6t_vltime = new->ndpr_vltime; 107682cd038dSYoshinobu Inoue } 107733841545SHajimu UMEMOTO } else { 107833841545SHajimu UMEMOTO /* 107933841545SHajimu UMEMOTO * new->ndpr_vltime <= TWOHOUR && 108033841545SHajimu UMEMOTO * TWOHOUR < storedlifetime 108133841545SHajimu UMEMOTO */ 108233841545SHajimu UMEMOTO lt6_tmp.ia6t_vltime = TWOHOUR; 108382cd038dSYoshinobu Inoue } 108482cd038dSYoshinobu Inoue 108533841545SHajimu UMEMOTO /* The 2 hour rule is not imposed for preferred lifetime. */ 108633841545SHajimu UMEMOTO lt6_tmp.ia6t_pltime = new->ndpr_pltime; 108733841545SHajimu UMEMOTO 108833841545SHajimu UMEMOTO in6_init_address_ltimes(pr, <6_tmp); 108933841545SHajimu UMEMOTO 109033841545SHajimu UMEMOTO /* 109133841545SHajimu UMEMOTO * When adjusting the lifetimes of an existing temporary 109233841545SHajimu UMEMOTO * address, only lower the lifetimes. 109333841545SHajimu UMEMOTO * RFC 3041 3.3. (1). 109433841545SHajimu UMEMOTO * XXX: how should we modify ia6t_[pv]ltime? 109533841545SHajimu UMEMOTO */ 109633841545SHajimu UMEMOTO if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 109733841545SHajimu UMEMOTO if (lt6_tmp.ia6t_expire == 0 || /* no expire */ 109833841545SHajimu UMEMOTO lt6_tmp.ia6t_expire > 109933841545SHajimu UMEMOTO ifa6->ia6_lifetime.ia6t_expire) { 110033841545SHajimu UMEMOTO lt6_tmp.ia6t_expire = 110133841545SHajimu UMEMOTO ifa6->ia6_lifetime.ia6t_expire; 110233841545SHajimu UMEMOTO } 110333841545SHajimu UMEMOTO if (lt6_tmp.ia6t_preferred == 0 || /* no expire */ 110433841545SHajimu UMEMOTO lt6_tmp.ia6t_preferred > 110533841545SHajimu UMEMOTO ifa6->ia6_lifetime.ia6t_preferred) { 110633841545SHajimu UMEMOTO lt6_tmp.ia6t_preferred = 110733841545SHajimu UMEMOTO ifa6->ia6_lifetime.ia6t_preferred; 110833841545SHajimu UMEMOTO } 110933841545SHajimu UMEMOTO } 111033841545SHajimu UMEMOTO 111133841545SHajimu UMEMOTO ifa6->ia6_lifetime = lt6_tmp; 111233841545SHajimu UMEMOTO } 111333841545SHajimu UMEMOTO if (ia6_match == NULL && new->ndpr_vltime) { 111433841545SHajimu UMEMOTO /* 111533841545SHajimu UMEMOTO * No address matched and the valid lifetime is non-zero. 111633841545SHajimu UMEMOTO * Create a new address. 111733841545SHajimu UMEMOTO */ 111833841545SHajimu UMEMOTO if ((ia6 = in6_ifadd(new, NULL)) != NULL) { 111933841545SHajimu UMEMOTO /* 112033841545SHajimu UMEMOTO * note that we should use pr (not new) for reference. 112133841545SHajimu UMEMOTO */ 112233841545SHajimu UMEMOTO pr->ndpr_refcnt++; 112333841545SHajimu UMEMOTO ia6->ia6_ndpr = pr; 112433841545SHajimu UMEMOTO 112533841545SHajimu UMEMOTO /* 112633841545SHajimu UMEMOTO * RFC 3041 3.3 (2). 112733841545SHajimu UMEMOTO * When a new public address is created as described 112833841545SHajimu UMEMOTO * in RFC2462, also create a new temporary address. 112933841545SHajimu UMEMOTO * 113033841545SHajimu UMEMOTO * RFC 3041 3.5. 113133841545SHajimu UMEMOTO * When an interface connects to a new link, a new 113233841545SHajimu UMEMOTO * randomized interface identifier should be generated 113333841545SHajimu UMEMOTO * immediately together with a new set of temporary 113433841545SHajimu UMEMOTO * addresses. Thus, we specifiy 1 as the 2nd arg of 113533841545SHajimu UMEMOTO * in6_tmpifadd(). 113633841545SHajimu UMEMOTO */ 113733841545SHajimu UMEMOTO if (ip6_use_tempaddr) { 113833841545SHajimu UMEMOTO int e; 113933841545SHajimu UMEMOTO if ((e = in6_tmpifadd(ia6, 1)) != 0) { 114033841545SHajimu UMEMOTO nd6log((LOG_NOTICE, "prelist_update: " 114133841545SHajimu UMEMOTO "failed to create a temporary " 114233841545SHajimu UMEMOTO "address, errno=%d\n", 114333841545SHajimu UMEMOTO e)); 114433841545SHajimu UMEMOTO } 114533841545SHajimu UMEMOTO } 114633841545SHajimu UMEMOTO 114733841545SHajimu UMEMOTO /* 114833841545SHajimu UMEMOTO * A newly added address might affect the status 114933841545SHajimu UMEMOTO * of other addresses, so we check and update it. 115033841545SHajimu UMEMOTO * XXX: what if address duplication happens? 115133841545SHajimu UMEMOTO */ 115233841545SHajimu UMEMOTO pfxlist_onlink_check(); 115333841545SHajimu UMEMOTO } else { 115433841545SHajimu UMEMOTO /* just set an error. do not bark here. */ 115533841545SHajimu UMEMOTO error = EADDRNOTAVAIL; /* XXX: might be unused. */ 115633841545SHajimu UMEMOTO } 115733841545SHajimu UMEMOTO } 115833841545SHajimu UMEMOTO 115933841545SHajimu UMEMOTO afteraddrconf: 116033841545SHajimu UMEMOTO 116182cd038dSYoshinobu Inoue end: 116282cd038dSYoshinobu Inoue splx(s); 116382cd038dSYoshinobu Inoue return error; 116482cd038dSYoshinobu Inoue } 116582cd038dSYoshinobu Inoue 116682cd038dSYoshinobu Inoue /* 1167686cdd19SJun-ichiro itojun Hagino * A supplement function used in the on-link detection below; 1168686cdd19SJun-ichiro itojun Hagino * detect if a given prefix has a (probably) reachable advertising router. 1169686cdd19SJun-ichiro itojun Hagino * XXX: lengthy function name... 1170686cdd19SJun-ichiro itojun Hagino */ 117133841545SHajimu UMEMOTO static struct nd_pfxrouter * 1172686cdd19SJun-ichiro itojun Hagino find_pfxlist_reachable_router(pr) 1173686cdd19SJun-ichiro itojun Hagino struct nd_prefix *pr; 1174686cdd19SJun-ichiro itojun Hagino { 1175686cdd19SJun-ichiro itojun Hagino struct nd_pfxrouter *pfxrtr; 1176686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 1177686cdd19SJun-ichiro itojun Hagino struct llinfo_nd6 *ln; 1178686cdd19SJun-ichiro itojun Hagino 1179686cdd19SJun-ichiro itojun Hagino for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr; 1180686cdd19SJun-ichiro itojun Hagino pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { 1181686cdd19SJun-ichiro itojun Hagino if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0, 1182686cdd19SJun-ichiro itojun Hagino pfxrtr->router->ifp)) && 1183686cdd19SJun-ichiro itojun Hagino (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 1184686cdd19SJun-ichiro itojun Hagino ND6_IS_LLINFO_PROBREACH(ln)) 1185686cdd19SJun-ichiro itojun Hagino break; /* found */ 1186686cdd19SJun-ichiro itojun Hagino } 1187686cdd19SJun-ichiro itojun Hagino 1188686cdd19SJun-ichiro itojun Hagino return (pfxrtr); 1189686cdd19SJun-ichiro itojun Hagino } 1190686cdd19SJun-ichiro itojun Hagino 1191686cdd19SJun-ichiro itojun Hagino /* 119282cd038dSYoshinobu Inoue * Check if each prefix in the prefix list has at least one available router 119333841545SHajimu UMEMOTO * that advertised the prefix (a router is "available" if its neighbor cache 119433841545SHajimu UMEMOTO * entry is reachable or probably reachable). 1195686cdd19SJun-ichiro itojun Hagino * If the check fails, the prefix may be off-link, because, for example, 119682cd038dSYoshinobu Inoue * we have moved from the network but the lifetime of the prefix has not 119733841545SHajimu UMEMOTO * expired yet. So we should not use the prefix if there is another prefix 119833841545SHajimu UMEMOTO * that has an available router. 119933841545SHajimu UMEMOTO * But, if there is no prefix that has an available router, we still regards 120082cd038dSYoshinobu Inoue * all the prefixes as on-link. This is because we can't tell if all the 120182cd038dSYoshinobu Inoue * routers are simply dead or if we really moved from the network and there 120282cd038dSYoshinobu Inoue * is no router around us. 120382cd038dSYoshinobu Inoue */ 1204686cdd19SJun-ichiro itojun Hagino void 120582cd038dSYoshinobu Inoue pfxlist_onlink_check() 120682cd038dSYoshinobu Inoue { 120782cd038dSYoshinobu Inoue struct nd_prefix *pr; 120833841545SHajimu UMEMOTO struct in6_ifaddr *ifa; 120982cd038dSYoshinobu Inoue 1210686cdd19SJun-ichiro itojun Hagino /* 1211686cdd19SJun-ichiro itojun Hagino * Check if there is a prefix that has a reachable advertising 1212686cdd19SJun-ichiro itojun Hagino * router. 1213686cdd19SJun-ichiro itojun Hagino */ 1214686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 121533841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 121682cd038dSYoshinobu Inoue break; 1217686cdd19SJun-ichiro itojun Hagino } 121882cd038dSYoshinobu Inoue 12192ce62dceSSUZUKI Shinsuke if (pr == NULL) { 122082cd038dSYoshinobu Inoue /* 1221686cdd19SJun-ichiro itojun Hagino * There is at least one prefix that has a reachable router. 122233841545SHajimu UMEMOTO * Detach prefixes which have no reachable advertising 122333841545SHajimu UMEMOTO * router, and attach other prefixes. 122482cd038dSYoshinobu Inoue */ 1225686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 122633841545SHajimu UMEMOTO /* XXX: a link-local prefix should never be detached */ 122733841545SHajimu UMEMOTO if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 122833841545SHajimu UMEMOTO continue; 122933841545SHajimu UMEMOTO 123033841545SHajimu UMEMOTO /* 123133841545SHajimu UMEMOTO * we aren't interested in prefixes without the L bit 123233841545SHajimu UMEMOTO * set. 123333841545SHajimu UMEMOTO */ 123433841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink == 0) 123533841545SHajimu UMEMOTO continue; 123633841545SHajimu UMEMOTO 123733841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 123833841545SHajimu UMEMOTO find_pfxlist_reachable_router(pr) == NULL) 123933841545SHajimu UMEMOTO pr->ndpr_stateflags |= NDPRF_DETACHED; 124033841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 124133841545SHajimu UMEMOTO find_pfxlist_reachable_router(pr) != 0) 124233841545SHajimu UMEMOTO pr->ndpr_stateflags &= ~NDPRF_DETACHED; 124382cd038dSYoshinobu Inoue } 124433841545SHajimu UMEMOTO } else { 124533841545SHajimu UMEMOTO /* there is no prefix that has a reachable router */ 1246686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 124733841545SHajimu UMEMOTO if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 124833841545SHajimu UMEMOTO continue; 124933841545SHajimu UMEMOTO 125033841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink == 0) 125133841545SHajimu UMEMOTO continue; 125233841545SHajimu UMEMOTO 125333841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 125433841545SHajimu UMEMOTO pr->ndpr_stateflags &= ~NDPRF_DETACHED; 125533841545SHajimu UMEMOTO } 125633841545SHajimu UMEMOTO } 125733841545SHajimu UMEMOTO 125833841545SHajimu UMEMOTO /* 125933841545SHajimu UMEMOTO * Remove each interface route associated with a (just) detached 126033841545SHajimu UMEMOTO * prefix, and reinstall the interface route for a (just) attached 126133841545SHajimu UMEMOTO * prefix. Note that all attempt of reinstallation does not 126233841545SHajimu UMEMOTO * necessarily success, when a same prefix is shared among multiple 126333841545SHajimu UMEMOTO * interfaces. Such cases will be handled in nd6_prefix_onlink, 126433841545SHajimu UMEMOTO * so we don't have to care about them. 126533841545SHajimu UMEMOTO */ 126633841545SHajimu UMEMOTO for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 126733841545SHajimu UMEMOTO int e; 126833841545SHajimu UMEMOTO 126933841545SHajimu UMEMOTO if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 127033841545SHajimu UMEMOTO continue; 127133841545SHajimu UMEMOTO 127233841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink == 0) 127333841545SHajimu UMEMOTO continue; 127433841545SHajimu UMEMOTO 127533841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 127633841545SHajimu UMEMOTO (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 127733841545SHajimu UMEMOTO if ((e = nd6_prefix_offlink(pr)) != 0) { 127833841545SHajimu UMEMOTO nd6log((LOG_ERR, 127933841545SHajimu UMEMOTO "pfxlist_onlink_check: failed to " 12807aa59493SSUZUKI Shinsuke "make %s/%d offlink, errno=%d\n", 128133841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 128233841545SHajimu UMEMOTO pr->ndpr_plen, e)); 128333841545SHajimu UMEMOTO } 128433841545SHajimu UMEMOTO } 128533841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 128633841545SHajimu UMEMOTO (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 128733841545SHajimu UMEMOTO pr->ndpr_raf_onlink) { 128833841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(pr)) != 0) { 128933841545SHajimu UMEMOTO nd6log((LOG_ERR, 129033841545SHajimu UMEMOTO "pfxlist_onlink_check: failed to " 12917aa59493SSUZUKI Shinsuke "make %s/%d onlink, errno=%d\n", 129233841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 129333841545SHajimu UMEMOTO pr->ndpr_plen, e)); 129433841545SHajimu UMEMOTO } 129533841545SHajimu UMEMOTO } 129633841545SHajimu UMEMOTO } 129733841545SHajimu UMEMOTO 129833841545SHajimu UMEMOTO /* 129933841545SHajimu UMEMOTO * Changes on the prefix status might affect address status as well. 130033841545SHajimu UMEMOTO * Make sure that all addresses derived from an attached prefix are 130133841545SHajimu UMEMOTO * attached, and that all addresses derived from a detached prefix are 130233841545SHajimu UMEMOTO * detached. Note, however, that a manually configured address should 130333841545SHajimu UMEMOTO * always be attached. 130433841545SHajimu UMEMOTO * The precise detection logic is same as the one for prefixes. 130533841545SHajimu UMEMOTO */ 130633841545SHajimu UMEMOTO for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 130707eb2995SHajimu UMEMOTO if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) 130833841545SHajimu UMEMOTO continue; 130933841545SHajimu UMEMOTO 131033841545SHajimu UMEMOTO if (ifa->ia6_ndpr == NULL) { 131133841545SHajimu UMEMOTO /* 131233841545SHajimu UMEMOTO * This can happen when we first configure the address 131333841545SHajimu UMEMOTO * (i.e. the address exists, but the prefix does not). 131433841545SHajimu UMEMOTO * XXX: complicated relationships... 131533841545SHajimu UMEMOTO */ 131633841545SHajimu UMEMOTO continue; 131733841545SHajimu UMEMOTO } 131833841545SHajimu UMEMOTO 131933841545SHajimu UMEMOTO if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 132033841545SHajimu UMEMOTO break; 132133841545SHajimu UMEMOTO } 132233841545SHajimu UMEMOTO if (ifa) { 132333841545SHajimu UMEMOTO for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 132433841545SHajimu UMEMOTO if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 132533841545SHajimu UMEMOTO continue; 132633841545SHajimu UMEMOTO 132733841545SHajimu UMEMOTO if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 132833841545SHajimu UMEMOTO continue; 132933841545SHajimu UMEMOTO 133033841545SHajimu UMEMOTO if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 133133841545SHajimu UMEMOTO ifa->ia6_flags &= ~IN6_IFF_DETACHED; 133233841545SHajimu UMEMOTO else 133333841545SHajimu UMEMOTO ifa->ia6_flags |= IN6_IFF_DETACHED; 133482cd038dSYoshinobu Inoue } 1335686cdd19SJun-ichiro itojun Hagino } 1336686cdd19SJun-ichiro itojun Hagino else { 133733841545SHajimu UMEMOTO for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 133833841545SHajimu UMEMOTO if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 133933841545SHajimu UMEMOTO continue; 134033841545SHajimu UMEMOTO 134133841545SHajimu UMEMOTO ifa->ia6_flags &= ~IN6_IFF_DETACHED; 134233841545SHajimu UMEMOTO } 134382cd038dSYoshinobu Inoue } 134482cd038dSYoshinobu Inoue } 134582cd038dSYoshinobu Inoue 134633841545SHajimu UMEMOTO int 134733841545SHajimu UMEMOTO nd6_prefix_onlink(pr) 134882cd038dSYoshinobu Inoue struct nd_prefix *pr; 134982cd038dSYoshinobu Inoue { 135033841545SHajimu UMEMOTO struct ifaddr *ifa; 135133841545SHajimu UMEMOTO struct ifnet *ifp = pr->ndpr_ifp; 135233841545SHajimu UMEMOTO struct sockaddr_in6 mask6; 135333841545SHajimu UMEMOTO struct nd_prefix *opr; 135433841545SHajimu UMEMOTO u_long rtflags; 135533841545SHajimu UMEMOTO int error = 0; 135633841545SHajimu UMEMOTO struct rtentry *rt = NULL; 135733841545SHajimu UMEMOTO 135833841545SHajimu UMEMOTO /* sanity check */ 135933841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 136033841545SHajimu UMEMOTO nd6log((LOG_ERR, 136133841545SHajimu UMEMOTO "nd6_prefix_onlink: %s/%d is already on-link\n", 13622ce62dceSSUZUKI Shinsuke ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen)); 13632ce62dceSSUZUKI Shinsuke return (EEXIST); 136433841545SHajimu UMEMOTO } 136582cd038dSYoshinobu Inoue 136682cd038dSYoshinobu Inoue /* 136733841545SHajimu UMEMOTO * Add the interface route associated with the prefix. Before 136833841545SHajimu UMEMOTO * installing the route, check if there's the same prefix on another 136933841545SHajimu UMEMOTO * interface, and the prefix has already installed the interface route. 137033841545SHajimu UMEMOTO * Although such a configuration is expected to be rare, we explicitly 137133841545SHajimu UMEMOTO * allow it. 137282cd038dSYoshinobu Inoue */ 137333841545SHajimu UMEMOTO for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 137433841545SHajimu UMEMOTO if (opr == pr) 137533841545SHajimu UMEMOTO continue; 137633841545SHajimu UMEMOTO 137733841545SHajimu UMEMOTO if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 137833841545SHajimu UMEMOTO continue; 137933841545SHajimu UMEMOTO 138033841545SHajimu UMEMOTO if (opr->ndpr_plen == pr->ndpr_plen && 138133841545SHajimu UMEMOTO in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 138207eb2995SHajimu UMEMOTO &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) 138333841545SHajimu UMEMOTO return (0); 138433841545SHajimu UMEMOTO } 138533841545SHajimu UMEMOTO 138633841545SHajimu UMEMOTO /* 138733841545SHajimu UMEMOTO * We prefer link-local addresses as the associated interface address. 138833841545SHajimu UMEMOTO */ 138933841545SHajimu UMEMOTO /* search for a link-local addr */ 139033841545SHajimu UMEMOTO ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 139107eb2995SHajimu UMEMOTO IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); 139233841545SHajimu UMEMOTO if (ifa == NULL) { 139333841545SHajimu UMEMOTO /* XXX: freebsd does not have ifa_ifwithaf */ 139407eb2995SHajimu UMEMOTO TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 139533841545SHajimu UMEMOTO if (ifa->ifa_addr->sa_family == AF_INET6) 139633841545SHajimu UMEMOTO break; 139733841545SHajimu UMEMOTO } 139833841545SHajimu UMEMOTO /* should we care about ia6_flags? */ 139933841545SHajimu UMEMOTO } 140033841545SHajimu UMEMOTO if (ifa == NULL) { 140133841545SHajimu UMEMOTO /* 140233841545SHajimu UMEMOTO * This can still happen, when, for example, we receive an RA 140333841545SHajimu UMEMOTO * containing a prefix with the L bit set and the A bit clear, 140433841545SHajimu UMEMOTO * after removing all IPv6 addresses on the receiving 140533841545SHajimu UMEMOTO * interface. This should, of course, be rare though. 140633841545SHajimu UMEMOTO */ 140733841545SHajimu UMEMOTO nd6log((LOG_NOTICE, 140833841545SHajimu UMEMOTO "nd6_prefix_onlink: failed to find any ifaddr" 140933841545SHajimu UMEMOTO " to add route for a prefix(%s/%d) on %s\n", 141033841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 141133841545SHajimu UMEMOTO pr->ndpr_plen, if_name(ifp))); 141233841545SHajimu UMEMOTO return (0); 141333841545SHajimu UMEMOTO } 141433841545SHajimu UMEMOTO 141533841545SHajimu UMEMOTO /* 141633841545SHajimu UMEMOTO * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 141733841545SHajimu UMEMOTO * ifa->ifa_rtrequest = nd6_rtrequest; 141833841545SHajimu UMEMOTO */ 141933841545SHajimu UMEMOTO bzero(&mask6, sizeof(mask6)); 142033841545SHajimu UMEMOTO mask6.sin6_len = sizeof(mask6); 142133841545SHajimu UMEMOTO mask6.sin6_addr = pr->ndpr_mask; 142233841545SHajimu UMEMOTO rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP; 142333841545SHajimu UMEMOTO if (nd6_need_cache(ifp)) { 142433841545SHajimu UMEMOTO /* explicitly set in case ifa_flags does not set the flag. */ 142533841545SHajimu UMEMOTO rtflags |= RTF_CLONING; 142633841545SHajimu UMEMOTO } else { 142733841545SHajimu UMEMOTO /* 142833841545SHajimu UMEMOTO * explicitly clear the cloning bit in case ifa_flags sets it. 142933841545SHajimu UMEMOTO */ 143033841545SHajimu UMEMOTO rtflags &= ~RTF_CLONING; 143133841545SHajimu UMEMOTO } 143233841545SHajimu UMEMOTO error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, 143307eb2995SHajimu UMEMOTO ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt); 143433841545SHajimu UMEMOTO if (error == 0) { 143533841545SHajimu UMEMOTO if (rt != NULL) /* this should be non NULL, though */ 143633841545SHajimu UMEMOTO nd6_rtmsg(RTM_ADD, rt); 143733841545SHajimu UMEMOTO pr->ndpr_stateflags |= NDPRF_ONLINK; 143807eb2995SHajimu UMEMOTO } else { 143933841545SHajimu UMEMOTO nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" 144033841545SHajimu UMEMOTO " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " 144133841545SHajimu UMEMOTO "errno = %d\n", 144233841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 144333841545SHajimu UMEMOTO pr->ndpr_plen, if_name(ifp), 144433841545SHajimu UMEMOTO ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), 144533841545SHajimu UMEMOTO ip6_sprintf(&mask6.sin6_addr), rtflags, error)); 144633841545SHajimu UMEMOTO } 144733841545SHajimu UMEMOTO 1448d1dd20beSSam Leffler if (rt != NULL) { 1449d1dd20beSSam Leffler RT_LOCK(rt); 14507138d65cSSam Leffler RT_REMREF(rt); 1451d1dd20beSSam Leffler RT_UNLOCK(rt); 1452d1dd20beSSam Leffler } 145333841545SHajimu UMEMOTO 145433841545SHajimu UMEMOTO return (error); 145533841545SHajimu UMEMOTO } 145633841545SHajimu UMEMOTO 145733841545SHajimu UMEMOTO int 145833841545SHajimu UMEMOTO nd6_prefix_offlink(pr) 145933841545SHajimu UMEMOTO struct nd_prefix *pr; 146033841545SHajimu UMEMOTO { 146133841545SHajimu UMEMOTO int error = 0; 146233841545SHajimu UMEMOTO struct ifnet *ifp = pr->ndpr_ifp; 146333841545SHajimu UMEMOTO struct nd_prefix *opr; 146433841545SHajimu UMEMOTO struct sockaddr_in6 sa6, mask6; 146533841545SHajimu UMEMOTO struct rtentry *rt = NULL; 146633841545SHajimu UMEMOTO 146733841545SHajimu UMEMOTO /* sanity check */ 146833841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 146933841545SHajimu UMEMOTO nd6log((LOG_ERR, 147033841545SHajimu UMEMOTO "nd6_prefix_offlink: %s/%d is already off-link\n", 147133841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen)); 147233841545SHajimu UMEMOTO return (EEXIST); 147333841545SHajimu UMEMOTO } 147433841545SHajimu UMEMOTO 147582cd038dSYoshinobu Inoue bzero(&sa6, sizeof(sa6)); 147682cd038dSYoshinobu Inoue sa6.sin6_family = AF_INET6; 147782cd038dSYoshinobu Inoue sa6.sin6_len = sizeof(sa6); 147882cd038dSYoshinobu Inoue bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 147982cd038dSYoshinobu Inoue sizeof(struct in6_addr)); 148082cd038dSYoshinobu Inoue bzero(&mask6, sizeof(mask6)); 148182cd038dSYoshinobu Inoue mask6.sin6_family = AF_INET6; 148282cd038dSYoshinobu Inoue mask6.sin6_len = sizeof(sa6); 148382cd038dSYoshinobu Inoue bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 148433841545SHajimu UMEMOTO error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 148533841545SHajimu UMEMOTO (struct sockaddr *)&mask6, 0, &rt); 148633841545SHajimu UMEMOTO if (error == 0) { 148733841545SHajimu UMEMOTO pr->ndpr_stateflags &= ~NDPRF_ONLINK; 148833841545SHajimu UMEMOTO 148933841545SHajimu UMEMOTO /* report the route deletion to the routing socket. */ 149033841545SHajimu UMEMOTO if (rt != NULL) 149133841545SHajimu UMEMOTO nd6_rtmsg(RTM_DELETE, rt); 149233841545SHajimu UMEMOTO 149333841545SHajimu UMEMOTO /* 149433841545SHajimu UMEMOTO * There might be the same prefix on another interface, 149533841545SHajimu UMEMOTO * the prefix which could not be on-link just because we have 149633841545SHajimu UMEMOTO * the interface route (see comments in nd6_prefix_onlink). 149733841545SHajimu UMEMOTO * If there's one, try to make the prefix on-link on the 149833841545SHajimu UMEMOTO * interface. 149933841545SHajimu UMEMOTO */ 150033841545SHajimu UMEMOTO for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 150133841545SHajimu UMEMOTO if (opr == pr) 150233841545SHajimu UMEMOTO continue; 150333841545SHajimu UMEMOTO 150433841545SHajimu UMEMOTO if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 150533841545SHajimu UMEMOTO continue; 150633841545SHajimu UMEMOTO 150733841545SHajimu UMEMOTO /* 150833841545SHajimu UMEMOTO * KAME specific: detached prefixes should not be 150933841545SHajimu UMEMOTO * on-link. 151033841545SHajimu UMEMOTO */ 151133841545SHajimu UMEMOTO if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 151233841545SHajimu UMEMOTO continue; 151333841545SHajimu UMEMOTO 151433841545SHajimu UMEMOTO if (opr->ndpr_plen == pr->ndpr_plen && 151533841545SHajimu UMEMOTO in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 151607eb2995SHajimu UMEMOTO &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 151782cd038dSYoshinobu Inoue int e; 151882cd038dSYoshinobu Inoue 151933841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(opr)) != 0) { 152033841545SHajimu UMEMOTO nd6log((LOG_ERR, 152133841545SHajimu UMEMOTO "nd6_prefix_offlink: failed to " 152233841545SHajimu UMEMOTO "recover a prefix %s/%d from %s " 152333841545SHajimu UMEMOTO "to %s (errno = %d)\n", 152433841545SHajimu UMEMOTO ip6_sprintf(&opr->ndpr_prefix.sin6_addr), 152533841545SHajimu UMEMOTO opr->ndpr_plen, if_name(ifp), 152633841545SHajimu UMEMOTO if_name(opr->ndpr_ifp), e)); 152782cd038dSYoshinobu Inoue } 152882cd038dSYoshinobu Inoue } 152982cd038dSYoshinobu Inoue } 153007eb2995SHajimu UMEMOTO } else { 153133841545SHajimu UMEMOTO /* XXX: can we still set the NDPRF_ONLINK flag? */ 153233841545SHajimu UMEMOTO nd6log((LOG_ERR, 153333841545SHajimu UMEMOTO "nd6_prefix_offlink: failed to delete route: " 153433841545SHajimu UMEMOTO "%s/%d on %s (errno = %d)\n", 153533841545SHajimu UMEMOTO ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp), 153633841545SHajimu UMEMOTO error)); 153733841545SHajimu UMEMOTO } 153882cd038dSYoshinobu Inoue 153907eb2995SHajimu UMEMOTO if (rt != NULL) { 154071eba915SRuslan Ermilov RTFREE(rt); 154107eb2995SHajimu UMEMOTO } 154282cd038dSYoshinobu Inoue 154333841545SHajimu UMEMOTO return (error); 154482cd038dSYoshinobu Inoue } 154582cd038dSYoshinobu Inoue 154682cd038dSYoshinobu Inoue static struct in6_ifaddr * 154733841545SHajimu UMEMOTO in6_ifadd(pr, ifid) 154833841545SHajimu UMEMOTO struct nd_prefix *pr; 154933841545SHajimu UMEMOTO struct in6_addr *ifid; /* Mobile IPv6 addition */ 155082cd038dSYoshinobu Inoue { 155133841545SHajimu UMEMOTO struct ifnet *ifp = pr->ndpr_ifp; 155282cd038dSYoshinobu Inoue struct ifaddr *ifa; 155333841545SHajimu UMEMOTO struct in6_aliasreq ifra; 155433841545SHajimu UMEMOTO struct in6_ifaddr *ia, *ib; 155533841545SHajimu UMEMOTO int error, plen0; 155682cd038dSYoshinobu Inoue struct in6_addr mask; 155733841545SHajimu UMEMOTO int prefixlen = pr->ndpr_plen; 155882cd038dSYoshinobu Inoue 1559ae360dddSHajimu UMEMOTO in6_prefixlen2mask(&mask, prefixlen); 156082cd038dSYoshinobu Inoue 156133841545SHajimu UMEMOTO /* 156233841545SHajimu UMEMOTO * find a link-local address (will be interface ID). 156333841545SHajimu UMEMOTO * Is it really mandatory? Theoretically, a global or a site-local 156433841545SHajimu UMEMOTO * address can be configured without a link-local address, if we 156533841545SHajimu UMEMOTO * have a unique interface identifier... 156633841545SHajimu UMEMOTO * 156733841545SHajimu UMEMOTO * it is not mandatory to have a link-local address, we can generate 156833841545SHajimu UMEMOTO * interface identifier on the fly. we do this because: 156933841545SHajimu UMEMOTO * (1) it should be the easiest way to find interface identifier. 157033841545SHajimu UMEMOTO * (2) RFC2462 5.4 suggesting the use of the same interface identifier 157133841545SHajimu UMEMOTO * for multiple addresses on a single interface, and possible shortcut 157233841545SHajimu UMEMOTO * of DAD. we omitted DAD for this reason in the past. 157333841545SHajimu UMEMOTO * (3) a user can prevent autoconfiguration of global address 157433841545SHajimu UMEMOTO * by removing link-local address by hand (this is partly because we 15759d5abbddSJens Schweikhardt * don't have other way to control the use of IPv6 on an interface. 157633841545SHajimu UMEMOTO * this has been our design choice - cf. NRL's "ifconfig auto"). 157733841545SHajimu UMEMOTO * (4) it is easier to manage when an interface has addresses 157833841545SHajimu UMEMOTO * with the same interface identifier, than to have multiple addresses 157933841545SHajimu UMEMOTO * with different interface identifiers. 158033841545SHajimu UMEMOTO */ 1581686cdd19SJun-ichiro itojun Hagino ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ 158282cd038dSYoshinobu Inoue if (ifa) 158382cd038dSYoshinobu Inoue ib = (struct in6_ifaddr *)ifa; 158482cd038dSYoshinobu Inoue else 158582cd038dSYoshinobu Inoue return NULL; 158682cd038dSYoshinobu Inoue 158782cd038dSYoshinobu Inoue /* prefixlen + ifidlen must be equal to 128 */ 158833841545SHajimu UMEMOTO plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 158933841545SHajimu UMEMOTO if (prefixlen != plen0) { 159033841545SHajimu UMEMOTO nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 159133841545SHajimu UMEMOTO "(prefix=%d ifid=%d)\n", 159233841545SHajimu UMEMOTO if_name(ifp), prefixlen, 128 - plen0)); 159382cd038dSYoshinobu Inoue return NULL; 159482cd038dSYoshinobu Inoue } 159582cd038dSYoshinobu Inoue 159682cd038dSYoshinobu Inoue /* make ifaddr */ 159782cd038dSYoshinobu Inoue 159833841545SHajimu UMEMOTO bzero(&ifra, sizeof(ifra)); 1599686cdd19SJun-ichiro itojun Hagino /* 160033841545SHajimu UMEMOTO * in6_update_ifa() does not use ifra_name, but we accurately set it 160133841545SHajimu UMEMOTO * for safety. 1602686cdd19SJun-ichiro itojun Hagino */ 160333841545SHajimu UMEMOTO strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 160433841545SHajimu UMEMOTO ifra.ifra_addr.sin6_family = AF_INET6; 160533841545SHajimu UMEMOTO ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 160682cd038dSYoshinobu Inoue /* prefix */ 160733841545SHajimu UMEMOTO bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr, 160833841545SHajimu UMEMOTO sizeof(ifra.ifra_addr.sin6_addr)); 160933841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 161033841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 161133841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 161233841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 161333841545SHajimu UMEMOTO 161482cd038dSYoshinobu Inoue /* interface ID */ 161533841545SHajimu UMEMOTO if (ifid == NULL || IN6_IS_ADDR_UNSPECIFIED(ifid)) 161633841545SHajimu UMEMOTO ifid = &ib->ia_addr.sin6_addr; 161707eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[0] |= 161807eb2995SHajimu UMEMOTO (ifid->s6_addr32[0] & ~mask.s6_addr32[0]); 161907eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[1] |= 162007eb2995SHajimu UMEMOTO (ifid->s6_addr32[1] & ~mask.s6_addr32[1]); 162107eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 162207eb2995SHajimu UMEMOTO (ifid->s6_addr32[2] & ~mask.s6_addr32[2]); 162307eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 162407eb2995SHajimu UMEMOTO (ifid->s6_addr32[3] & ~mask.s6_addr32[3]); 162582cd038dSYoshinobu Inoue 162633841545SHajimu UMEMOTO /* new prefix mask. */ 162733841545SHajimu UMEMOTO ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 162833841545SHajimu UMEMOTO ifra.ifra_prefixmask.sin6_family = AF_INET6; 162933841545SHajimu UMEMOTO bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 163033841545SHajimu UMEMOTO sizeof(ifra.ifra_prefixmask.sin6_addr)); 163182cd038dSYoshinobu Inoue 163282cd038dSYoshinobu Inoue /* 163333841545SHajimu UMEMOTO * lifetime. 163433841545SHajimu UMEMOTO * XXX: in6_init_address_ltimes would override these values later. 163533841545SHajimu UMEMOTO * We should reconsider this logic. 163682cd038dSYoshinobu Inoue */ 163733841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 163833841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 163933841545SHajimu UMEMOTO 164033841545SHajimu UMEMOTO /* XXX: scope zone ID? */ 164133841545SHajimu UMEMOTO 164233841545SHajimu UMEMOTO ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 164333841545SHajimu UMEMOTO /* 164433841545SHajimu UMEMOTO * temporarily set the nopfx flag to avoid conflict. 164533841545SHajimu UMEMOTO * XXX: we should reconsider the entire mechanism about prefix 164633841545SHajimu UMEMOTO * manipulation. 164733841545SHajimu UMEMOTO */ 164833841545SHajimu UMEMOTO ifra.ifra_flags |= IN6_IFF_NOPFX; 164933841545SHajimu UMEMOTO 165033841545SHajimu UMEMOTO /* 165133841545SHajimu UMEMOTO * keep the new address, regardless of the result of in6_update_ifa. 165233841545SHajimu UMEMOTO * XXX: this address is now meaningless. 165333841545SHajimu UMEMOTO * We should reconsider its role. 165433841545SHajimu UMEMOTO */ 165533841545SHajimu UMEMOTO pr->ndpr_addr = ifra.ifra_addr.sin6_addr; 165633841545SHajimu UMEMOTO 165733841545SHajimu UMEMOTO /* allocate ifaddr structure, link into chain, etc. */ 165833841545SHajimu UMEMOTO if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { 165933841545SHajimu UMEMOTO nd6log((LOG_ERR, 166033841545SHajimu UMEMOTO "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 166133841545SHajimu UMEMOTO ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp), 166233841545SHajimu UMEMOTO error)); 166333841545SHajimu UMEMOTO return (NULL); /* ifaddr must not have been allocated. */ 166482cd038dSYoshinobu Inoue } 166582cd038dSYoshinobu Inoue 166633841545SHajimu UMEMOTO ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 166782cd038dSYoshinobu Inoue 166807eb2995SHajimu UMEMOTO return (ia); /* this is always non-NULL */ 166982cd038dSYoshinobu Inoue } 167082cd038dSYoshinobu Inoue 167182cd038dSYoshinobu Inoue int 167233841545SHajimu UMEMOTO in6_tmpifadd(ia0, forcegen) 167333841545SHajimu UMEMOTO const struct in6_ifaddr *ia0; /* corresponding public address */ 1674c3aacd9eSHajimu UMEMOTO int forcegen; 167582cd038dSYoshinobu Inoue { 167633841545SHajimu UMEMOTO struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 167733841545SHajimu UMEMOTO struct in6_ifaddr *newia; 167833841545SHajimu UMEMOTO struct in6_aliasreq ifra; 167933841545SHajimu UMEMOTO int i, error; 168033841545SHajimu UMEMOTO int trylimit = 3; /* XXX: adhoc value */ 168133841545SHajimu UMEMOTO u_int32_t randid[2]; 168233841545SHajimu UMEMOTO time_t vltime0, pltime0; 168382cd038dSYoshinobu Inoue 168433841545SHajimu UMEMOTO bzero(&ifra, sizeof(ifra)); 168533841545SHajimu UMEMOTO strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 168633841545SHajimu UMEMOTO ifra.ifra_addr = ia0->ia_addr; 168733841545SHajimu UMEMOTO /* copy prefix mask */ 168833841545SHajimu UMEMOTO ifra.ifra_prefixmask = ia0->ia_prefixmask; 168933841545SHajimu UMEMOTO /* clear the old IFID */ 169033841545SHajimu UMEMOTO for (i = 0; i < 4; i++) { 169107eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[i] &= 169207eb2995SHajimu UMEMOTO ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 169333841545SHajimu UMEMOTO } 169482cd038dSYoshinobu Inoue 169533841545SHajimu UMEMOTO again: 169633841545SHajimu UMEMOTO in6_get_tmpifid(ifp, (u_int8_t *)randid, 169707eb2995SHajimu UMEMOTO (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen); 169807eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 169907eb2995SHajimu UMEMOTO (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 170007eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 170107eb2995SHajimu UMEMOTO (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 170282cd038dSYoshinobu Inoue 170382cd038dSYoshinobu Inoue /* 170433841545SHajimu UMEMOTO * If by chance the new temporary address is the same as an address 170533841545SHajimu UMEMOTO * already assigned to the interface, generate a new randomized 170633841545SHajimu UMEMOTO * interface identifier and repeat this step. 170733841545SHajimu UMEMOTO * RFC 3041 3.3 (4). 170882cd038dSYoshinobu Inoue */ 170933841545SHajimu UMEMOTO if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { 171033841545SHajimu UMEMOTO if (trylimit-- == 0) { 171133841545SHajimu UMEMOTO nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find " 171233841545SHajimu UMEMOTO "a unique random IFID\n")); 171333841545SHajimu UMEMOTO return (EEXIST); 171433841545SHajimu UMEMOTO } 171533841545SHajimu UMEMOTO forcegen = 1; 171633841545SHajimu UMEMOTO goto again; 171782cd038dSYoshinobu Inoue } 171882cd038dSYoshinobu Inoue 171933841545SHajimu UMEMOTO /* 172033841545SHajimu UMEMOTO * The Valid Lifetime is the lower of the Valid Lifetime of the 172133841545SHajimu UMEMOTO * public address or TEMP_VALID_LIFETIME. 172233841545SHajimu UMEMOTO * The Preferred Lifetime is the lower of the Preferred Lifetime 172333841545SHajimu UMEMOTO * of the public address or TEMP_PREFERRED_LIFETIME - 172433841545SHajimu UMEMOTO * DESYNC_FACTOR. 172582cd038dSYoshinobu Inoue */ 172633841545SHajimu UMEMOTO if (ia0->ia6_lifetime.ia6t_expire != 0) { 172733841545SHajimu UMEMOTO vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 172833841545SHajimu UMEMOTO (ia0->ia6_lifetime.ia6t_expire - time_second); 172933841545SHajimu UMEMOTO if (vltime0 > ip6_temp_valid_lifetime) 173033841545SHajimu UMEMOTO vltime0 = ip6_temp_valid_lifetime; 173133841545SHajimu UMEMOTO } else 173233841545SHajimu UMEMOTO vltime0 = ip6_temp_valid_lifetime; 173333841545SHajimu UMEMOTO if (ia0->ia6_lifetime.ia6t_preferred != 0) { 173433841545SHajimu UMEMOTO pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 173533841545SHajimu UMEMOTO (ia0->ia6_lifetime.ia6t_preferred - time_second); 173633841545SHajimu UMEMOTO if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){ 173733841545SHajimu UMEMOTO pltime0 = ip6_temp_preferred_lifetime - 173833841545SHajimu UMEMOTO ip6_desync_factor; 173933841545SHajimu UMEMOTO } 174033841545SHajimu UMEMOTO } else 174133841545SHajimu UMEMOTO pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor; 174233841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_vltime = vltime0; 174333841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_pltime = pltime0; 174433841545SHajimu UMEMOTO 174533841545SHajimu UMEMOTO /* 174633841545SHajimu UMEMOTO * A temporary address is created only if this calculated Preferred 174733841545SHajimu UMEMOTO * Lifetime is greater than REGEN_ADVANCE time units. 174833841545SHajimu UMEMOTO */ 174933841545SHajimu UMEMOTO if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance) 175033841545SHajimu UMEMOTO return (0); 175133841545SHajimu UMEMOTO 175233841545SHajimu UMEMOTO /* XXX: scope zone ID? */ 175333841545SHajimu UMEMOTO 175433841545SHajimu UMEMOTO ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 175533841545SHajimu UMEMOTO 175633841545SHajimu UMEMOTO /* allocate ifaddr structure, link into chain, etc. */ 175733841545SHajimu UMEMOTO if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) 175833841545SHajimu UMEMOTO return (error); 175933841545SHajimu UMEMOTO 176033841545SHajimu UMEMOTO newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 176133841545SHajimu UMEMOTO if (newia == NULL) { /* XXX: can it happen? */ 176233841545SHajimu UMEMOTO nd6log((LOG_ERR, 176333841545SHajimu UMEMOTO "in6_tmpifadd: ifa update succeeded, but we got " 176433841545SHajimu UMEMOTO "no ifaddr\n")); 176533841545SHajimu UMEMOTO return (EINVAL); /* XXX */ 176633841545SHajimu UMEMOTO } 176733841545SHajimu UMEMOTO newia->ia6_ndpr = ia0->ia6_ndpr; 176833841545SHajimu UMEMOTO newia->ia6_ndpr->ndpr_refcnt++; 176933841545SHajimu UMEMOTO 1770c3aacd9eSHajimu UMEMOTO /* 1771c3aacd9eSHajimu UMEMOTO * A newly added address might affect the status of other addresses. 1772c3aacd9eSHajimu UMEMOTO * XXX: when the temporary address is generated with a new public 1773c3aacd9eSHajimu UMEMOTO * address, the onlink check is redundant. However, it would be safe 1774c3aacd9eSHajimu UMEMOTO * to do the check explicitly everywhere a new address is generated, 1775c3aacd9eSHajimu UMEMOTO * and, in fact, we surely need the check when we create a new 1776c3aacd9eSHajimu UMEMOTO * temporary address due to deprecation of an old temporary address. 1777c3aacd9eSHajimu UMEMOTO */ 1778c3aacd9eSHajimu UMEMOTO pfxlist_onlink_check(); 1779c3aacd9eSHajimu UMEMOTO 178033841545SHajimu UMEMOTO return (0); 178182cd038dSYoshinobu Inoue } 178282cd038dSYoshinobu Inoue 178382cd038dSYoshinobu Inoue int 178482cd038dSYoshinobu Inoue in6_init_prefix_ltimes(struct nd_prefix *ndpr) 178582cd038dSYoshinobu Inoue { 178633841545SHajimu UMEMOTO /* check if preferred lifetime > valid lifetime. RFC2462 5.5.3 (c) */ 178782cd038dSYoshinobu Inoue if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) { 178833841545SHajimu UMEMOTO nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime" 178982cd038dSYoshinobu Inoue "(%d) is greater than valid lifetime(%d)\n", 179033841545SHajimu UMEMOTO (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime)); 179182cd038dSYoshinobu Inoue return (EINVAL); 179282cd038dSYoshinobu Inoue } 179382cd038dSYoshinobu Inoue if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 179482cd038dSYoshinobu Inoue ndpr->ndpr_preferred = 0; 179582cd038dSYoshinobu Inoue else 179682cd038dSYoshinobu Inoue ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; 179782cd038dSYoshinobu Inoue if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 179882cd038dSYoshinobu Inoue ndpr->ndpr_expire = 0; 179982cd038dSYoshinobu Inoue else 180082cd038dSYoshinobu Inoue ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; 180182cd038dSYoshinobu Inoue 180282cd038dSYoshinobu Inoue return 0; 180382cd038dSYoshinobu Inoue } 180482cd038dSYoshinobu Inoue 180582cd038dSYoshinobu Inoue static void 180633841545SHajimu UMEMOTO in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 180782cd038dSYoshinobu Inoue { 180882cd038dSYoshinobu Inoue /* init ia6t_expire */ 180982cd038dSYoshinobu Inoue if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 181082cd038dSYoshinobu Inoue lt6->ia6t_expire = 0; 181182cd038dSYoshinobu Inoue else { 181282cd038dSYoshinobu Inoue lt6->ia6t_expire = time_second; 181382cd038dSYoshinobu Inoue lt6->ia6t_expire += lt6->ia6t_vltime; 181482cd038dSYoshinobu Inoue } 1815686cdd19SJun-ichiro itojun Hagino 181682cd038dSYoshinobu Inoue /* init ia6t_preferred */ 181782cd038dSYoshinobu Inoue if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 181882cd038dSYoshinobu Inoue lt6->ia6t_preferred = 0; 181982cd038dSYoshinobu Inoue else { 182082cd038dSYoshinobu Inoue lt6->ia6t_preferred = time_second; 182182cd038dSYoshinobu Inoue lt6->ia6t_preferred += lt6->ia6t_pltime; 182282cd038dSYoshinobu Inoue } 182382cd038dSYoshinobu Inoue } 182482cd038dSYoshinobu Inoue 182582cd038dSYoshinobu Inoue /* 182682cd038dSYoshinobu Inoue * Delete all the routing table entries that use the specified gateway. 182782cd038dSYoshinobu Inoue * XXX: this function causes search through all entries of routing table, so 182882cd038dSYoshinobu Inoue * it shouldn't be called when acting as a router. 182982cd038dSYoshinobu Inoue */ 183082cd038dSYoshinobu Inoue void 183182cd038dSYoshinobu Inoue rt6_flush(gateway, ifp) 183282cd038dSYoshinobu Inoue struct in6_addr *gateway; 183382cd038dSYoshinobu Inoue struct ifnet *ifp; 183482cd038dSYoshinobu Inoue { 183582cd038dSYoshinobu Inoue struct radix_node_head *rnh = rt_tables[AF_INET6]; 183682cd038dSYoshinobu Inoue int s = splnet(); 183782cd038dSYoshinobu Inoue 183882cd038dSYoshinobu Inoue /* We'll care only link-local addresses */ 183982cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { 184082cd038dSYoshinobu Inoue splx(s); 184182cd038dSYoshinobu Inoue return; 184282cd038dSYoshinobu Inoue } 184382cd038dSYoshinobu Inoue 1844956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 184582cd038dSYoshinobu Inoue rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 1846956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 184782cd038dSYoshinobu Inoue splx(s); 184882cd038dSYoshinobu Inoue } 184982cd038dSYoshinobu Inoue 185082cd038dSYoshinobu Inoue static int 185182cd038dSYoshinobu Inoue rt6_deleteroute(rn, arg) 185282cd038dSYoshinobu Inoue struct radix_node *rn; 185382cd038dSYoshinobu Inoue void *arg; 185482cd038dSYoshinobu Inoue { 185582cd038dSYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)s) 185682cd038dSYoshinobu Inoue struct rtentry *rt = (struct rtentry *)rn; 185782cd038dSYoshinobu Inoue struct in6_addr *gate = (struct in6_addr *)arg; 185882cd038dSYoshinobu Inoue 185982cd038dSYoshinobu Inoue if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 186082cd038dSYoshinobu Inoue return (0); 186182cd038dSYoshinobu Inoue 186207eb2995SHajimu UMEMOTO if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) { 186382cd038dSYoshinobu Inoue return (0); 186407eb2995SHajimu UMEMOTO } 186582cd038dSYoshinobu Inoue 186682cd038dSYoshinobu Inoue /* 186733841545SHajimu UMEMOTO * Do not delete a static route. 186833841545SHajimu UMEMOTO * XXX: this seems to be a bit ad-hoc. Should we consider the 186933841545SHajimu UMEMOTO * 'cloned' bit instead? 187033841545SHajimu UMEMOTO */ 187133841545SHajimu UMEMOTO if ((rt->rt_flags & RTF_STATIC) != 0) 187233841545SHajimu UMEMOTO return (0); 187333841545SHajimu UMEMOTO 187433841545SHajimu UMEMOTO /* 187582cd038dSYoshinobu Inoue * We delete only host route. This means, in particular, we don't 187682cd038dSYoshinobu Inoue * delete default route. 187782cd038dSYoshinobu Inoue */ 187882cd038dSYoshinobu Inoue if ((rt->rt_flags & RTF_HOST) == 0) 187982cd038dSYoshinobu Inoue return (0); 188082cd038dSYoshinobu Inoue 188107eb2995SHajimu UMEMOTO return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 188207eb2995SHajimu UMEMOTO rt_mask(rt), rt->rt_flags, 0)); 188382cd038dSYoshinobu Inoue #undef SIN6 188482cd038dSYoshinobu Inoue } 1885686cdd19SJun-ichiro itojun Hagino 1886686cdd19SJun-ichiro itojun Hagino int 1887686cdd19SJun-ichiro itojun Hagino nd6_setdefaultiface(ifindex) 1888686cdd19SJun-ichiro itojun Hagino int ifindex; 1889686cdd19SJun-ichiro itojun Hagino { 1890686cdd19SJun-ichiro itojun Hagino int error = 0; 1891686cdd19SJun-ichiro itojun Hagino 1892686cdd19SJun-ichiro itojun Hagino if (ifindex < 0 || if_index < ifindex) 1893686cdd19SJun-ichiro itojun Hagino return (EINVAL); 1894686cdd19SJun-ichiro itojun Hagino 1895686cdd19SJun-ichiro itojun Hagino if (nd6_defifindex != ifindex) { 1896686cdd19SJun-ichiro itojun Hagino nd6_defifindex = ifindex; 1897686cdd19SJun-ichiro itojun Hagino if (nd6_defifindex > 0) 1898f9132cebSJonathan Lemon nd6_defifp = ifnet_byindex(nd6_defifindex); 1899686cdd19SJun-ichiro itojun Hagino else 1900686cdd19SJun-ichiro itojun Hagino nd6_defifp = NULL; 1901686cdd19SJun-ichiro itojun Hagino 1902686cdd19SJun-ichiro itojun Hagino /* 1903686cdd19SJun-ichiro itojun Hagino * If the Default Router List is empty, install a route 1904686cdd19SJun-ichiro itojun Hagino * to the specified interface as default or remove the default 1905686cdd19SJun-ichiro itojun Hagino * route when the default interface becomes canceled. 1906686cdd19SJun-ichiro itojun Hagino * The check for the queue is actually redundant, but 1907686cdd19SJun-ichiro itojun Hagino * we do this here to avoid re-install the default route 1908686cdd19SJun-ichiro itojun Hagino * if the list is NOT empty. 1909686cdd19SJun-ichiro itojun Hagino */ 1910686cdd19SJun-ichiro itojun Hagino if (TAILQ_FIRST(&nd_defrouter) == NULL) 1911686cdd19SJun-ichiro itojun Hagino defrouter_select(); 1912686cdd19SJun-ichiro itojun Hagino 1913686cdd19SJun-ichiro itojun Hagino /* 1914686cdd19SJun-ichiro itojun Hagino * Our current implementation assumes one-to-one maping between 1915686cdd19SJun-ichiro itojun Hagino * interfaces and links, so it would be natural to use the 1916686cdd19SJun-ichiro itojun Hagino * default interface as the default link. 1917686cdd19SJun-ichiro itojun Hagino */ 1918686cdd19SJun-ichiro itojun Hagino scope6_setdefault(nd6_defifp); 1919686cdd19SJun-ichiro itojun Hagino } 1920686cdd19SJun-ichiro itojun Hagino 1921686cdd19SJun-ichiro itojun Hagino return (error); 1922686cdd19SJun-ichiro itojun Hagino } 1923