182cd038dSYoshinobu Inoue /* 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. 2882cd038dSYoshinobu Inoue * 2982cd038dSYoshinobu Inoue * $FreeBSD$ 3082cd038dSYoshinobu Inoue */ 3182cd038dSYoshinobu Inoue 3282cd038dSYoshinobu Inoue #include <sys/param.h> 3382cd038dSYoshinobu Inoue #include <sys/systm.h> 3482cd038dSYoshinobu Inoue #include <sys/malloc.h> 3582cd038dSYoshinobu Inoue #include <sys/mbuf.h> 3682cd038dSYoshinobu Inoue #include <sys/socket.h> 3782cd038dSYoshinobu Inoue #include <sys/sockio.h> 3882cd038dSYoshinobu Inoue #include <sys/time.h> 3982cd038dSYoshinobu Inoue #include <sys/kernel.h> 4082cd038dSYoshinobu Inoue #include <sys/errno.h> 4182cd038dSYoshinobu Inoue #include <sys/syslog.h> 4282cd038dSYoshinobu Inoue 4382cd038dSYoshinobu Inoue #include <net/if.h> 4482cd038dSYoshinobu Inoue #include <net/if_types.h> 4582cd038dSYoshinobu Inoue #include <net/if_dl.h> 4682cd038dSYoshinobu Inoue #include <net/route.h> 4782cd038dSYoshinobu Inoue #include <net/radix.h> 4882cd038dSYoshinobu Inoue 4982cd038dSYoshinobu Inoue #include <netinet/in.h> 5082cd038dSYoshinobu Inoue #include <netinet6/in6_var.h> 5182cd038dSYoshinobu Inoue #include <netinet6/ip6.h> 5282cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 5382cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 5482cd038dSYoshinobu Inoue #include <netinet6/icmp6.h> 5582cd038dSYoshinobu Inoue 5682cd038dSYoshinobu Inoue #include <net/net_osdep.h> 5782cd038dSYoshinobu Inoue 5882cd038dSYoshinobu Inoue #define SDL(s) ((struct sockaddr_dl *)s) 5982cd038dSYoshinobu Inoue 6082cd038dSYoshinobu Inoue static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *)); 6182cd038dSYoshinobu Inoue static int prelist_add __P((struct nd_prefix *, struct nd_defrouter *)); 6282cd038dSYoshinobu Inoue static struct nd_prefix *prefix_lookup __P((struct nd_prefix *)); 6382cd038dSYoshinobu Inoue static struct in6_ifaddr *in6_ifadd __P((struct ifnet *, struct in6_addr *, 6482cd038dSYoshinobu Inoue struct in6_addr *, int)); 6582cd038dSYoshinobu Inoue static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, 6682cd038dSYoshinobu Inoue struct nd_defrouter *)); 6782cd038dSYoshinobu Inoue static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *)); 6882cd038dSYoshinobu Inoue static void pfxrtr_del __P((struct nd_pfxrouter *)); 6982cd038dSYoshinobu Inoue static void pfxlist_onlink_check __P((void)); 7082cd038dSYoshinobu Inoue static void nd6_detach_prefix __P((struct nd_prefix *)); 7182cd038dSYoshinobu Inoue static void nd6_attach_prefix __P((struct nd_prefix *)); 7282cd038dSYoshinobu Inoue 7382cd038dSYoshinobu Inoue static void in6_init_address_ltimes __P((struct nd_prefix *ndpr, 7482cd038dSYoshinobu Inoue struct in6_addrlifetime *lt6)); 7582cd038dSYoshinobu Inoue 7682cd038dSYoshinobu Inoue static int rt6_deleteroute __P((struct radix_node *, void *)); 7782cd038dSYoshinobu Inoue 7882cd038dSYoshinobu Inoue extern int nd6_recalc_reachtm_interval; 7982cd038dSYoshinobu Inoue 8082cd038dSYoshinobu Inoue /* 8182cd038dSYoshinobu Inoue * Receive Router Solicitation Message - just for routers. 8282cd038dSYoshinobu Inoue * Router solicitation/advertisement is mostly managed by userland program 8382cd038dSYoshinobu Inoue * (rtadvd) so here we have no function like nd6_ra_output(). 8482cd038dSYoshinobu Inoue * 8582cd038dSYoshinobu Inoue * Based on RFC 2461 8682cd038dSYoshinobu Inoue */ 8782cd038dSYoshinobu Inoue void 8882cd038dSYoshinobu Inoue nd6_rs_input(m, off, icmp6len) 8982cd038dSYoshinobu Inoue struct mbuf *m; 9082cd038dSYoshinobu Inoue int off, icmp6len; 9182cd038dSYoshinobu Inoue { 9282cd038dSYoshinobu Inoue struct ifnet *ifp = m->m_pkthdr.rcvif; 9382cd038dSYoshinobu Inoue struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 9482cd038dSYoshinobu Inoue struct nd_router_solicit *nd_rs 9582cd038dSYoshinobu Inoue = (struct nd_router_solicit *)((caddr_t)ip6 + off); 9682cd038dSYoshinobu Inoue struct in6_addr saddr6 = ip6->ip6_src; 9782cd038dSYoshinobu Inoue char *lladdr = NULL; 9882cd038dSYoshinobu Inoue int lladdrlen = 0; 9982cd038dSYoshinobu Inoue union nd_opts ndopts; 10082cd038dSYoshinobu Inoue 10182cd038dSYoshinobu Inoue /* If I'm not a router, ignore it. */ 10282cd038dSYoshinobu Inoue if (ip6_accept_rtadv != 0 || ip6_forwarding != 1) 10382cd038dSYoshinobu Inoue return; 10482cd038dSYoshinobu Inoue 10582cd038dSYoshinobu Inoue /* Sanity checks */ 10682cd038dSYoshinobu Inoue if (ip6->ip6_hlim != 255) { 10782cd038dSYoshinobu Inoue log(LOG_ERR, 10882cd038dSYoshinobu Inoue "nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim); 10982cd038dSYoshinobu Inoue return; 11082cd038dSYoshinobu Inoue } 11182cd038dSYoshinobu Inoue 11282cd038dSYoshinobu Inoue /* 11382cd038dSYoshinobu Inoue * Don't update the neighbor cache, if src = ::. 11482cd038dSYoshinobu Inoue * This indicates that the src has no IP address assigned yet. 11582cd038dSYoshinobu Inoue */ 11682cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) 11782cd038dSYoshinobu Inoue return; 11882cd038dSYoshinobu Inoue 11982cd038dSYoshinobu Inoue icmp6len -= sizeof(*nd_rs); 12082cd038dSYoshinobu Inoue nd6_option_init(nd_rs + 1, icmp6len, &ndopts); 12182cd038dSYoshinobu Inoue if (nd6_options(&ndopts) < 0) { 12282cd038dSYoshinobu Inoue log(LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n"); 12382cd038dSYoshinobu Inoue return; 12482cd038dSYoshinobu Inoue } 12582cd038dSYoshinobu Inoue 12682cd038dSYoshinobu Inoue if (ndopts.nd_opts_src_lladdr) { 12782cd038dSYoshinobu Inoue lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 12882cd038dSYoshinobu Inoue lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 12982cd038dSYoshinobu Inoue } 13082cd038dSYoshinobu Inoue 13182cd038dSYoshinobu Inoue if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 13282cd038dSYoshinobu Inoue log(LOG_INFO, 13382cd038dSYoshinobu Inoue "nd6_rs_input: lladdrlen mismatch for %s " 13482cd038dSYoshinobu Inoue "(if %d, RS packet %d)\n", 13582cd038dSYoshinobu Inoue ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2); 13682cd038dSYoshinobu Inoue } 13782cd038dSYoshinobu Inoue 13882cd038dSYoshinobu Inoue nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); 13982cd038dSYoshinobu Inoue } 14082cd038dSYoshinobu Inoue 14182cd038dSYoshinobu Inoue /* 14282cd038dSYoshinobu Inoue * Receive Router Advertisement Message. 14382cd038dSYoshinobu Inoue * 14482cd038dSYoshinobu Inoue * Based on RFC 2461 14582cd038dSYoshinobu Inoue * TODO: on-link bit on prefix information 14682cd038dSYoshinobu Inoue * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing 14782cd038dSYoshinobu Inoue */ 14882cd038dSYoshinobu Inoue void 14982cd038dSYoshinobu Inoue nd6_ra_input(m, off, icmp6len) 15082cd038dSYoshinobu Inoue struct mbuf *m; 15182cd038dSYoshinobu Inoue int off, icmp6len; 15282cd038dSYoshinobu Inoue { 15382cd038dSYoshinobu Inoue struct ifnet *ifp = m->m_pkthdr.rcvif; 15482cd038dSYoshinobu Inoue struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; 15582cd038dSYoshinobu Inoue struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 15682cd038dSYoshinobu Inoue struct nd_router_advert *nd_ra = 15782cd038dSYoshinobu Inoue (struct nd_router_advert *)((caddr_t)ip6 + off); 15882cd038dSYoshinobu Inoue struct in6_addr saddr6 = ip6->ip6_src; 15982cd038dSYoshinobu Inoue union nd_opts ndopts; 16082cd038dSYoshinobu Inoue struct nd_defrouter *dr; 16182cd038dSYoshinobu Inoue 16282cd038dSYoshinobu Inoue if (ip6_accept_rtadv == 0) 16382cd038dSYoshinobu Inoue return; 16482cd038dSYoshinobu Inoue 16582cd038dSYoshinobu Inoue if (ip6->ip6_hlim != 255) { 16682cd038dSYoshinobu Inoue log(LOG_ERR, 16782cd038dSYoshinobu Inoue "nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim); 16882cd038dSYoshinobu Inoue return; 16982cd038dSYoshinobu Inoue } 17082cd038dSYoshinobu Inoue 17182cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { 17282cd038dSYoshinobu Inoue log(LOG_ERR, 17382cd038dSYoshinobu Inoue "nd6_ra_input: src %s is not link-local\n", 17482cd038dSYoshinobu Inoue ip6_sprintf(&saddr6)); 17582cd038dSYoshinobu Inoue return; 17682cd038dSYoshinobu Inoue } 17782cd038dSYoshinobu Inoue 17882cd038dSYoshinobu Inoue icmp6len -= sizeof(*nd_ra); 17982cd038dSYoshinobu Inoue nd6_option_init(nd_ra + 1, icmp6len, &ndopts); 18082cd038dSYoshinobu Inoue if (nd6_options(&ndopts) < 0) { 18182cd038dSYoshinobu Inoue log(LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n"); 18282cd038dSYoshinobu Inoue return; 18382cd038dSYoshinobu Inoue } 18482cd038dSYoshinobu Inoue 18582cd038dSYoshinobu Inoue { 18682cd038dSYoshinobu Inoue struct nd_defrouter dr0; 18782cd038dSYoshinobu Inoue u_int32_t advreachable = nd_ra->nd_ra_reachable; 18882cd038dSYoshinobu Inoue 18982cd038dSYoshinobu Inoue dr0.rtaddr = saddr6; 19082cd038dSYoshinobu Inoue dr0.flags = nd_ra->nd_ra_flags_reserved; 19182cd038dSYoshinobu Inoue dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); 19282cd038dSYoshinobu Inoue dr0.expire = time_second + dr0.rtlifetime; 19382cd038dSYoshinobu Inoue dr0.ifp = ifp; 19482cd038dSYoshinobu Inoue /* unspecified or not? (RFC 2461 6.3.4) */ 19582cd038dSYoshinobu Inoue if (advreachable) { 19682cd038dSYoshinobu Inoue NTOHL(advreachable); 19782cd038dSYoshinobu Inoue if (advreachable <= MAX_REACHABLE_TIME && 19882cd038dSYoshinobu Inoue ndi->basereachable != advreachable) { 19982cd038dSYoshinobu Inoue ndi->basereachable = advreachable; 20082cd038dSYoshinobu Inoue ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); 20182cd038dSYoshinobu Inoue ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */ 20282cd038dSYoshinobu Inoue } 20382cd038dSYoshinobu Inoue } 20482cd038dSYoshinobu Inoue if (nd_ra->nd_ra_retransmit) 20582cd038dSYoshinobu Inoue ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); 20682cd038dSYoshinobu Inoue if (nd_ra->nd_ra_curhoplimit) 20782cd038dSYoshinobu Inoue ndi->chlim = nd_ra->nd_ra_curhoplimit; 20882cd038dSYoshinobu Inoue dr = defrtrlist_update(&dr0); 20982cd038dSYoshinobu Inoue } 21082cd038dSYoshinobu Inoue 21182cd038dSYoshinobu Inoue /* 21282cd038dSYoshinobu Inoue * prefix 21382cd038dSYoshinobu Inoue */ 21482cd038dSYoshinobu Inoue if (ndopts.nd_opts_pi) { 21582cd038dSYoshinobu Inoue struct nd_opt_hdr *pt; 21682cd038dSYoshinobu Inoue struct nd_opt_prefix_info *pi; 21782cd038dSYoshinobu Inoue struct nd_prefix pr; 21882cd038dSYoshinobu Inoue 21982cd038dSYoshinobu Inoue for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; 22082cd038dSYoshinobu Inoue pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; 22182cd038dSYoshinobu Inoue pt = (struct nd_opt_hdr *)((caddr_t)pt + 22282cd038dSYoshinobu Inoue (pt->nd_opt_len << 3))) { 22382cd038dSYoshinobu Inoue if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) 22482cd038dSYoshinobu Inoue continue; 22582cd038dSYoshinobu Inoue pi = (struct nd_opt_prefix_info *)pt; 22682cd038dSYoshinobu Inoue 22782cd038dSYoshinobu Inoue if (pi->nd_opt_pi_len != 4) { 22882cd038dSYoshinobu Inoue log(LOG_INFO, "nd6_ra_input: invalid option " 22982cd038dSYoshinobu Inoue "len %d for prefix information option, " 23082cd038dSYoshinobu Inoue "ignored\n", pi->nd_opt_pi_len); 23182cd038dSYoshinobu Inoue continue; 23282cd038dSYoshinobu Inoue } 23382cd038dSYoshinobu Inoue 23482cd038dSYoshinobu Inoue if (128 < pi->nd_opt_pi_prefix_len) { 23582cd038dSYoshinobu Inoue log(LOG_INFO, "nd6_ra_input: invalid prefix " 23682cd038dSYoshinobu Inoue "len %d for prefix information option, " 23782cd038dSYoshinobu Inoue "ignored\n", pi->nd_opt_pi_prefix_len); 23882cd038dSYoshinobu Inoue continue; 23982cd038dSYoshinobu Inoue } 24082cd038dSYoshinobu Inoue 24182cd038dSYoshinobu Inoue if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) 24282cd038dSYoshinobu Inoue || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { 24382cd038dSYoshinobu Inoue log(LOG_INFO, "nd6_ra_input: invalid prefix " 24482cd038dSYoshinobu Inoue "%s, ignored\n", 24582cd038dSYoshinobu Inoue ip6_sprintf(&pi->nd_opt_pi_prefix)); 24682cd038dSYoshinobu Inoue continue; 24782cd038dSYoshinobu Inoue } 24882cd038dSYoshinobu Inoue 24982cd038dSYoshinobu Inoue /* aggregatable unicast address, rfc2374 */ 25082cd038dSYoshinobu Inoue if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20 25182cd038dSYoshinobu Inoue && pi->nd_opt_pi_prefix_len != 64) { 25282cd038dSYoshinobu Inoue log(LOG_INFO, "nd6_ra_input: invalid prefixlen " 25382cd038dSYoshinobu Inoue "%d for rfc2374 prefix %s, ignored\n", 25482cd038dSYoshinobu Inoue pi->nd_opt_pi_prefix_len, 25582cd038dSYoshinobu Inoue ip6_sprintf(&pi->nd_opt_pi_prefix)); 25682cd038dSYoshinobu Inoue continue; 25782cd038dSYoshinobu Inoue } 25882cd038dSYoshinobu Inoue 25982cd038dSYoshinobu Inoue bzero(&pr, sizeof(pr)); 26082cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_family = AF_INET6; 26182cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); 26282cd038dSYoshinobu Inoue pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; 26382cd038dSYoshinobu Inoue pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; 26482cd038dSYoshinobu Inoue 26582cd038dSYoshinobu Inoue pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & 26682cd038dSYoshinobu Inoue ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; 26782cd038dSYoshinobu Inoue pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & 26882cd038dSYoshinobu Inoue ND_OPT_PI_FLAG_AUTO) ? 1 : 0; 26982cd038dSYoshinobu Inoue pr.ndpr_plen = pi->nd_opt_pi_prefix_len; 27082cd038dSYoshinobu Inoue pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); 27182cd038dSYoshinobu Inoue pr.ndpr_pltime = 27282cd038dSYoshinobu Inoue ntohl(pi->nd_opt_pi_preferred_time); 27382cd038dSYoshinobu Inoue 27482cd038dSYoshinobu Inoue if (in6_init_prefix_ltimes(&pr)) 27582cd038dSYoshinobu Inoue continue; /* prefix lifetime init failed */ 27682cd038dSYoshinobu Inoue 27782cd038dSYoshinobu Inoue (void)prelist_update(&pr, dr, m); 27882cd038dSYoshinobu Inoue } 27982cd038dSYoshinobu Inoue } 28082cd038dSYoshinobu Inoue 28182cd038dSYoshinobu Inoue /* 28282cd038dSYoshinobu Inoue * MTU 28382cd038dSYoshinobu Inoue */ 28482cd038dSYoshinobu Inoue if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { 28582cd038dSYoshinobu Inoue u_int32_t mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); 28682cd038dSYoshinobu Inoue 28782cd038dSYoshinobu Inoue /* lower bound */ 28882cd038dSYoshinobu Inoue if (mtu < IPV6_MMTU) { 28982cd038dSYoshinobu Inoue log(LOG_INFO, "nd6_ra_input: bogus mtu option " 29082cd038dSYoshinobu Inoue "mtu=%d sent from %s, ignoring\n", 29182cd038dSYoshinobu Inoue mtu, ip6_sprintf(&ip6->ip6_src)); 29282cd038dSYoshinobu Inoue goto skip; 29382cd038dSYoshinobu Inoue } 29482cd038dSYoshinobu Inoue 29582cd038dSYoshinobu Inoue /* upper bound */ 29682cd038dSYoshinobu Inoue if (ndi->maxmtu) { 29782cd038dSYoshinobu Inoue if (mtu <= ndi->maxmtu) { 29882cd038dSYoshinobu Inoue int change = (ndi->linkmtu != mtu); 29982cd038dSYoshinobu Inoue 30082cd038dSYoshinobu Inoue ndi->linkmtu = mtu; 30182cd038dSYoshinobu Inoue if (change) /* in6_maxmtu may change */ 30282cd038dSYoshinobu Inoue in6_setmaxmtu(); 30382cd038dSYoshinobu Inoue } else { 30482cd038dSYoshinobu Inoue log(LOG_INFO, "nd6_ra_input: bogus mtu " 30582cd038dSYoshinobu Inoue "mtu=%d sent from %s; " 30682cd038dSYoshinobu Inoue "exceeds maxmtu %d, ignoring\n", 30782cd038dSYoshinobu Inoue mtu, ip6_sprintf(&ip6->ip6_src), 30882cd038dSYoshinobu Inoue ndi->maxmtu); 30982cd038dSYoshinobu Inoue } 31082cd038dSYoshinobu Inoue } else { 31182cd038dSYoshinobu Inoue log(LOG_INFO, "nd6_ra_input: mtu option " 31282cd038dSYoshinobu Inoue "mtu=%d sent from %s; maxmtu unknown, " 31382cd038dSYoshinobu Inoue "ignoring\n", 31482cd038dSYoshinobu Inoue mtu, ip6_sprintf(&ip6->ip6_src)); 31582cd038dSYoshinobu Inoue } 31682cd038dSYoshinobu Inoue } 31782cd038dSYoshinobu Inoue 31882cd038dSYoshinobu Inoue skip: 31982cd038dSYoshinobu Inoue 32082cd038dSYoshinobu Inoue /* 32182cd038dSYoshinobu Inoue * Src linkaddress 32282cd038dSYoshinobu Inoue */ 32382cd038dSYoshinobu Inoue { 32482cd038dSYoshinobu Inoue char *lladdr = NULL; 32582cd038dSYoshinobu Inoue int lladdrlen = 0; 32682cd038dSYoshinobu Inoue 32782cd038dSYoshinobu Inoue if (ndopts.nd_opts_src_lladdr) { 32882cd038dSYoshinobu Inoue lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); 32982cd038dSYoshinobu Inoue lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; 33082cd038dSYoshinobu Inoue } 33182cd038dSYoshinobu Inoue 33282cd038dSYoshinobu Inoue if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { 33382cd038dSYoshinobu Inoue log(LOG_INFO, 33482cd038dSYoshinobu Inoue "nd6_ra_input: lladdrlen mismatch for %s " 33582cd038dSYoshinobu Inoue "(if %d, RA packet %d)\n", 33682cd038dSYoshinobu Inoue ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2); 33782cd038dSYoshinobu Inoue } 33882cd038dSYoshinobu Inoue 33982cd038dSYoshinobu Inoue nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0); 34082cd038dSYoshinobu Inoue } 34182cd038dSYoshinobu Inoue } 34282cd038dSYoshinobu Inoue 34382cd038dSYoshinobu Inoue /* 34482cd038dSYoshinobu Inoue * default router list proccessing sub routines 34582cd038dSYoshinobu Inoue */ 34682cd038dSYoshinobu Inoue void 34782cd038dSYoshinobu Inoue defrouter_addreq(new) 34882cd038dSYoshinobu Inoue struct nd_defrouter *new; 34982cd038dSYoshinobu Inoue { 35082cd038dSYoshinobu Inoue struct sockaddr_in6 def, mask, gate; 35182cd038dSYoshinobu Inoue int s; 35282cd038dSYoshinobu Inoue 35382cd038dSYoshinobu Inoue Bzero(&def, sizeof(def)); 35482cd038dSYoshinobu Inoue Bzero(&mask, sizeof(mask)); 35582cd038dSYoshinobu Inoue Bzero(&gate, sizeof(gate)); 35682cd038dSYoshinobu Inoue 35782cd038dSYoshinobu Inoue def.sin6_len = mask.sin6_len = gate.sin6_len 35882cd038dSYoshinobu Inoue = sizeof(struct sockaddr_in6); 35982cd038dSYoshinobu Inoue def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6; 36082cd038dSYoshinobu Inoue gate.sin6_addr = new->rtaddr; 36182cd038dSYoshinobu Inoue 36282cd038dSYoshinobu Inoue s = splnet(); 36382cd038dSYoshinobu Inoue (void)rtrequest(RTM_ADD, (struct sockaddr *)&def, 36482cd038dSYoshinobu Inoue (struct sockaddr *)&gate, (struct sockaddr *)&mask, 36582cd038dSYoshinobu Inoue RTF_GATEWAY, NULL); 36682cd038dSYoshinobu Inoue splx(s); 36782cd038dSYoshinobu Inoue return; 36882cd038dSYoshinobu Inoue } 36982cd038dSYoshinobu Inoue 37082cd038dSYoshinobu Inoue struct nd_defrouter * 37182cd038dSYoshinobu Inoue defrouter_lookup(addr, ifp) 37282cd038dSYoshinobu Inoue struct in6_addr *addr; 37382cd038dSYoshinobu Inoue struct ifnet *ifp; 37482cd038dSYoshinobu Inoue { 37582cd038dSYoshinobu Inoue struct nd_defrouter *dr; 37682cd038dSYoshinobu Inoue 37782cd038dSYoshinobu Inoue for(dr = nd_defrouter.lh_first; dr; dr = dr->dr_next) 37882cd038dSYoshinobu Inoue if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) 37982cd038dSYoshinobu Inoue return(dr); 38082cd038dSYoshinobu Inoue 38182cd038dSYoshinobu Inoue return(NULL); /* search failed */ 38282cd038dSYoshinobu Inoue } 38382cd038dSYoshinobu Inoue 38482cd038dSYoshinobu Inoue void 38582cd038dSYoshinobu Inoue defrouter_delreq(dr, dofree) 38682cd038dSYoshinobu Inoue struct nd_defrouter *dr; 38782cd038dSYoshinobu Inoue int dofree; 38882cd038dSYoshinobu Inoue { 38982cd038dSYoshinobu Inoue struct sockaddr_in6 def, mask, gate; 39082cd038dSYoshinobu Inoue 39182cd038dSYoshinobu Inoue Bzero(&def, sizeof(def)); 39282cd038dSYoshinobu Inoue Bzero(&mask, sizeof(mask)); 39382cd038dSYoshinobu Inoue Bzero(&gate, sizeof(gate)); 39482cd038dSYoshinobu Inoue 39582cd038dSYoshinobu Inoue def.sin6_len = mask.sin6_len = gate.sin6_len 39682cd038dSYoshinobu Inoue = sizeof(struct sockaddr_in6); 39782cd038dSYoshinobu Inoue def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6; 39882cd038dSYoshinobu Inoue gate.sin6_addr = dr->rtaddr; 39982cd038dSYoshinobu Inoue 40082cd038dSYoshinobu Inoue rtrequest(RTM_DELETE, (struct sockaddr *)&def, 40182cd038dSYoshinobu Inoue (struct sockaddr *)&gate, 40282cd038dSYoshinobu Inoue (struct sockaddr *)&mask, 40382cd038dSYoshinobu Inoue RTF_GATEWAY, (struct rtentry **)0); 40482cd038dSYoshinobu Inoue 40582cd038dSYoshinobu Inoue if (dofree) 40682cd038dSYoshinobu Inoue free(dr, M_IP6NDP); 40782cd038dSYoshinobu Inoue 40882cd038dSYoshinobu Inoue if (nd_defrouter.lh_first) 40982cd038dSYoshinobu Inoue defrouter_addreq(nd_defrouter.lh_first); 41082cd038dSYoshinobu Inoue 41182cd038dSYoshinobu Inoue /* 41282cd038dSYoshinobu Inoue * xxx update the Destination Cache entries for all 41382cd038dSYoshinobu Inoue * destinations using that neighbor as a router (7.2.5) 41482cd038dSYoshinobu Inoue */ 41582cd038dSYoshinobu Inoue } 41682cd038dSYoshinobu Inoue 41782cd038dSYoshinobu Inoue void 41882cd038dSYoshinobu Inoue defrtrlist_del(dr) 41982cd038dSYoshinobu Inoue struct nd_defrouter *dr; 42082cd038dSYoshinobu Inoue { 42182cd038dSYoshinobu Inoue struct nd_defrouter *deldr = NULL; 42282cd038dSYoshinobu Inoue struct nd_prefix *pr; 42382cd038dSYoshinobu Inoue 42482cd038dSYoshinobu Inoue /* 42582cd038dSYoshinobu Inoue * Flush all the routing table entries that use the router 42682cd038dSYoshinobu Inoue * as a next hop. 42782cd038dSYoshinobu Inoue */ 42882cd038dSYoshinobu Inoue if (!ip6_forwarding && ip6_accept_rtadv) { 42982cd038dSYoshinobu Inoue /* above is a good condition? */ 43082cd038dSYoshinobu Inoue rt6_flush(&dr->rtaddr, dr->ifp); 43182cd038dSYoshinobu Inoue } 43282cd038dSYoshinobu Inoue 43382cd038dSYoshinobu Inoue if (dr == nd_defrouter.lh_first) 43482cd038dSYoshinobu Inoue deldr = dr; /* The router is primary. */ 43582cd038dSYoshinobu Inoue 43682cd038dSYoshinobu Inoue LIST_REMOVE(dr, dr_entry); 43782cd038dSYoshinobu Inoue 43882cd038dSYoshinobu Inoue /* 43982cd038dSYoshinobu Inoue * Also delete all the pointers to the router in each prefix lists. 44082cd038dSYoshinobu Inoue */ 44182cd038dSYoshinobu Inoue for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 44282cd038dSYoshinobu Inoue struct nd_pfxrouter *pfxrtr; 44382cd038dSYoshinobu Inoue if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) 44482cd038dSYoshinobu Inoue pfxrtr_del(pfxrtr); 44582cd038dSYoshinobu Inoue } 44682cd038dSYoshinobu Inoue pfxlist_onlink_check(); 44782cd038dSYoshinobu Inoue 44882cd038dSYoshinobu Inoue /* 44982cd038dSYoshinobu Inoue * If the router is the primary one, delete the default route 45082cd038dSYoshinobu Inoue * entry in the routing table. 45182cd038dSYoshinobu Inoue */ 45282cd038dSYoshinobu Inoue if (deldr) 45382cd038dSYoshinobu Inoue defrouter_delreq(deldr, 0); 45482cd038dSYoshinobu Inoue free(dr, M_IP6NDP); 45582cd038dSYoshinobu Inoue } 45682cd038dSYoshinobu Inoue 45782cd038dSYoshinobu Inoue static struct nd_defrouter * 45882cd038dSYoshinobu Inoue defrtrlist_update(new) 45982cd038dSYoshinobu Inoue struct nd_defrouter *new; 46082cd038dSYoshinobu Inoue { 46182cd038dSYoshinobu Inoue struct nd_defrouter *dr, *n; 46282cd038dSYoshinobu Inoue int s = splnet(); 46382cd038dSYoshinobu Inoue 46482cd038dSYoshinobu Inoue if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { 46582cd038dSYoshinobu Inoue /* entry exists */ 46682cd038dSYoshinobu Inoue if (new->rtlifetime == 0) { 46782cd038dSYoshinobu Inoue defrtrlist_del(dr); 46882cd038dSYoshinobu Inoue dr = NULL; 46982cd038dSYoshinobu Inoue } else { 47082cd038dSYoshinobu Inoue /* override */ 47182cd038dSYoshinobu Inoue dr->flags = new->flags; /* xxx flag check */ 47282cd038dSYoshinobu Inoue dr->rtlifetime = new->rtlifetime; 47382cd038dSYoshinobu Inoue dr->expire = new->expire; 47482cd038dSYoshinobu Inoue } 47582cd038dSYoshinobu Inoue splx(s); 47682cd038dSYoshinobu Inoue return(dr); 47782cd038dSYoshinobu Inoue } 47882cd038dSYoshinobu Inoue 47982cd038dSYoshinobu Inoue /* entry does not exist */ 48082cd038dSYoshinobu Inoue if (new->rtlifetime == 0) { 48182cd038dSYoshinobu Inoue splx(s); 48282cd038dSYoshinobu Inoue return(NULL); 48382cd038dSYoshinobu Inoue } 48482cd038dSYoshinobu Inoue 48582cd038dSYoshinobu Inoue n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); 48682cd038dSYoshinobu Inoue if (n == NULL) { 48782cd038dSYoshinobu Inoue splx(s); 48882cd038dSYoshinobu Inoue return(NULL); 48982cd038dSYoshinobu Inoue } 49082cd038dSYoshinobu Inoue bzero(n, sizeof(*n)); 49182cd038dSYoshinobu Inoue *n = *new; 49282cd038dSYoshinobu Inoue if (nd_defrouter.lh_first == NULL) { 49382cd038dSYoshinobu Inoue LIST_INSERT_HEAD(&nd_defrouter, n, dr_entry); 49482cd038dSYoshinobu Inoue defrouter_addreq(n); 49582cd038dSYoshinobu Inoue } else { 49682cd038dSYoshinobu Inoue LIST_INSERT_AFTER(nd_defrouter.lh_first, n, dr_entry); 49782cd038dSYoshinobu Inoue defrouter_addreq(n); 49882cd038dSYoshinobu Inoue } 49982cd038dSYoshinobu Inoue splx(s); 50082cd038dSYoshinobu Inoue 50182cd038dSYoshinobu Inoue return(n); 50282cd038dSYoshinobu Inoue } 50382cd038dSYoshinobu Inoue 50482cd038dSYoshinobu Inoue static struct nd_pfxrouter * 50582cd038dSYoshinobu Inoue pfxrtr_lookup(pr, dr) 50682cd038dSYoshinobu Inoue struct nd_prefix *pr; 50782cd038dSYoshinobu Inoue struct nd_defrouter *dr; 50882cd038dSYoshinobu Inoue { 50982cd038dSYoshinobu Inoue struct nd_pfxrouter *search; 51082cd038dSYoshinobu Inoue 51182cd038dSYoshinobu Inoue for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { 51282cd038dSYoshinobu Inoue if (search->router == dr) 51382cd038dSYoshinobu Inoue break; 51482cd038dSYoshinobu Inoue } 51582cd038dSYoshinobu Inoue 51682cd038dSYoshinobu Inoue return(search); 51782cd038dSYoshinobu Inoue } 51882cd038dSYoshinobu Inoue 51982cd038dSYoshinobu Inoue static void 52082cd038dSYoshinobu Inoue pfxrtr_add(pr, dr) 52182cd038dSYoshinobu Inoue struct nd_prefix *pr; 52282cd038dSYoshinobu Inoue struct nd_defrouter *dr; 52382cd038dSYoshinobu Inoue { 52482cd038dSYoshinobu Inoue struct nd_pfxrouter *new; 52582cd038dSYoshinobu Inoue 52682cd038dSYoshinobu Inoue new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 52782cd038dSYoshinobu Inoue if (new == NULL) 52882cd038dSYoshinobu Inoue return; 52982cd038dSYoshinobu Inoue bzero(new, sizeof(*new)); 53082cd038dSYoshinobu Inoue new->router = dr; 53182cd038dSYoshinobu Inoue 53282cd038dSYoshinobu Inoue LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry); 53382cd038dSYoshinobu Inoue 53482cd038dSYoshinobu Inoue pfxlist_onlink_check(); 53582cd038dSYoshinobu Inoue } 53682cd038dSYoshinobu Inoue 53782cd038dSYoshinobu Inoue static void 53882cd038dSYoshinobu Inoue pfxrtr_del(pfr) 53982cd038dSYoshinobu Inoue struct nd_pfxrouter *pfr; 54082cd038dSYoshinobu Inoue { 54182cd038dSYoshinobu Inoue LIST_REMOVE(pfr, pfr_entry); 54282cd038dSYoshinobu Inoue free(pfr, M_IP6NDP); 54382cd038dSYoshinobu Inoue } 54482cd038dSYoshinobu Inoue 54582cd038dSYoshinobu Inoue static struct nd_prefix * 54682cd038dSYoshinobu Inoue prefix_lookup(pr) 54782cd038dSYoshinobu Inoue struct nd_prefix *pr; 54882cd038dSYoshinobu Inoue { 54982cd038dSYoshinobu Inoue struct nd_prefix *search; 55082cd038dSYoshinobu Inoue 55182cd038dSYoshinobu Inoue for (search = nd_prefix.lh_first; search; search = search->ndpr_next) { 55282cd038dSYoshinobu Inoue if (pr->ndpr_ifp == search->ndpr_ifp && 55382cd038dSYoshinobu Inoue pr->ndpr_plen == search->ndpr_plen && 55482cd038dSYoshinobu Inoue in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, 55582cd038dSYoshinobu Inoue &search->ndpr_prefix.sin6_addr, 55682cd038dSYoshinobu Inoue pr->ndpr_plen) 55782cd038dSYoshinobu Inoue ) { 55882cd038dSYoshinobu Inoue break; 55982cd038dSYoshinobu Inoue } 56082cd038dSYoshinobu Inoue } 56182cd038dSYoshinobu Inoue 56282cd038dSYoshinobu Inoue return(search); 56382cd038dSYoshinobu Inoue } 56482cd038dSYoshinobu Inoue 56582cd038dSYoshinobu Inoue static int 56682cd038dSYoshinobu Inoue prelist_add(pr, dr) 56782cd038dSYoshinobu Inoue struct nd_prefix *pr; 56882cd038dSYoshinobu Inoue struct nd_defrouter *dr; 56982cd038dSYoshinobu Inoue { 57082cd038dSYoshinobu Inoue struct nd_prefix *new; 57182cd038dSYoshinobu Inoue int i, s; 57282cd038dSYoshinobu Inoue 57382cd038dSYoshinobu Inoue new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); 57482cd038dSYoshinobu Inoue if (new == NULL) 57582cd038dSYoshinobu Inoue return ENOMEM; 57682cd038dSYoshinobu Inoue bzero(new, sizeof(*new)); 57782cd038dSYoshinobu Inoue *new = *pr; 57882cd038dSYoshinobu Inoue 57982cd038dSYoshinobu Inoue /* initilization */ 58082cd038dSYoshinobu Inoue new->ndpr_statef_onlink = pr->ndpr_statef_onlink; 58182cd038dSYoshinobu Inoue LIST_INIT(&new->ndpr_advrtrs); 58282cd038dSYoshinobu Inoue in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen); 58382cd038dSYoshinobu Inoue /* make prefix in the canonical form */ 58482cd038dSYoshinobu Inoue for (i = 0; i < 4; i++) 58582cd038dSYoshinobu Inoue new->ndpr_prefix.sin6_addr.s6_addr32[i] &= 58682cd038dSYoshinobu Inoue new->ndpr_mask.s6_addr32[i]; 58782cd038dSYoshinobu Inoue 58882cd038dSYoshinobu Inoue /* xxx ND_OPT_PI_FLAG_ONLINK processing */ 58982cd038dSYoshinobu Inoue 59082cd038dSYoshinobu Inoue s = splnet(); 59182cd038dSYoshinobu Inoue /* link ndpr_entry to nd_prefix list */ 59282cd038dSYoshinobu Inoue LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry); 59382cd038dSYoshinobu Inoue splx(s); 59482cd038dSYoshinobu Inoue 59582cd038dSYoshinobu Inoue if (dr) 59682cd038dSYoshinobu Inoue pfxrtr_add(new, dr); 59782cd038dSYoshinobu Inoue 59882cd038dSYoshinobu Inoue return 0; 59982cd038dSYoshinobu Inoue } 60082cd038dSYoshinobu Inoue 60182cd038dSYoshinobu Inoue void 60282cd038dSYoshinobu Inoue prelist_remove(pr) 60382cd038dSYoshinobu Inoue struct nd_prefix *pr; 60482cd038dSYoshinobu Inoue { 60582cd038dSYoshinobu Inoue struct nd_pfxrouter *pfr, *next; 60682cd038dSYoshinobu Inoue int s; 60782cd038dSYoshinobu Inoue 60882cd038dSYoshinobu Inoue s = splnet(); 60982cd038dSYoshinobu Inoue /* unlink ndpr_entry from nd_prefix list */ 61082cd038dSYoshinobu Inoue LIST_REMOVE(pr, ndpr_entry); 61182cd038dSYoshinobu Inoue splx(s); 61282cd038dSYoshinobu Inoue 61382cd038dSYoshinobu Inoue /* free list of routers that adversed the prefix */ 61482cd038dSYoshinobu Inoue for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { 61582cd038dSYoshinobu Inoue next = pfr->pfr_next; 61682cd038dSYoshinobu Inoue 61782cd038dSYoshinobu Inoue free(pfr, M_IP6NDP); 61882cd038dSYoshinobu Inoue } 61982cd038dSYoshinobu Inoue free(pr, M_IP6NDP); 62082cd038dSYoshinobu Inoue 62182cd038dSYoshinobu Inoue pfxlist_onlink_check(); 62282cd038dSYoshinobu Inoue } 62382cd038dSYoshinobu Inoue 62482cd038dSYoshinobu Inoue /* 62582cd038dSYoshinobu Inoue * NOTE: We set address lifetime to keep 62682cd038dSYoshinobu Inoue * address lifetime <= prefix lifetime 62782cd038dSYoshinobu Inoue * invariant. This is to simplify on-link determination code. 62882cd038dSYoshinobu Inoue * If onlink determination is udated, this routine may have to be updated too. 62982cd038dSYoshinobu Inoue */ 63082cd038dSYoshinobu Inoue int 63182cd038dSYoshinobu Inoue prelist_update(new, dr, m) 63282cd038dSYoshinobu Inoue struct nd_prefix *new; 63382cd038dSYoshinobu Inoue struct nd_defrouter *dr; /* may be NULL */ 63482cd038dSYoshinobu Inoue struct mbuf *m; 63582cd038dSYoshinobu Inoue { 63682cd038dSYoshinobu Inoue struct in6_ifaddr *ia6 = NULL; 63782cd038dSYoshinobu Inoue struct nd_prefix *pr; 63882cd038dSYoshinobu Inoue int s = splnet(); 63982cd038dSYoshinobu Inoue int error = 0; 64082cd038dSYoshinobu Inoue int auth; 64182cd038dSYoshinobu Inoue struct in6_addrlifetime *lt6; 64282cd038dSYoshinobu Inoue 64382cd038dSYoshinobu Inoue auth = 0; 64482cd038dSYoshinobu Inoue if (m) { 64582cd038dSYoshinobu Inoue /* 64682cd038dSYoshinobu Inoue * Authenticity for NA consists authentication for 64782cd038dSYoshinobu Inoue * both IP header and IP datagrams, doesn't it ? 64882cd038dSYoshinobu Inoue */ 64982cd038dSYoshinobu Inoue #if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM) 65082cd038dSYoshinobu Inoue auth = (m->m_flags & M_AUTHIPHDR 65182cd038dSYoshinobu Inoue && m->m_flags & M_AUTHIPDGM) ? 1 : 0; 65282cd038dSYoshinobu Inoue #endif 65382cd038dSYoshinobu Inoue } 65482cd038dSYoshinobu Inoue 65582cd038dSYoshinobu Inoue if ((pr = prefix_lookup(new)) != NULL) { 65682cd038dSYoshinobu Inoue if (pr->ndpr_ifp != new->ndpr_ifp) { 65782cd038dSYoshinobu Inoue error = EADDRNOTAVAIL; 65882cd038dSYoshinobu Inoue goto end; 65982cd038dSYoshinobu Inoue } 66082cd038dSYoshinobu Inoue /* update prefix information */ 66182cd038dSYoshinobu Inoue pr->ndpr_flags = new->ndpr_flags; 66282cd038dSYoshinobu Inoue pr->ndpr_vltime = new->ndpr_vltime; 66382cd038dSYoshinobu Inoue pr->ndpr_pltime = new->ndpr_pltime; 66482cd038dSYoshinobu Inoue pr->ndpr_preferred = new->ndpr_preferred; 66582cd038dSYoshinobu Inoue pr->ndpr_expire = new->ndpr_expire; 66682cd038dSYoshinobu Inoue 66782cd038dSYoshinobu Inoue /* 66882cd038dSYoshinobu Inoue * RFC 2462 5.5.3 (d) or (e) 66982cd038dSYoshinobu Inoue * We got a prefix which we have seen in the past. 67082cd038dSYoshinobu Inoue */ 67182cd038dSYoshinobu Inoue if (!new->ndpr_raf_auto) 67282cd038dSYoshinobu Inoue goto noautoconf1; 67382cd038dSYoshinobu Inoue 67482cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 67582cd038dSYoshinobu Inoue ia6 = NULL; 67682cd038dSYoshinobu Inoue else 67782cd038dSYoshinobu Inoue ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); 67882cd038dSYoshinobu Inoue 67982cd038dSYoshinobu Inoue if (ia6 == NULL) { 68082cd038dSYoshinobu Inoue /* 68182cd038dSYoshinobu Inoue * Special case: 68282cd038dSYoshinobu Inoue * (1) We have seen the prefix advertised before, but 68382cd038dSYoshinobu Inoue * we have never performed autoconfig for this prefix. 68482cd038dSYoshinobu Inoue * This is because Autonomous bit was 0 previously, or 68582cd038dSYoshinobu Inoue * autoconfig failed due to some other reasons. 68682cd038dSYoshinobu Inoue * (2) We have seen the prefix advertised before and 68782cd038dSYoshinobu Inoue * we have performed autoconfig in the past, but 68882cd038dSYoshinobu Inoue * we seem to have no interface address right now. 68982cd038dSYoshinobu Inoue * This is because the interface address have expired. 69082cd038dSYoshinobu Inoue * 69182cd038dSYoshinobu Inoue * This prefix is fresh, with respect to autoconfig 69282cd038dSYoshinobu Inoue * process. 69382cd038dSYoshinobu Inoue * 69482cd038dSYoshinobu Inoue * Add an address based on RFC 2462 5.5.3 (d). 69582cd038dSYoshinobu Inoue */ 69682cd038dSYoshinobu Inoue ia6 = in6_ifadd(pr->ndpr_ifp, 69782cd038dSYoshinobu Inoue &pr->ndpr_prefix.sin6_addr, &pr->ndpr_addr, 69882cd038dSYoshinobu Inoue new->ndpr_plen); 69982cd038dSYoshinobu Inoue if (!ia6) { 70082cd038dSYoshinobu Inoue error = EADDRNOTAVAIL; 70182cd038dSYoshinobu Inoue log(LOG_ERR, "prelist_update: failed to add a " 70282cd038dSYoshinobu Inoue "new address\n"); 70382cd038dSYoshinobu Inoue goto noautoconf1; 70482cd038dSYoshinobu Inoue } 70582cd038dSYoshinobu Inoue 70682cd038dSYoshinobu Inoue lt6 = &ia6->ia6_lifetime; 70782cd038dSYoshinobu Inoue 70882cd038dSYoshinobu Inoue /* address lifetime <= prefix lifetime */ 70982cd038dSYoshinobu Inoue lt6->ia6t_vltime = new->ndpr_vltime; 71082cd038dSYoshinobu Inoue lt6->ia6t_pltime = new->ndpr_pltime; 71182cd038dSYoshinobu Inoue in6_init_address_ltimes(new, lt6); 71282cd038dSYoshinobu Inoue } else { 71382cd038dSYoshinobu Inoue #define TWOHOUR (120*60) 71482cd038dSYoshinobu Inoue /* 71582cd038dSYoshinobu Inoue * We have seen the prefix before, and we have added 71682cd038dSYoshinobu Inoue * interface address in the past. We still have 71782cd038dSYoshinobu Inoue * the interface address assigned. 71882cd038dSYoshinobu Inoue * 71982cd038dSYoshinobu Inoue * update address lifetime based on RFC 2462 72082cd038dSYoshinobu Inoue * 5.5.3 (e). 72182cd038dSYoshinobu Inoue */ 72282cd038dSYoshinobu Inoue int update = 0; 72382cd038dSYoshinobu Inoue 72482cd038dSYoshinobu Inoue lt6 = &ia6->ia6_lifetime; 72582cd038dSYoshinobu Inoue 72682cd038dSYoshinobu Inoue /* 72782cd038dSYoshinobu Inoue * update to RFC 2462 5.5.3 (e) from Jim Bound, 72882cd038dSYoshinobu Inoue * (ipng 6712) 72982cd038dSYoshinobu Inoue */ 73082cd038dSYoshinobu Inoue if (TWOHOUR < new->ndpr_vltime 73182cd038dSYoshinobu Inoue || lt6->ia6t_vltime < new->ndpr_vltime) { 73282cd038dSYoshinobu Inoue lt6->ia6t_vltime = new->ndpr_vltime; 73382cd038dSYoshinobu Inoue update++; 73482cd038dSYoshinobu Inoue } else if (auth) { 73582cd038dSYoshinobu Inoue lt6->ia6t_vltime = new->ndpr_vltime; 73682cd038dSYoshinobu Inoue update++; 73782cd038dSYoshinobu Inoue } 73882cd038dSYoshinobu Inoue 73982cd038dSYoshinobu Inoue /* jim bound rule is not imposed for pref lifetime */ 74082cd038dSYoshinobu Inoue lt6->ia6t_pltime = new->ndpr_pltime; 74182cd038dSYoshinobu Inoue 74282cd038dSYoshinobu Inoue update++; 74382cd038dSYoshinobu Inoue if (update) 74482cd038dSYoshinobu Inoue in6_init_address_ltimes(new, lt6); 74582cd038dSYoshinobu Inoue } 74682cd038dSYoshinobu Inoue 74782cd038dSYoshinobu Inoue noautoconf1: 74882cd038dSYoshinobu Inoue 74982cd038dSYoshinobu Inoue if (dr && pfxrtr_lookup(pr, dr) == NULL) 75082cd038dSYoshinobu Inoue pfxrtr_add(pr, dr); 75182cd038dSYoshinobu Inoue } else { 75282cd038dSYoshinobu Inoue int error_tmp; 75382cd038dSYoshinobu Inoue 75482cd038dSYoshinobu Inoue if (new->ndpr_vltime == 0) goto end; 75582cd038dSYoshinobu Inoue 75682cd038dSYoshinobu Inoue bzero(&new->ndpr_addr, sizeof(struct in6_addr)); 75782cd038dSYoshinobu Inoue 75882cd038dSYoshinobu Inoue /* 75982cd038dSYoshinobu Inoue * RFC 2462 5.5.3 (d) 76082cd038dSYoshinobu Inoue * We got a fresh prefix. Perform some sanity checks 76182cd038dSYoshinobu Inoue * and add an interface address by appending interface ID 76282cd038dSYoshinobu Inoue * to the advertised prefix. 76382cd038dSYoshinobu Inoue */ 76482cd038dSYoshinobu Inoue if (!new->ndpr_raf_auto) 76582cd038dSYoshinobu Inoue goto noautoconf2; 76682cd038dSYoshinobu Inoue 76782cd038dSYoshinobu Inoue ia6 = in6_ifadd(new->ndpr_ifp, &new->ndpr_prefix.sin6_addr, 76882cd038dSYoshinobu Inoue &new->ndpr_addr, new->ndpr_plen); 76982cd038dSYoshinobu Inoue if (!ia6) { 77082cd038dSYoshinobu Inoue error = EADDRNOTAVAIL; 77182cd038dSYoshinobu Inoue log(LOG_ERR, "prelist_update: " 77282cd038dSYoshinobu Inoue "failed to add a new address\n"); 77382cd038dSYoshinobu Inoue goto noautoconf2; 77482cd038dSYoshinobu Inoue } 77582cd038dSYoshinobu Inoue /* set onlink bit if an interface route is configured */ 77682cd038dSYoshinobu Inoue new->ndpr_statef_onlink = (ia6->ia_flags & IFA_ROUTE) ? 1 : 0; 77782cd038dSYoshinobu Inoue 77882cd038dSYoshinobu Inoue lt6 = &ia6->ia6_lifetime; 77982cd038dSYoshinobu Inoue 78082cd038dSYoshinobu Inoue /* address lifetime <= prefix lifetime */ 78182cd038dSYoshinobu Inoue lt6->ia6t_vltime = new->ndpr_vltime; 78282cd038dSYoshinobu Inoue lt6->ia6t_pltime = new->ndpr_pltime; 78382cd038dSYoshinobu Inoue in6_init_address_ltimes(new, lt6); 78482cd038dSYoshinobu Inoue 78582cd038dSYoshinobu Inoue noautoconf2: 78682cd038dSYoshinobu Inoue error_tmp = prelist_add(new, dr); 78782cd038dSYoshinobu Inoue error = error_tmp ? error_tmp : error; 78882cd038dSYoshinobu Inoue } 78982cd038dSYoshinobu Inoue 79082cd038dSYoshinobu Inoue end: 79182cd038dSYoshinobu Inoue splx(s); 79282cd038dSYoshinobu Inoue return error; 79382cd038dSYoshinobu Inoue } 79482cd038dSYoshinobu Inoue 79582cd038dSYoshinobu Inoue /* 79682cd038dSYoshinobu Inoue * Check if each prefix in the prefix list has at least one available router 79782cd038dSYoshinobu Inoue * that advertised the prefix. 79882cd038dSYoshinobu Inoue * If the check fails, the prefix may be off-link because, for example, 79982cd038dSYoshinobu Inoue * we have moved from the network but the lifetime of the prefix has not 80082cd038dSYoshinobu Inoue * been expired yet. So we should not use the prefix if there is another 80182cd038dSYoshinobu Inoue * prefix that has an available router. 80282cd038dSYoshinobu Inoue * But if there is no prefix that has an availble router, we still regards 80382cd038dSYoshinobu Inoue * all the prefixes as on-link. This is because we can't tell if all the 80482cd038dSYoshinobu Inoue * routers are simply dead or if we really moved from the network and there 80582cd038dSYoshinobu Inoue * is no router around us. 80682cd038dSYoshinobu Inoue */ 80782cd038dSYoshinobu Inoue static void 80882cd038dSYoshinobu Inoue pfxlist_onlink_check() 80982cd038dSYoshinobu Inoue { 81082cd038dSYoshinobu Inoue struct nd_prefix *pr; 81182cd038dSYoshinobu Inoue 81282cd038dSYoshinobu Inoue for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) 81382cd038dSYoshinobu Inoue if (pr->ndpr_advrtrs.lh_first) /* pr has an available router */ 81482cd038dSYoshinobu Inoue break; 81582cd038dSYoshinobu Inoue 81682cd038dSYoshinobu Inoue if (pr) { 81782cd038dSYoshinobu Inoue /* 81882cd038dSYoshinobu Inoue * There is at least one prefix that has a router. First, 81982cd038dSYoshinobu Inoue * detach prefixes which has no advertising router and then 82082cd038dSYoshinobu Inoue * attach other prefixes. The order is important since an 82182cd038dSYoshinobu Inoue * attached prefix and a detached prefix may have a same 82282cd038dSYoshinobu Inoue * interface route. 82382cd038dSYoshinobu Inoue */ 82482cd038dSYoshinobu Inoue for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 82582cd038dSYoshinobu Inoue if (pr->ndpr_advrtrs.lh_first == NULL && 82682cd038dSYoshinobu Inoue pr->ndpr_statef_onlink) { 82782cd038dSYoshinobu Inoue pr->ndpr_statef_onlink = 0; 82882cd038dSYoshinobu Inoue nd6_detach_prefix(pr); 82982cd038dSYoshinobu Inoue } 83082cd038dSYoshinobu Inoue } 83182cd038dSYoshinobu Inoue for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { 83282cd038dSYoshinobu Inoue if (pr->ndpr_advrtrs.lh_first && 83382cd038dSYoshinobu Inoue pr->ndpr_statef_onlink == 0) 83482cd038dSYoshinobu Inoue nd6_attach_prefix(pr); 83582cd038dSYoshinobu Inoue } 83682cd038dSYoshinobu Inoue } else { 83782cd038dSYoshinobu Inoue /* there is no prefix that has a router */ 83882cd038dSYoshinobu Inoue for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) 83982cd038dSYoshinobu Inoue if (pr->ndpr_statef_onlink == 0) 84082cd038dSYoshinobu Inoue nd6_attach_prefix(pr); 84182cd038dSYoshinobu Inoue } 84282cd038dSYoshinobu Inoue } 84382cd038dSYoshinobu Inoue 84482cd038dSYoshinobu Inoue static void 84582cd038dSYoshinobu Inoue nd6_detach_prefix(pr) 84682cd038dSYoshinobu Inoue struct nd_prefix *pr; 84782cd038dSYoshinobu Inoue { 84882cd038dSYoshinobu Inoue struct in6_ifaddr *ia6; 84982cd038dSYoshinobu Inoue struct sockaddr_in6 sa6, mask6; 85082cd038dSYoshinobu Inoue 85182cd038dSYoshinobu Inoue /* 85282cd038dSYoshinobu Inoue * Delete the interface route associated with the prefix. 85382cd038dSYoshinobu Inoue */ 85482cd038dSYoshinobu Inoue bzero(&sa6, sizeof(sa6)); 85582cd038dSYoshinobu Inoue sa6.sin6_family = AF_INET6; 85682cd038dSYoshinobu Inoue sa6.sin6_len = sizeof(sa6); 85782cd038dSYoshinobu Inoue bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr, 85882cd038dSYoshinobu Inoue sizeof(struct in6_addr)); 85982cd038dSYoshinobu Inoue bzero(&mask6, sizeof(mask6)); 86082cd038dSYoshinobu Inoue mask6.sin6_family = AF_INET6; 86182cd038dSYoshinobu Inoue mask6.sin6_len = sizeof(sa6); 86282cd038dSYoshinobu Inoue bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr)); 86382cd038dSYoshinobu Inoue { 86482cd038dSYoshinobu Inoue int e; 86582cd038dSYoshinobu Inoue 86682cd038dSYoshinobu Inoue e = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL, 86782cd038dSYoshinobu Inoue (struct sockaddr *)&mask6, 0, NULL); 86882cd038dSYoshinobu Inoue if (e) { 86982cd038dSYoshinobu Inoue log(LOG_ERR, 87082cd038dSYoshinobu Inoue "nd6_detach_prefix: failed to delete route: " 87182cd038dSYoshinobu Inoue "%s/%d (errno = %d)\n", 87282cd038dSYoshinobu Inoue ip6_sprintf(&sa6.sin6_addr), 87382cd038dSYoshinobu Inoue pr->ndpr_plen, 87482cd038dSYoshinobu Inoue e); 87582cd038dSYoshinobu Inoue } 87682cd038dSYoshinobu Inoue } 87782cd038dSYoshinobu Inoue 87882cd038dSYoshinobu Inoue /* 87982cd038dSYoshinobu Inoue * Mark the address derived from the prefix detached so that 88082cd038dSYoshinobu Inoue * it won't be used as a source address for a new connection. 88182cd038dSYoshinobu Inoue */ 88282cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 88382cd038dSYoshinobu Inoue ia6 = NULL; 88482cd038dSYoshinobu Inoue else 88582cd038dSYoshinobu Inoue ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); 88682cd038dSYoshinobu Inoue if (ia6) 88782cd038dSYoshinobu Inoue ia6->ia6_flags |= IN6_IFF_DETACHED; 88882cd038dSYoshinobu Inoue } 88982cd038dSYoshinobu Inoue 89082cd038dSYoshinobu Inoue static void 89182cd038dSYoshinobu Inoue nd6_attach_prefix(pr) 89282cd038dSYoshinobu Inoue struct nd_prefix *pr; 89382cd038dSYoshinobu Inoue { 89482cd038dSYoshinobu Inoue struct ifaddr *ifa; 89582cd038dSYoshinobu Inoue struct in6_ifaddr *ia6; 89682cd038dSYoshinobu Inoue 89782cd038dSYoshinobu Inoue /* 89882cd038dSYoshinobu Inoue * Add the interface route associated with the prefix(if necessary) 89982cd038dSYoshinobu Inoue * Should we consider if the L bit is set in pr->ndpr_flags? 90082cd038dSYoshinobu Inoue */ 90182cd038dSYoshinobu Inoue ifa = ifaof_ifpforaddr((struct sockaddr *)&pr->ndpr_prefix, 90282cd038dSYoshinobu Inoue pr->ndpr_ifp); 90382cd038dSYoshinobu Inoue if (ifa == NULL) { 90482cd038dSYoshinobu Inoue log(LOG_ERR, 90582cd038dSYoshinobu Inoue "nd6_attach_prefix: failed to find any ifaddr" 90682cd038dSYoshinobu Inoue " to add route for a prefix(%s/%d)\n", 90782cd038dSYoshinobu Inoue ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen); 90882cd038dSYoshinobu Inoue } else { 90982cd038dSYoshinobu Inoue int e; 91082cd038dSYoshinobu Inoue struct sockaddr_in6 mask6; 91182cd038dSYoshinobu Inoue 91282cd038dSYoshinobu Inoue bzero(&mask6, sizeof(mask6)); 91382cd038dSYoshinobu Inoue mask6.sin6_family = AF_INET6; 91482cd038dSYoshinobu Inoue mask6.sin6_len = sizeof(mask6); 91582cd038dSYoshinobu Inoue mask6.sin6_addr = pr->ndpr_mask; 91682cd038dSYoshinobu Inoue e = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, 91782cd038dSYoshinobu Inoue ifa->ifa_addr, (struct sockaddr *)&mask6, 91882cd038dSYoshinobu Inoue ifa->ifa_flags, NULL); 91982cd038dSYoshinobu Inoue if (e == 0) 92082cd038dSYoshinobu Inoue pr->ndpr_statef_onlink = 1; 92182cd038dSYoshinobu Inoue else { 92282cd038dSYoshinobu Inoue log(LOG_ERR, 92382cd038dSYoshinobu Inoue "nd6_attach_prefix: failed to add route for" 92482cd038dSYoshinobu Inoue " a prefix(%s/%d), errno = %d\n", 92582cd038dSYoshinobu Inoue ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen, e); 92682cd038dSYoshinobu Inoue } 92782cd038dSYoshinobu Inoue } 92882cd038dSYoshinobu Inoue 92982cd038dSYoshinobu Inoue /* 93082cd038dSYoshinobu Inoue * Now the address derived from the prefix can be used as a source 93182cd038dSYoshinobu Inoue * for a new connection, so clear the detached flag. 93282cd038dSYoshinobu Inoue */ 93382cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 93482cd038dSYoshinobu Inoue ia6 = NULL; 93582cd038dSYoshinobu Inoue else 93682cd038dSYoshinobu Inoue ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); 93782cd038dSYoshinobu Inoue if (ia6) { 93882cd038dSYoshinobu Inoue ia6->ia6_flags &= ~IN6_IFF_DETACHED; 93982cd038dSYoshinobu Inoue if (pr->ndpr_statef_onlink) 94082cd038dSYoshinobu Inoue ia6->ia_flags |= IFA_ROUTE; 94182cd038dSYoshinobu Inoue } 94282cd038dSYoshinobu Inoue } 94382cd038dSYoshinobu Inoue 94482cd038dSYoshinobu Inoue static struct in6_ifaddr * 94582cd038dSYoshinobu Inoue in6_ifadd(ifp, in6, addr, prefixlen) 94682cd038dSYoshinobu Inoue struct ifnet *ifp; 94782cd038dSYoshinobu Inoue struct in6_addr *in6; 94882cd038dSYoshinobu Inoue struct in6_addr *addr; 94982cd038dSYoshinobu Inoue int prefixlen; /* prefix len of the new prefix in "in6" */ 95082cd038dSYoshinobu Inoue { 95182cd038dSYoshinobu Inoue struct ifaddr *ifa; 95282cd038dSYoshinobu Inoue struct in6_ifaddr *ia, *ib, *oia; 95382cd038dSYoshinobu Inoue int s, error; 95482cd038dSYoshinobu Inoue struct in6_addr mask; 95582cd038dSYoshinobu Inoue 95682cd038dSYoshinobu Inoue in6_len2mask(&mask, prefixlen); 95782cd038dSYoshinobu Inoue 95882cd038dSYoshinobu Inoue /* find link-local address (will be interface ID) */ 95982cd038dSYoshinobu Inoue ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp); 96082cd038dSYoshinobu Inoue if (ifa) 96182cd038dSYoshinobu Inoue ib = (struct in6_ifaddr *)ifa; 96282cd038dSYoshinobu Inoue else 96382cd038dSYoshinobu Inoue return NULL; 96482cd038dSYoshinobu Inoue 96582cd038dSYoshinobu Inoue /* prefixlen + ifidlen must be equal to 128 */ 96682cd038dSYoshinobu Inoue if (prefixlen != in6_mask2len(&ib->ia_prefixmask.sin6_addr)) { 96782cd038dSYoshinobu Inoue log(LOG_ERR, "in6_ifadd: wrong prefixlen for %s" 96882cd038dSYoshinobu Inoue "(prefix=%d ifid=%d)\n", if_name(ifp), 96982cd038dSYoshinobu Inoue prefixlen, 97082cd038dSYoshinobu Inoue 128 - in6_mask2len(&ib->ia_prefixmask.sin6_addr)); 97182cd038dSYoshinobu Inoue return NULL; 97282cd038dSYoshinobu Inoue } 97382cd038dSYoshinobu Inoue 97482cd038dSYoshinobu Inoue /* make ifaddr */ 97582cd038dSYoshinobu Inoue ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_DONTWAIT); 97682cd038dSYoshinobu Inoue if (ia == NULL) { 97782cd038dSYoshinobu Inoue printf("ENOBUFS in in6_ifadd %d\n", __LINE__); 97882cd038dSYoshinobu Inoue return NULL; 97982cd038dSYoshinobu Inoue } 98082cd038dSYoshinobu Inoue 98182cd038dSYoshinobu Inoue bzero((caddr_t)ia, sizeof(*ia)); 98282cd038dSYoshinobu Inoue ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 98382cd038dSYoshinobu Inoue ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 98482cd038dSYoshinobu Inoue ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; 98582cd038dSYoshinobu Inoue ia->ia_ifp = ifp; 98682cd038dSYoshinobu Inoue 98782cd038dSYoshinobu Inoue /* link to in6_ifaddr */ 98882cd038dSYoshinobu Inoue if ((oia = in6_ifaddr) != NULL) { 98982cd038dSYoshinobu Inoue for( ; oia->ia_next; oia = oia->ia_next) 99082cd038dSYoshinobu Inoue continue; 99182cd038dSYoshinobu Inoue oia->ia_next = ia; 99282cd038dSYoshinobu Inoue } else 99382cd038dSYoshinobu Inoue in6_ifaddr = ia; 99482cd038dSYoshinobu Inoue 99582cd038dSYoshinobu Inoue /* link to if_addrlist */ 99682cd038dSYoshinobu Inoue if (ifp->if_addrlist.tqh_first != NULL) { 99782cd038dSYoshinobu Inoue TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, 99882cd038dSYoshinobu Inoue ifa_list); 99982cd038dSYoshinobu Inoue } 100082cd038dSYoshinobu Inoue 100182cd038dSYoshinobu Inoue /* new address */ 100282cd038dSYoshinobu Inoue ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6); 100382cd038dSYoshinobu Inoue ia->ia_addr.sin6_family = AF_INET6; 100482cd038dSYoshinobu Inoue /* prefix */ 100582cd038dSYoshinobu Inoue bcopy(in6, &ia->ia_addr.sin6_addr, sizeof(ia->ia_addr.sin6_addr)); 100682cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; 100782cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; 100882cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; 100982cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; 101082cd038dSYoshinobu Inoue /* interface ID */ 101182cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[0] 101282cd038dSYoshinobu Inoue |= (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); 101382cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[1] 101482cd038dSYoshinobu Inoue |= (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); 101582cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[2] 101682cd038dSYoshinobu Inoue |= (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); 101782cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[3] 101882cd038dSYoshinobu Inoue |= (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); 101982cd038dSYoshinobu Inoue 102082cd038dSYoshinobu Inoue /* new prefix */ 102182cd038dSYoshinobu Inoue ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6); 102282cd038dSYoshinobu Inoue ia->ia_prefixmask.sin6_family = AF_INET6; 102382cd038dSYoshinobu Inoue bcopy(&mask, &ia->ia_prefixmask.sin6_addr, 102482cd038dSYoshinobu Inoue sizeof(ia->ia_prefixmask.sin6_addr)); 102582cd038dSYoshinobu Inoue 102682cd038dSYoshinobu Inoue /* same routine */ 102782cd038dSYoshinobu Inoue ia->ia_ifa.ifa_rtrequest = 102882cd038dSYoshinobu Inoue (ifp->if_type == IFT_PPP) ? nd6_p2p_rtrequest : nd6_rtrequest; 102982cd038dSYoshinobu Inoue ia->ia_ifa.ifa_flags |= RTF_CLONING; 103082cd038dSYoshinobu Inoue ia->ia_ifa.ifa_metric = ifp->if_metric; 103182cd038dSYoshinobu Inoue 103282cd038dSYoshinobu Inoue /* add interface route */ 103382cd038dSYoshinobu Inoue if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP|RTF_CLONING))) { 103482cd038dSYoshinobu Inoue log(LOG_NOTICE, "in6_ifadd: failed to add an interface route " 103582cd038dSYoshinobu Inoue "for %s/%d on %s, errno = %d\n", 103682cd038dSYoshinobu Inoue ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen, 103782cd038dSYoshinobu Inoue if_name(ifp), error); 103882cd038dSYoshinobu Inoue } else 103982cd038dSYoshinobu Inoue ia->ia_flags |= IFA_ROUTE; 104082cd038dSYoshinobu Inoue 104182cd038dSYoshinobu Inoue *addr = ia->ia_addr.sin6_addr; 104282cd038dSYoshinobu Inoue 104382cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_MULTICAST) { 104482cd038dSYoshinobu Inoue int error; /* not used */ 104582cd038dSYoshinobu Inoue struct in6_addr sol6; 104682cd038dSYoshinobu Inoue 104782cd038dSYoshinobu Inoue /* join solicited node multicast address */ 104882cd038dSYoshinobu Inoue bzero(&sol6, sizeof(sol6)); 104982cd038dSYoshinobu Inoue sol6.s6_addr16[0] = htons(0xff02); 105082cd038dSYoshinobu Inoue sol6.s6_addr16[1] = htons(ifp->if_index); 105182cd038dSYoshinobu Inoue sol6.s6_addr32[1] = 0; 105282cd038dSYoshinobu Inoue sol6.s6_addr32[2] = htonl(1); 105382cd038dSYoshinobu Inoue sol6.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3]; 105482cd038dSYoshinobu Inoue sol6.s6_addr8[12] = 0xff; 105582cd038dSYoshinobu Inoue (void)in6_addmulti(&sol6, ifp, &error); 105682cd038dSYoshinobu Inoue } 105782cd038dSYoshinobu Inoue 105882cd038dSYoshinobu Inoue ia->ia6_flags |= IN6_IFF_TENTATIVE; 105982cd038dSYoshinobu Inoue 106082cd038dSYoshinobu Inoue /* 106182cd038dSYoshinobu Inoue * To make the interface up. Only AF_INET6 in ia is used... 106282cd038dSYoshinobu Inoue */ 106382cd038dSYoshinobu Inoue s = splimp(); 106482cd038dSYoshinobu Inoue if (ifp->if_ioctl && (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) { 106582cd038dSYoshinobu Inoue splx(s); 106682cd038dSYoshinobu Inoue return NULL; 106782cd038dSYoshinobu Inoue } 106882cd038dSYoshinobu Inoue splx(s); 106982cd038dSYoshinobu Inoue 107082cd038dSYoshinobu Inoue /* Perform DAD, if needed. */ 107182cd038dSYoshinobu Inoue nd6_dad_start((struct ifaddr *)ia, NULL); 107282cd038dSYoshinobu Inoue 107382cd038dSYoshinobu Inoue return ia; 107482cd038dSYoshinobu Inoue } 107582cd038dSYoshinobu Inoue 107682cd038dSYoshinobu Inoue int 107782cd038dSYoshinobu Inoue in6_ifdel(ifp, in6) 107882cd038dSYoshinobu Inoue struct ifnet *ifp; 107982cd038dSYoshinobu Inoue struct in6_addr *in6; 108082cd038dSYoshinobu Inoue { 108182cd038dSYoshinobu Inoue struct in6_ifaddr *ia = (struct in6_ifaddr *)NULL; 108282cd038dSYoshinobu Inoue struct in6_ifaddr *oia = (struct in6_ifaddr *)NULL; 108382cd038dSYoshinobu Inoue 108482cd038dSYoshinobu Inoue if (!ifp) 108582cd038dSYoshinobu Inoue return -1; 108682cd038dSYoshinobu Inoue 108782cd038dSYoshinobu Inoue ia = in6ifa_ifpwithaddr(ifp, in6); 108882cd038dSYoshinobu Inoue if (!ia) 108982cd038dSYoshinobu Inoue return -1; 109082cd038dSYoshinobu Inoue 109182cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_MULTICAST) { 109282cd038dSYoshinobu Inoue /* 109382cd038dSYoshinobu Inoue * delete solicited multicast addr for deleting host id 109482cd038dSYoshinobu Inoue */ 109582cd038dSYoshinobu Inoue struct in6_multi *in6m; 109682cd038dSYoshinobu Inoue struct in6_addr llsol; 109782cd038dSYoshinobu Inoue bzero(&llsol, sizeof(struct in6_addr)); 109882cd038dSYoshinobu Inoue llsol.s6_addr16[0] = htons(0xff02); 109982cd038dSYoshinobu Inoue llsol.s6_addr16[1] = htons(ifp->if_index); 110082cd038dSYoshinobu Inoue llsol.s6_addr32[1] = 0; 110182cd038dSYoshinobu Inoue llsol.s6_addr32[2] = htonl(1); 110282cd038dSYoshinobu Inoue llsol.s6_addr32[3] = 110382cd038dSYoshinobu Inoue ia->ia_addr.sin6_addr.s6_addr32[3]; 110482cd038dSYoshinobu Inoue llsol.s6_addr8[12] = 0xff; 110582cd038dSYoshinobu Inoue 110682cd038dSYoshinobu Inoue IN6_LOOKUP_MULTI(llsol, ifp, in6m); 110782cd038dSYoshinobu Inoue if (in6m) 110882cd038dSYoshinobu Inoue in6_delmulti(in6m); 110982cd038dSYoshinobu Inoue } 111082cd038dSYoshinobu Inoue 111182cd038dSYoshinobu Inoue if (ia->ia_flags & IFA_ROUTE) { 111282cd038dSYoshinobu Inoue rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 111382cd038dSYoshinobu Inoue ia->ia_flags &= ~IFA_ROUTE; 111482cd038dSYoshinobu Inoue } 111582cd038dSYoshinobu Inoue 111682cd038dSYoshinobu Inoue TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); 111782cd038dSYoshinobu Inoue 111882cd038dSYoshinobu Inoue /* lladdr is never deleted */ 111982cd038dSYoshinobu Inoue oia = ia; 112082cd038dSYoshinobu Inoue if (oia == (ia = in6_ifaddr)) 112182cd038dSYoshinobu Inoue in6_ifaddr = ia->ia_next; 112282cd038dSYoshinobu Inoue else { 112382cd038dSYoshinobu Inoue while (ia->ia_next && (ia->ia_next != oia)) 112482cd038dSYoshinobu Inoue ia = ia->ia_next; 112582cd038dSYoshinobu Inoue if (ia->ia_next) 112682cd038dSYoshinobu Inoue ia->ia_next = oia->ia_next; 112782cd038dSYoshinobu Inoue else 112882cd038dSYoshinobu Inoue return -1; 112982cd038dSYoshinobu Inoue } 113082cd038dSYoshinobu Inoue 113182cd038dSYoshinobu Inoue IFAFREE((&oia->ia_ifa)); 113282cd038dSYoshinobu Inoue /* xxx 113382cd038dSYoshinobu Inoue rtrequest(RTM_DELETE, 113482cd038dSYoshinobu Inoue (struct sockaddr *)&ia->ia_addr, 113582cd038dSYoshinobu Inoue (struct sockaddr *)0 113682cd038dSYoshinobu Inoue (struct sockaddr *)&ia->ia_prefixmask, 113782cd038dSYoshinobu Inoue RTF_UP|RTF_CLONING, 113882cd038dSYoshinobu Inoue (struct rtentry **)0); 113982cd038dSYoshinobu Inoue */ 114082cd038dSYoshinobu Inoue return 0; 114182cd038dSYoshinobu Inoue } 114282cd038dSYoshinobu Inoue 114382cd038dSYoshinobu Inoue int 114482cd038dSYoshinobu Inoue in6_init_prefix_ltimes(struct nd_prefix *ndpr) 114582cd038dSYoshinobu Inoue { 114682cd038dSYoshinobu Inoue 114782cd038dSYoshinobu Inoue /* check if preferred lifetime > valid lifetime */ 114882cd038dSYoshinobu Inoue if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) { 114982cd038dSYoshinobu Inoue log(LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime" 115082cd038dSYoshinobu Inoue "(%d) is greater than valid lifetime(%d)\n", 115182cd038dSYoshinobu Inoue (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime); 115282cd038dSYoshinobu Inoue return (EINVAL); 115382cd038dSYoshinobu Inoue } 115482cd038dSYoshinobu Inoue if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) 115582cd038dSYoshinobu Inoue ndpr->ndpr_preferred = 0; 115682cd038dSYoshinobu Inoue else 115782cd038dSYoshinobu Inoue ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime; 115882cd038dSYoshinobu Inoue if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) 115982cd038dSYoshinobu Inoue ndpr->ndpr_expire = 0; 116082cd038dSYoshinobu Inoue else 116182cd038dSYoshinobu Inoue ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime; 116282cd038dSYoshinobu Inoue 116382cd038dSYoshinobu Inoue return 0; 116482cd038dSYoshinobu Inoue } 116582cd038dSYoshinobu Inoue 116682cd038dSYoshinobu Inoue static void 116782cd038dSYoshinobu Inoue in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6) 116882cd038dSYoshinobu Inoue { 116982cd038dSYoshinobu Inoue 117082cd038dSYoshinobu Inoue /* init ia6t_expire */ 117182cd038dSYoshinobu Inoue if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) 117282cd038dSYoshinobu Inoue lt6->ia6t_expire = 0; 117382cd038dSYoshinobu Inoue else { 117482cd038dSYoshinobu Inoue lt6->ia6t_expire = time_second; 117582cd038dSYoshinobu Inoue lt6->ia6t_expire += lt6->ia6t_vltime; 117682cd038dSYoshinobu Inoue } 117782cd038dSYoshinobu Inoue /* init ia6t_preferred */ 117882cd038dSYoshinobu Inoue if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) 117982cd038dSYoshinobu Inoue lt6->ia6t_preferred = 0; 118082cd038dSYoshinobu Inoue else { 118182cd038dSYoshinobu Inoue lt6->ia6t_preferred = time_second; 118282cd038dSYoshinobu Inoue lt6->ia6t_preferred += lt6->ia6t_pltime; 118382cd038dSYoshinobu Inoue } 118482cd038dSYoshinobu Inoue /* ensure addr lifetime <= prefix lifetime */ 118582cd038dSYoshinobu Inoue if (new->ndpr_expire && lt6->ia6t_expire && 118682cd038dSYoshinobu Inoue new->ndpr_expire < lt6->ia6t_expire) 118782cd038dSYoshinobu Inoue lt6->ia6t_expire = new->ndpr_expire; 118882cd038dSYoshinobu Inoue if (new->ndpr_preferred && lt6->ia6t_preferred 118982cd038dSYoshinobu Inoue && new->ndpr_preferred < lt6->ia6t_preferred) 119082cd038dSYoshinobu Inoue lt6->ia6t_preferred = new->ndpr_preferred; 119182cd038dSYoshinobu Inoue } 119282cd038dSYoshinobu Inoue 119382cd038dSYoshinobu Inoue /* 119482cd038dSYoshinobu Inoue * Delete all the routing table entries that use the specified gateway. 119582cd038dSYoshinobu Inoue * XXX: this function causes search through all entries of routing table, so 119682cd038dSYoshinobu Inoue * it shouldn't be called when acting as a router. 119782cd038dSYoshinobu Inoue */ 119882cd038dSYoshinobu Inoue void 119982cd038dSYoshinobu Inoue rt6_flush(gateway, ifp) 120082cd038dSYoshinobu Inoue struct in6_addr *gateway; 120182cd038dSYoshinobu Inoue struct ifnet *ifp; 120282cd038dSYoshinobu Inoue { 120382cd038dSYoshinobu Inoue struct radix_node_head *rnh = rt_tables[AF_INET6]; 120482cd038dSYoshinobu Inoue int s = splnet(); 120582cd038dSYoshinobu Inoue 120682cd038dSYoshinobu Inoue /* We'll care only link-local addresses */ 120782cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_LINKLOCAL(gateway)) { 120882cd038dSYoshinobu Inoue splx(s); 120982cd038dSYoshinobu Inoue return; 121082cd038dSYoshinobu Inoue } 121182cd038dSYoshinobu Inoue /* XXX: hack for KAME's link-local address kludge */ 121282cd038dSYoshinobu Inoue gateway->s6_addr16[1] = htons(ifp->if_index); 121382cd038dSYoshinobu Inoue 121482cd038dSYoshinobu Inoue rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway); 121582cd038dSYoshinobu Inoue splx(s); 121682cd038dSYoshinobu Inoue } 121782cd038dSYoshinobu Inoue 121882cd038dSYoshinobu Inoue static int 121982cd038dSYoshinobu Inoue rt6_deleteroute(rn, arg) 122082cd038dSYoshinobu Inoue struct radix_node *rn; 122182cd038dSYoshinobu Inoue void *arg; 122282cd038dSYoshinobu Inoue { 122382cd038dSYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)s) 122482cd038dSYoshinobu Inoue struct rtentry *rt = (struct rtentry *)rn; 122582cd038dSYoshinobu Inoue struct in6_addr *gate = (struct in6_addr *)arg; 122682cd038dSYoshinobu Inoue 122782cd038dSYoshinobu Inoue if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) 122882cd038dSYoshinobu Inoue return(0); 122982cd038dSYoshinobu Inoue 123082cd038dSYoshinobu Inoue if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr)) 123182cd038dSYoshinobu Inoue return(0); 123282cd038dSYoshinobu Inoue 123382cd038dSYoshinobu Inoue /* 123482cd038dSYoshinobu Inoue * We delete only host route. This means, in particular, we don't 123582cd038dSYoshinobu Inoue * delete default route. 123682cd038dSYoshinobu Inoue */ 123782cd038dSYoshinobu Inoue if ((rt->rt_flags & RTF_HOST) == 0) 123882cd038dSYoshinobu Inoue return(0); 123982cd038dSYoshinobu Inoue 124082cd038dSYoshinobu Inoue return(rtrequest(RTM_DELETE, rt_key(rt), 124182cd038dSYoshinobu Inoue rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0)); 124282cd038dSYoshinobu Inoue #undef SIN6 124382cd038dSYoshinobu Inoue } 1244