1caf43b02SWarner Losh /*- 282cd038dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 382cd038dSYoshinobu Inoue * All rights reserved. 482cd038dSYoshinobu Inoue * 582cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 682cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 782cd038dSYoshinobu Inoue * are met: 882cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 982cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1082cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1182cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1282cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1382cd038dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1482cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 1582cd038dSYoshinobu Inoue * without specific prior written permission. 1682cd038dSYoshinobu Inoue * 1782cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 1882cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1982cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2082cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2182cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2282cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2382cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2482cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2582cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2682cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2782cd038dSYoshinobu Inoue * SUCH DAMAGE. 28b48287a3SDavid E. O'Brien * 29b48287a3SDavid E. O'Brien * $KAME: nd6_rtr.c,v 1.111 2001/04/27 01:37:15 jinmei Exp $ 3082cd038dSYoshinobu Inoue */ 3182cd038dSYoshinobu Inoue 32b48287a3SDavid E. O'Brien #include <sys/cdefs.h> 33b48287a3SDavid E. O'Brien __FBSDID("$FreeBSD$"); 34b48287a3SDavid E. O'Brien 35686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h" 36686cdd19SJun-ichiro itojun Hagino #include "opt_inet6.h" 3733553d6eSBjoern A. Zeeb #include "opt_route.h" 38686cdd19SJun-ichiro itojun Hagino 3982cd038dSYoshinobu Inoue #include <sys/param.h> 4082cd038dSYoshinobu Inoue #include <sys/systm.h> 4182cd038dSYoshinobu Inoue #include <sys/malloc.h> 4282cd038dSYoshinobu Inoue #include <sys/mbuf.h> 4382cd038dSYoshinobu Inoue #include <sys/socket.h> 4482cd038dSYoshinobu Inoue #include <sys/sockio.h> 4582cd038dSYoshinobu Inoue #include <sys/time.h> 4633841545SHajimu UMEMOTO #include <sys/kernel.h> 47609ff41fSWarner Losh #include <sys/lock.h> 4882cd038dSYoshinobu Inoue #include <sys/errno.h> 493120b9d4SKip Macy #include <sys/rwlock.h> 5082cd038dSYoshinobu Inoue #include <sys/syslog.h> 5133841545SHajimu UMEMOTO #include <sys/queue.h> 52603724d3SBjoern A. Zeeb #include <sys/vimage.h> 5382cd038dSYoshinobu Inoue 5482cd038dSYoshinobu Inoue #include <net/if.h> 5582cd038dSYoshinobu Inoue #include <net/if_types.h> 5682cd038dSYoshinobu Inoue #include <net/if_dl.h> 5782cd038dSYoshinobu Inoue #include <net/route.h> 5882cd038dSYoshinobu Inoue #include <net/radix.h> 594b79449eSBjoern A. Zeeb #include <net/vnet.h> 6082cd038dSYoshinobu Inoue 6182cd038dSYoshinobu Inoue #include <netinet/in.h> 626e6b3f7cSQing Li #include <net/if_llatbl.h> 6382cd038dSYoshinobu Inoue #include <netinet6/in6_var.h> 6433841545SHajimu UMEMOTO #include <netinet6/in6_ifattach.h> 65686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 6682cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 6782cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 68686cdd19SJun-ichiro itojun Hagino #include <netinet/icmp6.h> 69686cdd19SJun-ichiro itojun Hagino #include <netinet6/scope6_var.h> 704b79449eSBjoern A. Zeeb #include <netinet6/vinet6.h> 7182cd038dSYoshinobu Inoue 729233d8f3SDavid E. O'Brien static int rtpref(struct nd_defrouter *); 739233d8f3SDavid E. O'Brien static struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); 74743eee66SSUZUKI Shinsuke static int prelist_update __P((struct nd_prefixctl *, struct nd_defrouter *, 75743eee66SSUZUKI Shinsuke struct mbuf *, int)); 769233d8f3SDavid E. O'Brien static struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int); 7782cd038dSYoshinobu Inoue static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, 7882cd038dSYoshinobu Inoue struct nd_defrouter *)); 799233d8f3SDavid E. O'Brien static void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *); 809233d8f3SDavid E. O'Brien static void pfxrtr_del(struct nd_pfxrouter *); 81686cdd19SJun-ichiro itojun Hagino static struct nd_pfxrouter *find_pfxlist_reachable_router 829233d8f3SDavid E. O'Brien (struct nd_prefix *); 839233d8f3SDavid E. O'Brien static void defrouter_delreq(struct nd_defrouter *); 849233d8f3SDavid E. O'Brien static void nd6_rtmsg(int, struct rtentry *); 8582cd038dSYoshinobu Inoue 869233d8f3SDavid E. O'Brien static int in6_init_prefix_ltimes(struct nd_prefix *); 8707eb2995SHajimu UMEMOTO static void in6_init_address_ltimes __P((struct nd_prefix *, 8807eb2995SHajimu UMEMOTO struct in6_addrlifetime *)); 8982cd038dSYoshinobu Inoue 909233d8f3SDavid E. O'Brien static int rt6_deleteroute(struct radix_node *, void *); 9182cd038dSYoshinobu Inoue 9297021c24SMarko Zec #ifdef VIMAGE_GLOBALS 9382cd038dSYoshinobu Inoue extern int nd6_recalc_reachtm_interval; 9482cd038dSYoshinobu Inoue 9533841545SHajimu UMEMOTO static struct ifnet *nd6_defifp; 96686cdd19SJun-ichiro itojun Hagino int nd6_defifindex; 97686cdd19SJun-ichiro itojun Hagino 9844e33a07SMarko Zec int ip6_use_tempaddr; 9933841545SHajimu UMEMOTO int ip6_desync_factor; 10044e33a07SMarko Zec u_int32_t ip6_temp_preferred_lifetime; 10144e33a07SMarko Zec u_int32_t ip6_temp_valid_lifetime; 10244e33a07SMarko Zec int ip6_temp_regen_advance; 10344e33a07SMarko Zec #endif 10433841545SHajimu UMEMOTO 105743eee66SSUZUKI Shinsuke /* RTPREF_MEDIUM has to be 0! */ 106743eee66SSUZUKI Shinsuke #define RTPREF_HIGH 1 107743eee66SSUZUKI Shinsuke #define RTPREF_MEDIUM 0 108743eee66SSUZUKI Shinsuke #define RTPREF_LOW (-1) 109743eee66SSUZUKI Shinsuke #define RTPREF_RESERVED (-2) 110743eee66SSUZUKI Shinsuke #define RTPREF_INVALID (-3) /* internal */ 111743eee66SSUZUKI Shinsuke 11282cd038dSYoshinobu Inoue /* 11382cd038dSYoshinobu Inoue * Receive Router Solicitation Message - just for routers. 11482cd038dSYoshinobu Inoue * Router solicitation/advertisement is mostly managed by userland program 11582cd038dSYoshinobu Inoue * (rtadvd) so here we have no function like nd6_ra_output(). 11682cd038dSYoshinobu Inoue * 11782cd038dSYoshinobu Inoue * Based on RFC 2461 11882cd038dSYoshinobu Inoue */ 11982cd038dSYoshinobu Inoue void 1201272577eSXin LI nd6_rs_input(struct mbuf *m, int off, int icmp6len) 12182cd038dSYoshinobu Inoue { 1228b615593SMarko Zec INIT_VNET_INET6(curvnet); 12382cd038dSYoshinobu Inoue struct ifnet *ifp = m->m_pkthdr.rcvif; 12482cd038dSYoshinobu Inoue struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 125686cdd19SJun-ichiro itojun Hagino struct nd_router_solicit *nd_rs; 12682cd038dSYoshinobu Inoue struct in6_addr saddr6 = ip6->ip6_src; 12782cd038dSYoshinobu Inoue char *lladdr = NULL; 12882cd038dSYoshinobu Inoue int lladdrlen = 0; 12982cd038dSYoshinobu Inoue union nd_opts ndopts; 1301d54aa3bSBjoern A. Zeeb char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 13182cd038dSYoshinobu Inoue 13282cd038dSYoshinobu Inoue /* If I'm not a router, ignore it. */ 133603724d3SBjoern A. Zeeb if (V_ip6_accept_rtadv != 0 || V_ip6_forwarding != 1) 134686cdd19SJun-ichiro itojun Hagino goto freeit; 13582cd038dSYoshinobu Inoue 13682cd038dSYoshinobu Inoue /* Sanity checks */ 13782cd038dSYoshinobu Inoue if (ip6->ip6_hlim != 255) { 13833841545SHajimu UMEMOTO nd6log((LOG_ERR, 13933841545SHajimu UMEMOTO "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", 1401d54aa3bSBjoern A. Zeeb ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 1411d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 14233841545SHajimu UMEMOTO goto bad; 14382cd038dSYoshinobu Inoue } 14482cd038dSYoshinobu Inoue 14582cd038dSYoshinobu Inoue /* 14682cd038dSYoshinobu Inoue * Don't update the neighbor cache, if src = ::. 14782cd038dSYoshinobu Inoue * This indicates that the src has no IP address assigned yet. 14882cd038dSYoshinobu Inoue */ 14982cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 150686cdd19SJun-ichiro itojun Hagino goto freeit; 151686cdd19SJun-ichiro itojun Hagino 152686cdd19SJun-ichiro itojun Hagino #ifndef PULLDOWN_TEST 153686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_CHECK(m, off, icmp6len,); 154686cdd19SJun-ichiro itojun Hagino nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); 155686cdd19SJun-ichiro itojun Hagino #else 156686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); 157686cdd19SJun-ichiro itojun Hagino if (nd_rs == NULL) { 158e27b0c87SRobert Watson ICMP6STAT_INC(icp6s_tooshort); 15982cd038dSYoshinobu Inoue return; 160686cdd19SJun-ichiro itojun Hagino } 161686cdd19SJun-ichiro itojun Hagino #endif 16282cd038dSYoshinobu Inoue 16382cd038dSYoshinobu Inoue icmp6len -= sizeof(*nd_rs); 16482cd038dSYoshinobu Inoue nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 16582cd038dSYoshinobu Inoue if (nd6_options(&ndopts) < 0) { 16633841545SHajimu UMEMOTO nd6log((LOG_INFO, 16733841545SHajimu UMEMOTO "nd6_rs_input: invalid ND option, ignored\n")); 16833841545SHajimu UMEMOTO /* nd6_options have incremented stats */ 169686cdd19SJun-ichiro itojun Hagino goto freeit; 17082cd038dSYoshinobu Inoue } 17182cd038dSYoshinobu Inoue 17282cd038dSYoshinobu Inoue if (ndopts.nd_opts_src_lladdr) { 17382cd038dSYoshinobu Inoue lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 17482cd038dSYoshinobu Inoue lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 17582cd038dSYoshinobu Inoue } 17682cd038dSYoshinobu Inoue 17782cd038dSYoshinobu Inoue if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 17833841545SHajimu UMEMOTO nd6log((LOG_INFO, 17982cd038dSYoshinobu Inoue "nd6_rs_input: lladdrlen mismatch for %s " 18082cd038dSYoshinobu Inoue "(if %d, RS packet %d)\n", 1811d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6bufs, &saddr6), 18207eb2995SHajimu UMEMOTO ifp->if_addrlen, lladdrlen - 2)); 18333841545SHajimu UMEMOTO goto bad; 18482cd038dSYoshinobu Inoue } 18582cd038dSYoshinobu Inoue 18682cd038dSYoshinobu Inoue nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 187686cdd19SJun-ichiro itojun Hagino 188686cdd19SJun-ichiro itojun Hagino freeit: 189686cdd19SJun-ichiro itojun Hagino m_freem(m); 19033841545SHajimu UMEMOTO return; 19133841545SHajimu UMEMOTO 19233841545SHajimu UMEMOTO bad: 193e27b0c87SRobert Watson ICMP6STAT_INC(icp6s_badrs); 19433841545SHajimu UMEMOTO m_freem(m); 19582cd038dSYoshinobu Inoue } 19682cd038dSYoshinobu Inoue 19782cd038dSYoshinobu Inoue /* 19882cd038dSYoshinobu Inoue * Receive Router Advertisement Message. 19982cd038dSYoshinobu Inoue * 20082cd038dSYoshinobu Inoue * Based on RFC 2461 20182cd038dSYoshinobu Inoue * TODO: on-link bit on prefix information 20282cd038dSYoshinobu Inoue * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 20382cd038dSYoshinobu Inoue */ 20482cd038dSYoshinobu Inoue void 2051272577eSXin LI nd6_ra_input(struct mbuf *m, int off, int icmp6len) 20682cd038dSYoshinobu Inoue { 2078b615593SMarko Zec INIT_VNET_INET6(curvnet); 20882cd038dSYoshinobu Inoue struct ifnet *ifp = m->m_pkthdr.rcvif; 20931b1bfe1SHajimu UMEMOTO struct nd_ifinfo *ndi = ND_IFINFO(ifp); 21082cd038dSYoshinobu Inoue struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 211686cdd19SJun-ichiro itojun Hagino struct nd_router_advert *nd_ra; 21282cd038dSYoshinobu Inoue struct in6_addr saddr6 = ip6->ip6_src; 213743eee66SSUZUKI Shinsuke int mcast = 0; 21482cd038dSYoshinobu Inoue union nd_opts ndopts; 21582cd038dSYoshinobu Inoue struct nd_defrouter *dr; 2161d54aa3bSBjoern A. Zeeb char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; 21782cd038dSYoshinobu Inoue 21807cf047dSHajimu UMEMOTO /* 21907cf047dSHajimu UMEMOTO * We only accept RAs only when 22007cf047dSHajimu UMEMOTO * the system-wide variable allows the acceptance, and 22107cf047dSHajimu UMEMOTO * per-interface variable allows RAs on the receiving interface. 22207cf047dSHajimu UMEMOTO */ 223603724d3SBjoern A. Zeeb if (V_ip6_accept_rtadv == 0) 224686cdd19SJun-ichiro itojun Hagino goto freeit; 22507cf047dSHajimu UMEMOTO if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV)) 22607cf047dSHajimu UMEMOTO goto freeit; 22782cd038dSYoshinobu Inoue 22882cd038dSYoshinobu Inoue if (ip6->ip6_hlim != 255) { 22933841545SHajimu UMEMOTO nd6log((LOG_ERR, 23033841545SHajimu UMEMOTO "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", 2311d54aa3bSBjoern A. Zeeb ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), 2321d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); 23333841545SHajimu UMEMOTO goto bad; 23482cd038dSYoshinobu Inoue } 23582cd038dSYoshinobu Inoue 23682cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 23733841545SHajimu UMEMOTO nd6log((LOG_ERR, 23882cd038dSYoshinobu Inoue "nd6_ra_input: src %s is not link-local\n", 2391d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6bufs, &saddr6))); 24033841545SHajimu UMEMOTO goto bad; 241686cdd19SJun-ichiro itojun Hagino } 242686cdd19SJun-ichiro itojun Hagino 243686cdd19SJun-ichiro itojun Hagino #ifndef PULLDOWN_TEST 244686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_CHECK(m, off, icmp6len,); 245686cdd19SJun-ichiro itojun Hagino nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); 246686cdd19SJun-ichiro itojun Hagino #else 247686cdd19SJun-ichiro itojun Hagino IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); 248686cdd19SJun-ichiro itojun Hagino if (nd_ra == NULL) { 249e27b0c87SRobert Watson ICMP6STAT_INC(icp6s_tooshort); 25082cd038dSYoshinobu Inoue return; 25182cd038dSYoshinobu Inoue } 252686cdd19SJun-ichiro itojun Hagino #endif 25382cd038dSYoshinobu Inoue 25482cd038dSYoshinobu Inoue icmp6len -= sizeof(*nd_ra); 25582cd038dSYoshinobu Inoue nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 25682cd038dSYoshinobu Inoue if (nd6_options(&ndopts) < 0) { 25733841545SHajimu UMEMOTO nd6log((LOG_INFO, 25833841545SHajimu UMEMOTO "nd6_ra_input: invalid ND option, ignored\n")); 25933841545SHajimu UMEMOTO /* nd6_options have incremented stats */ 260686cdd19SJun-ichiro itojun Hagino goto freeit; 26182cd038dSYoshinobu Inoue } 26282cd038dSYoshinobu Inoue 26382cd038dSYoshinobu Inoue { 26482cd038dSYoshinobu Inoue struct nd_defrouter dr0; 26582cd038dSYoshinobu Inoue u_int32_t advreachable = nd_ra->nd_ra_reachable; 26682cd038dSYoshinobu Inoue 267743eee66SSUZUKI Shinsuke /* remember if this is a multicasted advertisement */ 268743eee66SSUZUKI Shinsuke if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) 269743eee66SSUZUKI Shinsuke mcast = 1; 270743eee66SSUZUKI Shinsuke 271743eee66SSUZUKI Shinsuke bzero(&dr0, sizeof(dr0)); 27282cd038dSYoshinobu Inoue dr0.rtaddr = saddr6; 27382cd038dSYoshinobu Inoue dr0.flags = nd_ra->nd_ra_flags_reserved; 27482cd038dSYoshinobu Inoue dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 27582cd038dSYoshinobu Inoue dr0.expire = time_second + dr0.rtlifetime; 27682cd038dSYoshinobu Inoue dr0.ifp = ifp; 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); 284603724d3SBjoern A. Zeeb ndi->recalctm = V_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; 300743eee66SSUZUKI Shinsuke struct nd_prefixctl 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", 3311d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6bufs, 3321d54aa3bSBjoern A. Zeeb &pi->nd_opt_pi_prefix))); 33382cd038dSYoshinobu Inoue continue; 33482cd038dSYoshinobu Inoue } 33582cd038dSYoshinobu Inoue 33682cd038dSYoshinobu Inoue bzero(&pr, sizeof(pr)); 33782cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_family = AF_INET6; 33882cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 33982cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 34082cd038dSYoshinobu Inoue pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 34182cd038dSYoshinobu Inoue 34282cd038dSYoshinobu Inoue pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 34382cd038dSYoshinobu Inoue ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 34482cd038dSYoshinobu Inoue pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 34582cd038dSYoshinobu Inoue ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 34682cd038dSYoshinobu Inoue pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 34782cd038dSYoshinobu Inoue pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 34807eb2995SHajimu UMEMOTO pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); 349743eee66SSUZUKI Shinsuke (void)prelist_update(&pr, dr, m, mcast); 35082cd038dSYoshinobu Inoue } 35182cd038dSYoshinobu Inoue } 35282cd038dSYoshinobu Inoue 35382cd038dSYoshinobu Inoue /* 35482cd038dSYoshinobu Inoue * MTU 35582cd038dSYoshinobu Inoue */ 35682cd038dSYoshinobu Inoue if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 35731b3783cSHajimu UMEMOTO u_long mtu; 35831b3783cSHajimu UMEMOTO u_long maxmtu; 35907eb2995SHajimu UMEMOTO 36031b3783cSHajimu UMEMOTO mtu = (u_long)ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 36182cd038dSYoshinobu Inoue 36282cd038dSYoshinobu Inoue /* lower bound */ 36382cd038dSYoshinobu Inoue if (mtu < IPV6_MMTU) { 36433841545SHajimu UMEMOTO nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " 36531b3783cSHajimu UMEMOTO "mtu=%lu sent from %s, ignoring\n", 3661d54aa3bSBjoern A. Zeeb mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src))); 36782cd038dSYoshinobu Inoue goto skip; 36882cd038dSYoshinobu Inoue } 36982cd038dSYoshinobu Inoue 37082cd038dSYoshinobu Inoue /* upper bound */ 37131b3783cSHajimu UMEMOTO maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu) 37231b3783cSHajimu UMEMOTO ? ndi->maxmtu : ifp->if_mtu; 37331b3783cSHajimu UMEMOTO if (mtu <= maxmtu) { 37482cd038dSYoshinobu Inoue int change = (ndi->linkmtu != mtu); 37582cd038dSYoshinobu Inoue 37682cd038dSYoshinobu Inoue ndi->linkmtu = mtu; 37782cd038dSYoshinobu Inoue if (change) /* in6_maxmtu may change */ 37882cd038dSYoshinobu Inoue in6_setmaxmtu(); 37982cd038dSYoshinobu Inoue } else { 38033841545SHajimu UMEMOTO nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " 38131b3783cSHajimu UMEMOTO "mtu=%lu sent from %s; " 38231b3783cSHajimu UMEMOTO "exceeds maxmtu %lu, ignoring\n", 3831d54aa3bSBjoern A. Zeeb mtu, ip6_sprintf(ip6bufs, &ip6->ip6_src), maxmtu)); 38482cd038dSYoshinobu Inoue } 38582cd038dSYoshinobu Inoue } 38682cd038dSYoshinobu Inoue 38782cd038dSYoshinobu Inoue skip: 38882cd038dSYoshinobu Inoue 38982cd038dSYoshinobu Inoue /* 39088ff5695SSUZUKI Shinsuke * Source link layer address 39182cd038dSYoshinobu Inoue */ 39282cd038dSYoshinobu Inoue { 39382cd038dSYoshinobu Inoue char *lladdr = NULL; 39482cd038dSYoshinobu Inoue int lladdrlen = 0; 39582cd038dSYoshinobu Inoue 39682cd038dSYoshinobu Inoue if (ndopts.nd_opts_src_lladdr) { 39782cd038dSYoshinobu Inoue lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 39882cd038dSYoshinobu Inoue lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 39982cd038dSYoshinobu Inoue } 40082cd038dSYoshinobu Inoue 40182cd038dSYoshinobu Inoue if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 40233841545SHajimu UMEMOTO nd6log((LOG_INFO, 40382cd038dSYoshinobu Inoue "nd6_ra_input: lladdrlen mismatch for %s " 4041d54aa3bSBjoern A. Zeeb "(if %d, RA packet %d)\n", ip6_sprintf(ip6bufs, &saddr6), 40507eb2995SHajimu UMEMOTO ifp->if_addrlen, lladdrlen - 2)); 40633841545SHajimu UMEMOTO goto bad; 40782cd038dSYoshinobu Inoue } 40882cd038dSYoshinobu Inoue 40907eb2995SHajimu UMEMOTO nd6_cache_lladdr(ifp, &saddr6, lladdr, 41007eb2995SHajimu UMEMOTO lladdrlen, ND_ROUTER_ADVERT, 0); 411686cdd19SJun-ichiro itojun Hagino 412686cdd19SJun-ichiro itojun Hagino /* 413686cdd19SJun-ichiro itojun Hagino * Installing a link-layer address might change the state of the 414686cdd19SJun-ichiro itojun Hagino * router's neighbor cache, which might also affect our on-link 415686cdd19SJun-ichiro itojun Hagino * detection of adveritsed prefixes. 416686cdd19SJun-ichiro itojun Hagino */ 417686cdd19SJun-ichiro itojun Hagino pfxlist_onlink_check(); 41882cd038dSYoshinobu Inoue } 419686cdd19SJun-ichiro itojun Hagino 420686cdd19SJun-ichiro itojun Hagino freeit: 421686cdd19SJun-ichiro itojun Hagino m_freem(m); 42233841545SHajimu UMEMOTO return; 42333841545SHajimu UMEMOTO 42433841545SHajimu UMEMOTO bad: 425e27b0c87SRobert Watson ICMP6STAT_INC(icp6s_badra); 42633841545SHajimu UMEMOTO m_freem(m); 42782cd038dSYoshinobu Inoue } 42882cd038dSYoshinobu Inoue 42982cd038dSYoshinobu Inoue /* 43082cd038dSYoshinobu Inoue * default router list proccessing sub routines 43182cd038dSYoshinobu Inoue */ 432686cdd19SJun-ichiro itojun Hagino 433686cdd19SJun-ichiro itojun Hagino /* tell the change to user processes watching the routing socket. */ 434686cdd19SJun-ichiro itojun Hagino static void 4351272577eSXin LI nd6_rtmsg(int cmd, struct rtentry *rt) 436686cdd19SJun-ichiro itojun Hagino { 437686cdd19SJun-ichiro itojun Hagino struct rt_addrinfo info; 438686cdd19SJun-ichiro itojun Hagino 439686cdd19SJun-ichiro itojun Hagino bzero((caddr_t)&info, sizeof(info)); 440686cdd19SJun-ichiro itojun Hagino info.rti_info[RTAX_DST] = rt_key(rt); 441686cdd19SJun-ichiro itojun Hagino info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; 442686cdd19SJun-ichiro itojun Hagino info.rti_info[RTAX_NETMASK] = rt_mask(rt); 443743eee66SSUZUKI Shinsuke if (rt->rt_ifp) { 44433841545SHajimu UMEMOTO info.rti_info[RTAX_IFP] = 445743eee66SSUZUKI Shinsuke TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr; 44633841545SHajimu UMEMOTO info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; 447743eee66SSUZUKI Shinsuke } 448686cdd19SJun-ichiro itojun Hagino 449686cdd19SJun-ichiro itojun Hagino rt_missmsg(cmd, &info, rt->rt_flags, 0); 450686cdd19SJun-ichiro itojun Hagino } 451686cdd19SJun-ichiro itojun Hagino 45282cd038dSYoshinobu Inoue void 4531272577eSXin LI defrouter_addreq(struct nd_defrouter *new) 45482cd038dSYoshinobu Inoue { 45582cd038dSYoshinobu Inoue struct sockaddr_in6 def, mask, gate; 456686cdd19SJun-ichiro itojun Hagino struct rtentry *newrt = NULL; 457743eee66SSUZUKI Shinsuke int s; 458743eee66SSUZUKI Shinsuke int error; 45982cd038dSYoshinobu Inoue 460056c7327SLuigi Rizzo bzero(&def, sizeof(def)); 461056c7327SLuigi Rizzo bzero(&mask, sizeof(mask)); 462056c7327SLuigi Rizzo bzero(&gate, sizeof(gate)); 46382cd038dSYoshinobu Inoue 46407eb2995SHajimu UMEMOTO def.sin6_len = mask.sin6_len = gate.sin6_len = 46507eb2995SHajimu UMEMOTO sizeof(struct sockaddr_in6); 466743eee66SSUZUKI Shinsuke def.sin6_family = gate.sin6_family = AF_INET6; 46782cd038dSYoshinobu Inoue gate.sin6_addr = new->rtaddr; 46882cd038dSYoshinobu Inoue 469743eee66SSUZUKI Shinsuke s = splnet(); 470743eee66SSUZUKI Shinsuke error = rtrequest(RTM_ADD, (struct sockaddr *)&def, 47182cd038dSYoshinobu Inoue (struct sockaddr *)&gate, (struct sockaddr *)&mask, 472686cdd19SJun-ichiro itojun Hagino RTF_GATEWAY, &newrt); 473686cdd19SJun-ichiro itojun Hagino if (newrt) { 47433841545SHajimu UMEMOTO nd6_rtmsg(RTM_ADD, newrt); /* tell user process */ 4756e6b3f7cSQing Li RTFREE(newrt); 476686cdd19SJun-ichiro itojun Hagino } 477743eee66SSUZUKI Shinsuke if (error == 0) 478743eee66SSUZUKI Shinsuke new->installed = 1; 479743eee66SSUZUKI Shinsuke splx(s); 48082cd038dSYoshinobu Inoue return; 48182cd038dSYoshinobu Inoue } 48282cd038dSYoshinobu Inoue 48382cd038dSYoshinobu Inoue struct nd_defrouter * 4841272577eSXin LI defrouter_lookup(struct in6_addr *addr, struct ifnet *ifp) 48582cd038dSYoshinobu Inoue { 4868b615593SMarko Zec INIT_VNET_INET6(ifp->if_vnet); 48782cd038dSYoshinobu Inoue struct nd_defrouter *dr; 48882cd038dSYoshinobu Inoue 489603724d3SBjoern A. Zeeb for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 490686cdd19SJun-ichiro itojun Hagino dr = TAILQ_NEXT(dr, dr_entry)) { 49182cd038dSYoshinobu Inoue if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 49282cd038dSYoshinobu Inoue return (dr); 493686cdd19SJun-ichiro itojun Hagino } 49482cd038dSYoshinobu Inoue 49582cd038dSYoshinobu Inoue return (NULL); /* search failed */ 49682cd038dSYoshinobu Inoue } 49782cd038dSYoshinobu Inoue 498743eee66SSUZUKI Shinsuke /* 499743eee66SSUZUKI Shinsuke * Remove the default route for a given router. 500743eee66SSUZUKI Shinsuke * This is just a subroutine function for defrouter_select(), and should 501743eee66SSUZUKI Shinsuke * not be called from anywhere else. 502743eee66SSUZUKI Shinsuke */ 503743eee66SSUZUKI Shinsuke static void 5041272577eSXin LI defrouter_delreq(struct nd_defrouter *dr) 50582cd038dSYoshinobu Inoue { 50682cd038dSYoshinobu Inoue struct sockaddr_in6 def, mask, gate; 507686cdd19SJun-ichiro itojun Hagino struct rtentry *oldrt = NULL; 50882cd038dSYoshinobu Inoue 509056c7327SLuigi Rizzo bzero(&def, sizeof(def)); 510056c7327SLuigi Rizzo bzero(&mask, sizeof(mask)); 511056c7327SLuigi Rizzo bzero(&gate, sizeof(gate)); 51282cd038dSYoshinobu Inoue 51307eb2995SHajimu UMEMOTO def.sin6_len = mask.sin6_len = gate.sin6_len = 51407eb2995SHajimu UMEMOTO sizeof(struct sockaddr_in6); 515743eee66SSUZUKI Shinsuke def.sin6_family = gate.sin6_family = AF_INET6; 51682cd038dSYoshinobu Inoue gate.sin6_addr = dr->rtaddr; 51782cd038dSYoshinobu Inoue 51882cd038dSYoshinobu Inoue rtrequest(RTM_DELETE, (struct sockaddr *)&def, 51982cd038dSYoshinobu Inoue (struct sockaddr *)&gate, 52007eb2995SHajimu UMEMOTO (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt); 521686cdd19SJun-ichiro itojun Hagino if (oldrt) { 52233841545SHajimu UMEMOTO nd6_rtmsg(RTM_DELETE, oldrt); 52371eba915SRuslan Ermilov RTFREE(oldrt); 52420220070SJun-ichiro itojun Hagino } 52582cd038dSYoshinobu Inoue 526743eee66SSUZUKI Shinsuke dr->installed = 0; 527743eee66SSUZUKI Shinsuke } 528743eee66SSUZUKI Shinsuke 529743eee66SSUZUKI Shinsuke /* 530743eee66SSUZUKI Shinsuke * remove all default routes from default router list 531743eee66SSUZUKI Shinsuke */ 532743eee66SSUZUKI Shinsuke void 5331272577eSXin LI defrouter_reset(void) 534743eee66SSUZUKI Shinsuke { 5358b615593SMarko Zec INIT_VNET_INET6(curvnet); 536743eee66SSUZUKI Shinsuke struct nd_defrouter *dr; 537743eee66SSUZUKI Shinsuke 538603724d3SBjoern A. Zeeb for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 539743eee66SSUZUKI Shinsuke dr = TAILQ_NEXT(dr, dr_entry)) 540743eee66SSUZUKI Shinsuke defrouter_delreq(dr); 541743eee66SSUZUKI Shinsuke 542743eee66SSUZUKI Shinsuke /* 543743eee66SSUZUKI Shinsuke * XXX should we also nuke any default routers in the kernel, by 544743eee66SSUZUKI Shinsuke * going through them by rtalloc1()? 545743eee66SSUZUKI Shinsuke */ 54682cd038dSYoshinobu Inoue } 54782cd038dSYoshinobu Inoue 54882cd038dSYoshinobu Inoue void 5491272577eSXin LI defrtrlist_del(struct nd_defrouter *dr) 55082cd038dSYoshinobu Inoue { 5518b615593SMarko Zec INIT_VNET_INET6(curvnet); 55282cd038dSYoshinobu Inoue struct nd_defrouter *deldr = NULL; 55382cd038dSYoshinobu Inoue struct nd_prefix *pr; 55482cd038dSYoshinobu Inoue 55582cd038dSYoshinobu Inoue /* 55682cd038dSYoshinobu Inoue * Flush all the routing table entries that use the router 55782cd038dSYoshinobu Inoue * as a next hop. 55882cd038dSYoshinobu Inoue */ 559603724d3SBjoern A. Zeeb if (!V_ip6_forwarding && V_ip6_accept_rtadv) /* XXX: better condition? */ 56082cd038dSYoshinobu Inoue rt6_flush(&dr->rtaddr, dr->ifp); 56182cd038dSYoshinobu Inoue 562743eee66SSUZUKI Shinsuke if (dr->installed) { 563743eee66SSUZUKI Shinsuke deldr = dr; 564743eee66SSUZUKI Shinsuke defrouter_delreq(dr); 565743eee66SSUZUKI Shinsuke } 566603724d3SBjoern A. Zeeb TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 56782cd038dSYoshinobu Inoue 56882cd038dSYoshinobu Inoue /* 56982cd038dSYoshinobu Inoue * Also delete all the pointers to the router in each prefix lists. 57082cd038dSYoshinobu Inoue */ 571603724d3SBjoern A. Zeeb for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 57282cd038dSYoshinobu Inoue struct nd_pfxrouter *pfxrtr; 57382cd038dSYoshinobu Inoue if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 57482cd038dSYoshinobu Inoue pfxrtr_del(pfxrtr); 57582cd038dSYoshinobu Inoue } 57682cd038dSYoshinobu Inoue pfxlist_onlink_check(); 57782cd038dSYoshinobu Inoue 57882cd038dSYoshinobu Inoue /* 579686cdd19SJun-ichiro itojun Hagino * If the router is the primary one, choose a new one. 580686cdd19SJun-ichiro itojun Hagino * Note that defrouter_select() will remove the current gateway 581686cdd19SJun-ichiro itojun Hagino * from the routing table. 58282cd038dSYoshinobu Inoue */ 58382cd038dSYoshinobu Inoue if (deldr) 584686cdd19SJun-ichiro itojun Hagino defrouter_select(); 585686cdd19SJun-ichiro itojun Hagino 58682cd038dSYoshinobu Inoue free(dr, M_IP6NDP); 58782cd038dSYoshinobu Inoue } 58882cd038dSYoshinobu Inoue 589686cdd19SJun-ichiro itojun Hagino /* 590743eee66SSUZUKI Shinsuke * Default Router Selection according to Section 6.3.6 of RFC 2461 and 591743eee66SSUZUKI Shinsuke * draft-ietf-ipngwg-router-selection: 592743eee66SSUZUKI Shinsuke * 1) Routers that are reachable or probably reachable should be preferred. 593743eee66SSUZUKI Shinsuke * If we have more than one (probably) reachable router, prefer ones 594743eee66SSUZUKI Shinsuke * with the highest router preference. 595686cdd19SJun-ichiro itojun Hagino * 2) When no routers on the list are known to be reachable or 596686cdd19SJun-ichiro itojun Hagino * probably reachable, routers SHOULD be selected in a round-robin 597743eee66SSUZUKI Shinsuke * fashion, regardless of router preference values. 598686cdd19SJun-ichiro itojun Hagino * 3) If the Default Router List is empty, assume that all 599686cdd19SJun-ichiro itojun Hagino * destinations are on-link. 600743eee66SSUZUKI Shinsuke * 601743eee66SSUZUKI Shinsuke * We assume nd_defrouter is sorted by router preference value. 602743eee66SSUZUKI Shinsuke * Since the code below covers both with and without router preference cases, 603743eee66SSUZUKI Shinsuke * we do not need to classify the cases by ifdef. 604743eee66SSUZUKI Shinsuke * 605743eee66SSUZUKI Shinsuke * At this moment, we do not try to install more than one default router, 606743eee66SSUZUKI Shinsuke * even when the multipath routing is available, because we're not sure about 607743eee66SSUZUKI Shinsuke * the benefits for stub hosts comparing to the risk of making the code 608743eee66SSUZUKI Shinsuke * complicated and the possibility of introducing bugs. 609686cdd19SJun-ichiro itojun Hagino */ 610686cdd19SJun-ichiro itojun Hagino void 6111272577eSXin LI defrouter_select(void) 612686cdd19SJun-ichiro itojun Hagino { 6138b615593SMarko Zec INIT_VNET_INET6(curvnet); 614686cdd19SJun-ichiro itojun Hagino int s = splnet(); 615743eee66SSUZUKI Shinsuke struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; 6166e6b3f7cSQing Li struct llentry *ln = NULL; 617686cdd19SJun-ichiro itojun Hagino 618686cdd19SJun-ichiro itojun Hagino /* 619743eee66SSUZUKI Shinsuke * This function should be called only when acting as an autoconfigured 620743eee66SSUZUKI Shinsuke * host. Although the remaining part of this function is not effective 621743eee66SSUZUKI Shinsuke * if the node is not an autoconfigured host, we explicitly exclude 622743eee66SSUZUKI Shinsuke * such cases here for safety. 623743eee66SSUZUKI Shinsuke */ 624603724d3SBjoern A. Zeeb if (V_ip6_forwarding || !V_ip6_accept_rtadv) { 625743eee66SSUZUKI Shinsuke nd6log((LOG_WARNING, 626743eee66SSUZUKI Shinsuke "defrouter_select: called unexpectedly (forwarding=%d, " 627603724d3SBjoern A. Zeeb "accept_rtadv=%d)\n", V_ip6_forwarding, V_ip6_accept_rtadv)); 628743eee66SSUZUKI Shinsuke splx(s); 629743eee66SSUZUKI Shinsuke return; 630743eee66SSUZUKI Shinsuke } 631743eee66SSUZUKI Shinsuke 632743eee66SSUZUKI Shinsuke /* 633743eee66SSUZUKI Shinsuke * Let's handle easy case (3) first: 634743eee66SSUZUKI Shinsuke * If default router list is empty, there's nothing to be done. 635743eee66SSUZUKI Shinsuke */ 636603724d3SBjoern A. Zeeb if (!TAILQ_FIRST(&V_nd_defrouter)) { 637743eee66SSUZUKI Shinsuke splx(s); 638743eee66SSUZUKI Shinsuke return; 639743eee66SSUZUKI Shinsuke } 640743eee66SSUZUKI Shinsuke 641743eee66SSUZUKI Shinsuke /* 642686cdd19SJun-ichiro itojun Hagino * Search for a (probably) reachable router from the list. 643743eee66SSUZUKI Shinsuke * We just pick up the first reachable one (if any), assuming that 644743eee66SSUZUKI Shinsuke * the ordering rule of the list described in defrtrlist_update(). 645686cdd19SJun-ichiro itojun Hagino */ 646603724d3SBjoern A. Zeeb for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 647686cdd19SJun-ichiro itojun Hagino dr = TAILQ_NEXT(dr, dr_entry)) { 6486e6b3f7cSQing Li IF_AFDATA_LOCK(dr->ifp); 649743eee66SSUZUKI Shinsuke if (selected_dr == NULL && 6506e6b3f7cSQing Li (ln = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) && 651686cdd19SJun-ichiro itojun Hagino ND6_IS_LLINFO_PROBREACH(ln)) { 652743eee66SSUZUKI Shinsuke selected_dr = dr; 653686cdd19SJun-ichiro itojun Hagino } 6546e6b3f7cSQing Li IF_AFDATA_UNLOCK(dr->ifp); 6555f16e341SBjoern A. Zeeb if (ln != NULL) { 656c0641cc0SKip Macy LLE_RUNLOCK(ln); 6575f16e341SBjoern A. Zeeb ln = NULL; 6585f16e341SBjoern A. Zeeb } 659686cdd19SJun-ichiro itojun Hagino 660743eee66SSUZUKI Shinsuke if (dr->installed && installed_dr == NULL) 661743eee66SSUZUKI Shinsuke installed_dr = dr; 662743eee66SSUZUKI Shinsuke else if (dr->installed && installed_dr) { 663743eee66SSUZUKI Shinsuke /* this should not happen. warn for diagnosis. */ 664743eee66SSUZUKI Shinsuke log(LOG_ERR, "defrouter_select: more than one router" 665743eee66SSUZUKI Shinsuke " is installed\n"); 66633841545SHajimu UMEMOTO } 667686cdd19SJun-ichiro itojun Hagino } 668743eee66SSUZUKI Shinsuke /* 669743eee66SSUZUKI Shinsuke * If none of the default routers was found to be reachable, 670743eee66SSUZUKI Shinsuke * round-robin the list regardless of preference. 671743eee66SSUZUKI Shinsuke * Otherwise, if we have an installed router, check if the selected 672743eee66SSUZUKI Shinsuke * (reachable) router should really be preferred to the installed one. 673743eee66SSUZUKI Shinsuke * We only prefer the new router when the old one is not reachable 674743eee66SSUZUKI Shinsuke * or when the new one has a really higher preference value. 675743eee66SSUZUKI Shinsuke */ 676743eee66SSUZUKI Shinsuke if (selected_dr == NULL) { 677743eee66SSUZUKI Shinsuke if (installed_dr == NULL || !TAILQ_NEXT(installed_dr, dr_entry)) 678603724d3SBjoern A. Zeeb selected_dr = TAILQ_FIRST(&V_nd_defrouter); 679743eee66SSUZUKI Shinsuke else 680743eee66SSUZUKI Shinsuke selected_dr = TAILQ_NEXT(installed_dr, dr_entry); 6816e6b3f7cSQing Li } else if (installed_dr) { 6826e6b3f7cSQing Li IF_AFDATA_LOCK(installed_dr->ifp); 6836e6b3f7cSQing Li if ((ln = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) && 684743eee66SSUZUKI Shinsuke ND6_IS_LLINFO_PROBREACH(ln) && 685743eee66SSUZUKI Shinsuke rtpref(selected_dr) <= rtpref(installed_dr)) { 686743eee66SSUZUKI Shinsuke selected_dr = installed_dr; 687743eee66SSUZUKI Shinsuke } 6886e6b3f7cSQing Li IF_AFDATA_UNLOCK(installed_dr->ifp); 689c0641cc0SKip Macy if (ln != NULL) 690c0641cc0SKip Macy LLE_RUNLOCK(ln); 6916e6b3f7cSQing Li } 692743eee66SSUZUKI Shinsuke 693743eee66SSUZUKI Shinsuke /* 694743eee66SSUZUKI Shinsuke * If the selected router is different than the installed one, 695743eee66SSUZUKI Shinsuke * remove the installed router and install the selected one. 696743eee66SSUZUKI Shinsuke * Note that the selected router is never NULL here. 697743eee66SSUZUKI Shinsuke */ 698743eee66SSUZUKI Shinsuke if (installed_dr != selected_dr) { 699743eee66SSUZUKI Shinsuke if (installed_dr) 700743eee66SSUZUKI Shinsuke defrouter_delreq(installed_dr); 701743eee66SSUZUKI Shinsuke defrouter_addreq(selected_dr); 702686cdd19SJun-ichiro itojun Hagino } 703686cdd19SJun-ichiro itojun Hagino 704686cdd19SJun-ichiro itojun Hagino splx(s); 705686cdd19SJun-ichiro itojun Hagino return; 706686cdd19SJun-ichiro itojun Hagino } 707686cdd19SJun-ichiro itojun Hagino 708743eee66SSUZUKI Shinsuke /* 709743eee66SSUZUKI Shinsuke * for default router selection 710743eee66SSUZUKI Shinsuke * regards router-preference field as a 2-bit signed integer 711743eee66SSUZUKI Shinsuke */ 712743eee66SSUZUKI Shinsuke static int 713743eee66SSUZUKI Shinsuke rtpref(struct nd_defrouter *dr) 714743eee66SSUZUKI Shinsuke { 715743eee66SSUZUKI Shinsuke switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) { 716743eee66SSUZUKI Shinsuke case ND_RA_FLAG_RTPREF_HIGH: 717743eee66SSUZUKI Shinsuke return (RTPREF_HIGH); 718743eee66SSUZUKI Shinsuke case ND_RA_FLAG_RTPREF_MEDIUM: 719743eee66SSUZUKI Shinsuke case ND_RA_FLAG_RTPREF_RSV: 720d3693a63SSUZUKI Shinsuke return (RTPREF_MEDIUM); 721743eee66SSUZUKI Shinsuke case ND_RA_FLAG_RTPREF_LOW: 722743eee66SSUZUKI Shinsuke return (RTPREF_LOW); 723743eee66SSUZUKI Shinsuke default: 724743eee66SSUZUKI Shinsuke /* 725743eee66SSUZUKI Shinsuke * This case should never happen. If it did, it would mean a 726743eee66SSUZUKI Shinsuke * serious bug of kernel internal. We thus always bark here. 727743eee66SSUZUKI Shinsuke * Or, can we even panic? 728743eee66SSUZUKI Shinsuke */ 729743eee66SSUZUKI Shinsuke log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags); 730743eee66SSUZUKI Shinsuke return (RTPREF_INVALID); 731743eee66SSUZUKI Shinsuke } 732743eee66SSUZUKI Shinsuke /* NOTREACHED */ 733743eee66SSUZUKI Shinsuke } 734743eee66SSUZUKI Shinsuke 73582cd038dSYoshinobu Inoue static struct nd_defrouter * 7361272577eSXin LI defrtrlist_update(struct nd_defrouter *new) 73782cd038dSYoshinobu Inoue { 7388b615593SMarko Zec INIT_VNET_INET6(curvnet); 73982cd038dSYoshinobu Inoue struct nd_defrouter *dr, *n; 74082cd038dSYoshinobu Inoue int s = splnet(); 74182cd038dSYoshinobu Inoue 74282cd038dSYoshinobu Inoue if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 74382cd038dSYoshinobu Inoue /* entry exists */ 74482cd038dSYoshinobu Inoue if (new->rtlifetime == 0) { 74582cd038dSYoshinobu Inoue defrtrlist_del(dr); 74682cd038dSYoshinobu Inoue dr = NULL; 74782cd038dSYoshinobu Inoue } else { 748743eee66SSUZUKI Shinsuke int oldpref = rtpref(dr); 749743eee66SSUZUKI Shinsuke 75082cd038dSYoshinobu Inoue /* override */ 75182cd038dSYoshinobu Inoue dr->flags = new->flags; /* xxx flag check */ 75282cd038dSYoshinobu Inoue dr->rtlifetime = new->rtlifetime; 75382cd038dSYoshinobu Inoue dr->expire = new->expire; 754743eee66SSUZUKI Shinsuke 755743eee66SSUZUKI Shinsuke /* 756743eee66SSUZUKI Shinsuke * If the preference does not change, there's no need 757743eee66SSUZUKI Shinsuke * to sort the entries. 758743eee66SSUZUKI Shinsuke */ 759743eee66SSUZUKI Shinsuke if (rtpref(new) == oldpref) { 760743eee66SSUZUKI Shinsuke splx(s); 761743eee66SSUZUKI Shinsuke return (dr); 762743eee66SSUZUKI Shinsuke } 763743eee66SSUZUKI Shinsuke 764743eee66SSUZUKI Shinsuke /* 765743eee66SSUZUKI Shinsuke * preferred router may be changed, so relocate 766743eee66SSUZUKI Shinsuke * this router. 767743eee66SSUZUKI Shinsuke * XXX: calling TAILQ_REMOVE directly is a bad manner. 768743eee66SSUZUKI Shinsuke * However, since defrtrlist_del() has many side 769743eee66SSUZUKI Shinsuke * effects, we intentionally do so here. 770743eee66SSUZUKI Shinsuke * defrouter_select() below will handle routing 771743eee66SSUZUKI Shinsuke * changes later. 772743eee66SSUZUKI Shinsuke */ 773603724d3SBjoern A. Zeeb TAILQ_REMOVE(&V_nd_defrouter, dr, dr_entry); 774743eee66SSUZUKI Shinsuke n = dr; 775743eee66SSUZUKI Shinsuke goto insert; 77682cd038dSYoshinobu Inoue } 77782cd038dSYoshinobu Inoue splx(s); 77882cd038dSYoshinobu Inoue return (dr); 77982cd038dSYoshinobu Inoue } 78082cd038dSYoshinobu Inoue 78182cd038dSYoshinobu Inoue /* entry does not exist */ 78282cd038dSYoshinobu Inoue if (new->rtlifetime == 0) { 78382cd038dSYoshinobu Inoue splx(s); 78482cd038dSYoshinobu Inoue return (NULL); 78582cd038dSYoshinobu Inoue } 78682cd038dSYoshinobu Inoue 78782cd038dSYoshinobu Inoue n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 78882cd038dSYoshinobu Inoue if (n == NULL) { 78982cd038dSYoshinobu Inoue splx(s); 79082cd038dSYoshinobu Inoue return (NULL); 79182cd038dSYoshinobu Inoue } 79282cd038dSYoshinobu Inoue bzero(n, sizeof(*n)); 79382cd038dSYoshinobu Inoue *n = *new; 794686cdd19SJun-ichiro itojun Hagino 795743eee66SSUZUKI Shinsuke insert: 796686cdd19SJun-ichiro itojun Hagino /* 797743eee66SSUZUKI Shinsuke * Insert the new router in the Default Router List; 798743eee66SSUZUKI Shinsuke * The Default Router List should be in the descending order 799743eee66SSUZUKI Shinsuke * of router-preferece. Routers with the same preference are 800743eee66SSUZUKI Shinsuke * sorted in the arriving time order. 801686cdd19SJun-ichiro itojun Hagino */ 802743eee66SSUZUKI Shinsuke 803743eee66SSUZUKI Shinsuke /* insert at the end of the group */ 804603724d3SBjoern A. Zeeb for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 805743eee66SSUZUKI Shinsuke dr = TAILQ_NEXT(dr, dr_entry)) { 806743eee66SSUZUKI Shinsuke if (rtpref(n) > rtpref(dr)) 807743eee66SSUZUKI Shinsuke break; 808743eee66SSUZUKI Shinsuke } 809743eee66SSUZUKI Shinsuke if (dr) 810743eee66SSUZUKI Shinsuke TAILQ_INSERT_BEFORE(dr, n, dr_entry); 811743eee66SSUZUKI Shinsuke else 812603724d3SBjoern A. Zeeb TAILQ_INSERT_TAIL(&V_nd_defrouter, n, dr_entry); 813743eee66SSUZUKI Shinsuke 814686cdd19SJun-ichiro itojun Hagino defrouter_select(); 815743eee66SSUZUKI Shinsuke 81682cd038dSYoshinobu Inoue splx(s); 81782cd038dSYoshinobu Inoue 81882cd038dSYoshinobu Inoue return (n); 81982cd038dSYoshinobu Inoue } 82082cd038dSYoshinobu Inoue 82182cd038dSYoshinobu Inoue static struct nd_pfxrouter * 8221272577eSXin LI pfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) 82382cd038dSYoshinobu Inoue { 82482cd038dSYoshinobu Inoue struct nd_pfxrouter *search; 82582cd038dSYoshinobu Inoue 826686cdd19SJun-ichiro itojun Hagino for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { 82782cd038dSYoshinobu Inoue if (search->router == dr) 82882cd038dSYoshinobu Inoue break; 82982cd038dSYoshinobu Inoue } 83082cd038dSYoshinobu Inoue 83182cd038dSYoshinobu Inoue return (search); 83282cd038dSYoshinobu Inoue } 83382cd038dSYoshinobu Inoue 83482cd038dSYoshinobu Inoue static void 8351272577eSXin LI pfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) 83682cd038dSYoshinobu Inoue { 83782cd038dSYoshinobu Inoue struct nd_pfxrouter *new; 83882cd038dSYoshinobu Inoue 83982cd038dSYoshinobu Inoue new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 84082cd038dSYoshinobu Inoue if (new == NULL) 84182cd038dSYoshinobu Inoue return; 84282cd038dSYoshinobu Inoue bzero(new, sizeof(*new)); 84382cd038dSYoshinobu Inoue new->router = dr; 84482cd038dSYoshinobu Inoue 84582cd038dSYoshinobu Inoue LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 84682cd038dSYoshinobu Inoue 84782cd038dSYoshinobu Inoue pfxlist_onlink_check(); 84882cd038dSYoshinobu Inoue } 84982cd038dSYoshinobu Inoue 85082cd038dSYoshinobu Inoue static void 8511272577eSXin LI pfxrtr_del(struct nd_pfxrouter *pfr) 85282cd038dSYoshinobu Inoue { 85382cd038dSYoshinobu Inoue LIST_REMOVE(pfr, pfr_entry); 85482cd038dSYoshinobu Inoue free(pfr, M_IP6NDP); 85582cd038dSYoshinobu Inoue } 85682cd038dSYoshinobu Inoue 85733841545SHajimu UMEMOTO struct nd_prefix * 8581272577eSXin LI nd6_prefix_lookup(struct nd_prefixctl *key) 85982cd038dSYoshinobu Inoue { 8608b615593SMarko Zec INIT_VNET_INET6(curvnet); 86182cd038dSYoshinobu Inoue struct nd_prefix *search; 86282cd038dSYoshinobu Inoue 863ac957cd2SJulian Elischer for (search = V_nd_prefix.lh_first; 864ac957cd2SJulian Elischer search; search = search->ndpr_next) { 865743eee66SSUZUKI Shinsuke if (key->ndpr_ifp == search->ndpr_ifp && 866743eee66SSUZUKI Shinsuke key->ndpr_plen == search->ndpr_plen && 867743eee66SSUZUKI Shinsuke in6_are_prefix_equal(&key->ndpr_prefix.sin6_addr, 868743eee66SSUZUKI Shinsuke &search->ndpr_prefix.sin6_addr, key->ndpr_plen)) { 86982cd038dSYoshinobu Inoue break; 87082cd038dSYoshinobu Inoue } 87182cd038dSYoshinobu Inoue } 87282cd038dSYoshinobu Inoue 87382cd038dSYoshinobu Inoue return (search); 87482cd038dSYoshinobu Inoue } 87582cd038dSYoshinobu Inoue 87633841545SHajimu UMEMOTO int 8771272577eSXin LI nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr, 8781272577eSXin LI struct nd_prefix **newp) 87982cd038dSYoshinobu Inoue { 8808b615593SMarko Zec INIT_VNET_INET6(curvnet); 88133841545SHajimu UMEMOTO struct nd_prefix *new = NULL; 882743eee66SSUZUKI Shinsuke int error = 0; 88382cd038dSYoshinobu Inoue int i, s; 8841d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 88582cd038dSYoshinobu Inoue 88682cd038dSYoshinobu Inoue new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 88782cd038dSYoshinobu Inoue if (new == NULL) 88807eb2995SHajimu UMEMOTO return(ENOMEM); 88982cd038dSYoshinobu Inoue bzero(new, sizeof(*new)); 890743eee66SSUZUKI Shinsuke new->ndpr_ifp = pr->ndpr_ifp; 891743eee66SSUZUKI Shinsuke new->ndpr_prefix = pr->ndpr_prefix; 892743eee66SSUZUKI Shinsuke new->ndpr_plen = pr->ndpr_plen; 893743eee66SSUZUKI Shinsuke new->ndpr_vltime = pr->ndpr_vltime; 894743eee66SSUZUKI Shinsuke new->ndpr_pltime = pr->ndpr_pltime; 895743eee66SSUZUKI Shinsuke new->ndpr_flags = pr->ndpr_flags; 896743eee66SSUZUKI Shinsuke if ((error = in6_init_prefix_ltimes(new)) != 0) { 897743eee66SSUZUKI Shinsuke free(new, M_IP6NDP); 898743eee66SSUZUKI Shinsuke return(error); 899743eee66SSUZUKI Shinsuke } 900743eee66SSUZUKI Shinsuke new->ndpr_lastupdate = time_second; 90133841545SHajimu UMEMOTO if (newp != NULL) 90233841545SHajimu UMEMOTO *newp = new; 90382cd038dSYoshinobu Inoue 90407eb2995SHajimu UMEMOTO /* initialization */ 90582cd038dSYoshinobu Inoue LIST_INIT(&new->ndpr_advrtrs); 90682cd038dSYoshinobu Inoue in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 90782cd038dSYoshinobu Inoue /* make prefix in the canonical form */ 90882cd038dSYoshinobu Inoue for (i = 0; i < 4; i++) 90982cd038dSYoshinobu Inoue new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 91082cd038dSYoshinobu Inoue new->ndpr_mask.s6_addr32[i]; 91182cd038dSYoshinobu Inoue 91282cd038dSYoshinobu Inoue s = splnet(); 91382cd038dSYoshinobu Inoue /* link ndpr_entry to nd_prefix list */ 914603724d3SBjoern A. Zeeb LIST_INSERT_HEAD(&V_nd_prefix, new, ndpr_entry); 91582cd038dSYoshinobu Inoue splx(s); 91682cd038dSYoshinobu Inoue 91733841545SHajimu UMEMOTO /* ND_OPT_PI_FLAG_ONLINK processing */ 91833841545SHajimu UMEMOTO if (new->ndpr_raf_onlink) { 91933841545SHajimu UMEMOTO int e; 92033841545SHajimu UMEMOTO 92133841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(new)) != 0) { 92233841545SHajimu UMEMOTO nd6log((LOG_ERR, "nd6_prelist_add: failed to make " 92333841545SHajimu UMEMOTO "the prefix %s/%d on-link on %s (errno=%d)\n", 9241d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 92533841545SHajimu UMEMOTO pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 92633841545SHajimu UMEMOTO /* proceed anyway. XXX: is it correct? */ 92733841545SHajimu UMEMOTO } 92833841545SHajimu UMEMOTO } 92933841545SHajimu UMEMOTO 93007eb2995SHajimu UMEMOTO if (dr) 93182cd038dSYoshinobu Inoue pfxrtr_add(new, dr); 93282cd038dSYoshinobu Inoue 93382cd038dSYoshinobu Inoue return 0; 93482cd038dSYoshinobu Inoue } 93582cd038dSYoshinobu Inoue 93682cd038dSYoshinobu Inoue void 9371272577eSXin LI prelist_remove(struct nd_prefix *pr) 93882cd038dSYoshinobu Inoue { 9398b615593SMarko Zec INIT_VNET_INET6(curvnet); 94082cd038dSYoshinobu Inoue struct nd_pfxrouter *pfr, *next; 94133841545SHajimu UMEMOTO int e, s; 9421d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 94333841545SHajimu UMEMOTO 94433841545SHajimu UMEMOTO /* make sure to invalidate the prefix until it is really freed. */ 94533841545SHajimu UMEMOTO pr->ndpr_vltime = 0; 94633841545SHajimu UMEMOTO pr->ndpr_pltime = 0; 947743eee66SSUZUKI Shinsuke 94833841545SHajimu UMEMOTO /* 94933841545SHajimu UMEMOTO * Though these flags are now meaningless, we'd rather keep the value 9507aa59493SSUZUKI Shinsuke * of pr->ndpr_raf_onlink and pr->ndpr_raf_auto not to confuse users 9517aa59493SSUZUKI Shinsuke * when executing "ndp -p". 95233841545SHajimu UMEMOTO */ 9537aa59493SSUZUKI Shinsuke 95433841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && 95533841545SHajimu UMEMOTO (e = nd6_prefix_offlink(pr)) != 0) { 95633841545SHajimu UMEMOTO nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink " 95733841545SHajimu UMEMOTO "on %s, errno=%d\n", 9581d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 95933841545SHajimu UMEMOTO pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 96033841545SHajimu UMEMOTO /* what should we do? */ 96133841545SHajimu UMEMOTO } 96233841545SHajimu UMEMOTO 96333841545SHajimu UMEMOTO if (pr->ndpr_refcnt > 0) 96433841545SHajimu UMEMOTO return; /* notice here? */ 96582cd038dSYoshinobu Inoue 96682cd038dSYoshinobu Inoue s = splnet(); 96733841545SHajimu UMEMOTO 96882cd038dSYoshinobu Inoue /* unlink ndpr_entry from nd_prefix list */ 96982cd038dSYoshinobu Inoue LIST_REMOVE(pr, ndpr_entry); 97082cd038dSYoshinobu Inoue 97182cd038dSYoshinobu Inoue /* free list of routers that adversed the prefix */ 972686cdd19SJun-ichiro itojun Hagino for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { 973686cdd19SJun-ichiro itojun Hagino next = pfr->pfr_next; 97482cd038dSYoshinobu Inoue 97582cd038dSYoshinobu Inoue free(pfr, M_IP6NDP); 97682cd038dSYoshinobu Inoue } 97733841545SHajimu UMEMOTO splx(s); 97833841545SHajimu UMEMOTO 97982cd038dSYoshinobu Inoue free(pr, M_IP6NDP); 98082cd038dSYoshinobu Inoue 98182cd038dSYoshinobu Inoue pfxlist_onlink_check(); 98282cd038dSYoshinobu Inoue } 98382cd038dSYoshinobu Inoue 9841272577eSXin LI /* 9851272577eSXin LI * dr - may be NULL 9861272577eSXin LI */ 9871272577eSXin LI 988743eee66SSUZUKI Shinsuke static int 9891272577eSXin LI prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr, 9901272577eSXin LI struct mbuf *m, int mcast) 99182cd038dSYoshinobu Inoue { 9928b615593SMarko Zec INIT_VNET_INET6(curvnet); 99333841545SHajimu UMEMOTO struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL; 99433841545SHajimu UMEMOTO struct ifaddr *ifa; 99533841545SHajimu UMEMOTO struct ifnet *ifp = new->ndpr_ifp; 99682cd038dSYoshinobu Inoue struct nd_prefix *pr; 99782cd038dSYoshinobu Inoue int s = splnet(); 99882cd038dSYoshinobu Inoue int error = 0; 99933841545SHajimu UMEMOTO int newprefix = 0; 100082cd038dSYoshinobu Inoue int auth; 100133841545SHajimu UMEMOTO struct in6_addrlifetime lt6_tmp; 10021d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 100382cd038dSYoshinobu Inoue 100482cd038dSYoshinobu Inoue auth = 0; 100582cd038dSYoshinobu Inoue if (m) { 100682cd038dSYoshinobu Inoue /* 100782cd038dSYoshinobu Inoue * Authenticity for NA consists authentication for 100882cd038dSYoshinobu Inoue * both IP header and IP datagrams, doesn't it ? 100982cd038dSYoshinobu Inoue */ 101082cd038dSYoshinobu Inoue #if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 101107eb2995SHajimu UMEMOTO auth = ((m->m_flags & M_AUTHIPHDR) && 101207eb2995SHajimu UMEMOTO (m->m_flags & M_AUTHIPDGM)); 101382cd038dSYoshinobu Inoue #endif 101482cd038dSYoshinobu Inoue } 101582cd038dSYoshinobu Inoue 101633841545SHajimu UMEMOTO if ((pr = nd6_prefix_lookup(new)) != NULL) { 101733841545SHajimu UMEMOTO /* 101833841545SHajimu UMEMOTO * nd6_prefix_lookup() ensures that pr and new have the same 101933841545SHajimu UMEMOTO * prefix on a same interface. 102033841545SHajimu UMEMOTO */ 102133841545SHajimu UMEMOTO 102233841545SHajimu UMEMOTO /* 102333841545SHajimu UMEMOTO * Update prefix information. Note that the on-link (L) bit 102433841545SHajimu UMEMOTO * and the autonomous (A) bit should NOT be changed from 1 102533841545SHajimu UMEMOTO * to 0. 102633841545SHajimu UMEMOTO */ 102733841545SHajimu UMEMOTO if (new->ndpr_raf_onlink == 1) 102833841545SHajimu UMEMOTO pr->ndpr_raf_onlink = 1; 102933841545SHajimu UMEMOTO if (new->ndpr_raf_auto == 1) 103033841545SHajimu UMEMOTO pr->ndpr_raf_auto = 1; 103133841545SHajimu UMEMOTO if (new->ndpr_raf_onlink) { 103282cd038dSYoshinobu Inoue pr->ndpr_vltime = new->ndpr_vltime; 103382cd038dSYoshinobu Inoue pr->ndpr_pltime = new->ndpr_pltime; 1034743eee66SSUZUKI Shinsuke (void)in6_init_prefix_ltimes(pr); /* XXX error case? */ 1035743eee66SSUZUKI Shinsuke pr->ndpr_lastupdate = time_second; 103682cd038dSYoshinobu Inoue } 103782cd038dSYoshinobu Inoue 103833841545SHajimu UMEMOTO if (new->ndpr_raf_onlink && 103933841545SHajimu UMEMOTO (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 104033841545SHajimu UMEMOTO int e; 104182cd038dSYoshinobu Inoue 104233841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(pr)) != 0) { 104333841545SHajimu UMEMOTO nd6log((LOG_ERR, 104433841545SHajimu UMEMOTO "prelist_update: failed to make " 104533841545SHajimu UMEMOTO "the prefix %s/%d on-link on %s " 104633841545SHajimu UMEMOTO "(errno=%d)\n", 10471d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, 10481d54aa3bSBjoern A. Zeeb &pr->ndpr_prefix.sin6_addr), 104933841545SHajimu UMEMOTO pr->ndpr_plen, if_name(pr->ndpr_ifp), e)); 105033841545SHajimu UMEMOTO /* proceed anyway. XXX: is it correct? */ 1051686cdd19SJun-ichiro itojun Hagino } 105282cd038dSYoshinobu Inoue } 105382cd038dSYoshinobu Inoue 105482cd038dSYoshinobu Inoue if (dr && pfxrtr_lookup(pr, dr) == NULL) 105582cd038dSYoshinobu Inoue pfxrtr_add(pr, dr); 105682cd038dSYoshinobu Inoue } else { 105733841545SHajimu UMEMOTO struct nd_prefix *newpr = NULL; 105882cd038dSYoshinobu Inoue 105933841545SHajimu UMEMOTO newprefix = 1; 106033841545SHajimu UMEMOTO 106133841545SHajimu UMEMOTO if (new->ndpr_vltime == 0) 106233841545SHajimu UMEMOTO goto end; 106333841545SHajimu UMEMOTO if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0) 106433841545SHajimu UMEMOTO goto end; 106582cd038dSYoshinobu Inoue 106633841545SHajimu UMEMOTO error = nd6_prelist_add(new, dr, &newpr); 106733841545SHajimu UMEMOTO if (error != 0 || newpr == NULL) { 106833841545SHajimu UMEMOTO nd6log((LOG_NOTICE, "prelist_update: " 106933841545SHajimu UMEMOTO "nd6_prelist_add failed for %s/%d on %s " 107033841545SHajimu UMEMOTO "errno=%d, returnpr=%p\n", 10711d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &new->ndpr_prefix.sin6_addr), 107233841545SHajimu UMEMOTO new->ndpr_plen, if_name(new->ndpr_ifp), 107333841545SHajimu UMEMOTO error, newpr)); 107433841545SHajimu UMEMOTO goto end; /* we should just give up in this case. */ 107533841545SHajimu UMEMOTO } 107633841545SHajimu UMEMOTO 107782cd038dSYoshinobu Inoue /* 107833841545SHajimu UMEMOTO * XXX: from the ND point of view, we can ignore a prefix 107933841545SHajimu UMEMOTO * with the on-link bit being zero. However, we need a 108033841545SHajimu UMEMOTO * prefix structure for references from autoconfigured 108107eb2995SHajimu UMEMOTO * addresses. Thus, we explicitly make sure that the prefix 108233841545SHajimu UMEMOTO * itself expires now. 108382cd038dSYoshinobu Inoue */ 108433841545SHajimu UMEMOTO if (newpr->ndpr_raf_onlink == 0) { 108533841545SHajimu UMEMOTO newpr->ndpr_vltime = 0; 108633841545SHajimu UMEMOTO newpr->ndpr_pltime = 0; 108733841545SHajimu UMEMOTO in6_init_prefix_ltimes(newpr); 108833841545SHajimu UMEMOTO } 108933841545SHajimu UMEMOTO 109033841545SHajimu UMEMOTO pr = newpr; 109133841545SHajimu UMEMOTO } 109233841545SHajimu UMEMOTO 109333841545SHajimu UMEMOTO /* 109433841545SHajimu UMEMOTO * Address autoconfiguration based on Section 5.5.3 of RFC 2462. 109533841545SHajimu UMEMOTO * Note that pr must be non NULL at this point. 109633841545SHajimu UMEMOTO */ 109733841545SHajimu UMEMOTO 109833841545SHajimu UMEMOTO /* 5.5.3 (a). Ignore the prefix without the A bit set. */ 109982cd038dSYoshinobu Inoue if (!new->ndpr_raf_auto) 1100743eee66SSUZUKI Shinsuke goto end; 110182cd038dSYoshinobu Inoue 110233841545SHajimu UMEMOTO /* 110333841545SHajimu UMEMOTO * 5.5.3 (b). the link-local prefix should have been ignored in 110433841545SHajimu UMEMOTO * nd6_ra_input. 110533841545SHajimu UMEMOTO */ 110633841545SHajimu UMEMOTO 1107743eee66SSUZUKI Shinsuke /* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */ 1108743eee66SSUZUKI Shinsuke if (new->ndpr_pltime > new->ndpr_vltime) { 1109743eee66SSUZUKI Shinsuke error = EINVAL; /* XXX: won't be used */ 1110743eee66SSUZUKI Shinsuke goto end; 1111743eee66SSUZUKI Shinsuke } 111233841545SHajimu UMEMOTO 111333841545SHajimu UMEMOTO /* 1114743eee66SSUZUKI Shinsuke * 5.5.3 (d). If the prefix advertised is not equal to the prefix of 1115743eee66SSUZUKI Shinsuke * an address configured by stateless autoconfiguration already in the 1116743eee66SSUZUKI Shinsuke * list of addresses associated with the interface, and the Valid 1117743eee66SSUZUKI Shinsuke * Lifetime is not 0, form an address. We first check if we have 1118743eee66SSUZUKI Shinsuke * a matching prefix. 1119743eee66SSUZUKI Shinsuke * Note: we apply a clarification in rfc2462bis-02 here. We only 1120743eee66SSUZUKI Shinsuke * consider autoconfigured addresses while RFC2462 simply said 1121743eee66SSUZUKI Shinsuke * "address". 112233841545SHajimu UMEMOTO */ 112307eb2995SHajimu UMEMOTO TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 112433841545SHajimu UMEMOTO struct in6_ifaddr *ifa6; 1125743eee66SSUZUKI Shinsuke u_int32_t remaininglifetime; 112633841545SHajimu UMEMOTO 112733841545SHajimu UMEMOTO if (ifa->ifa_addr->sa_family != AF_INET6) 112833841545SHajimu UMEMOTO continue; 112933841545SHajimu UMEMOTO 113033841545SHajimu UMEMOTO ifa6 = (struct in6_ifaddr *)ifa; 113133841545SHajimu UMEMOTO 113233841545SHajimu UMEMOTO /* 1133743eee66SSUZUKI Shinsuke * We only consider autoconfigured addresses as per rfc2462bis. 1134743eee66SSUZUKI Shinsuke */ 1135743eee66SSUZUKI Shinsuke if (!(ifa6->ia6_flags & IN6_IFF_AUTOCONF)) 1136743eee66SSUZUKI Shinsuke continue; 1137743eee66SSUZUKI Shinsuke 1138743eee66SSUZUKI Shinsuke /* 113933841545SHajimu UMEMOTO * Spec is not clear here, but I believe we should concentrate 114033841545SHajimu UMEMOTO * on unicast (i.e. not anycast) addresses. 114133841545SHajimu UMEMOTO * XXX: other ia6_flags? detached or duplicated? 114233841545SHajimu UMEMOTO */ 114333841545SHajimu UMEMOTO if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0) 114433841545SHajimu UMEMOTO continue; 114533841545SHajimu UMEMOTO 1146743eee66SSUZUKI Shinsuke /* 1147743eee66SSUZUKI Shinsuke * Ignore the address if it is not associated with a prefix 1148743eee66SSUZUKI Shinsuke * or is associated with a prefix that is different from this 1149743eee66SSUZUKI Shinsuke * one. (pr is never NULL here) 1150743eee66SSUZUKI Shinsuke */ 1151743eee66SSUZUKI Shinsuke if (ifa6->ia6_ndpr != pr) 115233841545SHajimu UMEMOTO continue; 115333841545SHajimu UMEMOTO 115433841545SHajimu UMEMOTO if (ia6_match == NULL) /* remember the first one */ 115533841545SHajimu UMEMOTO ia6_match = ifa6; 115633841545SHajimu UMEMOTO 115733841545SHajimu UMEMOTO /* 115833841545SHajimu UMEMOTO * An already autoconfigured address matched. Now that we 115933841545SHajimu UMEMOTO * are sure there is at least one matched address, we can 116033841545SHajimu UMEMOTO * proceed to 5.5.3. (e): update the lifetimes according to the 116133841545SHajimu UMEMOTO * "two hours" rule and the privacy extension. 1162743eee66SSUZUKI Shinsuke * We apply some clarifications in rfc2462bis: 1163743eee66SSUZUKI Shinsuke * - use remaininglifetime instead of storedlifetime as a 1164743eee66SSUZUKI Shinsuke * variable name 1165743eee66SSUZUKI Shinsuke * - remove the dead code in the "two-hour" rule 116633841545SHajimu UMEMOTO */ 116733841545SHajimu UMEMOTO #define TWOHOUR (120*60) 116833841545SHajimu UMEMOTO lt6_tmp = ifa6->ia6_lifetime; 116933841545SHajimu UMEMOTO 117011f3a6e2SHajimu UMEMOTO if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) 1171743eee66SSUZUKI Shinsuke remaininglifetime = ND6_INFINITE_LIFETIME; 1172743eee66SSUZUKI Shinsuke else if (time_second - ifa6->ia6_updatetime > 1173743eee66SSUZUKI Shinsuke lt6_tmp.ia6t_vltime) { 1174743eee66SSUZUKI Shinsuke /* 1175743eee66SSUZUKI Shinsuke * The case of "invalid" address. We should usually 1176743eee66SSUZUKI Shinsuke * not see this case. 1177743eee66SSUZUKI Shinsuke */ 1178743eee66SSUZUKI Shinsuke remaininglifetime = 0; 1179743eee66SSUZUKI Shinsuke } else 1180743eee66SSUZUKI Shinsuke remaininglifetime = lt6_tmp.ia6t_vltime - 1181743eee66SSUZUKI Shinsuke (time_second - ifa6->ia6_updatetime); 118211f3a6e2SHajimu UMEMOTO 118311f3a6e2SHajimu UMEMOTO /* when not updating, keep the current stored lifetime. */ 1184743eee66SSUZUKI Shinsuke lt6_tmp.ia6t_vltime = remaininglifetime; 118533841545SHajimu UMEMOTO 118633841545SHajimu UMEMOTO if (TWOHOUR < new->ndpr_vltime || 1187743eee66SSUZUKI Shinsuke remaininglifetime < new->ndpr_vltime) { 118833841545SHajimu UMEMOTO lt6_tmp.ia6t_vltime = new->ndpr_vltime; 1189743eee66SSUZUKI Shinsuke } else if (remaininglifetime <= TWOHOUR) { 119033841545SHajimu UMEMOTO if (auth) { 119133841545SHajimu UMEMOTO lt6_tmp.ia6t_vltime = new->ndpr_vltime; 119282cd038dSYoshinobu Inoue } 119333841545SHajimu UMEMOTO } else { 119433841545SHajimu UMEMOTO /* 119533841545SHajimu UMEMOTO * new->ndpr_vltime <= TWOHOUR && 1196743eee66SSUZUKI Shinsuke * TWOHOUR < remaininglifetime 119733841545SHajimu UMEMOTO */ 119833841545SHajimu UMEMOTO lt6_tmp.ia6t_vltime = TWOHOUR; 119982cd038dSYoshinobu Inoue } 120082cd038dSYoshinobu Inoue 120133841545SHajimu UMEMOTO /* The 2 hour rule is not imposed for preferred lifetime. */ 120233841545SHajimu UMEMOTO lt6_tmp.ia6t_pltime = new->ndpr_pltime; 120333841545SHajimu UMEMOTO 120433841545SHajimu UMEMOTO in6_init_address_ltimes(pr, <6_tmp); 120533841545SHajimu UMEMOTO 120633841545SHajimu UMEMOTO /* 1207743eee66SSUZUKI Shinsuke * We need to treat lifetimes for temporary addresses 1208743eee66SSUZUKI Shinsuke * differently, according to 1209743eee66SSUZUKI Shinsuke * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1); 1210743eee66SSUZUKI Shinsuke * we only update the lifetimes when they are in the maximum 1211743eee66SSUZUKI Shinsuke * intervals. 121233841545SHajimu UMEMOTO */ 121333841545SHajimu UMEMOTO if ((ifa6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { 1214743eee66SSUZUKI Shinsuke u_int32_t maxvltime, maxpltime; 121533841545SHajimu UMEMOTO 1216603724d3SBjoern A. Zeeb if (V_ip6_temp_valid_lifetime > 1217743eee66SSUZUKI Shinsuke (u_int32_t)((time_second - ifa6->ia6_createtime) + 1218603724d3SBjoern A. Zeeb V_ip6_desync_factor)) { 1219603724d3SBjoern A. Zeeb maxvltime = V_ip6_temp_valid_lifetime - 1220743eee66SSUZUKI Shinsuke (time_second - ifa6->ia6_createtime) - 1221603724d3SBjoern A. Zeeb V_ip6_desync_factor; 1222743eee66SSUZUKI Shinsuke } else 1223743eee66SSUZUKI Shinsuke maxvltime = 0; 1224603724d3SBjoern A. Zeeb if (V_ip6_temp_preferred_lifetime > 1225743eee66SSUZUKI Shinsuke (u_int32_t)((time_second - ifa6->ia6_createtime) + 1226603724d3SBjoern A. Zeeb V_ip6_desync_factor)) { 1227603724d3SBjoern A. Zeeb maxpltime = V_ip6_temp_preferred_lifetime - 1228743eee66SSUZUKI Shinsuke (time_second - ifa6->ia6_createtime) - 1229603724d3SBjoern A. Zeeb V_ip6_desync_factor; 1230743eee66SSUZUKI Shinsuke } else 1231743eee66SSUZUKI Shinsuke maxpltime = 0; 1232743eee66SSUZUKI Shinsuke 1233743eee66SSUZUKI Shinsuke if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME || 1234743eee66SSUZUKI Shinsuke lt6_tmp.ia6t_vltime > maxvltime) { 1235743eee66SSUZUKI Shinsuke lt6_tmp.ia6t_vltime = maxvltime; 1236743eee66SSUZUKI Shinsuke } 1237743eee66SSUZUKI Shinsuke if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || 1238743eee66SSUZUKI Shinsuke lt6_tmp.ia6t_pltime > maxpltime) { 1239743eee66SSUZUKI Shinsuke lt6_tmp.ia6t_pltime = maxpltime; 1240743eee66SSUZUKI Shinsuke } 1241743eee66SSUZUKI Shinsuke } 124233841545SHajimu UMEMOTO ifa6->ia6_lifetime = lt6_tmp; 1243743eee66SSUZUKI Shinsuke ifa6->ia6_updatetime = time_second; 124433841545SHajimu UMEMOTO } 124533841545SHajimu UMEMOTO if (ia6_match == NULL && new->ndpr_vltime) { 1246743eee66SSUZUKI Shinsuke int ifidlen; 1247743eee66SSUZUKI Shinsuke 124833841545SHajimu UMEMOTO /* 1249743eee66SSUZUKI Shinsuke * 5.5.3 (d) (continued) 125033841545SHajimu UMEMOTO * No address matched and the valid lifetime is non-zero. 125133841545SHajimu UMEMOTO * Create a new address. 125233841545SHajimu UMEMOTO */ 1253743eee66SSUZUKI Shinsuke 1254743eee66SSUZUKI Shinsuke /* 1255743eee66SSUZUKI Shinsuke * Prefix Length check: 1256743eee66SSUZUKI Shinsuke * If the sum of the prefix length and interface identifier 1257743eee66SSUZUKI Shinsuke * length does not equal 128 bits, the Prefix Information 1258743eee66SSUZUKI Shinsuke * option MUST be ignored. The length of the interface 1259743eee66SSUZUKI Shinsuke * identifier is defined in a separate link-type specific 1260743eee66SSUZUKI Shinsuke * document. 1261743eee66SSUZUKI Shinsuke */ 1262743eee66SSUZUKI Shinsuke ifidlen = in6_if2idlen(ifp); 1263743eee66SSUZUKI Shinsuke if (ifidlen < 0) { 1264743eee66SSUZUKI Shinsuke /* this should not happen, so we always log it. */ 1265743eee66SSUZUKI Shinsuke log(LOG_ERR, "prelist_update: IFID undefined (%s)\n", 1266743eee66SSUZUKI Shinsuke if_name(ifp)); 1267743eee66SSUZUKI Shinsuke goto end; 1268743eee66SSUZUKI Shinsuke } 1269743eee66SSUZUKI Shinsuke if (ifidlen + pr->ndpr_plen != 128) { 1270743eee66SSUZUKI Shinsuke nd6log((LOG_INFO, 1271743eee66SSUZUKI Shinsuke "prelist_update: invalid prefixlen " 1272743eee66SSUZUKI Shinsuke "%d for %s, ignored\n", 1273743eee66SSUZUKI Shinsuke pr->ndpr_plen, if_name(ifp))); 1274743eee66SSUZUKI Shinsuke goto end; 1275743eee66SSUZUKI Shinsuke } 1276743eee66SSUZUKI Shinsuke 1277743eee66SSUZUKI Shinsuke if ((ia6 = in6_ifadd(new, mcast)) != NULL) { 127833841545SHajimu UMEMOTO /* 127933841545SHajimu UMEMOTO * note that we should use pr (not new) for reference. 128033841545SHajimu UMEMOTO */ 128133841545SHajimu UMEMOTO pr->ndpr_refcnt++; 128233841545SHajimu UMEMOTO ia6->ia6_ndpr = pr; 128333841545SHajimu UMEMOTO 128433841545SHajimu UMEMOTO /* 128533841545SHajimu UMEMOTO * RFC 3041 3.3 (2). 128633841545SHajimu UMEMOTO * When a new public address is created as described 128733841545SHajimu UMEMOTO * in RFC2462, also create a new temporary address. 128833841545SHajimu UMEMOTO * 128933841545SHajimu UMEMOTO * RFC 3041 3.5. 129033841545SHajimu UMEMOTO * When an interface connects to a new link, a new 129133841545SHajimu UMEMOTO * randomized interface identifier should be generated 129233841545SHajimu UMEMOTO * immediately together with a new set of temporary 129333841545SHajimu UMEMOTO * addresses. Thus, we specifiy 1 as the 2nd arg of 129433841545SHajimu UMEMOTO * in6_tmpifadd(). 129533841545SHajimu UMEMOTO */ 1296603724d3SBjoern A. Zeeb if (V_ip6_use_tempaddr) { 129733841545SHajimu UMEMOTO int e; 1298743eee66SSUZUKI Shinsuke if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) { 129933841545SHajimu UMEMOTO nd6log((LOG_NOTICE, "prelist_update: " 130033841545SHajimu UMEMOTO "failed to create a temporary " 130133841545SHajimu UMEMOTO "address, errno=%d\n", 130233841545SHajimu UMEMOTO e)); 130333841545SHajimu UMEMOTO } 130433841545SHajimu UMEMOTO } 130533841545SHajimu UMEMOTO 130633841545SHajimu UMEMOTO /* 130733841545SHajimu UMEMOTO * A newly added address might affect the status 130833841545SHajimu UMEMOTO * of other addresses, so we check and update it. 130933841545SHajimu UMEMOTO * XXX: what if address duplication happens? 131033841545SHajimu UMEMOTO */ 131133841545SHajimu UMEMOTO pfxlist_onlink_check(); 131233841545SHajimu UMEMOTO } else { 131333841545SHajimu UMEMOTO /* just set an error. do not bark here. */ 131433841545SHajimu UMEMOTO error = EADDRNOTAVAIL; /* XXX: might be unused. */ 131533841545SHajimu UMEMOTO } 131633841545SHajimu UMEMOTO } 131733841545SHajimu UMEMOTO 131882cd038dSYoshinobu Inoue end: 131982cd038dSYoshinobu Inoue splx(s); 132082cd038dSYoshinobu Inoue return error; 132182cd038dSYoshinobu Inoue } 132282cd038dSYoshinobu Inoue 132382cd038dSYoshinobu Inoue /* 1324686cdd19SJun-ichiro itojun Hagino * A supplement function used in the on-link detection below; 1325686cdd19SJun-ichiro itojun Hagino * detect if a given prefix has a (probably) reachable advertising router. 1326686cdd19SJun-ichiro itojun Hagino * XXX: lengthy function name... 1327686cdd19SJun-ichiro itojun Hagino */ 132833841545SHajimu UMEMOTO static struct nd_pfxrouter * 13291272577eSXin LI find_pfxlist_reachable_router(struct nd_prefix *pr) 1330686cdd19SJun-ichiro itojun Hagino { 1331686cdd19SJun-ichiro itojun Hagino struct nd_pfxrouter *pfxrtr; 13326e6b3f7cSQing Li struct llentry *ln; 1333d78be3a9SKip Macy int canreach; 1334686cdd19SJun-ichiro itojun Hagino 1335a6146780SKip Macy for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr != NULL; 1336686cdd19SJun-ichiro itojun Hagino pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { 13376e6b3f7cSQing Li IF_AFDATA_LOCK(pfxrtr->router->ifp); 1338d78be3a9SKip Macy ln = nd6_lookup(&pfxrtr->router->rtaddr, 0, pfxrtr->router->ifp); 13396e6b3f7cSQing Li IF_AFDATA_UNLOCK(pfxrtr->router->ifp); 1340a6146780SKip Macy if (ln == NULL) 1341a6146780SKip Macy continue; 1342d78be3a9SKip Macy canreach = ND6_IS_LLINFO_PROBREACH(ln); 1343d78be3a9SKip Macy LLE_RUNLOCK(ln); 1344d78be3a9SKip Macy if (canreach) 1345d78be3a9SKip Macy break; 13466e6b3f7cSQing Li } 1347686cdd19SJun-ichiro itojun Hagino return (pfxrtr); 1348686cdd19SJun-ichiro itojun Hagino } 1349686cdd19SJun-ichiro itojun Hagino 1350686cdd19SJun-ichiro itojun Hagino /* 135182cd038dSYoshinobu Inoue * Check if each prefix in the prefix list has at least one available router 135233841545SHajimu UMEMOTO * that advertised the prefix (a router is "available" if its neighbor cache 135333841545SHajimu UMEMOTO * entry is reachable or probably reachable). 1354686cdd19SJun-ichiro itojun Hagino * If the check fails, the prefix may be off-link, because, for example, 135582cd038dSYoshinobu Inoue * we have moved from the network but the lifetime of the prefix has not 135633841545SHajimu UMEMOTO * expired yet. So we should not use the prefix if there is another prefix 135733841545SHajimu UMEMOTO * that has an available router. 135833841545SHajimu UMEMOTO * But, if there is no prefix that has an available router, we still regards 135982cd038dSYoshinobu Inoue * all the prefixes as on-link. This is because we can't tell if all the 136082cd038dSYoshinobu Inoue * routers are simply dead or if we really moved from the network and there 136182cd038dSYoshinobu Inoue * is no router around us. 136282cd038dSYoshinobu Inoue */ 1363686cdd19SJun-ichiro itojun Hagino void 136482cd038dSYoshinobu Inoue pfxlist_onlink_check() 136582cd038dSYoshinobu Inoue { 13668b615593SMarko Zec INIT_VNET_INET6(curvnet); 136782cd038dSYoshinobu Inoue struct nd_prefix *pr; 136833841545SHajimu UMEMOTO struct in6_ifaddr *ifa; 1369743eee66SSUZUKI Shinsuke struct nd_defrouter *dr; 1370743eee66SSUZUKI Shinsuke struct nd_pfxrouter *pfxrtr = NULL; 137182cd038dSYoshinobu Inoue 1372686cdd19SJun-ichiro itojun Hagino /* 1373686cdd19SJun-ichiro itojun Hagino * Check if there is a prefix that has a reachable advertising 1374686cdd19SJun-ichiro itojun Hagino * router. 1375686cdd19SJun-ichiro itojun Hagino */ 1376603724d3SBjoern A. Zeeb for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 137733841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) 137882cd038dSYoshinobu Inoue break; 1379686cdd19SJun-ichiro itojun Hagino } 138082cd038dSYoshinobu Inoue 138182cd038dSYoshinobu Inoue /* 1382743eee66SSUZUKI Shinsuke * If we have no such prefix, check whether we still have a router 1383743eee66SSUZUKI Shinsuke * that does not advertise any prefixes. 1384743eee66SSUZUKI Shinsuke */ 1385743eee66SSUZUKI Shinsuke if (pr == NULL) { 1386603724d3SBjoern A. Zeeb for (dr = TAILQ_FIRST(&V_nd_defrouter); dr; 1387743eee66SSUZUKI Shinsuke dr = TAILQ_NEXT(dr, dr_entry)) { 1388743eee66SSUZUKI Shinsuke struct nd_prefix *pr0; 1389743eee66SSUZUKI Shinsuke 1390603724d3SBjoern A. Zeeb for (pr0 = V_nd_prefix.lh_first; pr0; 1391743eee66SSUZUKI Shinsuke pr0 = pr0->ndpr_next) { 1392743eee66SSUZUKI Shinsuke if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) 1393743eee66SSUZUKI Shinsuke break; 1394743eee66SSUZUKI Shinsuke } 1395743eee66SSUZUKI Shinsuke if (pfxrtr != NULL) 1396743eee66SSUZUKI Shinsuke break; 1397743eee66SSUZUKI Shinsuke } 1398743eee66SSUZUKI Shinsuke } 1399603724d3SBjoern A. Zeeb if (pr != NULL || (TAILQ_FIRST(&V_nd_defrouter) && pfxrtr == NULL)) { 1400743eee66SSUZUKI Shinsuke /* 1401743eee66SSUZUKI Shinsuke * There is at least one prefix that has a reachable router, 1402743eee66SSUZUKI Shinsuke * or at least a router which probably does not advertise 1403743eee66SSUZUKI Shinsuke * any prefixes. The latter would be the case when we move 1404743eee66SSUZUKI Shinsuke * to a new link where we have a router that does not provide 1405743eee66SSUZUKI Shinsuke * prefixes and we configure an address by hand. 140633841545SHajimu UMEMOTO * Detach prefixes which have no reachable advertising 140733841545SHajimu UMEMOTO * router, and attach other prefixes. 140882cd038dSYoshinobu Inoue */ 1409603724d3SBjoern A. Zeeb for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 141033841545SHajimu UMEMOTO /* XXX: a link-local prefix should never be detached */ 141133841545SHajimu UMEMOTO if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 141233841545SHajimu UMEMOTO continue; 141333841545SHajimu UMEMOTO 141433841545SHajimu UMEMOTO /* 141533841545SHajimu UMEMOTO * we aren't interested in prefixes without the L bit 141633841545SHajimu UMEMOTO * set. 141733841545SHajimu UMEMOTO */ 141833841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink == 0) 141933841545SHajimu UMEMOTO continue; 142033841545SHajimu UMEMOTO 142133841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 142233841545SHajimu UMEMOTO find_pfxlist_reachable_router(pr) == NULL) 142333841545SHajimu UMEMOTO pr->ndpr_stateflags |= NDPRF_DETACHED; 142433841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 142533841545SHajimu UMEMOTO find_pfxlist_reachable_router(pr) != 0) 142633841545SHajimu UMEMOTO pr->ndpr_stateflags &= ~NDPRF_DETACHED; 142782cd038dSYoshinobu Inoue } 142833841545SHajimu UMEMOTO } else { 142933841545SHajimu UMEMOTO /* there is no prefix that has a reachable router */ 1430603724d3SBjoern A. Zeeb for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 143133841545SHajimu UMEMOTO if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 143233841545SHajimu UMEMOTO continue; 143333841545SHajimu UMEMOTO 143433841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink == 0) 143533841545SHajimu UMEMOTO continue; 143633841545SHajimu UMEMOTO 143733841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) 143833841545SHajimu UMEMOTO pr->ndpr_stateflags &= ~NDPRF_DETACHED; 143933841545SHajimu UMEMOTO } 144033841545SHajimu UMEMOTO } 144133841545SHajimu UMEMOTO 144233841545SHajimu UMEMOTO /* 144333841545SHajimu UMEMOTO * Remove each interface route associated with a (just) detached 144433841545SHajimu UMEMOTO * prefix, and reinstall the interface route for a (just) attached 144533841545SHajimu UMEMOTO * prefix. Note that all attempt of reinstallation does not 144633841545SHajimu UMEMOTO * necessarily success, when a same prefix is shared among multiple 144733841545SHajimu UMEMOTO * interfaces. Such cases will be handled in nd6_prefix_onlink, 144833841545SHajimu UMEMOTO * so we don't have to care about them. 144933841545SHajimu UMEMOTO */ 1450603724d3SBjoern A. Zeeb for (pr = V_nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 145133841545SHajimu UMEMOTO int e; 14521d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 145333841545SHajimu UMEMOTO 145433841545SHajimu UMEMOTO if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) 145533841545SHajimu UMEMOTO continue; 145633841545SHajimu UMEMOTO 145733841545SHajimu UMEMOTO if (pr->ndpr_raf_onlink == 0) 145833841545SHajimu UMEMOTO continue; 145933841545SHajimu UMEMOTO 146033841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && 146133841545SHajimu UMEMOTO (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 146233841545SHajimu UMEMOTO if ((e = nd6_prefix_offlink(pr)) != 0) { 146333841545SHajimu UMEMOTO nd6log((LOG_ERR, 146433841545SHajimu UMEMOTO "pfxlist_onlink_check: failed to " 14657aa59493SSUZUKI Shinsuke "make %s/%d offlink, errno=%d\n", 14661d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, 14671d54aa3bSBjoern A. Zeeb &pr->ndpr_prefix.sin6_addr), 146833841545SHajimu UMEMOTO pr->ndpr_plen, e)); 146933841545SHajimu UMEMOTO } 147033841545SHajimu UMEMOTO } 147133841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && 147233841545SHajimu UMEMOTO (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && 147333841545SHajimu UMEMOTO pr->ndpr_raf_onlink) { 147433841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(pr)) != 0) { 147533841545SHajimu UMEMOTO nd6log((LOG_ERR, 147633841545SHajimu UMEMOTO "pfxlist_onlink_check: failed to " 14777aa59493SSUZUKI Shinsuke "make %s/%d onlink, errno=%d\n", 14781d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, 14791d54aa3bSBjoern A. Zeeb &pr->ndpr_prefix.sin6_addr), 148033841545SHajimu UMEMOTO pr->ndpr_plen, e)); 148133841545SHajimu UMEMOTO } 148233841545SHajimu UMEMOTO } 148333841545SHajimu UMEMOTO } 148433841545SHajimu UMEMOTO 148533841545SHajimu UMEMOTO /* 148633841545SHajimu UMEMOTO * Changes on the prefix status might affect address status as well. 148733841545SHajimu UMEMOTO * Make sure that all addresses derived from an attached prefix are 148833841545SHajimu UMEMOTO * attached, and that all addresses derived from a detached prefix are 148933841545SHajimu UMEMOTO * detached. Note, however, that a manually configured address should 149033841545SHajimu UMEMOTO * always be attached. 149133841545SHajimu UMEMOTO * The precise detection logic is same as the one for prefixes. 149233841545SHajimu UMEMOTO */ 1493603724d3SBjoern A. Zeeb for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) { 149407eb2995SHajimu UMEMOTO if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF)) 149533841545SHajimu UMEMOTO continue; 149633841545SHajimu UMEMOTO 149733841545SHajimu UMEMOTO if (ifa->ia6_ndpr == NULL) { 149833841545SHajimu UMEMOTO /* 149933841545SHajimu UMEMOTO * This can happen when we first configure the address 150033841545SHajimu UMEMOTO * (i.e. the address exists, but the prefix does not). 150133841545SHajimu UMEMOTO * XXX: complicated relationships... 150233841545SHajimu UMEMOTO */ 150333841545SHajimu UMEMOTO continue; 150433841545SHajimu UMEMOTO } 150533841545SHajimu UMEMOTO 150633841545SHajimu UMEMOTO if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) 150733841545SHajimu UMEMOTO break; 150833841545SHajimu UMEMOTO } 150933841545SHajimu UMEMOTO if (ifa) { 1510603724d3SBjoern A. Zeeb for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) { 151133841545SHajimu UMEMOTO if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 151233841545SHajimu UMEMOTO continue; 151333841545SHajimu UMEMOTO 151433841545SHajimu UMEMOTO if (ifa->ia6_ndpr == NULL) /* XXX: see above. */ 151533841545SHajimu UMEMOTO continue; 151633841545SHajimu UMEMOTO 1517743eee66SSUZUKI Shinsuke if (find_pfxlist_reachable_router(ifa->ia6_ndpr)) { 1518743eee66SSUZUKI Shinsuke if (ifa->ia6_flags & IN6_IFF_DETACHED) { 151933841545SHajimu UMEMOTO ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1520743eee66SSUZUKI Shinsuke ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1521743eee66SSUZUKI Shinsuke nd6_dad_start((struct ifaddr *)ifa, 0); 1522743eee66SSUZUKI Shinsuke } 1523743eee66SSUZUKI Shinsuke } else { 152433841545SHajimu UMEMOTO ifa->ia6_flags |= IN6_IFF_DETACHED; 152582cd038dSYoshinobu Inoue } 1526686cdd19SJun-ichiro itojun Hagino } 1527743eee66SSUZUKI Shinsuke } 1528686cdd19SJun-ichiro itojun Hagino else { 1529603724d3SBjoern A. Zeeb for (ifa = V_in6_ifaddr; ifa; ifa = ifa->ia_next) { 153033841545SHajimu UMEMOTO if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0) 153133841545SHajimu UMEMOTO continue; 153233841545SHajimu UMEMOTO 1533743eee66SSUZUKI Shinsuke if (ifa->ia6_flags & IN6_IFF_DETACHED) { 153433841545SHajimu UMEMOTO ifa->ia6_flags &= ~IN6_IFF_DETACHED; 1535743eee66SSUZUKI Shinsuke ifa->ia6_flags |= IN6_IFF_TENTATIVE; 1536743eee66SSUZUKI Shinsuke /* Do we need a delay in this case? */ 1537743eee66SSUZUKI Shinsuke nd6_dad_start((struct ifaddr *)ifa, 0); 1538743eee66SSUZUKI Shinsuke } 153933841545SHajimu UMEMOTO } 154082cd038dSYoshinobu Inoue } 154182cd038dSYoshinobu Inoue } 154282cd038dSYoshinobu Inoue 154333841545SHajimu UMEMOTO int 15441272577eSXin LI nd6_prefix_onlink(struct nd_prefix *pr) 154582cd038dSYoshinobu Inoue { 15468b615593SMarko Zec INIT_VNET_INET6(curvnet); 154733841545SHajimu UMEMOTO struct ifaddr *ifa; 154833841545SHajimu UMEMOTO struct ifnet *ifp = pr->ndpr_ifp; 154933841545SHajimu UMEMOTO struct sockaddr_in6 mask6; 155033841545SHajimu UMEMOTO struct nd_prefix *opr; 155133841545SHajimu UMEMOTO u_long rtflags; 155233841545SHajimu UMEMOTO int error = 0; 15536e6b3f7cSQing Li struct radix_node_head *rnh; 155433841545SHajimu UMEMOTO struct rtentry *rt = NULL; 15551d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 15566e6b3f7cSQing Li struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 155733841545SHajimu UMEMOTO 155833841545SHajimu UMEMOTO /* sanity check */ 155933841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { 156033841545SHajimu UMEMOTO nd6log((LOG_ERR, 156133841545SHajimu UMEMOTO "nd6_prefix_onlink: %s/%d is already on-link\n", 15621d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 15631d54aa3bSBjoern A. Zeeb pr->ndpr_plen)); 15642ce62dceSSUZUKI Shinsuke return (EEXIST); 156533841545SHajimu UMEMOTO } 156682cd038dSYoshinobu Inoue 156782cd038dSYoshinobu Inoue /* 156833841545SHajimu UMEMOTO * Add the interface route associated with the prefix. Before 156933841545SHajimu UMEMOTO * installing the route, check if there's the same prefix on another 157033841545SHajimu UMEMOTO * interface, and the prefix has already installed the interface route. 157133841545SHajimu UMEMOTO * Although such a configuration is expected to be rare, we explicitly 157233841545SHajimu UMEMOTO * allow it. 157382cd038dSYoshinobu Inoue */ 1574603724d3SBjoern A. Zeeb for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 157533841545SHajimu UMEMOTO if (opr == pr) 157633841545SHajimu UMEMOTO continue; 157733841545SHajimu UMEMOTO 157833841545SHajimu UMEMOTO if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) 157933841545SHajimu UMEMOTO continue; 158033841545SHajimu UMEMOTO 158133841545SHajimu UMEMOTO if (opr->ndpr_plen == pr->ndpr_plen && 158233841545SHajimu UMEMOTO in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 158307eb2995SHajimu UMEMOTO &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) 158433841545SHajimu UMEMOTO return (0); 158533841545SHajimu UMEMOTO } 158633841545SHajimu UMEMOTO 158733841545SHajimu UMEMOTO /* 158833841545SHajimu UMEMOTO * We prefer link-local addresses as the associated interface address. 158933841545SHajimu UMEMOTO */ 159033841545SHajimu UMEMOTO /* search for a link-local addr */ 159133841545SHajimu UMEMOTO ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 159207eb2995SHajimu UMEMOTO IN6_IFF_NOTREADY | IN6_IFF_ANYCAST); 159333841545SHajimu UMEMOTO if (ifa == NULL) { 159433841545SHajimu UMEMOTO /* XXX: freebsd does not have ifa_ifwithaf */ 159507eb2995SHajimu UMEMOTO TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 159633841545SHajimu UMEMOTO if (ifa->ifa_addr->sa_family == AF_INET6) 159733841545SHajimu UMEMOTO break; 159833841545SHajimu UMEMOTO } 159933841545SHajimu UMEMOTO /* should we care about ia6_flags? */ 160033841545SHajimu UMEMOTO } 160133841545SHajimu UMEMOTO if (ifa == NULL) { 160233841545SHajimu UMEMOTO /* 160333841545SHajimu UMEMOTO * This can still happen, when, for example, we receive an RA 160433841545SHajimu UMEMOTO * containing a prefix with the L bit set and the A bit clear, 160533841545SHajimu UMEMOTO * after removing all IPv6 addresses on the receiving 160633841545SHajimu UMEMOTO * interface. This should, of course, be rare though. 160733841545SHajimu UMEMOTO */ 160833841545SHajimu UMEMOTO nd6log((LOG_NOTICE, 160933841545SHajimu UMEMOTO "nd6_prefix_onlink: failed to find any ifaddr" 161033841545SHajimu UMEMOTO " to add route for a prefix(%s/%d) on %s\n", 16111d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 161233841545SHajimu UMEMOTO pr->ndpr_plen, if_name(ifp))); 161333841545SHajimu UMEMOTO return (0); 161433841545SHajimu UMEMOTO } 161533841545SHajimu UMEMOTO 161633841545SHajimu UMEMOTO /* 161733841545SHajimu UMEMOTO * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. 161833841545SHajimu UMEMOTO * ifa->ifa_rtrequest = nd6_rtrequest; 161933841545SHajimu UMEMOTO */ 162033841545SHajimu UMEMOTO bzero(&mask6, sizeof(mask6)); 162133841545SHajimu UMEMOTO mask6.sin6_len = sizeof(mask6); 162233841545SHajimu UMEMOTO mask6.sin6_addr = pr->ndpr_mask; 16236e6b3f7cSQing Li rtflags = ifa->ifa_flags | RTF_UP; 162433841545SHajimu UMEMOTO error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, 162507eb2995SHajimu UMEMOTO ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt); 162633841545SHajimu UMEMOTO if (error == 0) { 16276e6b3f7cSQing Li if (rt != NULL) /* this should be non NULL, though */ { 16286e6b3f7cSQing Li rnh = V_rt_tables[rt->rt_fibnum][AF_INET6]; 16296e6b3f7cSQing Li RADIX_NODE_HEAD_LOCK(rnh); 16306e6b3f7cSQing Li RT_LOCK(rt); 16316e6b3f7cSQing Li if (!rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl)) { 16326e6b3f7cSQing Li ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type = 16336e6b3f7cSQing Li rt->rt_ifp->if_type; 16346e6b3f7cSQing Li ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index = 16356e6b3f7cSQing Li rt->rt_ifp->if_index; 16366e6b3f7cSQing Li } 16376e6b3f7cSQing Li RADIX_NODE_HEAD_UNLOCK(rnh); 163833841545SHajimu UMEMOTO nd6_rtmsg(RTM_ADD, rt); 16396e6b3f7cSQing Li RT_UNLOCK(rt); 16406e6b3f7cSQing Li } 164133841545SHajimu UMEMOTO pr->ndpr_stateflags |= NDPRF_ONLINK; 164207eb2995SHajimu UMEMOTO } else { 16431d54aa3bSBjoern A. Zeeb char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN]; 164433841545SHajimu UMEMOTO nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a" 164533841545SHajimu UMEMOTO " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " 164633841545SHajimu UMEMOTO "errno = %d\n", 16471d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 164833841545SHajimu UMEMOTO pr->ndpr_plen, if_name(ifp), 16491d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), 16501d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error)); 165133841545SHajimu UMEMOTO } 165233841545SHajimu UMEMOTO 1653d1dd20beSSam Leffler if (rt != NULL) { 1654d1dd20beSSam Leffler RT_LOCK(rt); 16557138d65cSSam Leffler RT_REMREF(rt); 1656d1dd20beSSam Leffler RT_UNLOCK(rt); 1657d1dd20beSSam Leffler } 165833841545SHajimu UMEMOTO 165933841545SHajimu UMEMOTO return (error); 166033841545SHajimu UMEMOTO } 166133841545SHajimu UMEMOTO 166233841545SHajimu UMEMOTO int 16631272577eSXin LI nd6_prefix_offlink(struct nd_prefix *pr) 166433841545SHajimu UMEMOTO { 16658b615593SMarko Zec INIT_VNET_INET6(curvnet); 166633841545SHajimu UMEMOTO int error = 0; 166733841545SHajimu UMEMOTO struct ifnet *ifp = pr->ndpr_ifp; 166833841545SHajimu UMEMOTO struct nd_prefix *opr; 166933841545SHajimu UMEMOTO struct sockaddr_in6 sa6, mask6; 167033841545SHajimu UMEMOTO struct rtentry *rt = NULL; 16711d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 167233841545SHajimu UMEMOTO 167333841545SHajimu UMEMOTO /* sanity check */ 167433841545SHajimu UMEMOTO if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { 167533841545SHajimu UMEMOTO nd6log((LOG_ERR, 167633841545SHajimu UMEMOTO "nd6_prefix_offlink: %s/%d is already off-link\n", 16771d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr), 16781d54aa3bSBjoern A. Zeeb pr->ndpr_plen)); 167933841545SHajimu UMEMOTO return (EEXIST); 168033841545SHajimu UMEMOTO } 168133841545SHajimu UMEMOTO 168282cd038dSYoshinobu Inoue bzero(&sa6, sizeof(sa6)); 168382cd038dSYoshinobu Inoue sa6.sin6_family = AF_INET6; 168482cd038dSYoshinobu Inoue sa6.sin6_len = sizeof(sa6); 168582cd038dSYoshinobu Inoue bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 168682cd038dSYoshinobu Inoue sizeof(struct in6_addr)); 168782cd038dSYoshinobu Inoue bzero(&mask6, sizeof(mask6)); 168882cd038dSYoshinobu Inoue mask6.sin6_family = AF_INET6; 168982cd038dSYoshinobu Inoue mask6.sin6_len = sizeof(sa6); 169082cd038dSYoshinobu Inoue bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 169133841545SHajimu UMEMOTO error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 169233841545SHajimu UMEMOTO (struct sockaddr *)&mask6, 0, &rt); 169333841545SHajimu UMEMOTO if (error == 0) { 169433841545SHajimu UMEMOTO pr->ndpr_stateflags &= ~NDPRF_ONLINK; 169533841545SHajimu UMEMOTO 169633841545SHajimu UMEMOTO /* report the route deletion to the routing socket. */ 169733841545SHajimu UMEMOTO if (rt != NULL) 169833841545SHajimu UMEMOTO nd6_rtmsg(RTM_DELETE, rt); 169933841545SHajimu UMEMOTO 170033841545SHajimu UMEMOTO /* 170133841545SHajimu UMEMOTO * There might be the same prefix on another interface, 170233841545SHajimu UMEMOTO * the prefix which could not be on-link just because we have 170333841545SHajimu UMEMOTO * the interface route (see comments in nd6_prefix_onlink). 170433841545SHajimu UMEMOTO * If there's one, try to make the prefix on-link on the 170533841545SHajimu UMEMOTO * interface. 170633841545SHajimu UMEMOTO */ 1707603724d3SBjoern A. Zeeb for (opr = V_nd_prefix.lh_first; opr; opr = opr->ndpr_next) { 170833841545SHajimu UMEMOTO if (opr == pr) 170933841545SHajimu UMEMOTO continue; 171033841545SHajimu UMEMOTO 171133841545SHajimu UMEMOTO if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) 171233841545SHajimu UMEMOTO continue; 171333841545SHajimu UMEMOTO 171433841545SHajimu UMEMOTO /* 171533841545SHajimu UMEMOTO * KAME specific: detached prefixes should not be 171633841545SHajimu UMEMOTO * on-link. 171733841545SHajimu UMEMOTO */ 171833841545SHajimu UMEMOTO if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) 171933841545SHajimu UMEMOTO continue; 172033841545SHajimu UMEMOTO 172133841545SHajimu UMEMOTO if (opr->ndpr_plen == pr->ndpr_plen && 172233841545SHajimu UMEMOTO in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 172307eb2995SHajimu UMEMOTO &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { 172482cd038dSYoshinobu Inoue int e; 172582cd038dSYoshinobu Inoue 172633841545SHajimu UMEMOTO if ((e = nd6_prefix_onlink(opr)) != 0) { 172733841545SHajimu UMEMOTO nd6log((LOG_ERR, 172833841545SHajimu UMEMOTO "nd6_prefix_offlink: failed to " 172933841545SHajimu UMEMOTO "recover a prefix %s/%d from %s " 173033841545SHajimu UMEMOTO "to %s (errno = %d)\n", 17311d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, 17321d54aa3bSBjoern A. Zeeb &opr->ndpr_prefix.sin6_addr), 173333841545SHajimu UMEMOTO opr->ndpr_plen, if_name(ifp), 173433841545SHajimu UMEMOTO if_name(opr->ndpr_ifp), e)); 173582cd038dSYoshinobu Inoue } 173682cd038dSYoshinobu Inoue } 173782cd038dSYoshinobu Inoue } 173807eb2995SHajimu UMEMOTO } else { 173933841545SHajimu UMEMOTO /* XXX: can we still set the NDPRF_ONLINK flag? */ 174033841545SHajimu UMEMOTO nd6log((LOG_ERR, 174133841545SHajimu UMEMOTO "nd6_prefix_offlink: failed to delete route: " 174233841545SHajimu UMEMOTO "%s/%d on %s (errno = %d)\n", 17431d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &sa6.sin6_addr), pr->ndpr_plen, 17441d54aa3bSBjoern A. Zeeb if_name(ifp), error)); 174533841545SHajimu UMEMOTO } 174682cd038dSYoshinobu Inoue 174707eb2995SHajimu UMEMOTO if (rt != NULL) { 174871eba915SRuslan Ermilov RTFREE(rt); 174907eb2995SHajimu UMEMOTO } 175082cd038dSYoshinobu Inoue 175133841545SHajimu UMEMOTO return (error); 175282cd038dSYoshinobu Inoue } 175382cd038dSYoshinobu Inoue 175482cd038dSYoshinobu Inoue static struct in6_ifaddr * 17551272577eSXin LI in6_ifadd(struct nd_prefixctl *pr, int mcast) 175682cd038dSYoshinobu Inoue { 17578b615593SMarko Zec INIT_VNET_INET6(curvnet); 175833841545SHajimu UMEMOTO struct ifnet *ifp = pr->ndpr_ifp; 175982cd038dSYoshinobu Inoue struct ifaddr *ifa; 176033841545SHajimu UMEMOTO struct in6_aliasreq ifra; 176133841545SHajimu UMEMOTO struct in6_ifaddr *ia, *ib; 176233841545SHajimu UMEMOTO int error, plen0; 176382cd038dSYoshinobu Inoue struct in6_addr mask; 176433841545SHajimu UMEMOTO int prefixlen = pr->ndpr_plen; 1765743eee66SSUZUKI Shinsuke int updateflags; 17661d54aa3bSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 176782cd038dSYoshinobu Inoue 1768ae360dddSHajimu UMEMOTO in6_prefixlen2mask(&mask, prefixlen); 176982cd038dSYoshinobu Inoue 177033841545SHajimu UMEMOTO /* 177133841545SHajimu UMEMOTO * find a link-local address (will be interface ID). 177233841545SHajimu UMEMOTO * Is it really mandatory? Theoretically, a global or a site-local 177333841545SHajimu UMEMOTO * address can be configured without a link-local address, if we 177433841545SHajimu UMEMOTO * have a unique interface identifier... 177533841545SHajimu UMEMOTO * 177633841545SHajimu UMEMOTO * it is not mandatory to have a link-local address, we can generate 177733841545SHajimu UMEMOTO * interface identifier on the fly. we do this because: 177833841545SHajimu UMEMOTO * (1) it should be the easiest way to find interface identifier. 177933841545SHajimu UMEMOTO * (2) RFC2462 5.4 suggesting the use of the same interface identifier 178033841545SHajimu UMEMOTO * for multiple addresses on a single interface, and possible shortcut 178133841545SHajimu UMEMOTO * of DAD. we omitted DAD for this reason in the past. 178233841545SHajimu UMEMOTO * (3) a user can prevent autoconfiguration of global address 178333841545SHajimu UMEMOTO * by removing link-local address by hand (this is partly because we 17849d5abbddSJens Schweikhardt * don't have other way to control the use of IPv6 on an interface. 178533841545SHajimu UMEMOTO * this has been our design choice - cf. NRL's "ifconfig auto"). 178633841545SHajimu UMEMOTO * (4) it is easier to manage when an interface has addresses 178733841545SHajimu UMEMOTO * with the same interface identifier, than to have multiple addresses 178833841545SHajimu UMEMOTO * with different interface identifiers. 178933841545SHajimu UMEMOTO */ 1790686cdd19SJun-ichiro itojun Hagino ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ 179182cd038dSYoshinobu Inoue if (ifa) 179282cd038dSYoshinobu Inoue ib = (struct in6_ifaddr *)ifa; 179382cd038dSYoshinobu Inoue else 179482cd038dSYoshinobu Inoue return NULL; 179582cd038dSYoshinobu Inoue 179682cd038dSYoshinobu Inoue /* prefixlen + ifidlen must be equal to 128 */ 179733841545SHajimu UMEMOTO plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); 179833841545SHajimu UMEMOTO if (prefixlen != plen0) { 179933841545SHajimu UMEMOTO nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s " 180033841545SHajimu UMEMOTO "(prefix=%d ifid=%d)\n", 180133841545SHajimu UMEMOTO if_name(ifp), prefixlen, 128 - plen0)); 180282cd038dSYoshinobu Inoue return NULL; 180382cd038dSYoshinobu Inoue } 180482cd038dSYoshinobu Inoue 180582cd038dSYoshinobu Inoue /* make ifaddr */ 180682cd038dSYoshinobu Inoue 180733841545SHajimu UMEMOTO bzero(&ifra, sizeof(ifra)); 1808686cdd19SJun-ichiro itojun Hagino /* 180933841545SHajimu UMEMOTO * in6_update_ifa() does not use ifra_name, but we accurately set it 181033841545SHajimu UMEMOTO * for safety. 1811686cdd19SJun-ichiro itojun Hagino */ 181233841545SHajimu UMEMOTO strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 181333841545SHajimu UMEMOTO ifra.ifra_addr.sin6_family = AF_INET6; 181433841545SHajimu UMEMOTO ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); 181582cd038dSYoshinobu Inoue /* prefix */ 1816743eee66SSUZUKI Shinsuke ifra.ifra_addr.sin6_addr = pr->ndpr_prefix.sin6_addr; 181733841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 181833841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 181933841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 182033841545SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 182133841545SHajimu UMEMOTO 182282cd038dSYoshinobu Inoue /* interface ID */ 182307eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[0] |= 1824743eee66SSUZUKI Shinsuke (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); 182507eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[1] |= 1826743eee66SSUZUKI Shinsuke (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); 182707eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 1828743eee66SSUZUKI Shinsuke (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); 182907eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 1830743eee66SSUZUKI Shinsuke (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); 183182cd038dSYoshinobu Inoue 183233841545SHajimu UMEMOTO /* new prefix mask. */ 183333841545SHajimu UMEMOTO ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 183433841545SHajimu UMEMOTO ifra.ifra_prefixmask.sin6_family = AF_INET6; 183533841545SHajimu UMEMOTO bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr, 183633841545SHajimu UMEMOTO sizeof(ifra.ifra_prefixmask.sin6_addr)); 183782cd038dSYoshinobu Inoue 1838743eee66SSUZUKI Shinsuke /* lifetimes. */ 183933841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime; 184033841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime; 184133841545SHajimu UMEMOTO 184233841545SHajimu UMEMOTO /* XXX: scope zone ID? */ 184333841545SHajimu UMEMOTO 184433841545SHajimu UMEMOTO ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ 184533841545SHajimu UMEMOTO 184633841545SHajimu UMEMOTO /* 1847743eee66SSUZUKI Shinsuke * Make sure that we do not have this address already. This should 1848743eee66SSUZUKI Shinsuke * usually not happen, but we can still see this case, e.g., if we 1849743eee66SSUZUKI Shinsuke * have manually configured the exact address to be configured. 185033841545SHajimu UMEMOTO */ 1851743eee66SSUZUKI Shinsuke if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { 1852743eee66SSUZUKI Shinsuke /* this should be rare enough to make an explicit log */ 1853743eee66SSUZUKI Shinsuke log(LOG_INFO, "in6_ifadd: %s is already configured\n", 18541d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr)); 1855743eee66SSUZUKI Shinsuke return (NULL); 1856743eee66SSUZUKI Shinsuke } 185733841545SHajimu UMEMOTO 1858743eee66SSUZUKI Shinsuke /* 1859743eee66SSUZUKI Shinsuke * Allocate ifaddr structure, link into chain, etc. 1860743eee66SSUZUKI Shinsuke * If we are going to create a new address upon receiving a multicasted 1861743eee66SSUZUKI Shinsuke * RA, we need to impose a random delay before starting DAD. 1862743eee66SSUZUKI Shinsuke * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] 1863743eee66SSUZUKI Shinsuke */ 1864743eee66SSUZUKI Shinsuke updateflags = 0; 1865743eee66SSUZUKI Shinsuke if (mcast) 1866743eee66SSUZUKI Shinsuke updateflags |= IN6_IFAUPDATE_DADDELAY; 1867743eee66SSUZUKI Shinsuke if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) { 186833841545SHajimu UMEMOTO nd6log((LOG_ERR, 186933841545SHajimu UMEMOTO "in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n", 18701d54aa3bSBjoern A. Zeeb ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr), 18711d54aa3bSBjoern A. Zeeb if_name(ifp), error)); 187233841545SHajimu UMEMOTO return (NULL); /* ifaddr must not have been allocated. */ 187382cd038dSYoshinobu Inoue } 187482cd038dSYoshinobu Inoue 187533841545SHajimu UMEMOTO ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 187682cd038dSYoshinobu Inoue 187707eb2995SHajimu UMEMOTO return (ia); /* this is always non-NULL */ 187882cd038dSYoshinobu Inoue } 187982cd038dSYoshinobu Inoue 18801272577eSXin LI /* 18811272577eSXin LI * ia0 - corresponding public address 18821272577eSXin LI */ 188382cd038dSYoshinobu Inoue int 18841272577eSXin LI in6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay) 188582cd038dSYoshinobu Inoue { 18868b615593SMarko Zec INIT_VNET_INET6(curvnet); 188733841545SHajimu UMEMOTO struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; 1888743eee66SSUZUKI Shinsuke struct in6_ifaddr *newia, *ia; 188933841545SHajimu UMEMOTO struct in6_aliasreq ifra; 189033841545SHajimu UMEMOTO int i, error; 189133841545SHajimu UMEMOTO int trylimit = 3; /* XXX: adhoc value */ 1892743eee66SSUZUKI Shinsuke int updateflags; 189333841545SHajimu UMEMOTO u_int32_t randid[2]; 189433841545SHajimu UMEMOTO time_t vltime0, pltime0; 189582cd038dSYoshinobu Inoue 189633841545SHajimu UMEMOTO bzero(&ifra, sizeof(ifra)); 189733841545SHajimu UMEMOTO strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); 189833841545SHajimu UMEMOTO ifra.ifra_addr = ia0->ia_addr; 189933841545SHajimu UMEMOTO /* copy prefix mask */ 190033841545SHajimu UMEMOTO ifra.ifra_prefixmask = ia0->ia_prefixmask; 190133841545SHajimu UMEMOTO /* clear the old IFID */ 190233841545SHajimu UMEMOTO for (i = 0; i < 4; i++) { 190307eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[i] &= 190407eb2995SHajimu UMEMOTO ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; 190533841545SHajimu UMEMOTO } 190682cd038dSYoshinobu Inoue 190733841545SHajimu UMEMOTO again: 1908743eee66SSUZUKI Shinsuke if (in6_get_tmpifid(ifp, (u_int8_t *)randid, 1909743eee66SSUZUKI Shinsuke (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { 1910743eee66SSUZUKI Shinsuke nd6log((LOG_NOTICE, "in6_tmpifadd: failed to find a good " 1911743eee66SSUZUKI Shinsuke "random IFID\n")); 1912743eee66SSUZUKI Shinsuke return (EINVAL); 1913743eee66SSUZUKI Shinsuke } 191407eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[2] |= 191507eb2995SHajimu UMEMOTO (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); 191607eb2995SHajimu UMEMOTO ifra.ifra_addr.sin6_addr.s6_addr32[3] |= 191707eb2995SHajimu UMEMOTO (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); 191882cd038dSYoshinobu Inoue 191982cd038dSYoshinobu Inoue /* 1920743eee66SSUZUKI Shinsuke * in6_get_tmpifid() quite likely provided a unique interface ID. 1921743eee66SSUZUKI Shinsuke * However, we may still have a chance to see collision, because 1922743eee66SSUZUKI Shinsuke * there may be a time lag between generation of the ID and generation 1923743eee66SSUZUKI Shinsuke * of the address. So, we'll do one more sanity check. 192482cd038dSYoshinobu Inoue */ 1925603724d3SBjoern A. Zeeb for (ia = V_in6_ifaddr; ia; ia = ia->ia_next) { 1926743eee66SSUZUKI Shinsuke if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, 1927743eee66SSUZUKI Shinsuke &ifra.ifra_addr.sin6_addr)) { 192833841545SHajimu UMEMOTO if (trylimit-- == 0) { 1929743eee66SSUZUKI Shinsuke /* 1930743eee66SSUZUKI Shinsuke * Give up. Something strange should have 1931743eee66SSUZUKI Shinsuke * happened. 1932743eee66SSUZUKI Shinsuke */ 1933743eee66SSUZUKI Shinsuke nd6log((LOG_NOTICE, "in6_tmpifadd: failed to " 1934743eee66SSUZUKI Shinsuke "find a unique random IFID\n")); 193533841545SHajimu UMEMOTO return (EEXIST); 193633841545SHajimu UMEMOTO } 193733841545SHajimu UMEMOTO forcegen = 1; 193833841545SHajimu UMEMOTO goto again; 193982cd038dSYoshinobu Inoue } 1940743eee66SSUZUKI Shinsuke } 194182cd038dSYoshinobu Inoue 194233841545SHajimu UMEMOTO /* 194333841545SHajimu UMEMOTO * The Valid Lifetime is the lower of the Valid Lifetime of the 194433841545SHajimu UMEMOTO * public address or TEMP_VALID_LIFETIME. 194533841545SHajimu UMEMOTO * The Preferred Lifetime is the lower of the Preferred Lifetime 194633841545SHajimu UMEMOTO * of the public address or TEMP_PREFERRED_LIFETIME - 194733841545SHajimu UMEMOTO * DESYNC_FACTOR. 194882cd038dSYoshinobu Inoue */ 1949743eee66SSUZUKI Shinsuke if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { 195033841545SHajimu UMEMOTO vltime0 = IFA6_IS_INVALID(ia0) ? 0 : 1951743eee66SSUZUKI Shinsuke (ia0->ia6_lifetime.ia6t_vltime - 1952743eee66SSUZUKI Shinsuke (time_second - ia0->ia6_updatetime)); 1953603724d3SBjoern A. Zeeb if (vltime0 > V_ip6_temp_valid_lifetime) 1954603724d3SBjoern A. Zeeb vltime0 = V_ip6_temp_valid_lifetime; 195533841545SHajimu UMEMOTO } else 1956603724d3SBjoern A. Zeeb vltime0 = V_ip6_temp_valid_lifetime; 1957743eee66SSUZUKI Shinsuke if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { 195833841545SHajimu UMEMOTO pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : 1959743eee66SSUZUKI Shinsuke (ia0->ia6_lifetime.ia6t_pltime - 1960743eee66SSUZUKI Shinsuke (time_second - ia0->ia6_updatetime)); 1961603724d3SBjoern A. Zeeb if (pltime0 > V_ip6_temp_preferred_lifetime - V_ip6_desync_factor){ 1962603724d3SBjoern A. Zeeb pltime0 = V_ip6_temp_preferred_lifetime - 1963603724d3SBjoern A. Zeeb V_ip6_desync_factor; 196433841545SHajimu UMEMOTO } 196533841545SHajimu UMEMOTO } else 1966603724d3SBjoern A. Zeeb pltime0 = V_ip6_temp_preferred_lifetime - V_ip6_desync_factor; 196733841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_vltime = vltime0; 196833841545SHajimu UMEMOTO ifra.ifra_lifetime.ia6t_pltime = pltime0; 196933841545SHajimu UMEMOTO 197033841545SHajimu UMEMOTO /* 197133841545SHajimu UMEMOTO * A temporary address is created only if this calculated Preferred 197233841545SHajimu UMEMOTO * Lifetime is greater than REGEN_ADVANCE time units. 197333841545SHajimu UMEMOTO */ 1974603724d3SBjoern A. Zeeb if (ifra.ifra_lifetime.ia6t_pltime <= V_ip6_temp_regen_advance) 197533841545SHajimu UMEMOTO return (0); 197633841545SHajimu UMEMOTO 197733841545SHajimu UMEMOTO /* XXX: scope zone ID? */ 197833841545SHajimu UMEMOTO 197933841545SHajimu UMEMOTO ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); 198033841545SHajimu UMEMOTO 198133841545SHajimu UMEMOTO /* allocate ifaddr structure, link into chain, etc. */ 1982743eee66SSUZUKI Shinsuke updateflags = 0; 1983743eee66SSUZUKI Shinsuke if (delay) 1984743eee66SSUZUKI Shinsuke updateflags |= IN6_IFAUPDATE_DADDELAY; 1985743eee66SSUZUKI Shinsuke if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0) 198633841545SHajimu UMEMOTO return (error); 198733841545SHajimu UMEMOTO 198833841545SHajimu UMEMOTO newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); 198933841545SHajimu UMEMOTO if (newia == NULL) { /* XXX: can it happen? */ 199033841545SHajimu UMEMOTO nd6log((LOG_ERR, 199133841545SHajimu UMEMOTO "in6_tmpifadd: ifa update succeeded, but we got " 199233841545SHajimu UMEMOTO "no ifaddr\n")); 199333841545SHajimu UMEMOTO return (EINVAL); /* XXX */ 199433841545SHajimu UMEMOTO } 199533841545SHajimu UMEMOTO newia->ia6_ndpr = ia0->ia6_ndpr; 199633841545SHajimu UMEMOTO newia->ia6_ndpr->ndpr_refcnt++; 199733841545SHajimu UMEMOTO 1998c3aacd9eSHajimu UMEMOTO /* 1999c3aacd9eSHajimu UMEMOTO * A newly added address might affect the status of other addresses. 2000c3aacd9eSHajimu UMEMOTO * XXX: when the temporary address is generated with a new public 2001c3aacd9eSHajimu UMEMOTO * address, the onlink check is redundant. However, it would be safe 2002c3aacd9eSHajimu UMEMOTO * to do the check explicitly everywhere a new address is generated, 2003c3aacd9eSHajimu UMEMOTO * and, in fact, we surely need the check when we create a new 2004c3aacd9eSHajimu UMEMOTO * temporary address due to deprecation of an old temporary address. 2005c3aacd9eSHajimu UMEMOTO */ 2006c3aacd9eSHajimu UMEMOTO pfxlist_onlink_check(); 2007c3aacd9eSHajimu UMEMOTO 200833841545SHajimu UMEMOTO return (0); 200982cd038dSYoshinobu Inoue } 201082cd038dSYoshinobu Inoue 2011743eee66SSUZUKI Shinsuke static int 201282cd038dSYoshinobu Inoue in6_init_prefix_ltimes(struct nd_prefix *ndpr) 201382cd038dSYoshinobu Inoue { 201482cd038dSYoshinobu Inoue if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 201582cd038dSYoshinobu Inoue ndpr->ndpr_preferred = 0; 201682cd038dSYoshinobu Inoue else 201782cd038dSYoshinobu Inoue ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; 201882cd038dSYoshinobu Inoue if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 201982cd038dSYoshinobu Inoue ndpr->ndpr_expire = 0; 202082cd038dSYoshinobu Inoue else 202182cd038dSYoshinobu Inoue ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; 202282cd038dSYoshinobu Inoue 202382cd038dSYoshinobu Inoue return 0; 202482cd038dSYoshinobu Inoue } 202582cd038dSYoshinobu Inoue 202682cd038dSYoshinobu Inoue static void 202733841545SHajimu UMEMOTO in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 202882cd038dSYoshinobu Inoue { 202982cd038dSYoshinobu Inoue /* init ia6t_expire */ 203082cd038dSYoshinobu Inoue if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 203182cd038dSYoshinobu Inoue lt6->ia6t_expire = 0; 203282cd038dSYoshinobu Inoue else { 203382cd038dSYoshinobu Inoue lt6->ia6t_expire = time_second; 203482cd038dSYoshinobu Inoue lt6->ia6t_expire += lt6->ia6t_vltime; 203582cd038dSYoshinobu Inoue } 2036686cdd19SJun-ichiro itojun Hagino 203782cd038dSYoshinobu Inoue /* init ia6t_preferred */ 203882cd038dSYoshinobu Inoue if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 203982cd038dSYoshinobu Inoue lt6->ia6t_preferred = 0; 204082cd038dSYoshinobu Inoue else { 204182cd038dSYoshinobu Inoue lt6->ia6t_preferred = time_second; 204282cd038dSYoshinobu Inoue lt6->ia6t_preferred += lt6->ia6t_pltime; 204382cd038dSYoshinobu Inoue } 204482cd038dSYoshinobu Inoue } 204582cd038dSYoshinobu Inoue 204682cd038dSYoshinobu Inoue /* 204782cd038dSYoshinobu Inoue * Delete all the routing table entries that use the specified gateway. 204882cd038dSYoshinobu Inoue * XXX: this function causes search through all entries of routing table, so 204982cd038dSYoshinobu Inoue * it shouldn't be called when acting as a router. 205082cd038dSYoshinobu Inoue */ 205182cd038dSYoshinobu Inoue void 20521272577eSXin LI rt6_flush(struct in6_addr *gateway, struct ifnet *ifp) 205382cd038dSYoshinobu Inoue { 20548b615593SMarko Zec INIT_VNET_NET(curvnet); 2055603724d3SBjoern A. Zeeb struct radix_node_head *rnh = V_rt_tables[0][AF_INET6]; 205682cd038dSYoshinobu Inoue int s = splnet(); 205782cd038dSYoshinobu Inoue 205882cd038dSYoshinobu Inoue /* We'll care only link-local addresses */ 205982cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { 206082cd038dSYoshinobu Inoue splx(s); 206182cd038dSYoshinobu Inoue return; 206282cd038dSYoshinobu Inoue } 206382cd038dSYoshinobu Inoue 2064956b0b65SJeffrey Hsu RADIX_NODE_HEAD_LOCK(rnh); 206582cd038dSYoshinobu Inoue rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 2066956b0b65SJeffrey Hsu RADIX_NODE_HEAD_UNLOCK(rnh); 206782cd038dSYoshinobu Inoue splx(s); 206882cd038dSYoshinobu Inoue } 206982cd038dSYoshinobu Inoue 207082cd038dSYoshinobu Inoue static int 20711272577eSXin LI rt6_deleteroute(struct radix_node *rn, void *arg) 207282cd038dSYoshinobu Inoue { 207382cd038dSYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)s) 207482cd038dSYoshinobu Inoue struct rtentry *rt = (struct rtentry *)rn; 207582cd038dSYoshinobu Inoue struct in6_addr *gate = (struct in6_addr *)arg; 207682cd038dSYoshinobu Inoue 207782cd038dSYoshinobu Inoue if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 207882cd038dSYoshinobu Inoue return (0); 207982cd038dSYoshinobu Inoue 208007eb2995SHajimu UMEMOTO if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) { 208182cd038dSYoshinobu Inoue return (0); 208207eb2995SHajimu UMEMOTO } 208382cd038dSYoshinobu Inoue 208482cd038dSYoshinobu Inoue /* 208533841545SHajimu UMEMOTO * Do not delete a static route. 208633841545SHajimu UMEMOTO * XXX: this seems to be a bit ad-hoc. Should we consider the 208733841545SHajimu UMEMOTO * 'cloned' bit instead? 208833841545SHajimu UMEMOTO */ 208933841545SHajimu UMEMOTO if ((rt->rt_flags & RTF_STATIC) != 0) 209033841545SHajimu UMEMOTO return (0); 209133841545SHajimu UMEMOTO 209233841545SHajimu UMEMOTO /* 209382cd038dSYoshinobu Inoue * We delete only host route. This means, in particular, we don't 209482cd038dSYoshinobu Inoue * delete default route. 209582cd038dSYoshinobu Inoue */ 209682cd038dSYoshinobu Inoue if ((rt->rt_flags & RTF_HOST) == 0) 209782cd038dSYoshinobu Inoue return (0); 209882cd038dSYoshinobu Inoue 209907eb2995SHajimu UMEMOTO return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 210007eb2995SHajimu UMEMOTO rt_mask(rt), rt->rt_flags, 0)); 210182cd038dSYoshinobu Inoue #undef SIN6 210282cd038dSYoshinobu Inoue } 2103686cdd19SJun-ichiro itojun Hagino 2104686cdd19SJun-ichiro itojun Hagino int 21051272577eSXin LI nd6_setdefaultiface(int ifindex) 2106686cdd19SJun-ichiro itojun Hagino { 21078b615593SMarko Zec INIT_VNET_NET(curvnet); 21088b615593SMarko Zec INIT_VNET_INET6(curvnet); 2109686cdd19SJun-ichiro itojun Hagino int error = 0; 2110686cdd19SJun-ichiro itojun Hagino 2111603724d3SBjoern A. Zeeb if (ifindex < 0 || V_if_index < ifindex) 2112686cdd19SJun-ichiro itojun Hagino return (EINVAL); 2113743eee66SSUZUKI Shinsuke if (ifindex != 0 && !ifnet_byindex(ifindex)) 2114743eee66SSUZUKI Shinsuke return (EINVAL); 2115686cdd19SJun-ichiro itojun Hagino 2116603724d3SBjoern A. Zeeb if (V_nd6_defifindex != ifindex) { 2117603724d3SBjoern A. Zeeb V_nd6_defifindex = ifindex; 2118603724d3SBjoern A. Zeeb if (V_nd6_defifindex > 0) 2119603724d3SBjoern A. Zeeb V_nd6_defifp = ifnet_byindex(V_nd6_defifindex); 2120686cdd19SJun-ichiro itojun Hagino else 2121603724d3SBjoern A. Zeeb V_nd6_defifp = NULL; 2122686cdd19SJun-ichiro itojun Hagino 2123686cdd19SJun-ichiro itojun Hagino /* 2124686cdd19SJun-ichiro itojun Hagino * Our current implementation assumes one-to-one maping between 2125686cdd19SJun-ichiro itojun Hagino * interfaces and links, so it would be natural to use the 2126686cdd19SJun-ichiro itojun Hagino * default interface as the default link. 2127686cdd19SJun-ichiro itojun Hagino */ 2128603724d3SBjoern A. Zeeb scope6_setdefault(V_nd6_defifp); 2129686cdd19SJun-ichiro itojun Hagino } 2130686cdd19SJun-ichiro itojun Hagino 2131686cdd19SJun-ichiro itojun Hagino return (error); 2132686cdd19SJun-ichiro itojun Hagino } 2133