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 482cd038dSYoshinobu Inoue /* 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 7982cd038dSYoshinobu Inoue static void in6_init_address_ltimes __P((struct nd_prefix *ndpr, 8033841545SHajimu UMEMOTO struct in6_addrlifetime *lt6)); 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; 117686cdd19SJun-ichiro itojun Hagino #if 0 118686cdd19SJun-ichiro itojun Hagino struct in6_addr daddr6 = ip6->ip6_dst; 119686cdd19SJun-ichiro itojun Hagino #endif 12082cd038dSYoshinobu Inoue char *lladdr = NULL; 12182cd038dSYoshinobu Inoue int lladdrlen = 0; 122686cdd19SJun-ichiro itojun Hagino #if 0 123686cdd19SJun-ichiro itojun Hagino struct sockaddr_dl *sdl = (struct sockaddr_dl *)NULL; 124686cdd19SJun-ichiro itojun Hagino struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; 125686cdd19SJun-ichiro itojun Hagino struct rtentry *rt = NULL; 126686cdd19SJun-ichiro itojun Hagino int is_newentry; 127686cdd19SJun-ichiro itojun Hagino #endif 12882cd038dSYoshinobu Inoue union nd_opts ndopts; 12982cd038dSYoshinobu Inoue 13082cd038dSYoshinobu Inoue /* If I'm not a router, ignore it. */ 13182cd038dSYoshinobu Inoue if (ip6_accept_rtadv != 0 || ip6_forwarding != 1) 132686cdd19SJun-ichiro itojun Hagino goto freeit; 13382cd038dSYoshinobu Inoue 13482cd038dSYoshinobu Inoue /* Sanity checks */ 13582cd038dSYoshinobu Inoue if (ip6->ip6_hlim != 255) { 13633841545SHajimu UMEMOTO nd6log((LOG_ERR, 13733841545SHajimu UMEMOTO "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 13833841545SHajimu UMEMOTO ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), 13933841545SHajimu UMEMOTO ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); 14033841545SHajimu UMEMOTO goto bad; 14182cd038dSYoshinobu Inoue } 14282cd038dSYoshinobu Inoue 14382cd038dSYoshinobu Inoue /* 14482cd038dSYoshinobu Inoue * Don't update the neighbor cache, if src = ::. 14582cd038dSYoshinobu Inoue * This indicates that the src has no IP address assigned yet. 14682cd038dSYoshinobu Inoue */ 14782cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 148686cdd19SJun-ichiro itojun Hagino goto freeit; 149686cdd19SJun-ichiro itojun Hagino 150686cdd19SJun-ichiro itojun Hagino #ifndef PULLDOWN_TEST 151686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_CHECK(m, off, icmp6len,); 152686cdd19SJun-ichiro itojun Hagino nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 153686cdd19SJun-ichiro itojun Hagino #else 154686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 155686cdd19SJun-ichiro itojun Hagino if (nd_rs == NULL) { 156686cdd19SJun-ichiro itojun Hagino icmp6stat.icp6s_tooshort++; 15782cd038dSYoshinobu Inoue return; 158686cdd19SJun-ichiro itojun Hagino } 159686cdd19SJun-ichiro itojun Hagino #endif 16082cd038dSYoshinobu Inoue 16182cd038dSYoshinobu Inoue icmp6len -= sizeof(*nd_rs); 16282cd038dSYoshinobu Inoue nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 16382cd038dSYoshinobu Inoue if (nd6_options(&ndopts) < 0) { 16433841545SHajimu UMEMOTO nd6log((LOG_INFO, 16533841545SHajimu UMEMOTO "nd6_rs_input: invalid ND option, ignored\n")); 16633841545SHajimu UMEMOTO /* nd6_options have incremented stats */ 167686cdd19SJun-ichiro itojun Hagino goto freeit; 16882cd038dSYoshinobu Inoue } 16982cd038dSYoshinobu Inoue 17082cd038dSYoshinobu Inoue if (ndopts.nd_opts_src_lladdr) { 17182cd038dSYoshinobu Inoue lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 17282cd038dSYoshinobu Inoue lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 17382cd038dSYoshinobu Inoue } 17482cd038dSYoshinobu Inoue 17582cd038dSYoshinobu Inoue if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 17633841545SHajimu UMEMOTO nd6log((LOG_INFO, 17782cd038dSYoshinobu Inoue "nd6_rs_input: lladdrlen mismatch for %s " 17882cd038dSYoshinobu Inoue "(if %d, RS packet %d)\n", 17933841545SHajimu UMEMOTO ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2)); 18033841545SHajimu UMEMOTO goto bad; 18182cd038dSYoshinobu Inoue } 18282cd038dSYoshinobu Inoue 18382cd038dSYoshinobu Inoue nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 184686cdd19SJun-ichiro itojun Hagino 185686cdd19SJun-ichiro itojun Hagino freeit: 186686cdd19SJun-ichiro itojun Hagino m_freem(m); 18733841545SHajimu UMEMOTO return; 18833841545SHajimu UMEMOTO 18933841545SHajimu UMEMOTO bad: 19033841545SHajimu UMEMOTO icmp6stat.icp6s_badrs++; 19133841545SHajimu UMEMOTO m_freem(m); 19282cd038dSYoshinobu Inoue } 19382cd038dSYoshinobu Inoue 19482cd038dSYoshinobu Inoue /* 19582cd038dSYoshinobu Inoue * Receive Router Advertisement Message. 19682cd038dSYoshinobu Inoue * 19782cd038dSYoshinobu Inoue * Based on RFC 2461 19882cd038dSYoshinobu Inoue * TODO: on-link bit on prefix information 19982cd038dSYoshinobu Inoue * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 20082cd038dSYoshinobu Inoue */ 20182cd038dSYoshinobu Inoue void 20282cd038dSYoshinobu Inoue nd6_ra_input(m, off, icmp6len) 20382cd038dSYoshinobu Inoue struct mbuf *m; 20482cd038dSYoshinobu Inoue int off, icmp6len; 20582cd038dSYoshinobu Inoue { 20682cd038dSYoshinobu Inoue struct ifnet *ifp = m->m_pkthdr.rcvif; 20782cd038dSYoshinobu Inoue struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; 20882cd038dSYoshinobu Inoue struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 209686cdd19SJun-ichiro itojun Hagino struct nd_router_advert *nd_ra; 21082cd038dSYoshinobu Inoue struct in6_addr saddr6 = ip6->ip6_src; 211686cdd19SJun-ichiro itojun Hagino #if 0 212686cdd19SJun-ichiro itojun Hagino struct in6_addr daddr6 = ip6->ip6_dst; 213686cdd19SJun-ichiro itojun Hagino int flags; /* = nd_ra->nd_ra_flags_reserved; */ 214686cdd19SJun-ichiro itojun Hagino int is_managed = ((flags & ND_RA_FLAG_MANAGED) != 0); 215686cdd19SJun-ichiro itojun Hagino int is_other = ((flags & ND_RA_FLAG_OTHER) != 0); 216686cdd19SJun-ichiro itojun Hagino #endif 21782cd038dSYoshinobu Inoue union nd_opts ndopts; 21882cd038dSYoshinobu Inoue struct nd_defrouter *dr; 21982cd038dSYoshinobu Inoue 22007cf047dSHajimu UMEMOTO /* 22107cf047dSHajimu UMEMOTO * We only accept RAs only when 22207cf047dSHajimu UMEMOTO * the system-wide variable allows the acceptance, and 22307cf047dSHajimu UMEMOTO * per-interface variable allows RAs on the receiving interface. 22407cf047dSHajimu UMEMOTO */ 22582cd038dSYoshinobu Inoue if (ip6_accept_rtadv == 0) 226686cdd19SJun-ichiro itojun Hagino goto freeit; 22707cf047dSHajimu UMEMOTO if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 22807cf047dSHajimu UMEMOTO goto freeit; 22982cd038dSYoshinobu Inoue 23082cd038dSYoshinobu Inoue if (ip6->ip6_hlim != 255) { 23133841545SHajimu UMEMOTO nd6log((LOG_ERR, 23233841545SHajimu UMEMOTO "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 23333841545SHajimu UMEMOTO ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), 23433841545SHajimu UMEMOTO ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); 23533841545SHajimu UMEMOTO goto bad; 23682cd038dSYoshinobu Inoue } 23782cd038dSYoshinobu Inoue 23882cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 23933841545SHajimu UMEMOTO nd6log((LOG_ERR, 24082cd038dSYoshinobu Inoue "nd6_ra_input: src %s is not link-local\n", 24133841545SHajimu UMEMOTO ip6_sprintf(&saddr6))); 24233841545SHajimu UMEMOTO goto bad; 243686cdd19SJun-ichiro itojun Hagino } 244686cdd19SJun-ichiro itojun Hagino 245686cdd19SJun-ichiro itojun Hagino #ifndef PULLDOWN_TEST 246686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_CHECK(m, off, icmp6len,); 247686cdd19SJun-ichiro itojun Hagino nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); 248686cdd19SJun-ichiro itojun Hagino #else 249686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); 250686cdd19SJun-ichiro itojun Hagino if (nd_ra == NULL) { 251686cdd19SJun-ichiro itojun Hagino icmp6stat.icp6s_tooshort++; 25282cd038dSYoshinobu Inoue return; 25382cd038dSYoshinobu Inoue } 254686cdd19SJun-ichiro itojun Hagino #endif 25582cd038dSYoshinobu Inoue 25682cd038dSYoshinobu Inoue icmp6len -= sizeof(*nd_ra); 25782cd038dSYoshinobu Inoue nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 25882cd038dSYoshinobu Inoue if (nd6_options(&ndopts) < 0) { 25933841545SHajimu UMEMOTO nd6log((LOG_INFO, 26033841545SHajimu UMEMOTO "nd6_ra_input: invalid ND option, ignored\n")); 26133841545SHajimu UMEMOTO /* nd6_options have incremented stats */ 262686cdd19SJun-ichiro itojun Hagino goto freeit; 26382cd038dSYoshinobu Inoue } 26482cd038dSYoshinobu Inoue 26582cd038dSYoshinobu Inoue { 26682cd038dSYoshinobu Inoue struct nd_defrouter dr0; 26782cd038dSYoshinobu Inoue u_int32_t advreachable = nd_ra->nd_ra_reachable; 26882cd038dSYoshinobu Inoue 26982cd038dSYoshinobu Inoue dr0.rtaddr = saddr6; 27082cd038dSYoshinobu Inoue dr0.flags = nd_ra->nd_ra_flags_reserved; 27182cd038dSYoshinobu Inoue dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 27282cd038dSYoshinobu Inoue dr0.expire = time_second + dr0.rtlifetime; 27382cd038dSYoshinobu Inoue dr0.ifp = ifp; 274686cdd19SJun-ichiro itojun Hagino dr0.advint = 0; /* Mobile IPv6 */ 275686cdd19SJun-ichiro itojun Hagino dr0.advint_expire = 0; /* Mobile IPv6 */ 276686cdd19SJun-ichiro itojun Hagino dr0.advints_lost = 0; /* Mobile IPv6 */ 27782cd038dSYoshinobu Inoue /* unspecified or not? (RFC 2461 6.3.4) */ 27882cd038dSYoshinobu Inoue if (advreachable) { 279fd8e4ebcSMike Barcroft advreachable = ntohl(advreachable); 28082cd038dSYoshinobu Inoue if (advreachable <= MAX_REACHABLE_TIME && 28182cd038dSYoshinobu Inoue ndi->basereachable != advreachable) { 28282cd038dSYoshinobu Inoue ndi->basereachable = advreachable; 28382cd038dSYoshinobu Inoue ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 28482cd038dSYoshinobu Inoue ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */ 28582cd038dSYoshinobu Inoue } 28682cd038dSYoshinobu Inoue } 28782cd038dSYoshinobu Inoue if (nd_ra->nd_ra_retransmit) 28882cd038dSYoshinobu Inoue ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 28982cd038dSYoshinobu Inoue if (nd_ra->nd_ra_curhoplimit) 29082cd038dSYoshinobu Inoue ndi->chlim = nd_ra->nd_ra_curhoplimit; 29182cd038dSYoshinobu Inoue dr = defrtrlist_update(&dr0); 29282cd038dSYoshinobu Inoue } 29382cd038dSYoshinobu Inoue 29482cd038dSYoshinobu Inoue /* 29582cd038dSYoshinobu Inoue * prefix 29682cd038dSYoshinobu Inoue */ 29782cd038dSYoshinobu Inoue if (ndopts.nd_opts_pi) { 29882cd038dSYoshinobu Inoue struct nd_opt_hdr *pt; 29933841545SHajimu UMEMOTO struct nd_opt_prefix_info *pi = NULL; 30082cd038dSYoshinobu Inoue struct nd_prefix pr; 30182cd038dSYoshinobu Inoue 30282cd038dSYoshinobu Inoue for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 30382cd038dSYoshinobu Inoue pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 30482cd038dSYoshinobu Inoue pt = (struct nd_opt_hdr *)((caddr_t)pt + 30582cd038dSYoshinobu Inoue (pt->nd_opt_len << 3))) { 30682cd038dSYoshinobu Inoue if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 30782cd038dSYoshinobu Inoue continue; 30882cd038dSYoshinobu Inoue pi = (struct nd_opt_prefix_info *)pt; 30982cd038dSYoshinobu Inoue 31082cd038dSYoshinobu Inoue if (pi->nd_opt_pi_len != 4) { 31133841545SHajimu UMEMOTO nd6log((LOG_INFO, 31233841545SHajimu UMEMOTO "nd6_ra_input: invalid option " 31382cd038dSYoshinobu Inoue "len %d for prefix information option, " 31433841545SHajimu UMEMOTO "ignored\n", pi->nd_opt_pi_len)); 31582cd038dSYoshinobu Inoue continue; 31682cd038dSYoshinobu Inoue } 31782cd038dSYoshinobu Inoue 31882cd038dSYoshinobu Inoue if (128 < pi->nd_opt_pi_prefix_len) { 31933841545SHajimu UMEMOTO nd6log((LOG_INFO, 32033841545SHajimu UMEMOTO "nd6_ra_input: invalid prefix " 32182cd038dSYoshinobu Inoue "len %d for prefix information option, " 32233841545SHajimu UMEMOTO "ignored\n", pi->nd_opt_pi_prefix_len)); 32382cd038dSYoshinobu Inoue continue; 32482cd038dSYoshinobu Inoue } 32582cd038dSYoshinobu Inoue 32682cd038dSYoshinobu Inoue if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 32782cd038dSYoshinobu Inoue || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 32833841545SHajimu UMEMOTO nd6log((LOG_INFO, 32933841545SHajimu UMEMOTO "nd6_ra_input: invalid prefix " 33082cd038dSYoshinobu Inoue "%s, ignored\n", 33133841545SHajimu UMEMOTO ip6_sprintf(&pi->nd_opt_pi_prefix))); 33282cd038dSYoshinobu Inoue continue; 33382cd038dSYoshinobu Inoue } 33482cd038dSYoshinobu Inoue 33582cd038dSYoshinobu Inoue /* aggregatable unicast address, rfc2374 */ 33682cd038dSYoshinobu Inoue if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20 33782cd038dSYoshinobu Inoue && pi->nd_opt_pi_prefix_len != 64) { 33833841545SHajimu UMEMOTO nd6log((LOG_INFO, 33933841545SHajimu UMEMOTO "nd6_ra_input: invalid prefixlen " 34082cd038dSYoshinobu Inoue "%d for rfc2374 prefix %s, ignored\n", 34182cd038dSYoshinobu Inoue pi->nd_opt_pi_prefix_len, 34233841545SHajimu UMEMOTO ip6_sprintf(&pi->nd_opt_pi_prefix))); 34382cd038dSYoshinobu Inoue continue; 34482cd038dSYoshinobu Inoue } 34582cd038dSYoshinobu Inoue 34682cd038dSYoshinobu Inoue bzero(&pr, sizeof(pr)); 34782cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_family = AF_INET6; 34882cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 34982cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 35082cd038dSYoshinobu Inoue pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 35182cd038dSYoshinobu Inoue 35282cd038dSYoshinobu Inoue pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 35382cd038dSYoshinobu Inoue ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 35482cd038dSYoshinobu Inoue pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 35582cd038dSYoshinobu Inoue ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 35682cd038dSYoshinobu Inoue pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 35782cd038dSYoshinobu Inoue pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 35882cd038dSYoshinobu Inoue pr.ndpr_pltime = 35982cd038dSYoshinobu Inoue ntohl(pi->nd_opt_pi_preferred_time); 36082cd038dSYoshinobu Inoue 36182cd038dSYoshinobu Inoue if (in6_init_prefix_ltimes(&pr)) 36282cd038dSYoshinobu Inoue continue; /* prefix lifetime init failed */ 36382cd038dSYoshinobu Inoue 36482cd038dSYoshinobu Inoue (void)prelist_update(&pr, dr, m); 36582cd038dSYoshinobu Inoue } 36682cd038dSYoshinobu Inoue } 36782cd038dSYoshinobu Inoue 36882cd038dSYoshinobu Inoue /* 36982cd038dSYoshinobu Inoue * MTU 37082cd038dSYoshinobu Inoue */ 37182cd038dSYoshinobu Inoue if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 37282cd038dSYoshinobu Inoue u_int32_t mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 37382cd038dSYoshinobu Inoue 37482cd038dSYoshinobu Inoue /* lower bound */ 37582cd038dSYoshinobu Inoue if (mtu < IPV6_MMTU) { 37633841545SHajimu UMEMOTO nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " 37782cd038dSYoshinobu Inoue "mtu=%d sent from %s, ignoring\n", 37833841545SHajimu UMEMOTO mtu, ip6_sprintf(&ip6->ip6_src))); 37982cd038dSYoshinobu Inoue goto skip; 38082cd038dSYoshinobu Inoue } 38182cd038dSYoshinobu Inoue 38282cd038dSYoshinobu Inoue /* upper bound */ 38382cd038dSYoshinobu Inoue if (ndi->maxmtu) { 38482cd038dSYoshinobu Inoue if (mtu <= ndi->maxmtu) { 38582cd038dSYoshinobu Inoue int change = (ndi->linkmtu != mtu); 38682cd038dSYoshinobu Inoue 38782cd038dSYoshinobu Inoue ndi->linkmtu = mtu; 38882cd038dSYoshinobu Inoue if (change) /* in6_maxmtu may change */ 38982cd038dSYoshinobu Inoue in6_setmaxmtu(); 39082cd038dSYoshinobu Inoue } else { 39133841545SHajimu UMEMOTO nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " 39282cd038dSYoshinobu Inoue "mtu=%d sent from %s; " 39382cd038dSYoshinobu Inoue "exceeds maxmtu %d, ignoring\n", 39482cd038dSYoshinobu Inoue mtu, ip6_sprintf(&ip6->ip6_src), 39533841545SHajimu UMEMOTO ndi->maxmtu)); 39682cd038dSYoshinobu Inoue } 39782cd038dSYoshinobu Inoue } else { 39833841545SHajimu UMEMOTO nd6log((LOG_INFO, "nd6_ra_input: mtu option " 39982cd038dSYoshinobu Inoue "mtu=%d sent from %s; maxmtu unknown, " 40082cd038dSYoshinobu Inoue "ignoring\n", 40133841545SHajimu UMEMOTO mtu, ip6_sprintf(&ip6->ip6_src))); 40282cd038dSYoshinobu Inoue } 40382cd038dSYoshinobu Inoue } 40482cd038dSYoshinobu Inoue 40582cd038dSYoshinobu Inoue skip: 40682cd038dSYoshinobu Inoue 40782cd038dSYoshinobu Inoue /* 40888ff5695SSUZUKI Shinsuke * Source link layer address 40982cd038dSYoshinobu Inoue */ 41082cd038dSYoshinobu Inoue { 41182cd038dSYoshinobu Inoue char *lladdr = NULL; 41282cd038dSYoshinobu Inoue int lladdrlen = 0; 41382cd038dSYoshinobu Inoue 41482cd038dSYoshinobu Inoue if (ndopts.nd_opts_src_lladdr) { 41582cd038dSYoshinobu Inoue lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 41682cd038dSYoshinobu Inoue lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 41782cd038dSYoshinobu Inoue } 41882cd038dSYoshinobu Inoue 41982cd038dSYoshinobu Inoue if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 42033841545SHajimu UMEMOTO nd6log((LOG_INFO, 42182cd038dSYoshinobu Inoue "nd6_ra_input: lladdrlen mismatch for %s " 42282cd038dSYoshinobu Inoue "(if %d, RA packet %d)\n", 42333841545SHajimu UMEMOTO ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2)); 42433841545SHajimu UMEMOTO goto bad; 42582cd038dSYoshinobu Inoue } 42682cd038dSYoshinobu Inoue 42782cd038dSYoshinobu Inoue nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0); 428686cdd19SJun-ichiro itojun Hagino 429686cdd19SJun-ichiro itojun Hagino /* 430686cdd19SJun-ichiro itojun Hagino * Installing a link-layer address might change the state of the 431686cdd19SJun-ichiro itojun Hagino * router's neighbor cache, which might also affect our on-link 432686cdd19SJun-ichiro itojun Hagino * detection of adveritsed prefixes. 433686cdd19SJun-ichiro itojun Hagino */ 434686cdd19SJun-ichiro itojun Hagino pfxlist_onlink_check(); 43582cd038dSYoshinobu Inoue } 436686cdd19SJun-ichiro itojun Hagino 437686cdd19SJun-ichiro itojun Hagino freeit: 438686cdd19SJun-ichiro itojun Hagino m_freem(m); 43933841545SHajimu UMEMOTO return; 44033841545SHajimu UMEMOTO 44133841545SHajimu UMEMOTO bad: 44233841545SHajimu UMEMOTO icmp6stat.icp6s_badra++; 44333841545SHajimu UMEMOTO m_freem(m); 44482cd038dSYoshinobu Inoue } 44582cd038dSYoshinobu Inoue 44682cd038dSYoshinobu Inoue /* 44782cd038dSYoshinobu Inoue * default router list proccessing sub routines 44882cd038dSYoshinobu Inoue */ 449686cdd19SJun-ichiro itojun Hagino 450686cdd19SJun-ichiro itojun Hagino /* tell the change to user processes watching the routing socket. */ 451686cdd19SJun-ichiro itojun Hagino static void 45233841545SHajimu UMEMOTO nd6_rtmsg(cmd, rt) 453686cdd19SJun-ichiro itojun Hagino int cmd; 454686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 455686cdd19SJun-ichiro itojun Hagino { 456686cdd19SJun-ichiro itojun Hagino struct rt_addrinfo info; 457686cdd19SJun-ichiro itojun Hagino 458686cdd19SJun-ichiro itojun Hagino bzero((caddr_t)&info, sizeof(info)); 459686cdd19SJun-ichiro itojun Hagino info.rti_info[RTAX_DST] = rt_key(rt); 460686cdd19SJun-ichiro itojun Hagino info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 461686cdd19SJun-ichiro itojun Hagino info.rti_info[RTAX_NETMASK] = rt_mask(rt); 46233841545SHajimu UMEMOTO info.rti_info[RTAX_IFP] = 46333841545SHajimu UMEMOTO (struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist); 46433841545SHajimu UMEMOTO info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 465686cdd19SJun-ichiro itojun Hagino 466686cdd19SJun-ichiro itojun Hagino rt_missmsg(cmd, &info, rt->rt_flags, 0); 467686cdd19SJun-ichiro itojun Hagino } 468686cdd19SJun-ichiro itojun Hagino 46982cd038dSYoshinobu Inoue void 47082cd038dSYoshinobu Inoue defrouter_addreq(new) 47182cd038dSYoshinobu Inoue struct nd_defrouter *new; 47282cd038dSYoshinobu Inoue { 47382cd038dSYoshinobu Inoue struct sockaddr_in6 def, mask, gate; 474686cdd19SJun-ichiro itojun Hagino struct rtentry *newrt = NULL; 47582cd038dSYoshinobu Inoue int s; 47682cd038dSYoshinobu Inoue 47782cd038dSYoshinobu Inoue Bzero(&def, sizeof(def)); 47882cd038dSYoshinobu Inoue Bzero(&mask, sizeof(mask)); 47982cd038dSYoshinobu Inoue Bzero(&gate, sizeof(gate)); 48082cd038dSYoshinobu Inoue 48182cd038dSYoshinobu Inoue def.sin6_len = mask.sin6_len = gate.sin6_len 48282cd038dSYoshinobu Inoue = sizeof(struct sockaddr_in6); 48382cd038dSYoshinobu Inoue def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6; 48482cd038dSYoshinobu Inoue gate.sin6_addr = new->rtaddr; 48582cd038dSYoshinobu Inoue 48682cd038dSYoshinobu Inoue s = splnet(); 48782cd038dSYoshinobu Inoue (void)rtrequest(RTM_ADD, (struct sockaddr *)&def, 48882cd038dSYoshinobu Inoue (struct sockaddr *)&gate, (struct sockaddr *)&mask, 489686cdd19SJun-ichiro itojun Hagino RTF_GATEWAY, &newrt); 490686cdd19SJun-ichiro itojun Hagino if (newrt) { 49133841545SHajimu UMEMOTO nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 492686cdd19SJun-ichiro itojun Hagino newrt->rt_refcnt--; 493686cdd19SJun-ichiro itojun Hagino } 49482cd038dSYoshinobu Inoue splx(s); 49582cd038dSYoshinobu Inoue return; 49682cd038dSYoshinobu Inoue } 49782cd038dSYoshinobu Inoue 498686cdd19SJun-ichiro itojun Hagino /* Add a route to a given interface as default */ 499686cdd19SJun-ichiro itojun Hagino void 500686cdd19SJun-ichiro itojun Hagino defrouter_addifreq(ifp) 501686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 502686cdd19SJun-ichiro itojun Hagino { 503686cdd19SJun-ichiro itojun Hagino struct sockaddr_in6 def, mask; 504686cdd19SJun-ichiro itojun Hagino struct ifaddr *ifa; 505686cdd19SJun-ichiro itojun Hagino struct rtentry *newrt = NULL; 506686cdd19SJun-ichiro itojun Hagino int error, flags; 507686cdd19SJun-ichiro itojun Hagino 508686cdd19SJun-ichiro itojun Hagino bzero(&def, sizeof(def)); 509686cdd19SJun-ichiro itojun Hagino bzero(&mask, sizeof(mask)); 510686cdd19SJun-ichiro itojun Hagino 511686cdd19SJun-ichiro itojun Hagino def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6); 512686cdd19SJun-ichiro itojun Hagino def.sin6_family = mask.sin6_family = AF_INET6; 513686cdd19SJun-ichiro itojun Hagino 514686cdd19SJun-ichiro itojun Hagino /* 515686cdd19SJun-ichiro itojun Hagino * Search for an ifaddr beloging to the specified interface. 516686cdd19SJun-ichiro itojun Hagino * XXX: An IPv6 address are required to be assigned on the interface. 517686cdd19SJun-ichiro itojun Hagino */ 518686cdd19SJun-ichiro itojun Hagino if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) { 51933841545SHajimu UMEMOTO nd6log((LOG_ERR, /* better error? */ 520686cdd19SJun-ichiro itojun Hagino "defrouter_addifreq: failed to find an ifaddr " 521686cdd19SJun-ichiro itojun Hagino "to install a route to interface %s\n", 52233841545SHajimu UMEMOTO if_name(ifp))); 523686cdd19SJun-ichiro itojun Hagino return; 524686cdd19SJun-ichiro itojun Hagino } 525686cdd19SJun-ichiro itojun Hagino 526686cdd19SJun-ichiro itojun Hagino flags = ifa->ifa_flags; 52733841545SHajimu UMEMOTO error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr, 52833841545SHajimu UMEMOTO (struct sockaddr *)&mask, flags, &newrt); 52933841545SHajimu UMEMOTO if (error != 0) { 53033841545SHajimu UMEMOTO nd6log((LOG_ERR, 531686cdd19SJun-ichiro itojun Hagino "defrouter_addifreq: failed to install a route to " 532686cdd19SJun-ichiro itojun Hagino "interface %s (errno = %d)\n", 53333841545SHajimu UMEMOTO if_name(ifp), error)); 534686cdd19SJun-ichiro itojun Hagino 535686cdd19SJun-ichiro itojun Hagino if (newrt) /* maybe unnecessary, but do it for safety */ 536686cdd19SJun-ichiro itojun Hagino newrt->rt_refcnt--; 537686cdd19SJun-ichiro itojun Hagino } else { 538686cdd19SJun-ichiro itojun Hagino if (newrt) { 53933841545SHajimu UMEMOTO nd6_rtmsg(RTM_ADD, newrt); 540686cdd19SJun-ichiro itojun Hagino newrt->rt_refcnt--; 541686cdd19SJun-ichiro itojun Hagino } 542686cdd19SJun-ichiro itojun Hagino } 543686cdd19SJun-ichiro itojun Hagino } 544686cdd19SJun-ichiro itojun Hagino 54582cd038dSYoshinobu Inoue struct nd_defrouter * 54682cd038dSYoshinobu Inoue defrouter_lookup(addr, ifp) 54782cd038dSYoshinobu Inoue struct in6_addr *addr; 54882cd038dSYoshinobu Inoue struct ifnet *ifp; 54982cd038dSYoshinobu Inoue { 55082cd038dSYoshinobu Inoue struct nd_defrouter *dr; 55182cd038dSYoshinobu Inoue 552686cdd19SJun-ichiro itojun Hagino for (dr = TAILQ_FIRST(&nd_defrouter); dr; 553686cdd19SJun-ichiro itojun Hagino dr = TAILQ_NEXT(dr, dr_entry)) { 55482cd038dSYoshinobu Inoue if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 55582cd038dSYoshinobu Inoue return(dr); 556686cdd19SJun-ichiro itojun Hagino } 55782cd038dSYoshinobu Inoue 55882cd038dSYoshinobu Inoue return(NULL); /* search failed */ 55982cd038dSYoshinobu Inoue } 56082cd038dSYoshinobu Inoue 56182cd038dSYoshinobu Inoue void 56282cd038dSYoshinobu Inoue defrouter_delreq(dr, dofree) 56382cd038dSYoshinobu Inoue struct nd_defrouter *dr; 56482cd038dSYoshinobu Inoue int dofree; 56582cd038dSYoshinobu Inoue { 56682cd038dSYoshinobu Inoue struct sockaddr_in6 def, mask, gate; 567686cdd19SJun-ichiro itojun Hagino struct rtentry *oldrt = NULL; 56882cd038dSYoshinobu Inoue 56982cd038dSYoshinobu Inoue Bzero(&def, sizeof(def)); 57082cd038dSYoshinobu Inoue Bzero(&mask, sizeof(mask)); 57182cd038dSYoshinobu Inoue Bzero(&gate, sizeof(gate)); 57282cd038dSYoshinobu Inoue 57382cd038dSYoshinobu Inoue def.sin6_len = mask.sin6_len = gate.sin6_len 57482cd038dSYoshinobu Inoue = sizeof(struct sockaddr_in6); 57582cd038dSYoshinobu Inoue def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6; 57682cd038dSYoshinobu Inoue gate.sin6_addr = dr->rtaddr; 57782cd038dSYoshinobu Inoue 57882cd038dSYoshinobu Inoue rtrequest(RTM_DELETE, (struct sockaddr *)&def, 57982cd038dSYoshinobu Inoue (struct sockaddr *)&gate, 58082cd038dSYoshinobu Inoue (struct sockaddr *)&mask, 581686cdd19SJun-ichiro itojun Hagino RTF_GATEWAY, &oldrt); 582686cdd19SJun-ichiro itojun Hagino if (oldrt) { 58333841545SHajimu UMEMOTO nd6_rtmsg(RTM_DELETE, oldrt); 58471eba915SRuslan Ermilov RTFREE(oldrt); 58520220070SJun-ichiro itojun Hagino } 58682cd038dSYoshinobu Inoue 587686cdd19SJun-ichiro itojun Hagino if (dofree) /* XXX: necessary? */ 58882cd038dSYoshinobu Inoue free(dr, M_IP6NDP); 58982cd038dSYoshinobu Inoue } 59082cd038dSYoshinobu Inoue 59182cd038dSYoshinobu Inoue void 59282cd038dSYoshinobu Inoue defrtrlist_del(dr) 59382cd038dSYoshinobu Inoue struct nd_defrouter *dr; 59482cd038dSYoshinobu Inoue { 59582cd038dSYoshinobu Inoue struct nd_defrouter *deldr = NULL; 59682cd038dSYoshinobu Inoue struct nd_prefix *pr; 59782cd038dSYoshinobu Inoue 59882cd038dSYoshinobu Inoue /* 59982cd038dSYoshinobu Inoue * Flush all the routing table entries that use the router 60082cd038dSYoshinobu Inoue * as a next hop. 60182cd038dSYoshinobu Inoue */ 60282cd038dSYoshinobu Inoue if (!ip6_forwarding && ip6_accept_rtadv) { 60382cd038dSYoshinobu Inoue /* above is a good condition? */ 60482cd038dSYoshinobu Inoue rt6_flush(&dr->rtaddr, dr->ifp); 60582cd038dSYoshinobu Inoue } 60682cd038dSYoshinobu Inoue 607686cdd19SJun-ichiro itojun Hagino if (dr == TAILQ_FIRST(&nd_defrouter)) 60882cd038dSYoshinobu Inoue deldr = dr; /* The router is primary. */ 60982cd038dSYoshinobu Inoue 610686cdd19SJun-ichiro itojun Hagino TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 61182cd038dSYoshinobu Inoue 61282cd038dSYoshinobu Inoue /* 61382cd038dSYoshinobu Inoue * Also delete all the pointers to the router in each prefix lists. 61482cd038dSYoshinobu Inoue */ 615686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 61682cd038dSYoshinobu Inoue struct nd_pfxrouter *pfxrtr; 61782cd038dSYoshinobu Inoue if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 61882cd038dSYoshinobu Inoue pfxrtr_del(pfxrtr); 61982cd038dSYoshinobu Inoue } 62082cd038dSYoshinobu Inoue pfxlist_onlink_check(); 62182cd038dSYoshinobu Inoue 62282cd038dSYoshinobu Inoue /* 623686cdd19SJun-ichiro itojun Hagino * If the router is the primary one, choose a new one. 624686cdd19SJun-ichiro itojun Hagino * Note that defrouter_select() will remove the current gateway 625686cdd19SJun-ichiro itojun Hagino * from the routing table. 62682cd038dSYoshinobu Inoue */ 62782cd038dSYoshinobu Inoue if (deldr) 628686cdd19SJun-ichiro itojun Hagino defrouter_select(); 629686cdd19SJun-ichiro itojun Hagino 63082cd038dSYoshinobu Inoue free(dr, M_IP6NDP); 63182cd038dSYoshinobu Inoue } 63282cd038dSYoshinobu Inoue 633686cdd19SJun-ichiro itojun Hagino /* 634686cdd19SJun-ichiro itojun Hagino * Default Router Selection according to Section 6.3.6 of RFC 2461: 635686cdd19SJun-ichiro itojun Hagino * 1) Routers that are reachable or probably reachable should be 636686cdd19SJun-ichiro itojun Hagino * preferred. 637686cdd19SJun-ichiro itojun Hagino * 2) When no routers on the list are known to be reachable or 638686cdd19SJun-ichiro itojun Hagino * probably reachable, routers SHOULD be selected in a round-robin 639686cdd19SJun-ichiro itojun Hagino * fashion. 640686cdd19SJun-ichiro itojun Hagino * 3) If the Default Router List is empty, assume that all 641686cdd19SJun-ichiro itojun Hagino * destinations are on-link. 642686cdd19SJun-ichiro itojun Hagino */ 643686cdd19SJun-ichiro itojun Hagino void 644686cdd19SJun-ichiro itojun Hagino defrouter_select() 645686cdd19SJun-ichiro itojun Hagino { 646686cdd19SJun-ichiro itojun Hagino int s = splnet(); 647686cdd19SJun-ichiro itojun Hagino struct nd_defrouter *dr, anydr; 648686cdd19SJun-ichiro itojun Hagino struct rtentry *rt = NULL; 649686cdd19SJun-ichiro itojun Hagino struct llinfo_nd6 *ln = NULL; 650686cdd19SJun-ichiro itojun Hagino 651686cdd19SJun-ichiro itojun Hagino /* 652686cdd19SJun-ichiro itojun Hagino * Search for a (probably) reachable router from the list. 653686cdd19SJun-ichiro itojun Hagino */ 654686cdd19SJun-ichiro itojun Hagino for (dr = TAILQ_FIRST(&nd_defrouter); dr; 655686cdd19SJun-ichiro itojun Hagino dr = TAILQ_NEXT(dr, dr_entry)) { 656686cdd19SJun-ichiro itojun Hagino if ((rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && 657686cdd19SJun-ichiro itojun Hagino (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 658686cdd19SJun-ichiro itojun Hagino ND6_IS_LLINFO_PROBREACH(ln)) { 659686cdd19SJun-ichiro itojun Hagino /* Got it, and move it to the head */ 660686cdd19SJun-ichiro itojun Hagino TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 661686cdd19SJun-ichiro itojun Hagino TAILQ_INSERT_HEAD(&nd_defrouter, dr, dr_entry); 662686cdd19SJun-ichiro itojun Hagino break; 663686cdd19SJun-ichiro itojun Hagino } 664686cdd19SJun-ichiro itojun Hagino } 665686cdd19SJun-ichiro itojun Hagino 666686cdd19SJun-ichiro itojun Hagino if ((dr = TAILQ_FIRST(&nd_defrouter))) { 667686cdd19SJun-ichiro itojun Hagino /* 668686cdd19SJun-ichiro itojun Hagino * De-install the previous default gateway and install 669686cdd19SJun-ichiro itojun Hagino * a new one. 670686cdd19SJun-ichiro itojun Hagino * Note that if there is no reachable router in the list, 671686cdd19SJun-ichiro itojun Hagino * the head entry will be used anyway. 672686cdd19SJun-ichiro itojun Hagino * XXX: do we have to check the current routing table entry? 673686cdd19SJun-ichiro itojun Hagino */ 674686cdd19SJun-ichiro itojun Hagino bzero(&anydr, sizeof(anydr)); 675686cdd19SJun-ichiro itojun Hagino defrouter_delreq(&anydr, 0); 676686cdd19SJun-ichiro itojun Hagino defrouter_addreq(dr); 677686cdd19SJun-ichiro itojun Hagino } 678686cdd19SJun-ichiro itojun Hagino else { 679686cdd19SJun-ichiro itojun Hagino /* 680686cdd19SJun-ichiro itojun Hagino * The Default Router List is empty, so install the default 681686cdd19SJun-ichiro itojun Hagino * route to an inteface. 682686cdd19SJun-ichiro itojun Hagino * XXX: The specification does not say this mechanism should 683686cdd19SJun-ichiro itojun Hagino * be restricted to hosts, but this would be not useful 684686cdd19SJun-ichiro itojun Hagino * (even harmful) for routers. 685686cdd19SJun-ichiro itojun Hagino */ 686686cdd19SJun-ichiro itojun Hagino if (!ip6_forwarding) { 687686cdd19SJun-ichiro itojun Hagino /* 688686cdd19SJun-ichiro itojun Hagino * De-install the current default route 689686cdd19SJun-ichiro itojun Hagino * in advance. 690686cdd19SJun-ichiro itojun Hagino */ 691686cdd19SJun-ichiro itojun Hagino bzero(&anydr, sizeof(anydr)); 692686cdd19SJun-ichiro itojun Hagino defrouter_delreq(&anydr, 0); 693686cdd19SJun-ichiro itojun Hagino if (nd6_defifp) { 694686cdd19SJun-ichiro itojun Hagino /* 695686cdd19SJun-ichiro itojun Hagino * Install a route to the default interface 696686cdd19SJun-ichiro itojun Hagino * as default route. 69733841545SHajimu UMEMOTO * XXX: we enable this for host only, because 69833841545SHajimu UMEMOTO * this may override a default route installed 69933841545SHajimu UMEMOTO * a user process (e.g. routing daemon) in a 70033841545SHajimu UMEMOTO * router case. 701686cdd19SJun-ichiro itojun Hagino */ 702686cdd19SJun-ichiro itojun Hagino defrouter_addifreq(nd6_defifp); 70333841545SHajimu UMEMOTO } else { 70433841545SHajimu UMEMOTO nd6log((LOG_INFO, "defrouter_select: " 705686cdd19SJun-ichiro itojun Hagino "there's no default router and no default" 70633841545SHajimu UMEMOTO " interface\n")); 70733841545SHajimu UMEMOTO } 708686cdd19SJun-ichiro itojun Hagino } 709686cdd19SJun-ichiro itojun Hagino } 710686cdd19SJun-ichiro itojun Hagino 711686cdd19SJun-ichiro itojun Hagino splx(s); 712686cdd19SJun-ichiro itojun Hagino return; 713686cdd19SJun-ichiro itojun Hagino } 714686cdd19SJun-ichiro itojun Hagino 71582cd038dSYoshinobu Inoue static struct nd_defrouter * 71682cd038dSYoshinobu Inoue defrtrlist_update(new) 71782cd038dSYoshinobu Inoue struct nd_defrouter *new; 71882cd038dSYoshinobu Inoue { 71982cd038dSYoshinobu Inoue struct nd_defrouter *dr, *n; 72082cd038dSYoshinobu Inoue int s = splnet(); 72182cd038dSYoshinobu Inoue 72282cd038dSYoshinobu Inoue if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 72382cd038dSYoshinobu Inoue /* entry exists */ 72482cd038dSYoshinobu Inoue if (new->rtlifetime == 0) { 72582cd038dSYoshinobu Inoue defrtrlist_del(dr); 72682cd038dSYoshinobu Inoue dr = NULL; 72782cd038dSYoshinobu Inoue } else { 72882cd038dSYoshinobu Inoue /* override */ 72982cd038dSYoshinobu Inoue dr->flags = new->flags; /* xxx flag check */ 73082cd038dSYoshinobu Inoue dr->rtlifetime = new->rtlifetime; 73182cd038dSYoshinobu Inoue dr->expire = new->expire; 73282cd038dSYoshinobu Inoue } 73382cd038dSYoshinobu Inoue splx(s); 73482cd038dSYoshinobu Inoue return(dr); 73582cd038dSYoshinobu Inoue } 73682cd038dSYoshinobu Inoue 73782cd038dSYoshinobu Inoue /* entry does not exist */ 73882cd038dSYoshinobu Inoue if (new->rtlifetime == 0) { 73982cd038dSYoshinobu Inoue splx(s); 74082cd038dSYoshinobu Inoue return(NULL); 74182cd038dSYoshinobu Inoue } 74282cd038dSYoshinobu Inoue 74382cd038dSYoshinobu Inoue n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 74482cd038dSYoshinobu Inoue if (n == NULL) { 74582cd038dSYoshinobu Inoue splx(s); 74682cd038dSYoshinobu Inoue return(NULL); 74782cd038dSYoshinobu Inoue } 74882cd038dSYoshinobu Inoue bzero(n, sizeof(*n)); 74982cd038dSYoshinobu Inoue *n = *new; 750686cdd19SJun-ichiro itojun Hagino 751686cdd19SJun-ichiro itojun Hagino /* 752686cdd19SJun-ichiro itojun Hagino * Insert the new router at the end of the Default Router List. 753686cdd19SJun-ichiro itojun Hagino * If there is no other router, install it anyway. Otherwise, 754686cdd19SJun-ichiro itojun Hagino * just continue to use the current default router. 755686cdd19SJun-ichiro itojun Hagino */ 756686cdd19SJun-ichiro itojun Hagino TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry); 757686cdd19SJun-ichiro itojun Hagino if (TAILQ_FIRST(&nd_defrouter) == n) 758686cdd19SJun-ichiro itojun Hagino defrouter_select(); 75982cd038dSYoshinobu Inoue splx(s); 76082cd038dSYoshinobu Inoue 76182cd038dSYoshinobu Inoue return(n); 76282cd038dSYoshinobu Inoue } 76382cd038dSYoshinobu Inoue 76482cd038dSYoshinobu Inoue static struct nd_pfxrouter * 76582cd038dSYoshinobu Inoue pfxrtr_lookup(pr, dr) 76682cd038dSYoshinobu Inoue struct nd_prefix *pr; 76782cd038dSYoshinobu Inoue struct nd_defrouter *dr; 76882cd038dSYoshinobu Inoue { 76982cd038dSYoshinobu Inoue struct nd_pfxrouter *search; 77082cd038dSYoshinobu Inoue 771686cdd19SJun-ichiro itojun Hagino for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { 77282cd038dSYoshinobu Inoue if (search->router == dr) 77382cd038dSYoshinobu Inoue break; 77482cd038dSYoshinobu Inoue } 77582cd038dSYoshinobu Inoue 77682cd038dSYoshinobu Inoue return(search); 77782cd038dSYoshinobu Inoue } 77882cd038dSYoshinobu Inoue 77982cd038dSYoshinobu Inoue static void 78082cd038dSYoshinobu Inoue pfxrtr_add(pr, dr) 78182cd038dSYoshinobu Inoue struct nd_prefix *pr; 78282cd038dSYoshinobu Inoue struct nd_defrouter *dr; 78382cd038dSYoshinobu Inoue { 78482cd038dSYoshinobu Inoue struct nd_pfxrouter *new; 78582cd038dSYoshinobu Inoue 78682cd038dSYoshinobu Inoue new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 78782cd038dSYoshinobu Inoue if (new == NULL) 78882cd038dSYoshinobu Inoue return; 78982cd038dSYoshinobu Inoue bzero(new, sizeof(*new)); 79082cd038dSYoshinobu Inoue new->router = dr; 79182cd038dSYoshinobu Inoue 79282cd038dSYoshinobu Inoue LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 79382cd038dSYoshinobu Inoue 79482cd038dSYoshinobu Inoue pfxlist_onlink_check(); 79582cd038dSYoshinobu Inoue } 79682cd038dSYoshinobu Inoue 79782cd038dSYoshinobu Inoue static void 79882cd038dSYoshinobu Inoue pfxrtr_del(pfr) 79982cd038dSYoshinobu Inoue struct nd_pfxrouter *pfr; 80082cd038dSYoshinobu Inoue { 80182cd038dSYoshinobu Inoue LIST_REMOVE(pfr, pfr_entry); 80282cd038dSYoshinobu Inoue free(pfr, M_IP6NDP); 80382cd038dSYoshinobu Inoue } 80482cd038dSYoshinobu Inoue 80533841545SHajimu UMEMOTO struct nd_prefix * 80633841545SHajimu UMEMOTO nd6_prefix_lookup(pr) 80782cd038dSYoshinobu Inoue struct nd_prefix *pr; 80882cd038dSYoshinobu Inoue { 80982cd038dSYoshinobu Inoue struct nd_prefix *search; 81082cd038dSYoshinobu Inoue 811686cdd19SJun-ichiro itojun Hagino for (search = nd_prefix.lh_first; search; search = search->ndpr_next) { 81282cd038dSYoshinobu Inoue if (pr->ndpr_ifp == search->ndpr_ifp && 81382cd038dSYoshinobu Inoue pr->ndpr_plen == search->ndpr_plen && 81482cd038dSYoshinobu Inoue in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 81582cd038dSYoshinobu Inoue &search->ndpr_prefix.sin6_addr, 81682cd038dSYoshinobu Inoue pr->ndpr_plen) 81782cd038dSYoshinobu Inoue ) { 81882cd038dSYoshinobu Inoue break; 81982cd038dSYoshinobu Inoue } 82082cd038dSYoshinobu Inoue } 82182cd038dSYoshinobu Inoue 82282cd038dSYoshinobu Inoue return(search); 82382cd038dSYoshinobu Inoue } 82482cd038dSYoshinobu Inoue 82533841545SHajimu UMEMOTO int 82633841545SHajimu UMEMOTO nd6_prelist_add(pr, dr, newp) 82733841545SHajimu UMEMOTO struct nd_prefix *pr, **newp; 82882cd038dSYoshinobu Inoue struct nd_defrouter *dr; 82982cd038dSYoshinobu Inoue { 83033841545SHajimu UMEMOTO struct nd_prefix *new = NULL; 83182cd038dSYoshinobu Inoue int i, s; 83282cd038dSYoshinobu Inoue 83382cd038dSYoshinobu Inoue new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 83482cd038dSYoshinobu Inoue if (new == NULL) 83582cd038dSYoshinobu Inoue return ENOMEM; 83682cd038dSYoshinobu Inoue bzero(new, sizeof(*new)); 83782cd038dSYoshinobu Inoue *new = *pr; 83833841545SHajimu UMEMOTO if (newp != NULL) 83933841545SHajimu UMEMOTO *newp = new; 84082cd038dSYoshinobu Inoue 84182cd038dSYoshinobu Inoue /* initilization */ 84282cd038dSYoshinobu Inoue LIST_INIT(&new->ndpr_advrtrs); 84382cd038dSYoshinobu Inoue in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 84482cd038dSYoshinobu Inoue /* make prefix in the canonical form */ 84582cd038dSYoshinobu Inoue for (i = 0; i < 4; i++) 84682cd038dSYoshinobu Inoue new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 84782cd038dSYoshinobu Inoue new->ndpr_mask.s6_addr32[i]; 84882cd038dSYoshinobu Inoue 84982cd038dSYoshinobu Inoue s = splnet(); 85082cd038dSYoshinobu Inoue /* link ndpr_entry to nd_prefix list */ 85182cd038dSYoshinobu Inoue LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry); 85282cd038dSYoshinobu Inoue splx(s); 85382cd038dSYoshinobu Inoue 85433841545SHajimu UMEMOTO /* ND_OPT_PI_FLAG_ONLINK processing */ 85533841545SHajimu UMEMOTO if (new->ndpr_raf_onlink) { 85633841545SHajimu UMEMOTO int e; 85733841545SHajimu UMEMOTO 85833841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(new)) != 0) { 85933841545SHajimu UMEMOTO nd6log((LOG_ERR, "nd6_prelist_add: failed to make " 86033841545SHajimu UMEMOTO "the prefix %s/%d on-link on %s (errno=%d)\n", 86133841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 86233841545SHajimu UMEMOTO pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 86333841545SHajimu UMEMOTO /* proceed anyway. XXX: is it correct? */ 86433841545SHajimu UMEMOTO } 86533841545SHajimu UMEMOTO } 86633841545SHajimu UMEMOTO 867686cdd19SJun-ichiro itojun Hagino if (dr) { 86882cd038dSYoshinobu Inoue pfxrtr_add(new, dr); 869686cdd19SJun-ichiro itojun Hagino } 87082cd038dSYoshinobu Inoue 87182cd038dSYoshinobu Inoue return 0; 87282cd038dSYoshinobu Inoue } 87382cd038dSYoshinobu Inoue 87482cd038dSYoshinobu Inoue void 87582cd038dSYoshinobu Inoue prelist_remove(pr) 87682cd038dSYoshinobu Inoue struct nd_prefix *pr; 87782cd038dSYoshinobu Inoue { 87882cd038dSYoshinobu Inoue struct nd_pfxrouter *pfr, *next; 87933841545SHajimu UMEMOTO int e, s; 88033841545SHajimu UMEMOTO 88133841545SHajimu UMEMOTO /* make sure to invalidate the prefix until it is really freed. */ 88233841545SHajimu UMEMOTO pr->ndpr_vltime = 0; 88333841545SHajimu UMEMOTO pr->ndpr_pltime = 0; 88433841545SHajimu UMEMOTO #if 0 88533841545SHajimu UMEMOTO /* 88633841545SHajimu UMEMOTO * Though these flags are now meaningless, we'd rather keep the value 88733841545SHajimu UMEMOTO * not to confuse users when executing "ndp -p". 88833841545SHajimu UMEMOTO */ 88933841545SHajimu UMEMOTO pr->ndpr_raf_onlink = 0; 89033841545SHajimu UMEMOTO pr->ndpr_raf_auto = 0; 89133841545SHajimu UMEMOTO #endif 89233841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && 89333841545SHajimu UMEMOTO (e = nd6_prefix_offlink(pr)) != 0) { 89433841545SHajimu UMEMOTO nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " 89533841545SHajimu UMEMOTO "on %s, errno=%d\n", 89633841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 89733841545SHajimu UMEMOTO pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 89833841545SHajimu UMEMOTO /* what should we do? */ 89933841545SHajimu UMEMOTO } 90033841545SHajimu UMEMOTO 90133841545SHajimu UMEMOTO if (pr->ndpr_refcnt > 0) 90233841545SHajimu UMEMOTO return; /* notice here? */ 90382cd038dSYoshinobu Inoue 90482cd038dSYoshinobu Inoue s = splnet(); 90533841545SHajimu UMEMOTO 90682cd038dSYoshinobu Inoue /* unlink ndpr_entry from nd_prefix list */ 90782cd038dSYoshinobu Inoue LIST_REMOVE(pr, ndpr_entry); 90882cd038dSYoshinobu Inoue 90982cd038dSYoshinobu Inoue /* free list of routers that adversed the prefix */ 910686cdd19SJun-ichiro itojun Hagino for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { 911686cdd19SJun-ichiro itojun Hagino next = pfr->pfr_next; 91282cd038dSYoshinobu Inoue 91382cd038dSYoshinobu Inoue free(pfr, M_IP6NDP); 91482cd038dSYoshinobu Inoue } 91533841545SHajimu UMEMOTO splx(s); 91633841545SHajimu UMEMOTO 91782cd038dSYoshinobu Inoue free(pr, M_IP6NDP); 91882cd038dSYoshinobu Inoue 91982cd038dSYoshinobu Inoue pfxlist_onlink_check(); 92082cd038dSYoshinobu Inoue } 92182cd038dSYoshinobu Inoue 92282cd038dSYoshinobu Inoue int 92382cd038dSYoshinobu Inoue prelist_update(new, dr, m) 92482cd038dSYoshinobu Inoue struct nd_prefix *new; 92582cd038dSYoshinobu Inoue struct nd_defrouter *dr; /* may be NULL */ 92682cd038dSYoshinobu Inoue struct mbuf *m; 92782cd038dSYoshinobu Inoue { 92833841545SHajimu UMEMOTO struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 92933841545SHajimu UMEMOTO struct ifaddr *ifa; 93033841545SHajimu UMEMOTO struct ifnet *ifp = new->ndpr_ifp; 93182cd038dSYoshinobu Inoue struct nd_prefix *pr; 93282cd038dSYoshinobu Inoue int s = splnet(); 93382cd038dSYoshinobu Inoue int error = 0; 93433841545SHajimu UMEMOTO int newprefix = 0; 93582cd038dSYoshinobu Inoue int auth; 93633841545SHajimu UMEMOTO struct in6_addrlifetime lt6_tmp; 93782cd038dSYoshinobu Inoue 93882cd038dSYoshinobu Inoue auth = 0; 93982cd038dSYoshinobu Inoue if (m) { 94082cd038dSYoshinobu Inoue /* 94182cd038dSYoshinobu Inoue * Authenticity for NA consists authentication for 94282cd038dSYoshinobu Inoue * both IP header and IP datagrams, doesn't it ? 94382cd038dSYoshinobu Inoue */ 94482cd038dSYoshinobu Inoue #if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 94582cd038dSYoshinobu Inoue auth = (m->m_flags & M_AUTHIPHDR 94682cd038dSYoshinobu Inoue && m->m_flags & M_AUTHIPDGM) ? 1 : 0; 94782cd038dSYoshinobu Inoue #endif 94882cd038dSYoshinobu Inoue } 94982cd038dSYoshinobu Inoue 950686cdd19SJun-ichiro itojun Hagino 95133841545SHajimu UMEMOTO if ((pr = nd6_prefix_lookup(new)) != NULL) { 95233841545SHajimu UMEMOTO /* 95333841545SHajimu UMEMOTO * nd6_prefix_lookup() ensures that pr and new have the same 95433841545SHajimu UMEMOTO * prefix on a same interface. 95533841545SHajimu UMEMOTO */ 95633841545SHajimu UMEMOTO 95733841545SHajimu UMEMOTO /* 95833841545SHajimu UMEMOTO * Update prefix information. Note that the on-link (L) bit 95933841545SHajimu UMEMOTO * and the autonomous (A) bit should NOT be changed from 1 96033841545SHajimu UMEMOTO * to 0. 96133841545SHajimu UMEMOTO */ 96233841545SHajimu UMEMOTO if (new->ndpr_raf_onlink == 1) 96333841545SHajimu UMEMOTO pr->ndpr_raf_onlink = 1; 96433841545SHajimu UMEMOTO if (new->ndpr_raf_auto == 1) 96533841545SHajimu UMEMOTO pr->ndpr_raf_auto = 1; 96633841545SHajimu UMEMOTO if (new->ndpr_raf_onlink) { 96782cd038dSYoshinobu Inoue pr->ndpr_vltime = new->ndpr_vltime; 96882cd038dSYoshinobu Inoue pr->ndpr_pltime = new->ndpr_pltime; 96982cd038dSYoshinobu Inoue pr->ndpr_preferred = new->ndpr_preferred; 97082cd038dSYoshinobu Inoue pr->ndpr_expire = new->ndpr_expire; 97182cd038dSYoshinobu Inoue } 97282cd038dSYoshinobu Inoue 97333841545SHajimu UMEMOTO if (new->ndpr_raf_onlink && 97433841545SHajimu UMEMOTO (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 97533841545SHajimu UMEMOTO int e; 97682cd038dSYoshinobu Inoue 97733841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(pr)) != 0) { 97833841545SHajimu UMEMOTO nd6log((LOG_ERR, 97933841545SHajimu UMEMOTO "prelist_update: failed to make " 98033841545SHajimu UMEMOTO "the prefix %s/%d on-link on %s " 98133841545SHajimu UMEMOTO "(errno=%d)\n", 98233841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 98333841545SHajimu UMEMOTO pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 98433841545SHajimu UMEMOTO /* proceed anyway. XXX: is it correct? */ 985686cdd19SJun-ichiro itojun Hagino } 98682cd038dSYoshinobu Inoue } 98782cd038dSYoshinobu Inoue 98882cd038dSYoshinobu Inoue if (dr && pfxrtr_lookup(pr, dr) == NULL) 98982cd038dSYoshinobu Inoue pfxrtr_add(pr, dr); 99082cd038dSYoshinobu Inoue } else { 99133841545SHajimu UMEMOTO struct nd_prefix *newpr = NULL; 99282cd038dSYoshinobu Inoue 99333841545SHajimu UMEMOTO newprefix = 1; 99433841545SHajimu UMEMOTO 99533841545SHajimu UMEMOTO if (new->ndpr_vltime == 0) 99633841545SHajimu UMEMOTO goto end; 99733841545SHajimu UMEMOTO if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 99833841545SHajimu UMEMOTO goto end; 99982cd038dSYoshinobu Inoue 100082cd038dSYoshinobu Inoue bzero(&new->ndpr_addr, sizeof(struct in6_addr)); 100182cd038dSYoshinobu Inoue 100233841545SHajimu UMEMOTO error = nd6_prelist_add(new, dr, &newpr); 100333841545SHajimu UMEMOTO if (error != 0 || newpr == NULL) { 100433841545SHajimu UMEMOTO nd6log((LOG_NOTICE, "prelist_update: " 100533841545SHajimu UMEMOTO "nd6_prelist_add failed for %s/%d on %s " 100633841545SHajimu UMEMOTO "errno=%d, returnpr=%p\n", 100733841545SHajimu UMEMOTO ip6_sprintf(&new->ndpr_prefix.sin6_addr), 100833841545SHajimu UMEMOTO new->ndpr_plen, if_name(new->ndpr_ifp), 100933841545SHajimu UMEMOTO error, newpr)); 101033841545SHajimu UMEMOTO goto end; /* we should just give up in this case. */ 101133841545SHajimu UMEMOTO } 101233841545SHajimu UMEMOTO 101382cd038dSYoshinobu Inoue /* 101433841545SHajimu UMEMOTO * XXX: from the ND point of view, we can ignore a prefix 101533841545SHajimu UMEMOTO * with the on-link bit being zero. However, we need a 101633841545SHajimu UMEMOTO * prefix structure for references from autoconfigured 101733841545SHajimu UMEMOTO * addresses. Thus, we explicitly make suret that the prefix 101833841545SHajimu UMEMOTO * itself expires now. 101982cd038dSYoshinobu Inoue */ 102033841545SHajimu UMEMOTO if (newpr->ndpr_raf_onlink == 0) { 102133841545SHajimu UMEMOTO newpr->ndpr_vltime = 0; 102233841545SHajimu UMEMOTO newpr->ndpr_pltime = 0; 102333841545SHajimu UMEMOTO in6_init_prefix_ltimes(newpr); 102433841545SHajimu UMEMOTO } 102533841545SHajimu UMEMOTO 102633841545SHajimu UMEMOTO pr = newpr; 102733841545SHajimu UMEMOTO } 102833841545SHajimu UMEMOTO 102933841545SHajimu UMEMOTO /* 103033841545SHajimu UMEMOTO * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 103133841545SHajimu UMEMOTO * Note that pr must be non NULL at this point. 103233841545SHajimu UMEMOTO */ 103333841545SHajimu UMEMOTO 103433841545SHajimu UMEMOTO /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 103582cd038dSYoshinobu Inoue if (!new->ndpr_raf_auto) 103633841545SHajimu UMEMOTO goto afteraddrconf; 103782cd038dSYoshinobu Inoue 103833841545SHajimu UMEMOTO /* 103933841545SHajimu UMEMOTO * 5.5.3 (b). the link-local prefix should have been ignored in 104033841545SHajimu UMEMOTO * nd6_ra_input. 104133841545SHajimu UMEMOTO */ 104233841545SHajimu UMEMOTO 104333841545SHajimu UMEMOTO /* 104433841545SHajimu UMEMOTO * 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. 104533841545SHajimu UMEMOTO * This should have been done in nd6_ra_input. 104633841545SHajimu UMEMOTO */ 104733841545SHajimu UMEMOTO 104833841545SHajimu UMEMOTO /* 104933841545SHajimu UMEMOTO * 5.5.3 (d). If the prefix advertised does not match the prefix of an 105033841545SHajimu UMEMOTO * address already in the list, and the Valid Lifetime is not 0, 105133841545SHajimu UMEMOTO * form an address. Note that even a manually configured address 105233841545SHajimu UMEMOTO * should reject autoconfiguration of a new address. 105333841545SHajimu UMEMOTO */ 105433841545SHajimu UMEMOTO TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 105533841545SHajimu UMEMOTO { 105633841545SHajimu UMEMOTO struct in6_ifaddr *ifa6; 105733841545SHajimu UMEMOTO int ifa_plen; 105833841545SHajimu UMEMOTO u_int32_t storedlifetime; 105933841545SHajimu UMEMOTO 106033841545SHajimu UMEMOTO if (ifa->ifa_addr->sa_family != AF_INET6) 106133841545SHajimu UMEMOTO continue; 106233841545SHajimu UMEMOTO 106333841545SHajimu UMEMOTO ifa6 = (struct in6_ifaddr *)ifa; 106433841545SHajimu UMEMOTO 106533841545SHajimu UMEMOTO /* 106633841545SHajimu UMEMOTO * Spec is not clear here, but I believe we should concentrate 106733841545SHajimu UMEMOTO * on unicast (i.e. not anycast) addresses. 106833841545SHajimu UMEMOTO * XXX: other ia6_flags? detached or duplicated? 106933841545SHajimu UMEMOTO */ 107033841545SHajimu UMEMOTO if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 107133841545SHajimu UMEMOTO continue; 107233841545SHajimu UMEMOTO 107333841545SHajimu UMEMOTO ifa_plen = in6_mask2len(&ifa6->ia_prefixmask.sin6_addr, NULL); 107433841545SHajimu UMEMOTO if (ifa_plen != new->ndpr_plen || 107533841545SHajimu UMEMOTO !in6_are_prefix_equal(&ifa6->ia_addr.sin6_addr, 107633841545SHajimu UMEMOTO &new->ndpr_prefix.sin6_addr, 107733841545SHajimu UMEMOTO ifa_plen)) 107833841545SHajimu UMEMOTO continue; 107933841545SHajimu UMEMOTO 108033841545SHajimu UMEMOTO if (ia6_match == NULL) /* remember the first one */ 108133841545SHajimu UMEMOTO ia6_match = ifa6; 108233841545SHajimu UMEMOTO 108333841545SHajimu UMEMOTO if ((ifa6->ia6_flags & IN6_IFF_AUTOCONF) == 0) 108433841545SHajimu UMEMOTO continue; 108533841545SHajimu UMEMOTO 108633841545SHajimu UMEMOTO /* 108733841545SHajimu UMEMOTO * An already autoconfigured address matched. Now that we 108833841545SHajimu UMEMOTO * are sure there is at least one matched address, we can 108933841545SHajimu UMEMOTO * proceed to 5.5.3. (e): update the lifetimes according to the 109033841545SHajimu UMEMOTO * "two hours" rule and the privacy extension. 109133841545SHajimu UMEMOTO */ 109233841545SHajimu UMEMOTO #define TWOHOUR (120*60) 109333841545SHajimu UMEMOTO lt6_tmp = ifa6->ia6_lifetime; 109433841545SHajimu UMEMOTO 109511f3a6e2SHajimu UMEMOTO if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 109611f3a6e2SHajimu UMEMOTO storedlifetime = ND6_INFINITE_LIFETIME; 109711f3a6e2SHajimu UMEMOTO else if (IFA6_IS_INVALID(ifa6)) 109811f3a6e2SHajimu UMEMOTO storedlifetime = 0; 109911f3a6e2SHajimu UMEMOTO else 110011f3a6e2SHajimu UMEMOTO storedlifetime = lt6_tmp.ia6t_expire - time_second; 110111f3a6e2SHajimu UMEMOTO 110211f3a6e2SHajimu UMEMOTO /* when not updating, keep the current stored lifetime. */ 110311f3a6e2SHajimu UMEMOTO lt6_tmp.ia6t_vltime = storedlifetime; 110433841545SHajimu UMEMOTO 110533841545SHajimu UMEMOTO if (TWOHOUR < new->ndpr_vltime || 110633841545SHajimu UMEMOTO storedlifetime < new->ndpr_vltime) { 110733841545SHajimu UMEMOTO lt6_tmp.ia6t_vltime = new->ndpr_vltime; 110833841545SHajimu UMEMOTO } else if (storedlifetime <= TWOHOUR 110933841545SHajimu UMEMOTO #if 0 111033841545SHajimu UMEMOTO /* 111133841545SHajimu UMEMOTO * This condition is logically redundant, so we just 111233841545SHajimu UMEMOTO * omit it. 111333841545SHajimu UMEMOTO * See IPng 6712, 6717, and 6721. 111433841545SHajimu UMEMOTO */ 111533841545SHajimu UMEMOTO && new->ndpr_vltime <= storedlifetime 111633841545SHajimu UMEMOTO #endif 111733841545SHajimu UMEMOTO ) { 111833841545SHajimu UMEMOTO if (auth) { 111933841545SHajimu UMEMOTO lt6_tmp.ia6t_vltime = new->ndpr_vltime; 112082cd038dSYoshinobu Inoue } 112133841545SHajimu UMEMOTO } else { 112233841545SHajimu UMEMOTO /* 112333841545SHajimu UMEMOTO * new->ndpr_vltime <= TWOHOUR && 112433841545SHajimu UMEMOTO * TWOHOUR < storedlifetime 112533841545SHajimu UMEMOTO */ 112633841545SHajimu UMEMOTO lt6_tmp.ia6t_vltime = TWOHOUR; 112782cd038dSYoshinobu Inoue } 112882cd038dSYoshinobu Inoue 112933841545SHajimu UMEMOTO /* The 2 hour rule is not imposed for preferred lifetime. */ 113033841545SHajimu UMEMOTO lt6_tmp.ia6t_pltime = new->ndpr_pltime; 113133841545SHajimu UMEMOTO 113233841545SHajimu UMEMOTO in6_init_address_ltimes(pr, <6_tmp); 113333841545SHajimu UMEMOTO 113433841545SHajimu UMEMOTO /* 113533841545SHajimu UMEMOTO * When adjusting the lifetimes of an existing temporary 113633841545SHajimu UMEMOTO * address, only lower the lifetimes. 113733841545SHajimu UMEMOTO * RFC 3041 3.3. (1). 113833841545SHajimu UMEMOTO * XXX: how should we modify ia6t_[pv]ltime? 113933841545SHajimu UMEMOTO */ 114033841545SHajimu UMEMOTO if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 114133841545SHajimu UMEMOTO if (lt6_tmp.ia6t_expire == 0 || /* no expire */ 114233841545SHajimu UMEMOTO lt6_tmp.ia6t_expire > 114333841545SHajimu UMEMOTO ifa6->ia6_lifetime.ia6t_expire) { 114433841545SHajimu UMEMOTO lt6_tmp.ia6t_expire = 114533841545SHajimu UMEMOTO ifa6->ia6_lifetime.ia6t_expire; 114633841545SHajimu UMEMOTO } 114733841545SHajimu UMEMOTO if (lt6_tmp.ia6t_preferred == 0 || /* no expire */ 114833841545SHajimu UMEMOTO lt6_tmp.ia6t_preferred > 114933841545SHajimu UMEMOTO ifa6->ia6_lifetime.ia6t_preferred) { 115033841545SHajimu UMEMOTO lt6_tmp.ia6t_preferred = 115133841545SHajimu UMEMOTO ifa6->ia6_lifetime.ia6t_preferred; 115233841545SHajimu UMEMOTO } 115333841545SHajimu UMEMOTO } 115433841545SHajimu UMEMOTO 115533841545SHajimu UMEMOTO ifa6->ia6_lifetime = lt6_tmp; 115633841545SHajimu UMEMOTO } 115733841545SHajimu UMEMOTO if (ia6_match == NULL && new->ndpr_vltime) { 115833841545SHajimu UMEMOTO /* 115933841545SHajimu UMEMOTO * No address matched and the valid lifetime is non-zero. 116033841545SHajimu UMEMOTO * Create a new address. 116133841545SHajimu UMEMOTO */ 116233841545SHajimu UMEMOTO if ((ia6 = in6_ifadd(new, NULL)) != NULL) { 116333841545SHajimu UMEMOTO /* 116433841545SHajimu UMEMOTO * note that we should use pr (not new) for reference. 116533841545SHajimu UMEMOTO */ 116633841545SHajimu UMEMOTO pr->ndpr_refcnt++; 116733841545SHajimu UMEMOTO ia6->ia6_ndpr = pr; 116833841545SHajimu UMEMOTO 116933841545SHajimu UMEMOTO #if 0 117033841545SHajimu UMEMOTO /* XXXYYY Don't do this, according to Jinmei. */ 117133841545SHajimu UMEMOTO pr->ndpr_addr = new->ndpr_addr; 117233841545SHajimu UMEMOTO #endif 117333841545SHajimu UMEMOTO 117433841545SHajimu UMEMOTO /* 117533841545SHajimu UMEMOTO * RFC 3041 3.3 (2). 117633841545SHajimu UMEMOTO * When a new public address is created as described 117733841545SHajimu UMEMOTO * in RFC2462, also create a new temporary address. 117833841545SHajimu UMEMOTO * 117933841545SHajimu UMEMOTO * RFC 3041 3.5. 118033841545SHajimu UMEMOTO * When an interface connects to a new link, a new 118133841545SHajimu UMEMOTO * randomized interface identifier should be generated 118233841545SHajimu UMEMOTO * immediately together with a new set of temporary 118333841545SHajimu UMEMOTO * addresses. Thus, we specifiy 1 as the 2nd arg of 118433841545SHajimu UMEMOTO * in6_tmpifadd(). 118533841545SHajimu UMEMOTO */ 118633841545SHajimu UMEMOTO if (ip6_use_tempaddr) { 118733841545SHajimu UMEMOTO int e; 118833841545SHajimu UMEMOTO if ((e = in6_tmpifadd(ia6, 1)) != 0) { 118933841545SHajimu UMEMOTO nd6log((LOG_NOTICE, "prelist_update: " 119033841545SHajimu UMEMOTO "failed to create a temporary " 119133841545SHajimu UMEMOTO "address, errno=%d\n", 119233841545SHajimu UMEMOTO e)); 119333841545SHajimu UMEMOTO } 119433841545SHajimu UMEMOTO } 119533841545SHajimu UMEMOTO 119633841545SHajimu UMEMOTO /* 119733841545SHajimu UMEMOTO * A newly added address might affect the status 119833841545SHajimu UMEMOTO * of other addresses, so we check and update it. 119933841545SHajimu UMEMOTO * XXX: what if address duplication happens? 120033841545SHajimu UMEMOTO */ 120133841545SHajimu UMEMOTO pfxlist_onlink_check(); 120233841545SHajimu UMEMOTO } else { 120333841545SHajimu UMEMOTO /* just set an error. do not bark here. */ 120433841545SHajimu UMEMOTO error = EADDRNOTAVAIL; /* XXX: might be unused. */ 120533841545SHajimu UMEMOTO } 120633841545SHajimu UMEMOTO } 120733841545SHajimu UMEMOTO 120833841545SHajimu UMEMOTO afteraddrconf: 120933841545SHajimu UMEMOTO 121082cd038dSYoshinobu Inoue end: 121182cd038dSYoshinobu Inoue splx(s); 121282cd038dSYoshinobu Inoue return error; 121382cd038dSYoshinobu Inoue } 121482cd038dSYoshinobu Inoue 121582cd038dSYoshinobu Inoue /* 1216686cdd19SJun-ichiro itojun Hagino * A supplement function used in the on-link detection below; 1217686cdd19SJun-ichiro itojun Hagino * detect if a given prefix has a (probably) reachable advertising router. 1218686cdd19SJun-ichiro itojun Hagino * XXX: lengthy function name... 1219686cdd19SJun-ichiro itojun Hagino */ 122033841545SHajimu UMEMOTO static struct nd_pfxrouter * 1221686cdd19SJun-ichiro itojun Hagino find_pfxlist_reachable_router(pr) 1222686cdd19SJun-ichiro itojun Hagino struct nd_prefix *pr; 1223686cdd19SJun-ichiro itojun Hagino { 1224686cdd19SJun-ichiro itojun Hagino struct nd_pfxrouter *pfxrtr; 1225686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 1226686cdd19SJun-ichiro itojun Hagino struct llinfo_nd6 *ln; 1227686cdd19SJun-ichiro itojun Hagino 1228686cdd19SJun-ichiro itojun Hagino for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr; 1229686cdd19SJun-ichiro itojun Hagino pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { 1230686cdd19SJun-ichiro itojun Hagino if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0, 1231686cdd19SJun-ichiro itojun Hagino pfxrtr->router->ifp)) && 1232686cdd19SJun-ichiro itojun Hagino (ln = (struct llinfo_nd6 *)rt->rt_llinfo) && 1233686cdd19SJun-ichiro itojun Hagino ND6_IS_LLINFO_PROBREACH(ln)) 1234686cdd19SJun-ichiro itojun Hagino break; /* found */ 1235686cdd19SJun-ichiro itojun Hagino } 1236686cdd19SJun-ichiro itojun Hagino 1237686cdd19SJun-ichiro itojun Hagino return(pfxrtr); 1238686cdd19SJun-ichiro itojun Hagino 1239686cdd19SJun-ichiro itojun Hagino } 1240686cdd19SJun-ichiro itojun Hagino 1241686cdd19SJun-ichiro itojun Hagino /* 124282cd038dSYoshinobu Inoue * Check if each prefix in the prefix list has at least one available router 124333841545SHajimu UMEMOTO * that advertised the prefix (a router is "available" if its neighbor cache 124433841545SHajimu UMEMOTO * entry is reachable or probably reachable). 1245686cdd19SJun-ichiro itojun Hagino * If the check fails, the prefix may be off-link, because, for example, 124682cd038dSYoshinobu Inoue * we have moved from the network but the lifetime of the prefix has not 124733841545SHajimu UMEMOTO * expired yet. So we should not use the prefix if there is another prefix 124833841545SHajimu UMEMOTO * that has an available router. 124933841545SHajimu UMEMOTO * But, if there is no prefix that has an available router, we still regards 125082cd038dSYoshinobu Inoue * all the prefixes as on-link. This is because we can't tell if all the 125182cd038dSYoshinobu Inoue * routers are simply dead or if we really moved from the network and there 125282cd038dSYoshinobu Inoue * is no router around us. 125382cd038dSYoshinobu Inoue */ 1254686cdd19SJun-ichiro itojun Hagino void 125582cd038dSYoshinobu Inoue pfxlist_onlink_check() 125682cd038dSYoshinobu Inoue { 125782cd038dSYoshinobu Inoue struct nd_prefix *pr; 125833841545SHajimu UMEMOTO struct in6_ifaddr *ifa; 125982cd038dSYoshinobu Inoue 1260686cdd19SJun-ichiro itojun Hagino /* 1261686cdd19SJun-ichiro itojun Hagino * Check if there is a prefix that has a reachable advertising 1262686cdd19SJun-ichiro itojun Hagino * router. 1263686cdd19SJun-ichiro itojun Hagino */ 1264686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 126533841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 126682cd038dSYoshinobu Inoue break; 1267686cdd19SJun-ichiro itojun Hagino } 126882cd038dSYoshinobu Inoue 126982cd038dSYoshinobu Inoue if (pr) { 127082cd038dSYoshinobu Inoue /* 1271686cdd19SJun-ichiro itojun Hagino * There is at least one prefix that has a reachable router. 127233841545SHajimu UMEMOTO * Detach prefixes which have no reachable advertising 127333841545SHajimu UMEMOTO * router, and attach other prefixes. 127482cd038dSYoshinobu Inoue */ 1275686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 127633841545SHajimu UMEMOTO /* XXX: a link-local prefix should never be detached */ 127733841545SHajimu UMEMOTO if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 127833841545SHajimu UMEMOTO continue; 127933841545SHajimu UMEMOTO 128033841545SHajimu UMEMOTO /* 128133841545SHajimu UMEMOTO * we aren't interested in prefixes without the L bit 128233841545SHajimu UMEMOTO * set. 128333841545SHajimu UMEMOTO */ 128433841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink == 0) 128533841545SHajimu UMEMOTO continue; 128633841545SHajimu UMEMOTO 128733841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 128833841545SHajimu UMEMOTO find_pfxlist_reachable_router(pr) == NULL) 128933841545SHajimu UMEMOTO pr->ndpr_stateflags |= NDPRF_DETACHED; 129033841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 129133841545SHajimu UMEMOTO find_pfxlist_reachable_router(pr) != 0) 129233841545SHajimu UMEMOTO pr->ndpr_stateflags &= ~NDPRF_DETACHED; 129382cd038dSYoshinobu Inoue } 129433841545SHajimu UMEMOTO } else { 129533841545SHajimu UMEMOTO /* there is no prefix that has a reachable router */ 1296686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 129733841545SHajimu UMEMOTO if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 129833841545SHajimu UMEMOTO continue; 129933841545SHajimu UMEMOTO 130033841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink == 0) 130133841545SHajimu UMEMOTO continue; 130233841545SHajimu UMEMOTO 130333841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 130433841545SHajimu UMEMOTO pr->ndpr_stateflags &= ~NDPRF_DETACHED; 130533841545SHajimu UMEMOTO } 130633841545SHajimu UMEMOTO } 130733841545SHajimu UMEMOTO 130833841545SHajimu UMEMOTO /* 130933841545SHajimu UMEMOTO * Remove each interface route associated with a (just) detached 131033841545SHajimu UMEMOTO * prefix, and reinstall the interface route for a (just) attached 131133841545SHajimu UMEMOTO * prefix. Note that all attempt of reinstallation does not 131233841545SHajimu UMEMOTO * necessarily success, when a same prefix is shared among multiple 131333841545SHajimu UMEMOTO * interfaces. Such cases will be handled in nd6_prefix_onlink, 131433841545SHajimu UMEMOTO * so we don't have to care about them. 131533841545SHajimu UMEMOTO */ 131633841545SHajimu UMEMOTO for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 131733841545SHajimu UMEMOTO int e; 131833841545SHajimu UMEMOTO 131933841545SHajimu UMEMOTO if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 132033841545SHajimu UMEMOTO continue; 132133841545SHajimu UMEMOTO 132233841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink == 0) 132333841545SHajimu UMEMOTO continue; 132433841545SHajimu UMEMOTO 132533841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 132633841545SHajimu UMEMOTO (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 132733841545SHajimu UMEMOTO if ((e = nd6_prefix_offlink(pr)) != 0) { 132833841545SHajimu UMEMOTO nd6log((LOG_ERR, 132933841545SHajimu UMEMOTO "pfxlist_onlink_check: failed to " 133033841545SHajimu UMEMOTO "make %s/%d offlink, errno=%d\n", 133133841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 133233841545SHajimu UMEMOTO pr->ndpr_plen, e)); 133333841545SHajimu UMEMOTO } 133433841545SHajimu UMEMOTO } 133533841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 133633841545SHajimu UMEMOTO (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 133733841545SHajimu UMEMOTO pr->ndpr_raf_onlink) { 133833841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(pr)) != 0) { 133933841545SHajimu UMEMOTO nd6log((LOG_ERR, 134033841545SHajimu UMEMOTO "pfxlist_onlink_check: failed to " 134133841545SHajimu UMEMOTO "make %s/%d offlink, errno=%d\n", 134233841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 134333841545SHajimu UMEMOTO pr->ndpr_plen, e)); 134433841545SHajimu UMEMOTO } 134533841545SHajimu UMEMOTO } 134633841545SHajimu UMEMOTO } 134733841545SHajimu UMEMOTO 134833841545SHajimu UMEMOTO /* 134933841545SHajimu UMEMOTO * Changes on the prefix status might affect address status as well. 135033841545SHajimu UMEMOTO * Make sure that all addresses derived from an attached prefix are 135133841545SHajimu UMEMOTO * attached, and that all addresses derived from a detached prefix are 135233841545SHajimu UMEMOTO * detached. Note, however, that a manually configured address should 135333841545SHajimu UMEMOTO * always be attached. 135433841545SHajimu UMEMOTO * The precise detection logic is same as the one for prefixes. 135533841545SHajimu UMEMOTO */ 135633841545SHajimu UMEMOTO for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 135733841545SHajimu UMEMOTO if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 135833841545SHajimu UMEMOTO continue; 135933841545SHajimu UMEMOTO 136033841545SHajimu UMEMOTO if (ifa->ia6_ndpr == NULL) { 136133841545SHajimu UMEMOTO /* 136233841545SHajimu UMEMOTO * This can happen when we first configure the address 136333841545SHajimu UMEMOTO * (i.e. the address exists, but the prefix does not). 136433841545SHajimu UMEMOTO * XXX: complicated relationships... 136533841545SHajimu UMEMOTO */ 136633841545SHajimu UMEMOTO continue; 136733841545SHajimu UMEMOTO } 136833841545SHajimu UMEMOTO 136933841545SHajimu UMEMOTO if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 137033841545SHajimu UMEMOTO break; 137133841545SHajimu UMEMOTO } 137233841545SHajimu UMEMOTO if (ifa) { 137333841545SHajimu UMEMOTO for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 137433841545SHajimu UMEMOTO if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 137533841545SHajimu UMEMOTO continue; 137633841545SHajimu UMEMOTO 137733841545SHajimu UMEMOTO if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 137833841545SHajimu UMEMOTO continue; 137933841545SHajimu UMEMOTO 138033841545SHajimu UMEMOTO if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 138133841545SHajimu UMEMOTO ifa->ia6_flags &= ~IN6_IFF_DETACHED; 138233841545SHajimu UMEMOTO else 138333841545SHajimu UMEMOTO ifa->ia6_flags |= IN6_IFF_DETACHED; 138482cd038dSYoshinobu Inoue } 1385686cdd19SJun-ichiro itojun Hagino } 1386686cdd19SJun-ichiro itojun Hagino else { 138733841545SHajimu UMEMOTO for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) { 138833841545SHajimu UMEMOTO if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 138933841545SHajimu UMEMOTO continue; 139033841545SHajimu UMEMOTO 139133841545SHajimu UMEMOTO ifa->ia6_flags &= ~IN6_IFF_DETACHED; 139233841545SHajimu UMEMOTO } 139382cd038dSYoshinobu Inoue } 139482cd038dSYoshinobu Inoue } 139582cd038dSYoshinobu Inoue 139633841545SHajimu UMEMOTO int 139733841545SHajimu UMEMOTO nd6_prefix_onlink(pr) 139882cd038dSYoshinobu Inoue struct nd_prefix *pr; 139982cd038dSYoshinobu Inoue { 140033841545SHajimu UMEMOTO struct ifaddr *ifa; 140133841545SHajimu UMEMOTO struct ifnet *ifp = pr->ndpr_ifp; 140233841545SHajimu UMEMOTO struct sockaddr_in6 mask6; 140333841545SHajimu UMEMOTO struct nd_prefix *opr; 140433841545SHajimu UMEMOTO u_long rtflags; 140533841545SHajimu UMEMOTO int error = 0; 140633841545SHajimu UMEMOTO struct rtentry *rt = NULL; 140733841545SHajimu UMEMOTO 140833841545SHajimu UMEMOTO /* sanity check */ 140933841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 141033841545SHajimu UMEMOTO nd6log((LOG_ERR, 141133841545SHajimu UMEMOTO "nd6_prefix_onlink: %s/%d is already on-link\n", 141233841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen); 141333841545SHajimu UMEMOTO return(EEXIST)); 141433841545SHajimu UMEMOTO } 141582cd038dSYoshinobu Inoue 141682cd038dSYoshinobu Inoue /* 141733841545SHajimu UMEMOTO * Add the interface route associated with the prefix. Before 141833841545SHajimu UMEMOTO * installing the route, check if there's the same prefix on another 141933841545SHajimu UMEMOTO * interface, and the prefix has already installed the interface route. 142033841545SHajimu UMEMOTO * Although such a configuration is expected to be rare, we explicitly 142133841545SHajimu UMEMOTO * allow it. 142282cd038dSYoshinobu Inoue */ 142333841545SHajimu UMEMOTO for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 142433841545SHajimu UMEMOTO if (opr == pr) 142533841545SHajimu UMEMOTO continue; 142633841545SHajimu UMEMOTO 142733841545SHajimu UMEMOTO if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 142833841545SHajimu UMEMOTO continue; 142933841545SHajimu UMEMOTO 143033841545SHajimu UMEMOTO if (opr->ndpr_plen == pr->ndpr_plen && 143133841545SHajimu UMEMOTO in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 143233841545SHajimu UMEMOTO &opr->ndpr_prefix.sin6_addr, 143333841545SHajimu UMEMOTO pr->ndpr_plen)) 143433841545SHajimu UMEMOTO return(0); 143533841545SHajimu UMEMOTO } 143633841545SHajimu UMEMOTO 143733841545SHajimu UMEMOTO /* 143833841545SHajimu UMEMOTO * We prefer link-local addresses as the associated interface address. 143933841545SHajimu UMEMOTO */ 144033841545SHajimu UMEMOTO /* search for a link-local addr */ 144133841545SHajimu UMEMOTO ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 144233841545SHajimu UMEMOTO IN6_IFF_NOTREADY| 144333841545SHajimu UMEMOTO IN6_IFF_ANYCAST); 144433841545SHajimu UMEMOTO if (ifa == NULL) { 144533841545SHajimu UMEMOTO /* XXX: freebsd does not have ifa_ifwithaf */ 144633841545SHajimu UMEMOTO TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) 144733841545SHajimu UMEMOTO { 144833841545SHajimu UMEMOTO if (ifa->ifa_addr->sa_family == AF_INET6) 144933841545SHajimu UMEMOTO break; 145033841545SHajimu UMEMOTO } 145133841545SHajimu UMEMOTO /* should we care about ia6_flags? */ 145233841545SHajimu UMEMOTO } 145333841545SHajimu UMEMOTO if (ifa == NULL) { 145433841545SHajimu UMEMOTO /* 145533841545SHajimu UMEMOTO * This can still happen, when, for example, we receive an RA 145633841545SHajimu UMEMOTO * containing a prefix with the L bit set and the A bit clear, 145733841545SHajimu UMEMOTO * after removing all IPv6 addresses on the receiving 145833841545SHajimu UMEMOTO * interface. This should, of course, be rare though. 145933841545SHajimu UMEMOTO */ 146033841545SHajimu UMEMOTO nd6log((LOG_NOTICE, 146133841545SHajimu UMEMOTO "nd6_prefix_onlink: failed to find any ifaddr" 146233841545SHajimu UMEMOTO " to add route for a prefix(%s/%d) on %s\n", 146333841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 146433841545SHajimu UMEMOTO pr->ndpr_plen, if_name(ifp))); 146533841545SHajimu UMEMOTO return(0); 146633841545SHajimu UMEMOTO } 146733841545SHajimu UMEMOTO 146833841545SHajimu UMEMOTO /* 146933841545SHajimu UMEMOTO * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 147033841545SHajimu UMEMOTO * ifa->ifa_rtrequest = nd6_rtrequest; 147133841545SHajimu UMEMOTO */ 147233841545SHajimu UMEMOTO bzero(&mask6, sizeof(mask6)); 147333841545SHajimu UMEMOTO mask6.sin6_len = sizeof(mask6); 147433841545SHajimu UMEMOTO mask6.sin6_addr = pr->ndpr_mask; 147533841545SHajimu UMEMOTO rtflags = ifa->ifa_flags | RTF_CLONING | RTF_UP; 147633841545SHajimu UMEMOTO if (nd6_need_cache(ifp)) { 147733841545SHajimu UMEMOTO /* explicitly set in case ifa_flags does not set the flag. */ 147833841545SHajimu UMEMOTO rtflags |= RTF_CLONING; 147933841545SHajimu UMEMOTO } else { 148033841545SHajimu UMEMOTO /* 148133841545SHajimu UMEMOTO * explicitly clear the cloning bit in case ifa_flags sets it. 148233841545SHajimu UMEMOTO */ 148333841545SHajimu UMEMOTO rtflags &= ~RTF_CLONING; 148433841545SHajimu UMEMOTO } 148533841545SHajimu UMEMOTO error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, 148633841545SHajimu UMEMOTO ifa->ifa_addr, (struct sockaddr *)&mask6, 148733841545SHajimu UMEMOTO rtflags, &rt); 148833841545SHajimu UMEMOTO if (error == 0) { 148933841545SHajimu UMEMOTO if (rt != NULL) /* this should be non NULL, though */ 149033841545SHajimu UMEMOTO nd6_rtmsg(RTM_ADD, rt); 149133841545SHajimu UMEMOTO pr->ndpr_stateflags |= NDPRF_ONLINK; 149233841545SHajimu UMEMOTO } 149333841545SHajimu UMEMOTO else { 149433841545SHajimu UMEMOTO nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" 149533841545SHajimu UMEMOTO " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " 149633841545SHajimu UMEMOTO "errno = %d\n", 149733841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), 149833841545SHajimu UMEMOTO pr->ndpr_plen, if_name(ifp), 149933841545SHajimu UMEMOTO ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), 150033841545SHajimu UMEMOTO ip6_sprintf(&mask6.sin6_addr), rtflags, error)); 150133841545SHajimu UMEMOTO } 150233841545SHajimu UMEMOTO 150333841545SHajimu UMEMOTO if (rt != NULL) 150433841545SHajimu UMEMOTO rt->rt_refcnt--; 150533841545SHajimu UMEMOTO 150633841545SHajimu UMEMOTO return(error); 150733841545SHajimu UMEMOTO } 150833841545SHajimu UMEMOTO 150933841545SHajimu UMEMOTO int 151033841545SHajimu UMEMOTO nd6_prefix_offlink(pr) 151133841545SHajimu UMEMOTO struct nd_prefix *pr; 151233841545SHajimu UMEMOTO { 151333841545SHajimu UMEMOTO int error = 0; 151433841545SHajimu UMEMOTO struct ifnet *ifp = pr->ndpr_ifp; 151533841545SHajimu UMEMOTO struct nd_prefix *opr; 151633841545SHajimu UMEMOTO struct sockaddr_in6 sa6, mask6; 151733841545SHajimu UMEMOTO struct rtentry *rt = NULL; 151833841545SHajimu UMEMOTO 151933841545SHajimu UMEMOTO /* sanity check */ 152033841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 152133841545SHajimu UMEMOTO nd6log((LOG_ERR, 152233841545SHajimu UMEMOTO "nd6_prefix_offlink: %s/%d is already off-link\n", 152333841545SHajimu UMEMOTO ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen)); 152433841545SHajimu UMEMOTO return(EEXIST); 152533841545SHajimu UMEMOTO } 152633841545SHajimu UMEMOTO 152782cd038dSYoshinobu Inoue bzero(&sa6, sizeof(sa6)); 152882cd038dSYoshinobu Inoue sa6.sin6_family = AF_INET6; 152982cd038dSYoshinobu Inoue sa6.sin6_len = sizeof(sa6); 153082cd038dSYoshinobu Inoue bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 153182cd038dSYoshinobu Inoue sizeof(struct in6_addr)); 153282cd038dSYoshinobu Inoue bzero(&mask6, sizeof(mask6)); 153382cd038dSYoshinobu Inoue mask6.sin6_family = AF_INET6; 153482cd038dSYoshinobu Inoue mask6.sin6_len = sizeof(sa6); 153582cd038dSYoshinobu Inoue bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 153633841545SHajimu UMEMOTO error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 153733841545SHajimu UMEMOTO (struct sockaddr *)&mask6, 0, &rt); 153833841545SHajimu UMEMOTO if (error == 0) { 153933841545SHajimu UMEMOTO pr->ndpr_stateflags &= ~NDPRF_ONLINK; 154033841545SHajimu UMEMOTO 154133841545SHajimu UMEMOTO /* report the route deletion to the routing socket. */ 154233841545SHajimu UMEMOTO if (rt != NULL) 154333841545SHajimu UMEMOTO nd6_rtmsg(RTM_DELETE, rt); 154433841545SHajimu UMEMOTO 154533841545SHajimu UMEMOTO /* 154633841545SHajimu UMEMOTO * There might be the same prefix on another interface, 154733841545SHajimu UMEMOTO * the prefix which could not be on-link just because we have 154833841545SHajimu UMEMOTO * the interface route (see comments in nd6_prefix_onlink). 154933841545SHajimu UMEMOTO * If there's one, try to make the prefix on-link on the 155033841545SHajimu UMEMOTO * interface. 155133841545SHajimu UMEMOTO */ 155233841545SHajimu UMEMOTO for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 155333841545SHajimu UMEMOTO if (opr == pr) 155433841545SHajimu UMEMOTO continue; 155533841545SHajimu UMEMOTO 155633841545SHajimu UMEMOTO if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 155733841545SHajimu UMEMOTO continue; 155833841545SHajimu UMEMOTO 155933841545SHajimu UMEMOTO /* 156033841545SHajimu UMEMOTO * KAME specific: detached prefixes should not be 156133841545SHajimu UMEMOTO * on-link. 156233841545SHajimu UMEMOTO */ 156333841545SHajimu UMEMOTO if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 156433841545SHajimu UMEMOTO continue; 156533841545SHajimu UMEMOTO 156633841545SHajimu UMEMOTO if (opr->ndpr_plen == pr->ndpr_plen && 156733841545SHajimu UMEMOTO in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 156833841545SHajimu UMEMOTO &opr->ndpr_prefix.sin6_addr, 156933841545SHajimu UMEMOTO pr->ndpr_plen)) { 157082cd038dSYoshinobu Inoue int e; 157182cd038dSYoshinobu Inoue 157233841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(opr)) != 0) { 157333841545SHajimu UMEMOTO nd6log((LOG_ERR, 157433841545SHajimu UMEMOTO "nd6_prefix_offlink: failed to " 157533841545SHajimu UMEMOTO "recover a prefix %s/%d from %s " 157633841545SHajimu UMEMOTO "to %s (errno = %d)\n", 157733841545SHajimu UMEMOTO ip6_sprintf(&opr->ndpr_prefix.sin6_addr), 157833841545SHajimu UMEMOTO opr->ndpr_plen, if_name(ifp), 157933841545SHajimu UMEMOTO if_name(opr->ndpr_ifp), e)); 158082cd038dSYoshinobu Inoue } 158182cd038dSYoshinobu Inoue } 158282cd038dSYoshinobu Inoue } 1583686cdd19SJun-ichiro itojun Hagino } 1584686cdd19SJun-ichiro itojun Hagino else { 158533841545SHajimu UMEMOTO /* XXX: can we still set the NDPRF_ONLINK flag? */ 158633841545SHajimu UMEMOTO nd6log((LOG_ERR, 158733841545SHajimu UMEMOTO "nd6_prefix_offlink: failed to delete route: " 158833841545SHajimu UMEMOTO "%s/%d on %s (errno = %d)\n", 158933841545SHajimu UMEMOTO ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp), 159033841545SHajimu UMEMOTO error)); 159133841545SHajimu UMEMOTO } 159282cd038dSYoshinobu Inoue 159371eba915SRuslan Ermilov if (rt != NULL) 159471eba915SRuslan Ermilov RTFREE(rt); 159582cd038dSYoshinobu Inoue 159633841545SHajimu UMEMOTO return(error); 159782cd038dSYoshinobu Inoue } 159882cd038dSYoshinobu Inoue 159982cd038dSYoshinobu Inoue static struct in6_ifaddr * 160033841545SHajimu UMEMOTO in6_ifadd(pr, ifid) 160133841545SHajimu UMEMOTO struct nd_prefix *pr; 160233841545SHajimu UMEMOTO struct in6_addr *ifid; /* Mobile IPv6 addition */ 160382cd038dSYoshinobu Inoue { 160433841545SHajimu UMEMOTO struct ifnet *ifp = pr->ndpr_ifp; 160582cd038dSYoshinobu Inoue struct ifaddr *ifa; 160633841545SHajimu UMEMOTO struct in6_aliasreq ifra; 160733841545SHajimu UMEMOTO struct in6_ifaddr *ia, *ib; 160833841545SHajimu UMEMOTO int error, plen0; 160982cd038dSYoshinobu Inoue struct in6_addr mask; 161033841545SHajimu UMEMOTO int prefixlen = pr->ndpr_plen; 161182cd038dSYoshinobu Inoue 161282cd038dSYoshinobu Inoue in6_len2mask(&mask, prefixlen); 161382cd038dSYoshinobu Inoue 161433841545SHajimu UMEMOTO /* 161533841545SHajimu UMEMOTO * find a link-local address (will be interface ID). 161633841545SHajimu UMEMOTO * Is it really mandatory? Theoretically, a global or a site-local 161733841545SHajimu UMEMOTO * address can be configured without a link-local address, if we 161833841545SHajimu UMEMOTO * have a unique interface identifier... 161933841545SHajimu UMEMOTO * 162033841545SHajimu UMEMOTO * it is not mandatory to have a link-local address, we can generate 162133841545SHajimu UMEMOTO * interface identifier on the fly. we do this because: 162233841545SHajimu UMEMOTO * (1) it should be the easiest way to find interface identifier. 162333841545SHajimu UMEMOTO * (2) RFC2462 5.4 suggesting the use of the same interface identifier 162433841545SHajimu UMEMOTO * for multiple addresses on a single interface, and possible shortcut 162533841545SHajimu UMEMOTO * of DAD. we omitted DAD for this reason in the past. 162633841545SHajimu UMEMOTO * (3) a user can prevent autoconfiguration of global address 162733841545SHajimu UMEMOTO * by removing link-local address by hand (this is partly because we 16289d5abbddSJens Schweikhardt * don't have other way to control the use of IPv6 on an interface. 162933841545SHajimu UMEMOTO * this has been our design choice - cf. NRL's "ifconfig auto"). 163033841545SHajimu UMEMOTO * (4) it is easier to manage when an interface has addresses 163133841545SHajimu UMEMOTO * with the same interface identifier, than to have multiple addresses 163233841545SHajimu UMEMOTO * with different interface identifiers. 163333841545SHajimu UMEMOTO * 163433841545SHajimu UMEMOTO * Mobile IPv6 addition: allow for caller to specify a wished interface 163533841545SHajimu UMEMOTO * ID. This is to not break connections when moving addresses between 163633841545SHajimu UMEMOTO * interfaces. 163733841545SHajimu UMEMOTO */ 1638686cdd19SJun-ichiro itojun Hagino ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0);/* 0 is OK? */ 163982cd038dSYoshinobu Inoue if (ifa) 164082cd038dSYoshinobu Inoue ib = (struct in6_ifaddr *)ifa; 164182cd038dSYoshinobu Inoue else 164282cd038dSYoshinobu Inoue return NULL; 164382cd038dSYoshinobu Inoue 1644686cdd19SJun-ichiro itojun Hagino #if 0 /* don't care link local addr state, and always do DAD */ 1645686cdd19SJun-ichiro itojun Hagino /* if link-local address is not eligible, do not autoconfigure. */ 1646686cdd19SJun-ichiro itojun Hagino if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) { 1647686cdd19SJun-ichiro itojun Hagino printf("in6_ifadd: link-local address not ready\n"); 1648686cdd19SJun-ichiro itojun Hagino return NULL; 1649686cdd19SJun-ichiro itojun Hagino } 1650686cdd19SJun-ichiro itojun Hagino #endif 1651686cdd19SJun-ichiro itojun Hagino 165282cd038dSYoshinobu Inoue /* prefixlen + ifidlen must be equal to 128 */ 165333841545SHajimu UMEMOTO plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 165433841545SHajimu UMEMOTO if (prefixlen != plen0) { 165533841545SHajimu UMEMOTO nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 165633841545SHajimu UMEMOTO "(prefix=%d ifid=%d)\n", 165733841545SHajimu UMEMOTO if_name(ifp), prefixlen, 128 - plen0)); 165882cd038dSYoshinobu Inoue return NULL; 165982cd038dSYoshinobu Inoue } 166082cd038dSYoshinobu Inoue 166182cd038dSYoshinobu Inoue /* make ifaddr */ 166282cd038dSYoshinobu Inoue 166333841545SHajimu UMEMOTO bzero(&ifra, sizeof(ifra)); 1664686cdd19SJun-ichiro itojun Hagino /* 166533841545SHajimu UMEMOTO * in6_update_ifa() does not use ifra_name, but we accurately set it 166633841545SHajimu UMEMOTO * for safety. 1667686cdd19SJun-ichiro itojun Hagino */ 166833841545SHajimu UMEMOTO strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 166933841545SHajimu UMEMOTO ifra.ifra_addr.sin6_family = AF_INET6; 167033841545SHajimu UMEMOTO ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 167182cd038dSYoshinobu Inoue /* prefix */ 167233841545SHajimu UMEMOTO bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr, 167333841545SHajimu UMEMOTO sizeof(ifra.ifra_addr.sin6_addr)); 167433841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 167533841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 167633841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 167733841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 167833841545SHajimu UMEMOTO 167982cd038dSYoshinobu Inoue /* interface ID */ 168033841545SHajimu UMEMOTO if (ifid == NULL || IN6_IS_ADDR_UNSPECIFIED(ifid)) 168133841545SHajimu UMEMOTO ifid = &ib->ia_addr.sin6_addr; 168233841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[0] 168333841545SHajimu UMEMOTO |= (ifid->s6_addr32[0] & ~mask.s6_addr32[0]); 168433841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[1] 168533841545SHajimu UMEMOTO |= (ifid->s6_addr32[1] & ~mask.s6_addr32[1]); 168633841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[2] 168733841545SHajimu UMEMOTO |= (ifid->s6_addr32[2] & ~mask.s6_addr32[2]); 168833841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[3] 168933841545SHajimu UMEMOTO |= (ifid->s6_addr32[3] & ~mask.s6_addr32[3]); 169082cd038dSYoshinobu Inoue 169133841545SHajimu UMEMOTO /* new prefix mask. */ 169233841545SHajimu UMEMOTO ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 169333841545SHajimu UMEMOTO ifra.ifra_prefixmask.sin6_family = AF_INET6; 169433841545SHajimu UMEMOTO bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 169533841545SHajimu UMEMOTO sizeof(ifra.ifra_prefixmask.sin6_addr)); 169682cd038dSYoshinobu Inoue 169782cd038dSYoshinobu Inoue /* 169833841545SHajimu UMEMOTO * lifetime. 169933841545SHajimu UMEMOTO * XXX: in6_init_address_ltimes would override these values later. 170033841545SHajimu UMEMOTO * We should reconsider this logic. 170182cd038dSYoshinobu Inoue */ 170233841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 170333841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 170433841545SHajimu UMEMOTO 170533841545SHajimu UMEMOTO /* XXX: scope zone ID? */ 170633841545SHajimu UMEMOTO 170733841545SHajimu UMEMOTO ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 170833841545SHajimu UMEMOTO /* 170933841545SHajimu UMEMOTO * temporarily set the nopfx flag to avoid conflict. 171033841545SHajimu UMEMOTO * XXX: we should reconsider the entire mechanism about prefix 171133841545SHajimu UMEMOTO * manipulation. 171233841545SHajimu UMEMOTO */ 171333841545SHajimu UMEMOTO ifra.ifra_flags |= IN6_IFF_NOPFX; 171433841545SHajimu UMEMOTO 171533841545SHajimu UMEMOTO /* 171633841545SHajimu UMEMOTO * keep the new address, regardless of the result of in6_update_ifa. 171733841545SHajimu UMEMOTO * XXX: this address is now meaningless. 171833841545SHajimu UMEMOTO * We should reconsider its role. 171933841545SHajimu UMEMOTO */ 172033841545SHajimu UMEMOTO pr->ndpr_addr = ifra.ifra_addr.sin6_addr; 172133841545SHajimu UMEMOTO 172233841545SHajimu UMEMOTO /* allocate ifaddr structure, link into chain, etc. */ 172333841545SHajimu UMEMOTO if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { 172433841545SHajimu UMEMOTO nd6log((LOG_ERR, 172533841545SHajimu UMEMOTO "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 172633841545SHajimu UMEMOTO ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp), 172733841545SHajimu UMEMOTO error)); 172833841545SHajimu UMEMOTO return(NULL); /* ifaddr must not have been allocated. */ 172982cd038dSYoshinobu Inoue } 173082cd038dSYoshinobu Inoue 173133841545SHajimu UMEMOTO ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 173282cd038dSYoshinobu Inoue 173333841545SHajimu UMEMOTO return(ia); /* this must NOT be NULL. */ 173482cd038dSYoshinobu Inoue } 173582cd038dSYoshinobu Inoue 173682cd038dSYoshinobu Inoue int 173733841545SHajimu UMEMOTO in6_tmpifadd(ia0, forcegen) 173833841545SHajimu UMEMOTO const struct in6_ifaddr *ia0; /* corresponding public address */ 1739c3aacd9eSHajimu UMEMOTO int forcegen; 174082cd038dSYoshinobu Inoue { 174133841545SHajimu UMEMOTO struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 174233841545SHajimu UMEMOTO struct in6_ifaddr *newia; 174333841545SHajimu UMEMOTO struct in6_aliasreq ifra; 174433841545SHajimu UMEMOTO int i, error; 174533841545SHajimu UMEMOTO int trylimit = 3; /* XXX: adhoc value */ 174633841545SHajimu UMEMOTO u_int32_t randid[2]; 174733841545SHajimu UMEMOTO time_t vltime0, pltime0; 174882cd038dSYoshinobu Inoue 174933841545SHajimu UMEMOTO bzero(&ifra, sizeof(ifra)); 175033841545SHajimu UMEMOTO strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 175133841545SHajimu UMEMOTO ifra.ifra_addr = ia0->ia_addr; 175233841545SHajimu UMEMOTO /* copy prefix mask */ 175333841545SHajimu UMEMOTO ifra.ifra_prefixmask = ia0->ia_prefixmask; 175433841545SHajimu UMEMOTO /* clear the old IFID */ 175533841545SHajimu UMEMOTO for (i = 0; i < 4; i++) { 175633841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[i] 175733841545SHajimu UMEMOTO &= ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 175833841545SHajimu UMEMOTO } 175982cd038dSYoshinobu Inoue 176033841545SHajimu UMEMOTO again: 176133841545SHajimu UMEMOTO in6_get_tmpifid(ifp, (u_int8_t *)randid, 176233841545SHajimu UMEMOTO (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], 176333841545SHajimu UMEMOTO forcegen); 176433841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[2] 176533841545SHajimu UMEMOTO |= (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 176633841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[3] 176733841545SHajimu UMEMOTO |= (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 176882cd038dSYoshinobu Inoue 176982cd038dSYoshinobu Inoue /* 177033841545SHajimu UMEMOTO * If by chance the new temporary address is the same as an address 177133841545SHajimu UMEMOTO * already assigned to the interface, generate a new randomized 177233841545SHajimu UMEMOTO * interface identifier and repeat this step. 177333841545SHajimu UMEMOTO * RFC 3041 3.3 (4). 177482cd038dSYoshinobu Inoue */ 177533841545SHajimu UMEMOTO if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { 177633841545SHajimu UMEMOTO if (trylimit-- == 0) { 177733841545SHajimu UMEMOTO nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find " 177833841545SHajimu UMEMOTO "a unique random IFID\n")); 177933841545SHajimu UMEMOTO return(EEXIST); 178033841545SHajimu UMEMOTO } 178133841545SHajimu UMEMOTO forcegen = 1; 178233841545SHajimu UMEMOTO goto again; 178382cd038dSYoshinobu Inoue } 178482cd038dSYoshinobu Inoue 178533841545SHajimu UMEMOTO /* 178633841545SHajimu UMEMOTO * The Valid Lifetime is the lower of the Valid Lifetime of the 178733841545SHajimu UMEMOTO * public address or TEMP_VALID_LIFETIME. 178833841545SHajimu UMEMOTO * The Preferred Lifetime is the lower of the Preferred Lifetime 178933841545SHajimu UMEMOTO * of the public address or TEMP_PREFERRED_LIFETIME - 179033841545SHajimu UMEMOTO * DESYNC_FACTOR. 179182cd038dSYoshinobu Inoue */ 179233841545SHajimu UMEMOTO if (ia0->ia6_lifetime.ia6t_expire != 0) { 179333841545SHajimu UMEMOTO vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 179433841545SHajimu UMEMOTO (ia0->ia6_lifetime.ia6t_expire - time_second); 179533841545SHajimu UMEMOTO if (vltime0 > ip6_temp_valid_lifetime) 179633841545SHajimu UMEMOTO vltime0 = ip6_temp_valid_lifetime; 179733841545SHajimu UMEMOTO } else 179833841545SHajimu UMEMOTO vltime0 = ip6_temp_valid_lifetime; 179933841545SHajimu UMEMOTO if (ia0->ia6_lifetime.ia6t_preferred != 0) { 180033841545SHajimu UMEMOTO pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 180133841545SHajimu UMEMOTO (ia0->ia6_lifetime.ia6t_preferred - time_second); 180233841545SHajimu UMEMOTO if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){ 180333841545SHajimu UMEMOTO pltime0 = ip6_temp_preferred_lifetime - 180433841545SHajimu UMEMOTO ip6_desync_factor; 180533841545SHajimu UMEMOTO } 180633841545SHajimu UMEMOTO } else 180733841545SHajimu UMEMOTO pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor; 180833841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_vltime = vltime0; 180933841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_pltime = pltime0; 181033841545SHajimu UMEMOTO 181133841545SHajimu UMEMOTO /* 181233841545SHajimu UMEMOTO * A temporary address is created only if this calculated Preferred 181333841545SHajimu UMEMOTO * Lifetime is greater than REGEN_ADVANCE time units. 181433841545SHajimu UMEMOTO */ 181533841545SHajimu UMEMOTO if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance) 181633841545SHajimu UMEMOTO return(0); 181733841545SHajimu UMEMOTO 181833841545SHajimu UMEMOTO /* XXX: scope zone ID? */ 181933841545SHajimu UMEMOTO 182033841545SHajimu UMEMOTO ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 182133841545SHajimu UMEMOTO 182233841545SHajimu UMEMOTO /* allocate ifaddr structure, link into chain, etc. */ 182333841545SHajimu UMEMOTO if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) 182433841545SHajimu UMEMOTO return(error); 182533841545SHajimu UMEMOTO 182633841545SHajimu UMEMOTO newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 182733841545SHajimu UMEMOTO if (newia == NULL) { /* XXX: can it happen? */ 182833841545SHajimu UMEMOTO nd6log((LOG_ERR, 182933841545SHajimu UMEMOTO "in6_tmpifadd: ifa update succeeded, but we got " 183033841545SHajimu UMEMOTO "no ifaddr\n")); 183133841545SHajimu UMEMOTO return(EINVAL); /* XXX */ 183233841545SHajimu UMEMOTO } 183333841545SHajimu UMEMOTO newia->ia6_ndpr = ia0->ia6_ndpr; 183433841545SHajimu UMEMOTO newia->ia6_ndpr->ndpr_refcnt++; 183533841545SHajimu UMEMOTO 1836c3aacd9eSHajimu UMEMOTO /* 1837c3aacd9eSHajimu UMEMOTO * A newly added address might affect the status of other addresses. 1838c3aacd9eSHajimu UMEMOTO * XXX: when the temporary address is generated with a new public 1839c3aacd9eSHajimu UMEMOTO * address, the onlink check is redundant. However, it would be safe 1840c3aacd9eSHajimu UMEMOTO * to do the check explicitly everywhere a new address is generated, 1841c3aacd9eSHajimu UMEMOTO * and, in fact, we surely need the check when we create a new 1842c3aacd9eSHajimu UMEMOTO * temporary address due to deprecation of an old temporary address. 1843c3aacd9eSHajimu UMEMOTO */ 1844c3aacd9eSHajimu UMEMOTO pfxlist_onlink_check(); 1845c3aacd9eSHajimu UMEMOTO 184633841545SHajimu UMEMOTO return(0); 184782cd038dSYoshinobu Inoue } 184882cd038dSYoshinobu Inoue 184982cd038dSYoshinobu Inoue int 185082cd038dSYoshinobu Inoue in6_init_prefix_ltimes(struct nd_prefix *ndpr) 185182cd038dSYoshinobu Inoue { 185233841545SHajimu UMEMOTO /* check if preferred lifetime > valid lifetime. RFC2462 5.5.3 (c) */ 185382cd038dSYoshinobu Inoue if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) { 185433841545SHajimu UMEMOTO nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime" 185582cd038dSYoshinobu Inoue "(%d) is greater than valid lifetime(%d)\n", 185633841545SHajimu UMEMOTO (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime)); 185782cd038dSYoshinobu Inoue return (EINVAL); 185882cd038dSYoshinobu Inoue } 185982cd038dSYoshinobu Inoue if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 186082cd038dSYoshinobu Inoue ndpr->ndpr_preferred = 0; 186182cd038dSYoshinobu Inoue else 186282cd038dSYoshinobu Inoue ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; 186382cd038dSYoshinobu Inoue if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 186482cd038dSYoshinobu Inoue ndpr->ndpr_expire = 0; 186582cd038dSYoshinobu Inoue else 186682cd038dSYoshinobu Inoue ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; 186782cd038dSYoshinobu Inoue 186882cd038dSYoshinobu Inoue return 0; 186982cd038dSYoshinobu Inoue } 187082cd038dSYoshinobu Inoue 187182cd038dSYoshinobu Inoue static void 187233841545SHajimu UMEMOTO in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 187382cd038dSYoshinobu Inoue { 187482cd038dSYoshinobu Inoue /* init ia6t_expire */ 187582cd038dSYoshinobu Inoue if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 187682cd038dSYoshinobu Inoue lt6->ia6t_expire = 0; 187782cd038dSYoshinobu Inoue else { 187882cd038dSYoshinobu Inoue lt6->ia6t_expire = time_second; 187982cd038dSYoshinobu Inoue lt6->ia6t_expire += lt6->ia6t_vltime; 188082cd038dSYoshinobu Inoue } 1881686cdd19SJun-ichiro itojun Hagino 188282cd038dSYoshinobu Inoue /* init ia6t_preferred */ 188382cd038dSYoshinobu Inoue if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 188482cd038dSYoshinobu Inoue lt6->ia6t_preferred = 0; 188582cd038dSYoshinobu Inoue else { 188682cd038dSYoshinobu Inoue lt6->ia6t_preferred = time_second; 188782cd038dSYoshinobu Inoue lt6->ia6t_preferred += lt6->ia6t_pltime; 188882cd038dSYoshinobu Inoue } 188982cd038dSYoshinobu Inoue } 189082cd038dSYoshinobu Inoue 189182cd038dSYoshinobu Inoue /* 189282cd038dSYoshinobu Inoue * Delete all the routing table entries that use the specified gateway. 189382cd038dSYoshinobu Inoue * XXX: this function causes search through all entries of routing table, so 189482cd038dSYoshinobu Inoue * it shouldn't be called when acting as a router. 189582cd038dSYoshinobu Inoue */ 189682cd038dSYoshinobu Inoue void 189782cd038dSYoshinobu Inoue rt6_flush(gateway, ifp) 189882cd038dSYoshinobu Inoue struct in6_addr *gateway; 189982cd038dSYoshinobu Inoue struct ifnet *ifp; 190082cd038dSYoshinobu Inoue { 190182cd038dSYoshinobu Inoue struct radix_node_head *rnh = rt_tables[AF_INET6]; 190282cd038dSYoshinobu Inoue int s = splnet(); 190382cd038dSYoshinobu Inoue 190482cd038dSYoshinobu Inoue /* We'll care only link-local addresses */ 190582cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { 190682cd038dSYoshinobu Inoue splx(s); 190782cd038dSYoshinobu Inoue return; 190882cd038dSYoshinobu Inoue } 190982cd038dSYoshinobu Inoue /* XXX: hack for KAME's link-local address kludge */ 191082cd038dSYoshinobu Inoue gateway->s6_addr16[1] = htons(ifp->if_index); 191182cd038dSYoshinobu Inoue 1912956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 191382cd038dSYoshinobu Inoue rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 1914956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 191582cd038dSYoshinobu Inoue splx(s); 191682cd038dSYoshinobu Inoue } 191782cd038dSYoshinobu Inoue 191882cd038dSYoshinobu Inoue static int 191982cd038dSYoshinobu Inoue rt6_deleteroute(rn, arg) 192082cd038dSYoshinobu Inoue struct radix_node *rn; 192182cd038dSYoshinobu Inoue void *arg; 192282cd038dSYoshinobu Inoue { 192382cd038dSYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)s) 192482cd038dSYoshinobu Inoue struct rtentry *rt = (struct rtentry *)rn; 192582cd038dSYoshinobu Inoue struct in6_addr *gate = (struct in6_addr *)arg; 192682cd038dSYoshinobu Inoue 192782cd038dSYoshinobu Inoue if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 192882cd038dSYoshinobu Inoue return(0); 192982cd038dSYoshinobu Inoue 193082cd038dSYoshinobu Inoue if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) 193182cd038dSYoshinobu Inoue return(0); 193282cd038dSYoshinobu Inoue 193382cd038dSYoshinobu Inoue /* 193433841545SHajimu UMEMOTO * Do not delete a static route. 193533841545SHajimu UMEMOTO * XXX: this seems to be a bit ad-hoc. Should we consider the 193633841545SHajimu UMEMOTO * 'cloned' bit instead? 193733841545SHajimu UMEMOTO */ 193833841545SHajimu UMEMOTO if ((rt->rt_flags & RTF_STATIC) != 0) 193933841545SHajimu UMEMOTO return(0); 194033841545SHajimu UMEMOTO 194133841545SHajimu UMEMOTO /* 194282cd038dSYoshinobu Inoue * We delete only host route. This means, in particular, we don't 194382cd038dSYoshinobu Inoue * delete default route. 194482cd038dSYoshinobu Inoue */ 194582cd038dSYoshinobu Inoue if ((rt->rt_flags & RTF_HOST) == 0) 194682cd038dSYoshinobu Inoue return(0); 194782cd038dSYoshinobu Inoue 194882cd038dSYoshinobu Inoue return(rtrequest(RTM_DELETE, rt_key(rt), 194982cd038dSYoshinobu Inoue rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0)); 195082cd038dSYoshinobu Inoue #undef SIN6 195182cd038dSYoshinobu Inoue } 1952686cdd19SJun-ichiro itojun Hagino 1953686cdd19SJun-ichiro itojun Hagino int 1954686cdd19SJun-ichiro itojun Hagino nd6_setdefaultiface(ifindex) 1955686cdd19SJun-ichiro itojun Hagino int ifindex; 1956686cdd19SJun-ichiro itojun Hagino { 1957686cdd19SJun-ichiro itojun Hagino int error = 0; 1958686cdd19SJun-ichiro itojun Hagino 1959686cdd19SJun-ichiro itojun Hagino if (ifindex < 0 || if_index < ifindex) 1960686cdd19SJun-ichiro itojun Hagino return(EINVAL); 1961686cdd19SJun-ichiro itojun Hagino 1962686cdd19SJun-ichiro itojun Hagino if (nd6_defifindex != ifindex) { 1963686cdd19SJun-ichiro itojun Hagino nd6_defifindex = ifindex; 1964686cdd19SJun-ichiro itojun Hagino if (nd6_defifindex > 0) 1965f9132cebSJonathan Lemon nd6_defifp = ifnet_byindex(nd6_defifindex); 1966686cdd19SJun-ichiro itojun Hagino else 1967686cdd19SJun-ichiro itojun Hagino nd6_defifp = NULL; 1968686cdd19SJun-ichiro itojun Hagino 1969686cdd19SJun-ichiro itojun Hagino /* 1970686cdd19SJun-ichiro itojun Hagino * If the Default Router List is empty, install a route 1971686cdd19SJun-ichiro itojun Hagino * to the specified interface as default or remove the default 1972686cdd19SJun-ichiro itojun Hagino * route when the default interface becomes canceled. 1973686cdd19SJun-ichiro itojun Hagino * The check for the queue is actually redundant, but 1974686cdd19SJun-ichiro itojun Hagino * we do this here to avoid re-install the default route 1975686cdd19SJun-ichiro itojun Hagino * if the list is NOT empty. 1976686cdd19SJun-ichiro itojun Hagino */ 1977686cdd19SJun-ichiro itojun Hagino if (TAILQ_FIRST(&nd_defrouter) == NULL) 1978686cdd19SJun-ichiro itojun Hagino defrouter_select(); 1979686cdd19SJun-ichiro itojun Hagino 1980686cdd19SJun-ichiro itojun Hagino /* 1981686cdd19SJun-ichiro itojun Hagino * Our current implementation assumes one-to-one maping between 1982686cdd19SJun-ichiro itojun Hagino * interfaces and links, so it would be natural to use the 1983686cdd19SJun-ichiro itojun Hagino * default interface as the default link. 1984686cdd19SJun-ichiro itojun Hagino */ 1985686cdd19SJun-ichiro itojun Hagino scope6_setdefault(nd6_defifp); 1986686cdd19SJun-ichiro itojun Hagino } 1987686cdd19SJun-ichiro itojun Hagino 1988686cdd19SJun-ichiro itojun Hagino return(error); 1989686cdd19SJun-ichiro itojun Hagino } 1990