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 /* 3382cd038dSYoshinobu Inoue * XXX 3482cd038dSYoshinobu Inoue * KAME 970409 note: 3582cd038dSYoshinobu Inoue * BSD/OS version heavily modifies this code, related to llinfo. 3682cd038dSYoshinobu Inoue * Since we don't have BSD/OS version of net/route.c in our hand, 3782cd038dSYoshinobu Inoue * I left the code mostly as it was in 970310. -- itojun 3882cd038dSYoshinobu Inoue */ 3982cd038dSYoshinobu Inoue 4082cd038dSYoshinobu Inoue #include <sys/param.h> 4182cd038dSYoshinobu Inoue #include <sys/systm.h> 4282cd038dSYoshinobu Inoue #include <sys/malloc.h> 4382cd038dSYoshinobu Inoue #include <sys/mbuf.h> 4482cd038dSYoshinobu Inoue #include <sys/socket.h> 4582cd038dSYoshinobu Inoue #include <sys/sockio.h> 4682cd038dSYoshinobu Inoue #include <sys/time.h> 4782cd038dSYoshinobu Inoue #include <sys/kernel.h> 4882cd038dSYoshinobu Inoue #include <sys/errno.h> 4982cd038dSYoshinobu Inoue #include <sys/syslog.h> 5082cd038dSYoshinobu Inoue #include <sys/queue.h> 5182cd038dSYoshinobu Inoue 5282cd038dSYoshinobu Inoue #include <net/if.h> 5382cd038dSYoshinobu Inoue #include <net/if_dl.h> 5482cd038dSYoshinobu Inoue #include <net/if_types.h> 5582cd038dSYoshinobu Inoue #include <net/if_atm.h> 5682cd038dSYoshinobu Inoue #include <net/route.h> 5782cd038dSYoshinobu Inoue 5882cd038dSYoshinobu Inoue #include <netinet/in.h> 5982cd038dSYoshinobu Inoue #include <netinet/if_ether.h> 6082cd038dSYoshinobu Inoue #include <netinet/if_fddi.h> 6182cd038dSYoshinobu Inoue #include <netinet6/in6_var.h> 6282cd038dSYoshinobu Inoue #include <netinet6/ip6.h> 6382cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 6482cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 6582cd038dSYoshinobu Inoue #include <netinet6/in6_prefix.h> 6682cd038dSYoshinobu Inoue #include <netinet6/icmp6.h> 6782cd038dSYoshinobu Inoue 6882cd038dSYoshinobu Inoue #include "loop.h" 6982cd038dSYoshinobu Inoue 7082cd038dSYoshinobu Inoue #include <net/net_osdep.h> 7182cd038dSYoshinobu Inoue 7282cd038dSYoshinobu Inoue #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */ 7382cd038dSYoshinobu Inoue #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */ 7482cd038dSYoshinobu Inoue 7582cd038dSYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)s) 7682cd038dSYoshinobu Inoue #define SDL(s) ((struct sockaddr_dl *)s) 7782cd038dSYoshinobu Inoue 7882cd038dSYoshinobu Inoue /* timer values */ 7982cd038dSYoshinobu Inoue int nd6_prune = 1; /* walk list every 1 seconds */ 8082cd038dSYoshinobu Inoue int nd6_delay = 5; /* delay first probe time 5 second */ 8182cd038dSYoshinobu Inoue int nd6_umaxtries = 3; /* maximum unicast query */ 8282cd038dSYoshinobu Inoue int nd6_mmaxtries = 3; /* maximum multicast query */ 8382cd038dSYoshinobu Inoue int nd6_useloopback = 1; /* use loopback interface for local traffic */ 8482cd038dSYoshinobu Inoue int nd6_proxyall = 0; /* enable Proxy Neighbor Advertisement */ 8582cd038dSYoshinobu Inoue 8682cd038dSYoshinobu Inoue /* for debugging? */ 8782cd038dSYoshinobu Inoue static int nd6_inuse, nd6_allocated; 8882cd038dSYoshinobu Inoue 8982cd038dSYoshinobu Inoue struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; 9082cd038dSYoshinobu Inoue struct nd_ifinfo *nd_ifinfo = NULL; 9182cd038dSYoshinobu Inoue struct nd_drhead nd_defrouter = { 0 }; 9282cd038dSYoshinobu Inoue struct nd_prhead nd_prefix = { 0 }; 9382cd038dSYoshinobu Inoue 9482cd038dSYoshinobu Inoue int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; 9582cd038dSYoshinobu Inoue static struct sockaddr_in6 all1_sa; 9682cd038dSYoshinobu Inoue 9782cd038dSYoshinobu Inoue static void nd6_slowtimo __P((void *)); 9882cd038dSYoshinobu Inoue 9982cd038dSYoshinobu Inoue void 10082cd038dSYoshinobu Inoue nd6_init() 10182cd038dSYoshinobu Inoue { 10282cd038dSYoshinobu Inoue static int nd6_init_done = 0; 10382cd038dSYoshinobu Inoue int i; 10482cd038dSYoshinobu Inoue 10582cd038dSYoshinobu Inoue if (nd6_init_done) { 10682cd038dSYoshinobu Inoue log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); 10782cd038dSYoshinobu Inoue return; 10882cd038dSYoshinobu Inoue } 10982cd038dSYoshinobu Inoue 11082cd038dSYoshinobu Inoue all1_sa.sin6_family = AF_INET6; 11182cd038dSYoshinobu Inoue all1_sa.sin6_len = sizeof(struct sockaddr_in6); 11282cd038dSYoshinobu Inoue for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) 11382cd038dSYoshinobu Inoue all1_sa.sin6_addr.s6_addr[i] = 0xff; 11482cd038dSYoshinobu Inoue 11582cd038dSYoshinobu Inoue nd6_init_done = 1; 11682cd038dSYoshinobu Inoue 11782cd038dSYoshinobu Inoue /* start timer */ 11882cd038dSYoshinobu Inoue timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); 11982cd038dSYoshinobu Inoue } 12082cd038dSYoshinobu Inoue 12182cd038dSYoshinobu Inoue void 12282cd038dSYoshinobu Inoue nd6_ifattach(ifp) 12382cd038dSYoshinobu Inoue struct ifnet *ifp; 12482cd038dSYoshinobu Inoue { 12582cd038dSYoshinobu Inoue static size_t if_indexlim = 8; 12682cd038dSYoshinobu Inoue 12782cd038dSYoshinobu Inoue /* 12882cd038dSYoshinobu Inoue * We have some arrays that should be indexed by if_index. 12982cd038dSYoshinobu Inoue * since if_index will grow dynamically, they should grow too. 13082cd038dSYoshinobu Inoue */ 13182cd038dSYoshinobu Inoue if (nd_ifinfo == NULL || if_index >= if_indexlim) { 13282cd038dSYoshinobu Inoue size_t n; 13382cd038dSYoshinobu Inoue caddr_t q; 13482cd038dSYoshinobu Inoue 13582cd038dSYoshinobu Inoue while (if_index >= if_indexlim) 13682cd038dSYoshinobu Inoue if_indexlim <<= 1; 13782cd038dSYoshinobu Inoue 13882cd038dSYoshinobu Inoue /* grow nd_ifinfo */ 13982cd038dSYoshinobu Inoue n = if_indexlim * sizeof(struct nd_ifinfo); 14082cd038dSYoshinobu Inoue q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK); 14182cd038dSYoshinobu Inoue bzero(q, n); 14282cd038dSYoshinobu Inoue if (nd_ifinfo) { 14382cd038dSYoshinobu Inoue bcopy((caddr_t)nd_ifinfo, q, n/2); 14482cd038dSYoshinobu Inoue free((caddr_t)nd_ifinfo, M_IP6NDP); 14582cd038dSYoshinobu Inoue } 14682cd038dSYoshinobu Inoue nd_ifinfo = (struct nd_ifinfo *)q; 14782cd038dSYoshinobu Inoue } 14882cd038dSYoshinobu Inoue 14982cd038dSYoshinobu Inoue #define ND nd_ifinfo[ifp->if_index] 15082cd038dSYoshinobu Inoue ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu; 15182cd038dSYoshinobu Inoue ND.chlim = IPV6_DEFHLIM; 15282cd038dSYoshinobu Inoue ND.basereachable = REACHABLE_TIME; 15382cd038dSYoshinobu Inoue ND.reachable = ND_COMPUTE_RTIME(ND.basereachable); 15482cd038dSYoshinobu Inoue ND.retrans = RETRANS_TIMER; 15582cd038dSYoshinobu Inoue ND.receivedra = 0; 15682cd038dSYoshinobu Inoue nd6_setmtu(ifp); 15782cd038dSYoshinobu Inoue #undef ND 15882cd038dSYoshinobu Inoue } 15982cd038dSYoshinobu Inoue 16082cd038dSYoshinobu Inoue /* 16182cd038dSYoshinobu Inoue * Reset ND level link MTU. This function is called when the physical MTU 16282cd038dSYoshinobu Inoue * changes, which means we might have to adjust the ND level MTU. 16382cd038dSYoshinobu Inoue */ 16482cd038dSYoshinobu Inoue void 16582cd038dSYoshinobu Inoue nd6_setmtu(ifp) 16682cd038dSYoshinobu Inoue struct ifnet *ifp; 16782cd038dSYoshinobu Inoue { 16882cd038dSYoshinobu Inoue #define MIN(a,b) ((a) < (b) ? (a) : (b)) 16982cd038dSYoshinobu Inoue struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; 17082cd038dSYoshinobu Inoue u_long oldmaxmtu = ndi->maxmtu; 17182cd038dSYoshinobu Inoue u_long oldlinkmtu = ndi->linkmtu; 17282cd038dSYoshinobu Inoue 17382cd038dSYoshinobu Inoue switch(ifp->if_type) { 17482cd038dSYoshinobu Inoue case IFT_ARCNET: /* XXX MTU handling needs more work */ 17582cd038dSYoshinobu Inoue ndi->maxmtu = MIN(60480, ifp->if_mtu); 17682cd038dSYoshinobu Inoue break; 17782cd038dSYoshinobu Inoue case IFT_ETHER: 17882cd038dSYoshinobu Inoue ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); 17982cd038dSYoshinobu Inoue break; 18082cd038dSYoshinobu Inoue case IFT_FDDI: 18182cd038dSYoshinobu Inoue ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); 18282cd038dSYoshinobu Inoue break; 18382cd038dSYoshinobu Inoue case IFT_ATM: 18482cd038dSYoshinobu Inoue ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); 18582cd038dSYoshinobu Inoue break; 18682cd038dSYoshinobu Inoue default: 18782cd038dSYoshinobu Inoue ndi->maxmtu = ifp->if_mtu; 18882cd038dSYoshinobu Inoue break; 18982cd038dSYoshinobu Inoue } 19082cd038dSYoshinobu Inoue 19182cd038dSYoshinobu Inoue if (oldmaxmtu != ndi->maxmtu) { 19282cd038dSYoshinobu Inoue /* 19382cd038dSYoshinobu Inoue * If the ND level MTU is not set yet, or if the maxmtu 19482cd038dSYoshinobu Inoue * is reset to a smaller value than the ND level MTU, 19582cd038dSYoshinobu Inoue * also reset the ND level MTU. 19682cd038dSYoshinobu Inoue */ 19782cd038dSYoshinobu Inoue if (ndi->linkmtu == 0 || 19882cd038dSYoshinobu Inoue ndi->maxmtu < ndi->linkmtu) { 19982cd038dSYoshinobu Inoue ndi->linkmtu = ndi->maxmtu; 20082cd038dSYoshinobu Inoue /* also adjust in6_maxmtu if necessary. */ 20182cd038dSYoshinobu Inoue if (oldlinkmtu == 0) { 20282cd038dSYoshinobu Inoue /* 20382cd038dSYoshinobu Inoue * XXX: the case analysis is grotty, but 20482cd038dSYoshinobu Inoue * it is not efficient to call in6_setmaxmtu() 20582cd038dSYoshinobu Inoue * here when we are during the initialization 20682cd038dSYoshinobu Inoue * procedure. 20782cd038dSYoshinobu Inoue */ 20882cd038dSYoshinobu Inoue if (in6_maxmtu < ndi->linkmtu) 20982cd038dSYoshinobu Inoue in6_maxmtu = ndi->linkmtu; 21082cd038dSYoshinobu Inoue } else 21182cd038dSYoshinobu Inoue in6_setmaxmtu(); 21282cd038dSYoshinobu Inoue } 21382cd038dSYoshinobu Inoue } 21482cd038dSYoshinobu Inoue #undef MIN 21582cd038dSYoshinobu Inoue } 21682cd038dSYoshinobu Inoue 21782cd038dSYoshinobu Inoue void 21882cd038dSYoshinobu Inoue nd6_option_init(opt, icmp6len, ndopts) 21982cd038dSYoshinobu Inoue void *opt; 22082cd038dSYoshinobu Inoue int icmp6len; 22182cd038dSYoshinobu Inoue union nd_opts *ndopts; 22282cd038dSYoshinobu Inoue { 22382cd038dSYoshinobu Inoue bzero(ndopts, sizeof(*ndopts)); 22482cd038dSYoshinobu Inoue ndopts->nd_opts_search = (struct nd_opt_hdr *)opt; 22582cd038dSYoshinobu Inoue ndopts->nd_opts_last 22682cd038dSYoshinobu Inoue = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len); 22782cd038dSYoshinobu Inoue 22882cd038dSYoshinobu Inoue if (icmp6len == 0) { 22982cd038dSYoshinobu Inoue ndopts->nd_opts_done = 1; 23082cd038dSYoshinobu Inoue ndopts->nd_opts_search = NULL; 23182cd038dSYoshinobu Inoue } 23282cd038dSYoshinobu Inoue } 23382cd038dSYoshinobu Inoue 23482cd038dSYoshinobu Inoue /* 23582cd038dSYoshinobu Inoue * Take one ND option. 23682cd038dSYoshinobu Inoue */ 23782cd038dSYoshinobu Inoue struct nd_opt_hdr * 23882cd038dSYoshinobu Inoue nd6_option(ndopts) 23982cd038dSYoshinobu Inoue union nd_opts *ndopts; 24082cd038dSYoshinobu Inoue { 24182cd038dSYoshinobu Inoue struct nd_opt_hdr *nd_opt; 24282cd038dSYoshinobu Inoue int olen; 24382cd038dSYoshinobu Inoue 24482cd038dSYoshinobu Inoue if (!ndopts) 24582cd038dSYoshinobu Inoue panic("ndopts == NULL in nd6_option\n"); 24682cd038dSYoshinobu Inoue if (!ndopts->nd_opts_last) 24782cd038dSYoshinobu Inoue panic("uninitialized ndopts in nd6_option\n"); 24882cd038dSYoshinobu Inoue if (!ndopts->nd_opts_search) 24982cd038dSYoshinobu Inoue return NULL; 25082cd038dSYoshinobu Inoue if (ndopts->nd_opts_done) 25182cd038dSYoshinobu Inoue return NULL; 25282cd038dSYoshinobu Inoue 25382cd038dSYoshinobu Inoue nd_opt = ndopts->nd_opts_search; 25482cd038dSYoshinobu Inoue 25582cd038dSYoshinobu Inoue olen = nd_opt->nd_opt_len << 3; 25682cd038dSYoshinobu Inoue if (olen == 0) { 25782cd038dSYoshinobu Inoue /* 25882cd038dSYoshinobu Inoue * Message validation requires that all included 25982cd038dSYoshinobu Inoue * options have a length that is greater than zero. 26082cd038dSYoshinobu Inoue */ 26182cd038dSYoshinobu Inoue bzero(ndopts, sizeof(*ndopts)); 26282cd038dSYoshinobu Inoue return NULL; 26382cd038dSYoshinobu Inoue } 26482cd038dSYoshinobu Inoue 26582cd038dSYoshinobu Inoue ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); 26682cd038dSYoshinobu Inoue if (!(ndopts->nd_opts_search < ndopts->nd_opts_last)) { 26782cd038dSYoshinobu Inoue ndopts->nd_opts_done = 1; 26882cd038dSYoshinobu Inoue ndopts->nd_opts_search = NULL; 26982cd038dSYoshinobu Inoue } 27082cd038dSYoshinobu Inoue return nd_opt; 27182cd038dSYoshinobu Inoue } 27282cd038dSYoshinobu Inoue 27382cd038dSYoshinobu Inoue /* 27482cd038dSYoshinobu Inoue * Parse multiple ND options. 27582cd038dSYoshinobu Inoue * This function is much easier to use, for ND routines that do not need 27682cd038dSYoshinobu Inoue * multiple options of the same type. 27782cd038dSYoshinobu Inoue */ 27882cd038dSYoshinobu Inoue int 27982cd038dSYoshinobu Inoue nd6_options(ndopts) 28082cd038dSYoshinobu Inoue union nd_opts *ndopts; 28182cd038dSYoshinobu Inoue { 28282cd038dSYoshinobu Inoue struct nd_opt_hdr *nd_opt; 28382cd038dSYoshinobu Inoue int i = 0; 28482cd038dSYoshinobu Inoue 28582cd038dSYoshinobu Inoue if (!ndopts) 28682cd038dSYoshinobu Inoue panic("ndopts == NULL in nd6_options\n"); 28782cd038dSYoshinobu Inoue if (!ndopts->nd_opts_last) 28882cd038dSYoshinobu Inoue panic("uninitialized ndopts in nd6_options\n"); 28982cd038dSYoshinobu Inoue if (!ndopts->nd_opts_search) 29082cd038dSYoshinobu Inoue return 0; 29182cd038dSYoshinobu Inoue 29282cd038dSYoshinobu Inoue while (1) { 29382cd038dSYoshinobu Inoue nd_opt = nd6_option(ndopts); 29482cd038dSYoshinobu Inoue if (!nd_opt && !ndopts->nd_opts_last) { 29582cd038dSYoshinobu Inoue /* 29682cd038dSYoshinobu Inoue * Message validation requires that all included 29782cd038dSYoshinobu Inoue * options have a length that is greater than zero. 29882cd038dSYoshinobu Inoue */ 29982cd038dSYoshinobu Inoue bzero(ndopts, sizeof(*ndopts)); 30082cd038dSYoshinobu Inoue return -1; 30182cd038dSYoshinobu Inoue } 30282cd038dSYoshinobu Inoue 30382cd038dSYoshinobu Inoue if (!nd_opt) 30482cd038dSYoshinobu Inoue goto skip1; 30582cd038dSYoshinobu Inoue 30682cd038dSYoshinobu Inoue switch (nd_opt->nd_opt_type) { 30782cd038dSYoshinobu Inoue case ND_OPT_SOURCE_LINKADDR: 30882cd038dSYoshinobu Inoue case ND_OPT_TARGET_LINKADDR: 30982cd038dSYoshinobu Inoue case ND_OPT_MTU: 31082cd038dSYoshinobu Inoue case ND_OPT_REDIRECTED_HEADER: 31182cd038dSYoshinobu Inoue if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { 31282cd038dSYoshinobu Inoue printf("duplicated ND6 option found " 31382cd038dSYoshinobu Inoue "(type=%d)\n", nd_opt->nd_opt_type); 31482cd038dSYoshinobu Inoue /* XXX bark? */ 31582cd038dSYoshinobu Inoue } else { 31682cd038dSYoshinobu Inoue ndopts->nd_opt_array[nd_opt->nd_opt_type] 31782cd038dSYoshinobu Inoue = nd_opt; 31882cd038dSYoshinobu Inoue } 31982cd038dSYoshinobu Inoue break; 32082cd038dSYoshinobu Inoue case ND_OPT_PREFIX_INFORMATION: 32182cd038dSYoshinobu Inoue if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) { 32282cd038dSYoshinobu Inoue ndopts->nd_opt_array[nd_opt->nd_opt_type] 32382cd038dSYoshinobu Inoue = nd_opt; 32482cd038dSYoshinobu Inoue } 32582cd038dSYoshinobu Inoue ndopts->nd_opts_pi_end = 32682cd038dSYoshinobu Inoue (struct nd_opt_prefix_info *)nd_opt; 32782cd038dSYoshinobu Inoue break; 32882cd038dSYoshinobu Inoue default: 32982cd038dSYoshinobu Inoue /* 33082cd038dSYoshinobu Inoue * Unknown options must be silently ignored, 33182cd038dSYoshinobu Inoue * to accomodate future extension to the protocol. 33282cd038dSYoshinobu Inoue */ 33382cd038dSYoshinobu Inoue log(LOG_INFO, 33482cd038dSYoshinobu Inoue "nd6_options: unsupported option %d - " 33582cd038dSYoshinobu Inoue "option ignored\n", nd_opt->nd_opt_type); 33682cd038dSYoshinobu Inoue } 33782cd038dSYoshinobu Inoue 33882cd038dSYoshinobu Inoue skip1: 33982cd038dSYoshinobu Inoue i++; 34082cd038dSYoshinobu Inoue if (i > 10) { 34182cd038dSYoshinobu Inoue printf("too many loop in nd opt\n"); 34282cd038dSYoshinobu Inoue break; 34382cd038dSYoshinobu Inoue } 34482cd038dSYoshinobu Inoue 34582cd038dSYoshinobu Inoue if (ndopts->nd_opts_done) 34682cd038dSYoshinobu Inoue break; 34782cd038dSYoshinobu Inoue } 34882cd038dSYoshinobu Inoue 34982cd038dSYoshinobu Inoue return 0; 35082cd038dSYoshinobu Inoue } 35182cd038dSYoshinobu Inoue 35282cd038dSYoshinobu Inoue /* 35382cd038dSYoshinobu Inoue * ND6 timer routine to expire default route list and prefix list 35482cd038dSYoshinobu Inoue */ 35582cd038dSYoshinobu Inoue void 35682cd038dSYoshinobu Inoue nd6_timer(ignored_arg) 35782cd038dSYoshinobu Inoue void *ignored_arg; 35882cd038dSYoshinobu Inoue { 35982cd038dSYoshinobu Inoue int s; 36082cd038dSYoshinobu Inoue register struct llinfo_nd6 *ln; 36182cd038dSYoshinobu Inoue register struct nd_defrouter *dr; 36282cd038dSYoshinobu Inoue register struct nd_prefix *pr; 36382cd038dSYoshinobu Inoue 36482cd038dSYoshinobu Inoue s = splnet(); 36582cd038dSYoshinobu Inoue timeout(nd6_timer, (caddr_t)0, nd6_prune * hz); 36682cd038dSYoshinobu Inoue 36782cd038dSYoshinobu Inoue ln = llinfo_nd6.ln_next; 36882cd038dSYoshinobu Inoue /* XXX BSD/OS separates this code -- itojun */ 36982cd038dSYoshinobu Inoue while (ln && ln != &llinfo_nd6) { 37082cd038dSYoshinobu Inoue struct rtentry *rt; 37182cd038dSYoshinobu Inoue struct ifnet *ifp; 37282cd038dSYoshinobu Inoue struct sockaddr_in6 *dst; 37382cd038dSYoshinobu Inoue struct llinfo_nd6 *next = ln->ln_next; 37482cd038dSYoshinobu Inoue 37582cd038dSYoshinobu Inoue if ((rt = ln->ln_rt) == NULL) { 37682cd038dSYoshinobu Inoue ln = next; 37782cd038dSYoshinobu Inoue continue; 37882cd038dSYoshinobu Inoue } 37982cd038dSYoshinobu Inoue if ((ifp = rt->rt_ifp) == NULL) { 38082cd038dSYoshinobu Inoue ln = next; 38182cd038dSYoshinobu Inoue continue; 38282cd038dSYoshinobu Inoue } 38382cd038dSYoshinobu Inoue dst = (struct sockaddr_in6 *)rt_key(rt); 38482cd038dSYoshinobu Inoue 38582cd038dSYoshinobu Inoue if (ln->ln_expire > time_second) { 38682cd038dSYoshinobu Inoue ln = next; 38782cd038dSYoshinobu Inoue continue; 38882cd038dSYoshinobu Inoue } 38982cd038dSYoshinobu Inoue 39082cd038dSYoshinobu Inoue /* sanity check */ 39182cd038dSYoshinobu Inoue if (!rt) 39282cd038dSYoshinobu Inoue panic("rt=0 in nd6_timer(ln=%p)\n", ln); 39382cd038dSYoshinobu Inoue if (!dst) 39482cd038dSYoshinobu Inoue panic("dst=0 in nd6_timer(ln=%p)\n", ln); 39582cd038dSYoshinobu Inoue 39682cd038dSYoshinobu Inoue switch (ln->ln_state) { 39782cd038dSYoshinobu Inoue case ND6_LLINFO_INCOMPLETE: 39882cd038dSYoshinobu Inoue if (ln->ln_asked < nd6_mmaxtries) { 39982cd038dSYoshinobu Inoue ln->ln_asked++; 40082cd038dSYoshinobu Inoue ln->ln_expire = time_second + 40182cd038dSYoshinobu Inoue nd_ifinfo[ifp->if_index].retrans / 1000; 40282cd038dSYoshinobu Inoue nd6_ns_output(ifp, NULL, &dst->sin6_addr, 40382cd038dSYoshinobu Inoue ln, 0); 40482cd038dSYoshinobu Inoue } else { 40582cd038dSYoshinobu Inoue struct mbuf *m = ln->ln_hold; 40682cd038dSYoshinobu Inoue if (m) { 40782cd038dSYoshinobu Inoue if (rt->rt_ifp) { 40882cd038dSYoshinobu Inoue /* 40982cd038dSYoshinobu Inoue * Fake rcvif to make ICMP error 41082cd038dSYoshinobu Inoue * more helpful in diagnosing 41182cd038dSYoshinobu Inoue * for the receiver. 41282cd038dSYoshinobu Inoue * XXX: should we consider 41382cd038dSYoshinobu Inoue * older rcvif? 41482cd038dSYoshinobu Inoue */ 41582cd038dSYoshinobu Inoue m->m_pkthdr.rcvif = rt->rt_ifp; 41682cd038dSYoshinobu Inoue } 41782cd038dSYoshinobu Inoue icmp6_error(m, ICMP6_DST_UNREACH, 41882cd038dSYoshinobu Inoue ICMP6_DST_UNREACH_ADDR, 0); 41982cd038dSYoshinobu Inoue ln->ln_hold = NULL; 42082cd038dSYoshinobu Inoue } 42182cd038dSYoshinobu Inoue nd6_free(rt); 42282cd038dSYoshinobu Inoue } 42382cd038dSYoshinobu Inoue break; 42482cd038dSYoshinobu Inoue case ND6_LLINFO_REACHABLE: 42582cd038dSYoshinobu Inoue if (ln->ln_expire) { 42682cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_STALE; 42782cd038dSYoshinobu Inoue } 42882cd038dSYoshinobu Inoue break; 42982cd038dSYoshinobu Inoue /* 43082cd038dSYoshinobu Inoue * ND6_LLINFO_STALE state requires nothing for timer 43182cd038dSYoshinobu Inoue * routine. 43282cd038dSYoshinobu Inoue */ 43382cd038dSYoshinobu Inoue case ND6_LLINFO_DELAY: 43482cd038dSYoshinobu Inoue ln->ln_asked = 1; 43582cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_PROBE; 43682cd038dSYoshinobu Inoue ln->ln_expire = time_second + 43782cd038dSYoshinobu Inoue nd_ifinfo[ifp->if_index].retrans / 1000; 43882cd038dSYoshinobu Inoue nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, 43982cd038dSYoshinobu Inoue ln, 0); 44082cd038dSYoshinobu Inoue break; 44182cd038dSYoshinobu Inoue 44282cd038dSYoshinobu Inoue case ND6_LLINFO_PROBE: 44382cd038dSYoshinobu Inoue if (ln->ln_asked < nd6_umaxtries) { 44482cd038dSYoshinobu Inoue ln->ln_asked++; 44582cd038dSYoshinobu Inoue ln->ln_expire = time_second + 44682cd038dSYoshinobu Inoue nd_ifinfo[ifp->if_index].retrans / 1000; 44782cd038dSYoshinobu Inoue nd6_ns_output(ifp, &dst->sin6_addr, 44882cd038dSYoshinobu Inoue &dst->sin6_addr, ln, 0); 44982cd038dSYoshinobu Inoue } else { 45082cd038dSYoshinobu Inoue nd6_free(rt); 45182cd038dSYoshinobu Inoue } 45282cd038dSYoshinobu Inoue break; 45382cd038dSYoshinobu Inoue case ND6_LLINFO_WAITDELETE: 45482cd038dSYoshinobu Inoue nd6_free(rt); 45582cd038dSYoshinobu Inoue break; 45682cd038dSYoshinobu Inoue } 45782cd038dSYoshinobu Inoue ln = next; 45882cd038dSYoshinobu Inoue } 45982cd038dSYoshinobu Inoue 46082cd038dSYoshinobu Inoue /* expire */ 46182cd038dSYoshinobu Inoue dr = nd_defrouter.lh_first; 46282cd038dSYoshinobu Inoue while (dr) { 46382cd038dSYoshinobu Inoue if (dr->expire && dr->expire < time_second) { 46482cd038dSYoshinobu Inoue struct nd_defrouter *t; 46582cd038dSYoshinobu Inoue t = dr->dr_next; 46682cd038dSYoshinobu Inoue defrtrlist_del(dr); 46782cd038dSYoshinobu Inoue dr = t; 46882cd038dSYoshinobu Inoue } else 46982cd038dSYoshinobu Inoue dr = dr->dr_next; 47082cd038dSYoshinobu Inoue } 47182cd038dSYoshinobu Inoue pr = nd_prefix.lh_first; 47282cd038dSYoshinobu Inoue while (pr) { 47382cd038dSYoshinobu Inoue struct in6_ifaddr *ia6; 47482cd038dSYoshinobu Inoue struct in6_addrlifetime *lt6; 47582cd038dSYoshinobu Inoue 47682cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 47782cd038dSYoshinobu Inoue ia6 = NULL; 47882cd038dSYoshinobu Inoue else 47982cd038dSYoshinobu Inoue ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); 48082cd038dSYoshinobu Inoue 48182cd038dSYoshinobu Inoue if (ia6) { 48282cd038dSYoshinobu Inoue /* check address lifetime */ 48382cd038dSYoshinobu Inoue lt6 = &ia6->ia6_lifetime; 48482cd038dSYoshinobu Inoue if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second) 48582cd038dSYoshinobu Inoue ia6->ia6_flags |= IN6_IFF_DEPRECATED; 48682cd038dSYoshinobu Inoue if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) { 48782cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 48882cd038dSYoshinobu Inoue in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 48982cd038dSYoshinobu Inoue /* xxx ND_OPT_PI_FLAG_ONLINK processing */ 49082cd038dSYoshinobu Inoue } 49182cd038dSYoshinobu Inoue } 49282cd038dSYoshinobu Inoue 49382cd038dSYoshinobu Inoue /* 49482cd038dSYoshinobu Inoue * check prefix lifetime. 49582cd038dSYoshinobu Inoue * since pltime is just for autoconf, pltime processing for 49682cd038dSYoshinobu Inoue * prefix is not necessary. 49782cd038dSYoshinobu Inoue * 49882cd038dSYoshinobu Inoue * we offset expire time by NDPR_KEEP_EXPIRE, so that we 49982cd038dSYoshinobu Inoue * can use the old prefix information to validate the 50082cd038dSYoshinobu Inoue * next prefix information to come. See prelist_update() 50182cd038dSYoshinobu Inoue * for actual validation. 50282cd038dSYoshinobu Inoue */ 50382cd038dSYoshinobu Inoue if (pr->ndpr_expire 50482cd038dSYoshinobu Inoue && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { 50582cd038dSYoshinobu Inoue struct nd_prefix *t; 50682cd038dSYoshinobu Inoue t = pr->ndpr_next; 50782cd038dSYoshinobu Inoue 50882cd038dSYoshinobu Inoue /* 50982cd038dSYoshinobu Inoue * address expiration and prefix expiration are 51082cd038dSYoshinobu Inoue * separate. NEVER perform in6_ifdel here. 51182cd038dSYoshinobu Inoue */ 51282cd038dSYoshinobu Inoue 51382cd038dSYoshinobu Inoue prelist_remove(pr); 51482cd038dSYoshinobu Inoue pr = t; 51582cd038dSYoshinobu Inoue } else 51682cd038dSYoshinobu Inoue pr = pr->ndpr_next; 51782cd038dSYoshinobu Inoue } 51882cd038dSYoshinobu Inoue splx(s); 51982cd038dSYoshinobu Inoue } 52082cd038dSYoshinobu Inoue 52182cd038dSYoshinobu Inoue struct rtentry * 52282cd038dSYoshinobu Inoue nd6_lookup(addr6, create, ifp) 52382cd038dSYoshinobu Inoue struct in6_addr *addr6; 52482cd038dSYoshinobu Inoue int create; 52582cd038dSYoshinobu Inoue struct ifnet *ifp; 52682cd038dSYoshinobu Inoue { 52782cd038dSYoshinobu Inoue struct rtentry *rt; 52882cd038dSYoshinobu Inoue struct sockaddr_in6 sin6; 52982cd038dSYoshinobu Inoue 53082cd038dSYoshinobu Inoue bzero(&sin6, sizeof(sin6)); 53182cd038dSYoshinobu Inoue sin6.sin6_len = sizeof(struct sockaddr_in6); 53282cd038dSYoshinobu Inoue sin6.sin6_family = AF_INET6; 53382cd038dSYoshinobu Inoue sin6.sin6_addr = *addr6; 53482cd038dSYoshinobu Inoue rt = rtalloc1((struct sockaddr *)&sin6, create, 0UL); 53582cd038dSYoshinobu Inoue if (rt && (rt->rt_flags & RTF_LLINFO) == 0) { 53682cd038dSYoshinobu Inoue /* 53782cd038dSYoshinobu Inoue * This is the case for the default route. 53882cd038dSYoshinobu Inoue * If we want to create a neighbor cache for the address, we 53982cd038dSYoshinobu Inoue * should free the route for the destination and allocate an 54082cd038dSYoshinobu Inoue * interface route. 54182cd038dSYoshinobu Inoue */ 54282cd038dSYoshinobu Inoue if (create) { 54382cd038dSYoshinobu Inoue RTFREE(rt); 54482cd038dSYoshinobu Inoue rt = 0; 54582cd038dSYoshinobu Inoue } 54682cd038dSYoshinobu Inoue } 54782cd038dSYoshinobu Inoue if (!rt) { 54882cd038dSYoshinobu Inoue if (create && ifp) { 54982cd038dSYoshinobu Inoue /* 55082cd038dSYoshinobu Inoue * If no route is available and create is set, 55182cd038dSYoshinobu Inoue * we allocate a host route for the destination 55282cd038dSYoshinobu Inoue * and treat it like an interface route. 55382cd038dSYoshinobu Inoue * This hack is necessary for a neighbor which can't 55482cd038dSYoshinobu Inoue * be covered by our own prefix. 55582cd038dSYoshinobu Inoue */ 55682cd038dSYoshinobu Inoue struct ifaddr *ifa = 55782cd038dSYoshinobu Inoue ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); 55882cd038dSYoshinobu Inoue if (ifa == NULL) 55982cd038dSYoshinobu Inoue return(NULL); 56082cd038dSYoshinobu Inoue 56182cd038dSYoshinobu Inoue /* 56282cd038dSYoshinobu Inoue * Create a new route. RTF_LLINFO is necessary 56382cd038dSYoshinobu Inoue * to create a Neighbor Cache entry for the 56482cd038dSYoshinobu Inoue * destination in nd6_rtrequest which will be 56582cd038dSYoshinobu Inoue * called in rtequest via ifa->ifa_rtrequest. 56682cd038dSYoshinobu Inoue */ 56782cd038dSYoshinobu Inoue if (rtrequest(RTM_ADD, (struct sockaddr *)&sin6, 56882cd038dSYoshinobu Inoue ifa->ifa_addr, 56982cd038dSYoshinobu Inoue (struct sockaddr *)&all1_sa, 57082cd038dSYoshinobu Inoue (ifa->ifa_flags | 57182cd038dSYoshinobu Inoue RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, 57282cd038dSYoshinobu Inoue &rt)) 57382cd038dSYoshinobu Inoue log(LOG_ERR, 57482cd038dSYoshinobu Inoue "nd6_lookup: failed to add route for a " 57582cd038dSYoshinobu Inoue "neighbor(%s)\n", ip6_sprintf(addr6)); 57682cd038dSYoshinobu Inoue if (rt == NULL) 57782cd038dSYoshinobu Inoue return(NULL); 57882cd038dSYoshinobu Inoue if (rt->rt_llinfo) { 57982cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = 58082cd038dSYoshinobu Inoue (struct llinfo_nd6 *)rt->rt_llinfo; 58182cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_NOSTATE; 58282cd038dSYoshinobu Inoue } 58382cd038dSYoshinobu Inoue } else 58482cd038dSYoshinobu Inoue return(NULL); 58582cd038dSYoshinobu Inoue } 58682cd038dSYoshinobu Inoue rt->rt_refcnt--; 58782cd038dSYoshinobu Inoue /* 58882cd038dSYoshinobu Inoue * Validation for the entry. 58982cd038dSYoshinobu Inoue * XXX: we can't use rt->rt_ifp to check for the interface, since 59082cd038dSYoshinobu Inoue * it might be the loopback interface if the entry is for our 59182cd038dSYoshinobu Inoue * own address on a non-loopback interface. Instead, we should 59282cd038dSYoshinobu Inoue * use rt->rt_ifa->ifa_ifp, which would specify the REAL interface. 59382cd038dSYoshinobu Inoue */ 59482cd038dSYoshinobu Inoue if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || 59582cd038dSYoshinobu Inoue rt->rt_gateway->sa_family != AF_LINK || 59682cd038dSYoshinobu Inoue (ifp && rt->rt_ifa->ifa_ifp != ifp)) { 59782cd038dSYoshinobu Inoue if (create) { 59882cd038dSYoshinobu Inoue log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", 59982cd038dSYoshinobu Inoue ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); 60082cd038dSYoshinobu Inoue /* xxx more logs... kazu */ 60182cd038dSYoshinobu Inoue } 60282cd038dSYoshinobu Inoue return(0); 60382cd038dSYoshinobu Inoue } 60482cd038dSYoshinobu Inoue return(rt); 60582cd038dSYoshinobu Inoue } 60682cd038dSYoshinobu Inoue 60782cd038dSYoshinobu Inoue /* 60882cd038dSYoshinobu Inoue * Detect if a given IPv6 address identifies a neighbor on a given link. 60982cd038dSYoshinobu Inoue * XXX: should take care of the destination of a p2p link? 61082cd038dSYoshinobu Inoue */ 61182cd038dSYoshinobu Inoue int 61282cd038dSYoshinobu Inoue nd6_is_addr_neighbor(addr, ifp) 61382cd038dSYoshinobu Inoue struct in6_addr *addr; 61482cd038dSYoshinobu Inoue struct ifnet *ifp; 61582cd038dSYoshinobu Inoue { 61682cd038dSYoshinobu Inoue register struct ifaddr *ifa; 61782cd038dSYoshinobu Inoue int i; 61882cd038dSYoshinobu Inoue 61982cd038dSYoshinobu Inoue #define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr) 62082cd038dSYoshinobu Inoue #define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr) 62182cd038dSYoshinobu Inoue 62282cd038dSYoshinobu Inoue /* A link-local address is always a neighbor. */ 62382cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(addr)) 62482cd038dSYoshinobu Inoue return(1); 62582cd038dSYoshinobu Inoue 62682cd038dSYoshinobu Inoue /* 62782cd038dSYoshinobu Inoue * If the address matches one of our addresses, 62882cd038dSYoshinobu Inoue * it should be a neighbor. 62982cd038dSYoshinobu Inoue */ 63082cd038dSYoshinobu Inoue for (ifa = ifp->if_addrlist.tqh_first; 63182cd038dSYoshinobu Inoue ifa; 63282cd038dSYoshinobu Inoue ifa = ifa->ifa_list.tqe_next) 63382cd038dSYoshinobu Inoue { 63482cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 63582cd038dSYoshinobu Inoue next: continue; 63682cd038dSYoshinobu Inoue 63782cd038dSYoshinobu Inoue for (i = 0; i < 4; i++) { 63882cd038dSYoshinobu Inoue if ((IFADDR6(ifa).s6_addr32[i] ^ addr->s6_addr32[i]) & 63982cd038dSYoshinobu Inoue IFMASK6(ifa).s6_addr32[i]) 64082cd038dSYoshinobu Inoue goto next; 64182cd038dSYoshinobu Inoue } 64282cd038dSYoshinobu Inoue return(1); 64382cd038dSYoshinobu Inoue } 64482cd038dSYoshinobu Inoue 64582cd038dSYoshinobu Inoue /* 64682cd038dSYoshinobu Inoue * Even if the address matches none of our addresses, it might be 64782cd038dSYoshinobu Inoue * in the neighbor cache. 64882cd038dSYoshinobu Inoue */ 64982cd038dSYoshinobu Inoue if (nd6_lookup(addr, 0, ifp)) 65082cd038dSYoshinobu Inoue return(1); 65182cd038dSYoshinobu Inoue 65282cd038dSYoshinobu Inoue return(0); 65382cd038dSYoshinobu Inoue #undef IFADDR6 65482cd038dSYoshinobu Inoue #undef IFMASK6 65582cd038dSYoshinobu Inoue } 65682cd038dSYoshinobu Inoue 65782cd038dSYoshinobu Inoue /* 65882cd038dSYoshinobu Inoue * Free an nd6 llinfo entry. 65982cd038dSYoshinobu Inoue */ 66082cd038dSYoshinobu Inoue void 66182cd038dSYoshinobu Inoue nd6_free(rt) 66282cd038dSYoshinobu Inoue struct rtentry *rt; 66382cd038dSYoshinobu Inoue { 66482cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; 66582cd038dSYoshinobu Inoue struct sockaddr_dl *sdl; 66682cd038dSYoshinobu Inoue 66782cd038dSYoshinobu Inoue if (ln->ln_router) { 66882cd038dSYoshinobu Inoue /* remove from default router list */ 66982cd038dSYoshinobu Inoue struct nd_defrouter *dr; 67082cd038dSYoshinobu Inoue struct in6_addr *in6; 67182cd038dSYoshinobu Inoue int s; 67282cd038dSYoshinobu Inoue in6 = &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; 67382cd038dSYoshinobu Inoue 67482cd038dSYoshinobu Inoue s = splnet(); 67582cd038dSYoshinobu Inoue dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))-> 67682cd038dSYoshinobu Inoue sin6_addr, 67782cd038dSYoshinobu Inoue rt->rt_ifp); 67882cd038dSYoshinobu Inoue if (dr) 67982cd038dSYoshinobu Inoue defrtrlist_del(dr); 68082cd038dSYoshinobu Inoue else if (!ip6_forwarding && ip6_accept_rtadv) { 68182cd038dSYoshinobu Inoue /* 68282cd038dSYoshinobu Inoue * rt6_flush must be called in any case. 68382cd038dSYoshinobu Inoue * see the comment in nd6_na_input(). 68482cd038dSYoshinobu Inoue */ 68582cd038dSYoshinobu Inoue rt6_flush(in6, rt->rt_ifp); 68682cd038dSYoshinobu Inoue } 68782cd038dSYoshinobu Inoue splx(s); 68882cd038dSYoshinobu Inoue } 68982cd038dSYoshinobu Inoue 69082cd038dSYoshinobu Inoue if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && 69182cd038dSYoshinobu Inoue sdl->sdl_family == AF_LINK) { 69282cd038dSYoshinobu Inoue sdl->sdl_alen = 0; 69382cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_WAITDELETE; 69482cd038dSYoshinobu Inoue ln->ln_asked = 0; 69582cd038dSYoshinobu Inoue rt->rt_flags &= ~RTF_REJECT; 69682cd038dSYoshinobu Inoue return; 69782cd038dSYoshinobu Inoue } 69882cd038dSYoshinobu Inoue rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt), 69982cd038dSYoshinobu Inoue 0, (struct rtentry **)0); 70082cd038dSYoshinobu Inoue } 70182cd038dSYoshinobu Inoue 70282cd038dSYoshinobu Inoue /* 70382cd038dSYoshinobu Inoue * Upper-layer reachability hint for Neighbor Unreachability Detection. 70482cd038dSYoshinobu Inoue * 70582cd038dSYoshinobu Inoue * XXX cost-effective metods? 70682cd038dSYoshinobu Inoue */ 70782cd038dSYoshinobu Inoue void 70882cd038dSYoshinobu Inoue nd6_nud_hint(rt, dst6) 70982cd038dSYoshinobu Inoue struct rtentry *rt; 71082cd038dSYoshinobu Inoue struct in6_addr *dst6; 71182cd038dSYoshinobu Inoue { 71282cd038dSYoshinobu Inoue struct llinfo_nd6 *ln; 71382cd038dSYoshinobu Inoue 71482cd038dSYoshinobu Inoue /* 71582cd038dSYoshinobu Inoue * If the caller specified "rt", use that. Otherwise, resolve the 71682cd038dSYoshinobu Inoue * routing table by supplied "dst6". 71782cd038dSYoshinobu Inoue */ 71882cd038dSYoshinobu Inoue if (!rt) { 71982cd038dSYoshinobu Inoue if (!dst6) 72082cd038dSYoshinobu Inoue return; 72182cd038dSYoshinobu Inoue if (!(rt = nd6_lookup(dst6, 0, NULL))) 72282cd038dSYoshinobu Inoue return; 72382cd038dSYoshinobu Inoue } 72482cd038dSYoshinobu Inoue 72582cd038dSYoshinobu Inoue if ((rt->rt_flags & RTF_GATEWAY) 72682cd038dSYoshinobu Inoue || (rt->rt_flags & RTF_LLINFO) == 0 72782cd038dSYoshinobu Inoue || !rt->rt_llinfo 72882cd038dSYoshinobu Inoue || !rt->rt_gateway 72982cd038dSYoshinobu Inoue || rt->rt_gateway->sa_family != AF_LINK) { 73082cd038dSYoshinobu Inoue /* This is not a host route. */ 73182cd038dSYoshinobu Inoue return; 73282cd038dSYoshinobu Inoue } 73382cd038dSYoshinobu Inoue 73482cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 73582cd038dSYoshinobu Inoue if (ln->ln_state == ND6_LLINFO_INCOMPLETE) 73682cd038dSYoshinobu Inoue return; 73782cd038dSYoshinobu Inoue 73882cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_REACHABLE; 73982cd038dSYoshinobu Inoue if (ln->ln_expire) 74082cd038dSYoshinobu Inoue ln->ln_expire = time_second + 74182cd038dSYoshinobu Inoue nd_ifinfo[rt->rt_ifp->if_index].reachable; 74282cd038dSYoshinobu Inoue } 74382cd038dSYoshinobu Inoue 74482cd038dSYoshinobu Inoue void 74582cd038dSYoshinobu Inoue nd6_rtrequest(req, rt, sa) 74682cd038dSYoshinobu Inoue int req; 74782cd038dSYoshinobu Inoue struct rtentry *rt; 74882cd038dSYoshinobu Inoue struct sockaddr *sa; /* xxx unused */ 74982cd038dSYoshinobu Inoue { 75082cd038dSYoshinobu Inoue struct sockaddr *gate = rt->rt_gateway; 75182cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; 75282cd038dSYoshinobu Inoue static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 75382cd038dSYoshinobu Inoue struct ifnet *ifp = rt->rt_ifp; 75482cd038dSYoshinobu Inoue struct ifaddr *ifa; 75582cd038dSYoshinobu Inoue 75682cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_GATEWAY) 75782cd038dSYoshinobu Inoue return; 75882cd038dSYoshinobu Inoue 75982cd038dSYoshinobu Inoue switch (req) { 76082cd038dSYoshinobu Inoue case RTM_ADD: 76182cd038dSYoshinobu Inoue /* 76282cd038dSYoshinobu Inoue * There is no backward compatibility :) 76382cd038dSYoshinobu Inoue * 76482cd038dSYoshinobu Inoue * if ((rt->rt_flags & RTF_HOST) == 0 && 76582cd038dSYoshinobu Inoue * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 76682cd038dSYoshinobu Inoue * rt->rt_flags |= RTF_CLONING; 76782cd038dSYoshinobu Inoue */ 76882cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_CLONING || rt->rt_flags & RTF_LLINFO) { 76982cd038dSYoshinobu Inoue /* 77082cd038dSYoshinobu Inoue * Case 1: This route should come from 77182cd038dSYoshinobu Inoue * a route to interface. RTF_LLINFO flag is set 77282cd038dSYoshinobu Inoue * for a host route whose destination should be 77382cd038dSYoshinobu Inoue * treated as on-link. 77482cd038dSYoshinobu Inoue */ 77582cd038dSYoshinobu Inoue rt_setgate(rt, rt_key(rt), 77682cd038dSYoshinobu Inoue (struct sockaddr *)&null_sdl); 77782cd038dSYoshinobu Inoue gate = rt->rt_gateway; 77882cd038dSYoshinobu Inoue SDL(gate)->sdl_type = ifp->if_type; 77982cd038dSYoshinobu Inoue SDL(gate)->sdl_index = ifp->if_index; 78082cd038dSYoshinobu Inoue if (ln) 78182cd038dSYoshinobu Inoue ln->ln_expire = time_second; 78282cd038dSYoshinobu Inoue if (ln && ln->ln_expire == 0) { 78382cd038dSYoshinobu Inoue /* cludge for desktops */ 78482cd038dSYoshinobu Inoue ln->ln_expire = 1; 78582cd038dSYoshinobu Inoue } 78682cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_CLONING) 78782cd038dSYoshinobu Inoue break; 78882cd038dSYoshinobu Inoue } 78982cd038dSYoshinobu Inoue /* Announce a new entry if requested. */ 79082cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_ANNOUNCE) 79182cd038dSYoshinobu Inoue nd6_na_output(ifp, 79282cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr, 79382cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr, 79482cd038dSYoshinobu Inoue ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 79582cd038dSYoshinobu Inoue 1); 79682cd038dSYoshinobu Inoue /* FALLTHROUGH */ 79782cd038dSYoshinobu Inoue case RTM_RESOLVE: 79882cd038dSYoshinobu Inoue if (gate->sa_family != AF_LINK || 79982cd038dSYoshinobu Inoue gate->sa_len < sizeof(null_sdl)) { 80082cd038dSYoshinobu Inoue log(LOG_DEBUG, "nd6_rtrequest: bad gateway value\n"); 80182cd038dSYoshinobu Inoue break; 80282cd038dSYoshinobu Inoue } 80382cd038dSYoshinobu Inoue SDL(gate)->sdl_type = ifp->if_type; 80482cd038dSYoshinobu Inoue SDL(gate)->sdl_index = ifp->if_index; 80582cd038dSYoshinobu Inoue if (ln != 0) 80682cd038dSYoshinobu Inoue break; /* This happens on a route change */ 80782cd038dSYoshinobu Inoue /* 80882cd038dSYoshinobu Inoue * Case 2: This route may come from cloning, or a manual route 80982cd038dSYoshinobu Inoue * add with a LL address. 81082cd038dSYoshinobu Inoue */ 81182cd038dSYoshinobu Inoue R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln)); 81282cd038dSYoshinobu Inoue rt->rt_llinfo = (caddr_t)ln; 81382cd038dSYoshinobu Inoue if (!ln) { 81482cd038dSYoshinobu Inoue log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); 81582cd038dSYoshinobu Inoue break; 81682cd038dSYoshinobu Inoue } 81782cd038dSYoshinobu Inoue nd6_inuse++; 81882cd038dSYoshinobu Inoue nd6_allocated++; 81982cd038dSYoshinobu Inoue Bzero(ln, sizeof(*ln)); 82082cd038dSYoshinobu Inoue ln->ln_rt = rt; 82182cd038dSYoshinobu Inoue /* this is required for "ndp" command. - shin */ 82282cd038dSYoshinobu Inoue if (req == RTM_ADD) { 82382cd038dSYoshinobu Inoue /* 82482cd038dSYoshinobu Inoue * gate should have some valid AF_LINK entry, 82582cd038dSYoshinobu Inoue * and ln->ln_expire should have some lifetime 82682cd038dSYoshinobu Inoue * which is specified by ndp command. 82782cd038dSYoshinobu Inoue */ 82882cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_REACHABLE; 82982cd038dSYoshinobu Inoue } else { 83082cd038dSYoshinobu Inoue /* 83182cd038dSYoshinobu Inoue * When req == RTM_RESOLVE, rt is created and 83282cd038dSYoshinobu Inoue * initialized in rtrequest(), so rt_expire is 0. 83382cd038dSYoshinobu Inoue */ 83482cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_INCOMPLETE; 83582cd038dSYoshinobu Inoue ln->ln_expire = time_second; 83682cd038dSYoshinobu Inoue } 83782cd038dSYoshinobu Inoue rt->rt_flags |= RTF_LLINFO; 83882cd038dSYoshinobu Inoue ln->ln_next = llinfo_nd6.ln_next; 83982cd038dSYoshinobu Inoue llinfo_nd6.ln_next = ln; 84082cd038dSYoshinobu Inoue ln->ln_prev = &llinfo_nd6; 84182cd038dSYoshinobu Inoue ln->ln_next->ln_prev = ln; 84282cd038dSYoshinobu Inoue 84382cd038dSYoshinobu Inoue /* 84482cd038dSYoshinobu Inoue * check if rt_key(rt) is one of my address assigned 84582cd038dSYoshinobu Inoue * to the interface. 84682cd038dSYoshinobu Inoue */ 84782cd038dSYoshinobu Inoue ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, 84882cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr); 84982cd038dSYoshinobu Inoue if (ifa) { 85082cd038dSYoshinobu Inoue caddr_t macp = nd6_ifptomac(ifp); 85182cd038dSYoshinobu Inoue ln->ln_expire = 0; 85282cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_REACHABLE; 85382cd038dSYoshinobu Inoue if (macp) { 85482cd038dSYoshinobu Inoue Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); 85582cd038dSYoshinobu Inoue SDL(gate)->sdl_alen = ifp->if_addrlen; 85682cd038dSYoshinobu Inoue } 85782cd038dSYoshinobu Inoue if (nd6_useloopback) { 85882cd038dSYoshinobu Inoue rt->rt_ifp = &loif[0]; /*XXX*/ 85982cd038dSYoshinobu Inoue /* 86082cd038dSYoshinobu Inoue * Make sure rt_ifa be equal to the ifaddr 86182cd038dSYoshinobu Inoue * corresponding to the address. 86282cd038dSYoshinobu Inoue * We need this because when we refer 86382cd038dSYoshinobu Inoue * rt_ifa->ia6_flags in ip6_input, we assume 86482cd038dSYoshinobu Inoue * that the rt_ifa points to the address instead 86582cd038dSYoshinobu Inoue * of the loopback address. 86682cd038dSYoshinobu Inoue */ 86782cd038dSYoshinobu Inoue if (ifa != rt->rt_ifa) { 86882cd038dSYoshinobu Inoue rt->rt_ifa->ifa_refcnt--; 86982cd038dSYoshinobu Inoue ifa->ifa_refcnt++; 87082cd038dSYoshinobu Inoue rt->rt_ifa = ifa; 87182cd038dSYoshinobu Inoue } 87282cd038dSYoshinobu Inoue } 87382cd038dSYoshinobu Inoue } 87482cd038dSYoshinobu Inoue break; 87582cd038dSYoshinobu Inoue 87682cd038dSYoshinobu Inoue case RTM_DELETE: 87782cd038dSYoshinobu Inoue if (!ln) 87882cd038dSYoshinobu Inoue break; 87982cd038dSYoshinobu Inoue nd6_inuse--; 88082cd038dSYoshinobu Inoue ln->ln_next->ln_prev = ln->ln_prev; 88182cd038dSYoshinobu Inoue ln->ln_prev->ln_next = ln->ln_next; 88282cd038dSYoshinobu Inoue ln->ln_prev = NULL; 88382cd038dSYoshinobu Inoue rt->rt_llinfo = 0; 88482cd038dSYoshinobu Inoue rt->rt_flags &= ~RTF_LLINFO; 88582cd038dSYoshinobu Inoue if (ln->ln_hold) 88682cd038dSYoshinobu Inoue m_freem(ln->ln_hold); 88782cd038dSYoshinobu Inoue Free((caddr_t)ln); 88882cd038dSYoshinobu Inoue } 88982cd038dSYoshinobu Inoue } 89082cd038dSYoshinobu Inoue 89182cd038dSYoshinobu Inoue void 89282cd038dSYoshinobu Inoue nd6_p2p_rtrequest(req, rt, sa) 89382cd038dSYoshinobu Inoue int req; 89482cd038dSYoshinobu Inoue struct rtentry *rt; 89582cd038dSYoshinobu Inoue struct sockaddr *sa; /* xxx unused */ 89682cd038dSYoshinobu Inoue { 89782cd038dSYoshinobu Inoue struct sockaddr *gate = rt->rt_gateway; 89882cd038dSYoshinobu Inoue static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 89982cd038dSYoshinobu Inoue struct ifnet *ifp = rt->rt_ifp; 90082cd038dSYoshinobu Inoue struct ifaddr *ifa; 90182cd038dSYoshinobu Inoue 90282cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_GATEWAY) 90382cd038dSYoshinobu Inoue return; 90482cd038dSYoshinobu Inoue 90582cd038dSYoshinobu Inoue switch (req) { 90682cd038dSYoshinobu Inoue case RTM_ADD: 90782cd038dSYoshinobu Inoue /* 90882cd038dSYoshinobu Inoue * There is no backward compatibility :) 90982cd038dSYoshinobu Inoue * 91082cd038dSYoshinobu Inoue * if ((rt->rt_flags & RTF_HOST) == 0 && 91182cd038dSYoshinobu Inoue * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 91282cd038dSYoshinobu Inoue * rt->rt_flags |= RTF_CLONING; 91382cd038dSYoshinobu Inoue */ 91482cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_CLONING) { 91582cd038dSYoshinobu Inoue /* 91682cd038dSYoshinobu Inoue * Case 1: This route should come from 91782cd038dSYoshinobu Inoue * a route to interface. 91882cd038dSYoshinobu Inoue */ 91982cd038dSYoshinobu Inoue rt_setgate(rt, rt_key(rt), 92082cd038dSYoshinobu Inoue (struct sockaddr *)&null_sdl); 92182cd038dSYoshinobu Inoue gate = rt->rt_gateway; 92282cd038dSYoshinobu Inoue SDL(gate)->sdl_type = ifp->if_type; 92382cd038dSYoshinobu Inoue SDL(gate)->sdl_index = ifp->if_index; 92482cd038dSYoshinobu Inoue break; 92582cd038dSYoshinobu Inoue } 92682cd038dSYoshinobu Inoue /* Announce a new entry if requested. */ 92782cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_ANNOUNCE) 92882cd038dSYoshinobu Inoue nd6_na_output(ifp, 92982cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr, 93082cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr, 93182cd038dSYoshinobu Inoue ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 93282cd038dSYoshinobu Inoue 1); 93382cd038dSYoshinobu Inoue /* FALLTHROUGH */ 93482cd038dSYoshinobu Inoue case RTM_RESOLVE: 93582cd038dSYoshinobu Inoue /* 93682cd038dSYoshinobu Inoue * check if rt_key(rt) is one of my address assigned 93782cd038dSYoshinobu Inoue * to the interface. 93882cd038dSYoshinobu Inoue */ 93982cd038dSYoshinobu Inoue ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, 94082cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr); 94182cd038dSYoshinobu Inoue if (ifa) { 94282cd038dSYoshinobu Inoue if (nd6_useloopback) { 94382cd038dSYoshinobu Inoue rt->rt_ifp = &loif[0]; /*XXX*/ 94482cd038dSYoshinobu Inoue } 94582cd038dSYoshinobu Inoue } 94682cd038dSYoshinobu Inoue break; 94782cd038dSYoshinobu Inoue } 94882cd038dSYoshinobu Inoue } 94982cd038dSYoshinobu Inoue 95082cd038dSYoshinobu Inoue int 95182cd038dSYoshinobu Inoue nd6_ioctl(cmd, data, ifp) 95282cd038dSYoshinobu Inoue u_long cmd; 95382cd038dSYoshinobu Inoue caddr_t data; 95482cd038dSYoshinobu Inoue struct ifnet *ifp; 95582cd038dSYoshinobu Inoue { 95682cd038dSYoshinobu Inoue struct in6_drlist *drl = (struct in6_drlist *)data; 95782cd038dSYoshinobu Inoue struct in6_prlist *prl = (struct in6_prlist *)data; 95882cd038dSYoshinobu Inoue struct in6_ndireq *ndi = (struct in6_ndireq *)data; 95982cd038dSYoshinobu Inoue struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; 96082cd038dSYoshinobu Inoue struct nd_defrouter *dr, any; 96182cd038dSYoshinobu Inoue struct nd_prefix *pr; 96282cd038dSYoshinobu Inoue struct rtentry *rt; 96382cd038dSYoshinobu Inoue int i = 0, error = 0; 96482cd038dSYoshinobu Inoue int s; 96582cd038dSYoshinobu Inoue 96682cd038dSYoshinobu Inoue switch (cmd) { 96782cd038dSYoshinobu Inoue case SIOCGDRLST_IN6: 96882cd038dSYoshinobu Inoue bzero(drl, sizeof(*drl)); 96982cd038dSYoshinobu Inoue s = splnet(); 97082cd038dSYoshinobu Inoue dr = nd_defrouter.lh_first; 97182cd038dSYoshinobu Inoue while (dr && i < DRLSTSIZ) { 97282cd038dSYoshinobu Inoue drl->defrouter[i].rtaddr = dr->rtaddr; 97382cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { 97482cd038dSYoshinobu Inoue /* XXX: need to this hack for KAME stack */ 97582cd038dSYoshinobu Inoue drl->defrouter[i].rtaddr.s6_addr16[1] = 0; 97682cd038dSYoshinobu Inoue } else 97782cd038dSYoshinobu Inoue log(LOG_ERR, 97882cd038dSYoshinobu Inoue "default router list contains a " 97982cd038dSYoshinobu Inoue "non-linklocal address(%s)\n", 98082cd038dSYoshinobu Inoue ip6_sprintf(&drl->defrouter[i].rtaddr)); 98182cd038dSYoshinobu Inoue 98282cd038dSYoshinobu Inoue drl->defrouter[i].flags = dr->flags; 98382cd038dSYoshinobu Inoue drl->defrouter[i].rtlifetime = dr->rtlifetime; 98482cd038dSYoshinobu Inoue drl->defrouter[i].expire = dr->expire; 98582cd038dSYoshinobu Inoue drl->defrouter[i].if_index = dr->ifp->if_index; 98682cd038dSYoshinobu Inoue i++; 98782cd038dSYoshinobu Inoue dr = dr->dr_next; 98882cd038dSYoshinobu Inoue } 98982cd038dSYoshinobu Inoue splx(s); 99082cd038dSYoshinobu Inoue break; 99182cd038dSYoshinobu Inoue case SIOCGPRLST_IN6: 99282cd038dSYoshinobu Inoue bzero(prl, sizeof(*prl)); 99382cd038dSYoshinobu Inoue s = splnet(); 99482cd038dSYoshinobu Inoue pr = nd_prefix.lh_first; 99582cd038dSYoshinobu Inoue while (pr && i < PRLSTSIZ) { 99682cd038dSYoshinobu Inoue struct nd_pfxrouter *pfr; 99782cd038dSYoshinobu Inoue int j; 99882cd038dSYoshinobu Inoue 99982cd038dSYoshinobu Inoue prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; 100082cd038dSYoshinobu Inoue prl->prefix[i].raflags = pr->ndpr_raf; 100182cd038dSYoshinobu Inoue prl->prefix[i].prefixlen = pr->ndpr_plen; 100282cd038dSYoshinobu Inoue prl->prefix[i].vltime = pr->ndpr_vltime; 100382cd038dSYoshinobu Inoue prl->prefix[i].pltime = pr->ndpr_pltime; 100482cd038dSYoshinobu Inoue prl->prefix[i].if_index = pr->ndpr_ifp->if_index; 100582cd038dSYoshinobu Inoue prl->prefix[i].expire = pr->ndpr_expire; 100682cd038dSYoshinobu Inoue 100782cd038dSYoshinobu Inoue pfr = pr->ndpr_advrtrs.lh_first; 100882cd038dSYoshinobu Inoue j = 0; 100982cd038dSYoshinobu Inoue while(pfr) { 101082cd038dSYoshinobu Inoue if (j < DRLSTSIZ) { 101182cd038dSYoshinobu Inoue #define RTRADDR prl->prefix[i].advrtr[j] 101282cd038dSYoshinobu Inoue RTRADDR = pfr->router->rtaddr; 101382cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) { 101482cd038dSYoshinobu Inoue /* XXX: hack for KAME */ 101582cd038dSYoshinobu Inoue RTRADDR.s6_addr16[1] = 0; 101682cd038dSYoshinobu Inoue } else 101782cd038dSYoshinobu Inoue log(LOG_ERR, 101882cd038dSYoshinobu Inoue "a router(%s) advertises " 101982cd038dSYoshinobu Inoue "a prefix with " 102082cd038dSYoshinobu Inoue "non-link local address\n", 102182cd038dSYoshinobu Inoue ip6_sprintf(&RTRADDR)); 102282cd038dSYoshinobu Inoue #undef RTRADDR 102382cd038dSYoshinobu Inoue } 102482cd038dSYoshinobu Inoue j++; 102582cd038dSYoshinobu Inoue pfr = pfr->pfr_next; 102682cd038dSYoshinobu Inoue } 102782cd038dSYoshinobu Inoue prl->prefix[i].advrtrs = j; 102882cd038dSYoshinobu Inoue 102982cd038dSYoshinobu Inoue i++; 103082cd038dSYoshinobu Inoue pr = pr->ndpr_next; 103182cd038dSYoshinobu Inoue } 103282cd038dSYoshinobu Inoue splx(s); 103382cd038dSYoshinobu Inoue { 103482cd038dSYoshinobu Inoue struct rr_prefix *rpp; 103582cd038dSYoshinobu Inoue 103682cd038dSYoshinobu Inoue for (rpp = LIST_FIRST(&rr_prefix); rpp; 103782cd038dSYoshinobu Inoue rpp = LIST_NEXT(rpp, rp_entry)) { 103882cd038dSYoshinobu Inoue if (i >= PRLSTSIZ) 103982cd038dSYoshinobu Inoue break; 104082cd038dSYoshinobu Inoue prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; 104182cd038dSYoshinobu Inoue prl->prefix[i].raflags = rpp->rp_raf; 104282cd038dSYoshinobu Inoue prl->prefix[i].prefixlen = rpp->rp_plen; 104382cd038dSYoshinobu Inoue prl->prefix[i].vltime = rpp->rp_vltime; 104482cd038dSYoshinobu Inoue prl->prefix[i].pltime = rpp->rp_pltime; 104582cd038dSYoshinobu Inoue prl->prefix[i].if_index = rpp->rp_ifp->if_index; 104682cd038dSYoshinobu Inoue prl->prefix[i].expire = rpp->rp_expire; 104782cd038dSYoshinobu Inoue prl->prefix[i].advrtrs = 0; 104882cd038dSYoshinobu Inoue i++; 104982cd038dSYoshinobu Inoue } 105082cd038dSYoshinobu Inoue } 105182cd038dSYoshinobu Inoue 105282cd038dSYoshinobu Inoue break; 105382cd038dSYoshinobu Inoue case SIOCGIFINFO_IN6: 105482cd038dSYoshinobu Inoue ndi->ndi = nd_ifinfo[ifp->if_index]; 105582cd038dSYoshinobu Inoue break; 105682cd038dSYoshinobu Inoue case SIOCSNDFLUSH_IN6: 105782cd038dSYoshinobu Inoue /* flush default router list */ 105882cd038dSYoshinobu Inoue /* 105982cd038dSYoshinobu Inoue * xxx sumikawa: should not delete route if default 106082cd038dSYoshinobu Inoue * route equals to the top of default router list 106182cd038dSYoshinobu Inoue */ 106282cd038dSYoshinobu Inoue bzero(&any, sizeof(any)); 106382cd038dSYoshinobu Inoue defrouter_delreq(&any, 0); 106482cd038dSYoshinobu Inoue /* xxx sumikawa: flush prefix list */ 106582cd038dSYoshinobu Inoue break; 106682cd038dSYoshinobu Inoue case SIOCSPFXFLUSH_IN6: 106782cd038dSYoshinobu Inoue { 106882cd038dSYoshinobu Inoue /* flush all the prefix advertised by routers */ 106982cd038dSYoshinobu Inoue struct nd_prefix *pr, *next; 107082cd038dSYoshinobu Inoue 107182cd038dSYoshinobu Inoue s = splnet(); 107282cd038dSYoshinobu Inoue for (pr = nd_prefix.lh_first; pr; pr = next) { 107382cd038dSYoshinobu Inoue next = pr->ndpr_next; 107482cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 107582cd038dSYoshinobu Inoue in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 107682cd038dSYoshinobu Inoue prelist_remove(pr); 107782cd038dSYoshinobu Inoue } 107882cd038dSYoshinobu Inoue splx(s); 107982cd038dSYoshinobu Inoue break; 108082cd038dSYoshinobu Inoue } 108182cd038dSYoshinobu Inoue case SIOCSRTRFLUSH_IN6: 108282cd038dSYoshinobu Inoue { 108382cd038dSYoshinobu Inoue /* flush all the default routers */ 108482cd038dSYoshinobu Inoue struct nd_defrouter *dr, *next; 108582cd038dSYoshinobu Inoue 108682cd038dSYoshinobu Inoue s = splnet(); 108782cd038dSYoshinobu Inoue if ((dr = nd_defrouter.lh_first) != NULL) { 108882cd038dSYoshinobu Inoue /* 108982cd038dSYoshinobu Inoue * The first entry of the list may be stored in 109082cd038dSYoshinobu Inoue * the routing table, so we'll delete it later. 109182cd038dSYoshinobu Inoue */ 109282cd038dSYoshinobu Inoue for (dr = dr->dr_next; dr; dr = next) { 109382cd038dSYoshinobu Inoue next = dr->dr_next; 109482cd038dSYoshinobu Inoue defrtrlist_del(dr); 109582cd038dSYoshinobu Inoue } 109682cd038dSYoshinobu Inoue defrtrlist_del(nd_defrouter.lh_first); 109782cd038dSYoshinobu Inoue } 109882cd038dSYoshinobu Inoue splx(s); 109982cd038dSYoshinobu Inoue break; 110082cd038dSYoshinobu Inoue } 110182cd038dSYoshinobu Inoue case SIOCGNBRINFO_IN6: 110282cd038dSYoshinobu Inoue { 110382cd038dSYoshinobu Inoue struct llinfo_nd6 *ln; 110482cd038dSYoshinobu Inoue struct in6_addr nb_addr = nbi->addr; /* make local for safety */ 110582cd038dSYoshinobu Inoue 110682cd038dSYoshinobu Inoue /* 110782cd038dSYoshinobu Inoue * XXX: KAME specific hack for scoped addresses 110882cd038dSYoshinobu Inoue * XXXX: for other scopes than link-local? 110982cd038dSYoshinobu Inoue */ 111082cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) || 111182cd038dSYoshinobu Inoue IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) { 111282cd038dSYoshinobu Inoue u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2]; 111382cd038dSYoshinobu Inoue 111482cd038dSYoshinobu Inoue if (*idp == 0) 111582cd038dSYoshinobu Inoue *idp = htons(ifp->if_index); 111682cd038dSYoshinobu Inoue } 111782cd038dSYoshinobu Inoue 111882cd038dSYoshinobu Inoue s = splnet(); 111982cd038dSYoshinobu Inoue if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { 112082cd038dSYoshinobu Inoue error = EINVAL; 112182cd038dSYoshinobu Inoue break; 112282cd038dSYoshinobu Inoue } 112382cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 112482cd038dSYoshinobu Inoue nbi->state = ln->ln_state; 112582cd038dSYoshinobu Inoue nbi->asked = ln->ln_asked; 112682cd038dSYoshinobu Inoue nbi->isrouter = ln->ln_router; 112782cd038dSYoshinobu Inoue nbi->expire = ln->ln_expire; 112882cd038dSYoshinobu Inoue splx(s); 112982cd038dSYoshinobu Inoue 113082cd038dSYoshinobu Inoue break; 113182cd038dSYoshinobu Inoue } 113282cd038dSYoshinobu Inoue } 113382cd038dSYoshinobu Inoue return(error); 113482cd038dSYoshinobu Inoue } 113582cd038dSYoshinobu Inoue 113682cd038dSYoshinobu Inoue /* 113782cd038dSYoshinobu Inoue * Create neighbor cache entry and cache link-layer address, 113882cd038dSYoshinobu Inoue * on reception of inbound ND6 packets. (RS/RA/NS/redirect) 113982cd038dSYoshinobu Inoue */ 114082cd038dSYoshinobu Inoue struct rtentry * 114182cd038dSYoshinobu Inoue nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) 114282cd038dSYoshinobu Inoue struct ifnet *ifp; 114382cd038dSYoshinobu Inoue struct in6_addr *from; 114482cd038dSYoshinobu Inoue char *lladdr; 114582cd038dSYoshinobu Inoue int lladdrlen; 114682cd038dSYoshinobu Inoue int type; /* ICMP6 type */ 114782cd038dSYoshinobu Inoue int code; /* type dependent information */ 114882cd038dSYoshinobu Inoue { 114982cd038dSYoshinobu Inoue struct rtentry *rt = NULL; 115082cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = NULL; 115182cd038dSYoshinobu Inoue int is_newentry; 115282cd038dSYoshinobu Inoue struct sockaddr_dl *sdl = NULL; 115382cd038dSYoshinobu Inoue int do_update; 115482cd038dSYoshinobu Inoue int olladdr; 115582cd038dSYoshinobu Inoue int llchange; 115682cd038dSYoshinobu Inoue int newstate = 0; 115782cd038dSYoshinobu Inoue 115882cd038dSYoshinobu Inoue if (!ifp) 115982cd038dSYoshinobu Inoue panic("ifp == NULL in nd6_cache_lladdr"); 116082cd038dSYoshinobu Inoue if (!from) 116182cd038dSYoshinobu Inoue panic("from == NULL in nd6_cache_lladdr"); 116282cd038dSYoshinobu Inoue 116382cd038dSYoshinobu Inoue /* nothing must be updated for unspecified address */ 116482cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(from)) 116582cd038dSYoshinobu Inoue return NULL; 116682cd038dSYoshinobu Inoue 116782cd038dSYoshinobu Inoue /* 116882cd038dSYoshinobu Inoue * Validation about ifp->if_addrlen and lladdrlen must be done in 116982cd038dSYoshinobu Inoue * the caller. 117082cd038dSYoshinobu Inoue * 117182cd038dSYoshinobu Inoue * XXX If the link does not have link-layer adderss, what should 117282cd038dSYoshinobu Inoue * we do? (ifp->if_addrlen == 0) 117382cd038dSYoshinobu Inoue * Spec says nothing in sections for RA, RS and NA. There's small 117482cd038dSYoshinobu Inoue * description on it in NS section (RFC 2461 7.2.3). 117582cd038dSYoshinobu Inoue */ 117682cd038dSYoshinobu Inoue 117782cd038dSYoshinobu Inoue rt = nd6_lookup(from, 0, ifp); 117882cd038dSYoshinobu Inoue if (!rt) { 117982cd038dSYoshinobu Inoue rt = nd6_lookup(from, 1, ifp); 118082cd038dSYoshinobu Inoue is_newentry = 1; 118182cd038dSYoshinobu Inoue } else 118282cd038dSYoshinobu Inoue is_newentry = 0; 118382cd038dSYoshinobu Inoue 118482cd038dSYoshinobu Inoue if (!rt) 118582cd038dSYoshinobu Inoue return NULL; 118682cd038dSYoshinobu Inoue if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { 118782cd038dSYoshinobu Inoue fail: 118882cd038dSYoshinobu Inoue nd6_free(rt); 118982cd038dSYoshinobu Inoue return NULL; 119082cd038dSYoshinobu Inoue } 119182cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 119282cd038dSYoshinobu Inoue if (!ln) 119382cd038dSYoshinobu Inoue goto fail; 119482cd038dSYoshinobu Inoue if (!rt->rt_gateway) 119582cd038dSYoshinobu Inoue goto fail; 119682cd038dSYoshinobu Inoue if (rt->rt_gateway->sa_family != AF_LINK) 119782cd038dSYoshinobu Inoue goto fail; 119882cd038dSYoshinobu Inoue sdl = SDL(rt->rt_gateway); 119982cd038dSYoshinobu Inoue 120082cd038dSYoshinobu Inoue olladdr = (sdl->sdl_alen) ? 1 : 0; 120182cd038dSYoshinobu Inoue if (olladdr && lladdr) { 120282cd038dSYoshinobu Inoue if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen)) 120382cd038dSYoshinobu Inoue llchange = 1; 120482cd038dSYoshinobu Inoue else 120582cd038dSYoshinobu Inoue llchange = 0; 120682cd038dSYoshinobu Inoue } else 120782cd038dSYoshinobu Inoue llchange = 0; 120882cd038dSYoshinobu Inoue 120982cd038dSYoshinobu Inoue /* 121082cd038dSYoshinobu Inoue * newentry olladdr lladdr llchange (*=record) 121182cd038dSYoshinobu Inoue * 0 n n -- (1) 121282cd038dSYoshinobu Inoue * 0 y n -- (2) 121382cd038dSYoshinobu Inoue * 0 n y -- (3) * STALE 121482cd038dSYoshinobu Inoue * 0 y y n (4) * 121582cd038dSYoshinobu Inoue * 0 y y y (5) * STALE 121682cd038dSYoshinobu Inoue * 1 -- n -- (6) NOSTATE(= PASSIVE) 121782cd038dSYoshinobu Inoue * 1 -- y -- (7) * STALE 121882cd038dSYoshinobu Inoue */ 121982cd038dSYoshinobu Inoue 122082cd038dSYoshinobu Inoue if (lladdr) { /*(3-5) and (7)*/ 122182cd038dSYoshinobu Inoue /* 122282cd038dSYoshinobu Inoue * Record source link-layer address 122382cd038dSYoshinobu Inoue * XXX is it dependent to ifp->if_type? 122482cd038dSYoshinobu Inoue */ 122582cd038dSYoshinobu Inoue sdl->sdl_alen = ifp->if_addrlen; 122682cd038dSYoshinobu Inoue bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); 122782cd038dSYoshinobu Inoue } 122882cd038dSYoshinobu Inoue 122982cd038dSYoshinobu Inoue if (!is_newentry) { 123082cd038dSYoshinobu Inoue if ((!olladdr && lladdr) /*(3)*/ 123182cd038dSYoshinobu Inoue || (olladdr && lladdr && llchange)) { /*(5)*/ 123282cd038dSYoshinobu Inoue do_update = 1; 123382cd038dSYoshinobu Inoue newstate = ND6_LLINFO_STALE; 123482cd038dSYoshinobu Inoue } else /*(1-2,4)*/ 123582cd038dSYoshinobu Inoue do_update = 0; 123682cd038dSYoshinobu Inoue } else { 123782cd038dSYoshinobu Inoue do_update = 1; 123882cd038dSYoshinobu Inoue if (!lladdr) /*(6)*/ 123982cd038dSYoshinobu Inoue newstate = ND6_LLINFO_NOSTATE; 124082cd038dSYoshinobu Inoue else /*(7)*/ 124182cd038dSYoshinobu Inoue newstate = ND6_LLINFO_STALE; 124282cd038dSYoshinobu Inoue } 124382cd038dSYoshinobu Inoue 124482cd038dSYoshinobu Inoue if (do_update) { 124582cd038dSYoshinobu Inoue /* 124682cd038dSYoshinobu Inoue * Update the state of the neighbor cache. 124782cd038dSYoshinobu Inoue */ 124882cd038dSYoshinobu Inoue ln->ln_state = newstate; 124982cd038dSYoshinobu Inoue 125082cd038dSYoshinobu Inoue if (ln->ln_state == ND6_LLINFO_STALE) { 125182cd038dSYoshinobu Inoue rt->rt_flags &= ~RTF_REJECT; 125282cd038dSYoshinobu Inoue if (ln->ln_hold) { 125382cd038dSYoshinobu Inoue nd6_output(ifp, ln->ln_hold, 125482cd038dSYoshinobu Inoue (struct sockaddr_in6 *)rt_key(rt), 125582cd038dSYoshinobu Inoue rt); 125682cd038dSYoshinobu Inoue ln->ln_hold = 0; 125782cd038dSYoshinobu Inoue } 125882cd038dSYoshinobu Inoue } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { 125982cd038dSYoshinobu Inoue /* probe right away */ 126082cd038dSYoshinobu Inoue ln->ln_expire = time_second; 126182cd038dSYoshinobu Inoue } 126282cd038dSYoshinobu Inoue } 126382cd038dSYoshinobu Inoue 126482cd038dSYoshinobu Inoue /* 126582cd038dSYoshinobu Inoue * ICMP6 type dependent behavior. 126682cd038dSYoshinobu Inoue * 126782cd038dSYoshinobu Inoue * NS: clear IsRouter if new entry 126882cd038dSYoshinobu Inoue * RS: clear IsRouter 126982cd038dSYoshinobu Inoue * RA: set IsRouter if there's lladdr 127082cd038dSYoshinobu Inoue * redir: clear IsRouter if new entry 127182cd038dSYoshinobu Inoue * 127282cd038dSYoshinobu Inoue * RA case, (1): 127382cd038dSYoshinobu Inoue * The spec says that we must set IsRouter in the following cases: 127482cd038dSYoshinobu Inoue * - If lladdr exist, set IsRouter. This means (1-5). 127582cd038dSYoshinobu Inoue * - If it is old entry (!newentry), set IsRouter. This means (7). 127682cd038dSYoshinobu Inoue * So, based on the spec, in (1-5) and (7) cases we must set IsRouter. 127782cd038dSYoshinobu Inoue * A quetion arises for (1) case. (1) case has no lladdr in the 127882cd038dSYoshinobu Inoue * neighbor cache, this is similar to (6). 127982cd038dSYoshinobu Inoue * This case is rare but we figured that we MUST NOT set IsRouter. 128082cd038dSYoshinobu Inoue * 128182cd038dSYoshinobu Inoue * newentry olladdr lladdr llchange NS RS RA redir 128282cd038dSYoshinobu Inoue * D R 128382cd038dSYoshinobu Inoue * 0 n n -- (1) c ? s 128482cd038dSYoshinobu Inoue * 0 y n -- (2) c s s 128582cd038dSYoshinobu Inoue * 0 n y -- (3) c s s 128682cd038dSYoshinobu Inoue * 0 y y n (4) c s s 128782cd038dSYoshinobu Inoue * 0 y y y (5) c s s 128882cd038dSYoshinobu Inoue * 1 -- n -- (6) c c c s 128982cd038dSYoshinobu Inoue * 1 -- y -- (7) c c s c s 129082cd038dSYoshinobu Inoue * 129182cd038dSYoshinobu Inoue * (c=clear s=set) 129282cd038dSYoshinobu Inoue */ 129382cd038dSYoshinobu Inoue switch (type & 0xff) { 129482cd038dSYoshinobu Inoue case ND_NEIGHBOR_SOLICIT: 129582cd038dSYoshinobu Inoue /* 129682cd038dSYoshinobu Inoue * New entry must have is_router flag cleared. 129782cd038dSYoshinobu Inoue */ 129882cd038dSYoshinobu Inoue if (is_newentry) /*(6-7)*/ 129982cd038dSYoshinobu Inoue ln->ln_router = 0; 130082cd038dSYoshinobu Inoue break; 130182cd038dSYoshinobu Inoue case ND_REDIRECT: 130282cd038dSYoshinobu Inoue /* 130382cd038dSYoshinobu Inoue * If the icmp is a redirect to a better router, always set the 130482cd038dSYoshinobu Inoue * is_router flag. Otherwise, if the entry is newly created, 130582cd038dSYoshinobu Inoue * clear the flag. [RFC 2461, sec 8.3] 130682cd038dSYoshinobu Inoue * 130782cd038dSYoshinobu Inoue */ 130882cd038dSYoshinobu Inoue if (code == ND_REDIRECT_ROUTER) 130982cd038dSYoshinobu Inoue ln->ln_router = 1; 131082cd038dSYoshinobu Inoue else if (is_newentry) /*(6-7)*/ 131182cd038dSYoshinobu Inoue ln->ln_router = 0; 131282cd038dSYoshinobu Inoue break; 131382cd038dSYoshinobu Inoue case ND_ROUTER_SOLICIT: 131482cd038dSYoshinobu Inoue /* 131582cd038dSYoshinobu Inoue * is_router flag must always be cleared. 131682cd038dSYoshinobu Inoue */ 131782cd038dSYoshinobu Inoue ln->ln_router = 0; 131882cd038dSYoshinobu Inoue break; 131982cd038dSYoshinobu Inoue case ND_ROUTER_ADVERT: 132082cd038dSYoshinobu Inoue /* 132182cd038dSYoshinobu Inoue * Mark an entry with lladdr as a router. 132282cd038dSYoshinobu Inoue */ 132382cd038dSYoshinobu Inoue if ((!is_newentry && (olladdr || lladdr)) /*(2-5)*/ 132482cd038dSYoshinobu Inoue || (is_newentry && lladdr)) { /*(7)*/ 132582cd038dSYoshinobu Inoue ln->ln_router = 1; 132682cd038dSYoshinobu Inoue } 132782cd038dSYoshinobu Inoue break; 132882cd038dSYoshinobu Inoue } 132982cd038dSYoshinobu Inoue 133082cd038dSYoshinobu Inoue return rt; 133182cd038dSYoshinobu Inoue } 133282cd038dSYoshinobu Inoue 133382cd038dSYoshinobu Inoue static void 133482cd038dSYoshinobu Inoue nd6_slowtimo(ignored_arg) 133582cd038dSYoshinobu Inoue void *ignored_arg; 133682cd038dSYoshinobu Inoue { 133782cd038dSYoshinobu Inoue int s = splnet(); 133882cd038dSYoshinobu Inoue register int i; 133982cd038dSYoshinobu Inoue register struct nd_ifinfo *nd6if; 134082cd038dSYoshinobu Inoue 134182cd038dSYoshinobu Inoue timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); 134282cd038dSYoshinobu Inoue for (i = 1; i < if_index + 1; i++) { 134382cd038dSYoshinobu Inoue nd6if = &nd_ifinfo[i]; 134482cd038dSYoshinobu Inoue if (nd6if->basereachable && /* already initialized */ 134582cd038dSYoshinobu Inoue (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { 134682cd038dSYoshinobu Inoue /* 134782cd038dSYoshinobu Inoue * Since reachable time rarely changes by router 134882cd038dSYoshinobu Inoue * advertisements, we SHOULD insure that a new random 134982cd038dSYoshinobu Inoue * value gets recomputed at least once every few hours. 135082cd038dSYoshinobu Inoue * (RFC 2461, 6.3.4) 135182cd038dSYoshinobu Inoue */ 135282cd038dSYoshinobu Inoue nd6if->recalctm = nd6_recalc_reachtm_interval; 135382cd038dSYoshinobu Inoue nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable); 135482cd038dSYoshinobu Inoue } 135582cd038dSYoshinobu Inoue } 135682cd038dSYoshinobu Inoue splx(s); 135782cd038dSYoshinobu Inoue } 135882cd038dSYoshinobu Inoue 135982cd038dSYoshinobu Inoue #define senderr(e) { error = (e); goto bad;} 136082cd038dSYoshinobu Inoue int 136182cd038dSYoshinobu Inoue nd6_output(ifp, m0, dst, rt0) 136282cd038dSYoshinobu Inoue register struct ifnet *ifp; 136382cd038dSYoshinobu Inoue struct mbuf *m0; 136482cd038dSYoshinobu Inoue struct sockaddr_in6 *dst; 136582cd038dSYoshinobu Inoue struct rtentry *rt0; 136682cd038dSYoshinobu Inoue { 136782cd038dSYoshinobu Inoue register struct mbuf *m = m0; 136882cd038dSYoshinobu Inoue register struct rtentry *rt = rt0; 136982cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = NULL; 137082cd038dSYoshinobu Inoue int error = 0; 137182cd038dSYoshinobu Inoue 137282cd038dSYoshinobu Inoue if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) 137382cd038dSYoshinobu Inoue goto sendpkt; 137482cd038dSYoshinobu Inoue 137582cd038dSYoshinobu Inoue /* 137682cd038dSYoshinobu Inoue * XXX: we currently do not make neighbor cache on any interface 137782cd038dSYoshinobu Inoue * other than ARCnet, Ethernet and FDDI. 137882cd038dSYoshinobu Inoue */ 137982cd038dSYoshinobu Inoue switch (ifp->if_type) { 138082cd038dSYoshinobu Inoue case IFT_ARCNET: 138182cd038dSYoshinobu Inoue case IFT_ETHER: 138282cd038dSYoshinobu Inoue case IFT_FDDI: 138382cd038dSYoshinobu Inoue break; 138482cd038dSYoshinobu Inoue default: 138582cd038dSYoshinobu Inoue goto sendpkt; 138682cd038dSYoshinobu Inoue } 138782cd038dSYoshinobu Inoue 138882cd038dSYoshinobu Inoue /* 138982cd038dSYoshinobu Inoue * next hop determination. This routine is derived from ether_outpout. 139082cd038dSYoshinobu Inoue */ 139182cd038dSYoshinobu Inoue if (rt) { 139282cd038dSYoshinobu Inoue if ((rt->rt_flags & RTF_UP) == 0) { 139382cd038dSYoshinobu Inoue if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1, 0UL)) != 139482cd038dSYoshinobu Inoue NULL) 139582cd038dSYoshinobu Inoue { 139682cd038dSYoshinobu Inoue rt->rt_refcnt--; 139782cd038dSYoshinobu Inoue if (rt->rt_ifp != ifp) 139882cd038dSYoshinobu Inoue return nd6_output(ifp, m0, dst, rt); /* XXX: loop care? */ 139982cd038dSYoshinobu Inoue } else 140082cd038dSYoshinobu Inoue senderr(EHOSTUNREACH); 140182cd038dSYoshinobu Inoue } 140282cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_GATEWAY) { 140382cd038dSYoshinobu Inoue if (rt->rt_gwroute == 0) 140482cd038dSYoshinobu Inoue goto lookup; 140582cd038dSYoshinobu Inoue if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 140682cd038dSYoshinobu Inoue rtfree(rt); rt = rt0; 140782cd038dSYoshinobu Inoue lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); 140882cd038dSYoshinobu Inoue if ((rt = rt->rt_gwroute) == 0) 140982cd038dSYoshinobu Inoue senderr(EHOSTUNREACH); 141082cd038dSYoshinobu Inoue } 141182cd038dSYoshinobu Inoue } 141282cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_REJECT) 141382cd038dSYoshinobu Inoue senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 141482cd038dSYoshinobu Inoue } 141582cd038dSYoshinobu Inoue 141682cd038dSYoshinobu Inoue /* 141782cd038dSYoshinobu Inoue * Address resolution or Neighbor Unreachability Detection 141882cd038dSYoshinobu Inoue * for the next hop. 141982cd038dSYoshinobu Inoue * At this point, the destination of the packet must be a unicast 142082cd038dSYoshinobu Inoue * or an anycast address(i.e. not a multicast). 142182cd038dSYoshinobu Inoue */ 142282cd038dSYoshinobu Inoue 142382cd038dSYoshinobu Inoue /* Look up the neighbor cache for the nexthop */ 142482cd038dSYoshinobu Inoue if (rt && (rt->rt_flags & RTF_LLINFO) != 0) 142582cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 142682cd038dSYoshinobu Inoue else { 142782cd038dSYoshinobu Inoue if ((rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) 142882cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 142982cd038dSYoshinobu Inoue } 143082cd038dSYoshinobu Inoue if (!ln || !rt) { 143182cd038dSYoshinobu Inoue log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " 143282cd038dSYoshinobu Inoue "(ln=%p, rt=%p)\n", 143382cd038dSYoshinobu Inoue ip6_sprintf(&dst->sin6_addr), ln, rt); 143482cd038dSYoshinobu Inoue senderr(EIO); /* XXX: good error? */ 143582cd038dSYoshinobu Inoue } 143682cd038dSYoshinobu Inoue 143782cd038dSYoshinobu Inoue 143882cd038dSYoshinobu Inoue /* 143982cd038dSYoshinobu Inoue * The first time we send a packet to a neighbor whose entry is 144082cd038dSYoshinobu Inoue * STALE, we have to change the state to DELAY and a sets a timer to 144182cd038dSYoshinobu Inoue * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do 144282cd038dSYoshinobu Inoue * neighbor unreachability detection on expiration. 144382cd038dSYoshinobu Inoue * (RFC 2461 7.3.3) 144482cd038dSYoshinobu Inoue */ 144582cd038dSYoshinobu Inoue if (ln->ln_state == ND6_LLINFO_STALE) { 144682cd038dSYoshinobu Inoue ln->ln_asked = 0; 144782cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_DELAY; 144882cd038dSYoshinobu Inoue ln->ln_expire = time_second + nd6_delay; 144982cd038dSYoshinobu Inoue } 145082cd038dSYoshinobu Inoue 145182cd038dSYoshinobu Inoue /* 145282cd038dSYoshinobu Inoue * If the neighbor cache entry has a state other than INCOMPLETE 145382cd038dSYoshinobu Inoue * (i.e. its link-layer address is already reloved), just 145482cd038dSYoshinobu Inoue * send the packet. 145582cd038dSYoshinobu Inoue */ 145682cd038dSYoshinobu Inoue if (ln->ln_state > ND6_LLINFO_INCOMPLETE) 145782cd038dSYoshinobu Inoue goto sendpkt; 145882cd038dSYoshinobu Inoue 145982cd038dSYoshinobu Inoue /* 146082cd038dSYoshinobu Inoue * There is a neighbor cache entry, but no ethernet address 146182cd038dSYoshinobu Inoue * response yet. Replace the held mbuf (if any) with this 146282cd038dSYoshinobu Inoue * latest one. 146382cd038dSYoshinobu Inoue * 146482cd038dSYoshinobu Inoue * XXX Does the code conform to rate-limiting rule? 146582cd038dSYoshinobu Inoue * (RFC 2461 7.2.2) 146682cd038dSYoshinobu Inoue */ 146782cd038dSYoshinobu Inoue if (ln->ln_state == ND6_LLINFO_WAITDELETE || 146882cd038dSYoshinobu Inoue ln->ln_state == ND6_LLINFO_NOSTATE) 146982cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_INCOMPLETE; 147082cd038dSYoshinobu Inoue if (ln->ln_hold) 147182cd038dSYoshinobu Inoue m_freem(ln->ln_hold); 147282cd038dSYoshinobu Inoue ln->ln_hold = m; 147382cd038dSYoshinobu Inoue if (ln->ln_expire) { 147482cd038dSYoshinobu Inoue rt->rt_flags &= ~RTF_REJECT; 147582cd038dSYoshinobu Inoue if (ln->ln_asked < nd6_mmaxtries && 147682cd038dSYoshinobu Inoue ln->ln_expire < time_second) { 147782cd038dSYoshinobu Inoue ln->ln_asked++; 147882cd038dSYoshinobu Inoue ln->ln_expire = time_second + 147982cd038dSYoshinobu Inoue nd_ifinfo[ifp->if_index].retrans / 1000; 148082cd038dSYoshinobu Inoue nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); 148182cd038dSYoshinobu Inoue } 148282cd038dSYoshinobu Inoue } 148382cd038dSYoshinobu Inoue return(0); 148482cd038dSYoshinobu Inoue 148582cd038dSYoshinobu Inoue sendpkt: 148682cd038dSYoshinobu Inoue return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); 148782cd038dSYoshinobu Inoue 148882cd038dSYoshinobu Inoue bad: 148982cd038dSYoshinobu Inoue if (m) 149082cd038dSYoshinobu Inoue m_freem(m); 149182cd038dSYoshinobu Inoue return (error); 149282cd038dSYoshinobu Inoue } 149382cd038dSYoshinobu Inoue #undef senderr 149482cd038dSYoshinobu Inoue 149582cd038dSYoshinobu Inoue int 149682cd038dSYoshinobu Inoue nd6_storelladdr(ifp, rt, m, dst, desten) 149782cd038dSYoshinobu Inoue struct ifnet *ifp; 149882cd038dSYoshinobu Inoue struct rtentry *rt; 149982cd038dSYoshinobu Inoue struct mbuf *m; 150082cd038dSYoshinobu Inoue struct sockaddr *dst; 150182cd038dSYoshinobu Inoue u_char *desten; 150282cd038dSYoshinobu Inoue { 150382cd038dSYoshinobu Inoue struct sockaddr_dl *sdl; 150482cd038dSYoshinobu Inoue 150582cd038dSYoshinobu Inoue if (m->m_flags & M_MCAST) { 150682cd038dSYoshinobu Inoue switch (ifp->if_type) { 150782cd038dSYoshinobu Inoue case IFT_ETHER: 150882cd038dSYoshinobu Inoue case IFT_FDDI: 150982cd038dSYoshinobu Inoue ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, 151082cd038dSYoshinobu Inoue desten); 151182cd038dSYoshinobu Inoue return(1); 151282cd038dSYoshinobu Inoue break; 151382cd038dSYoshinobu Inoue case IFT_ARCNET: 151482cd038dSYoshinobu Inoue *desten = 0; 151582cd038dSYoshinobu Inoue return(1); 151682cd038dSYoshinobu Inoue default: 151782cd038dSYoshinobu Inoue return(0); 151882cd038dSYoshinobu Inoue } 151982cd038dSYoshinobu Inoue } 152082cd038dSYoshinobu Inoue 152182cd038dSYoshinobu Inoue if (rt == NULL || 152282cd038dSYoshinobu Inoue rt->rt_gateway->sa_family != AF_LINK) { 152382cd038dSYoshinobu Inoue printf("nd6_storelladdr: something odd happens\n"); 152482cd038dSYoshinobu Inoue return(0); 152582cd038dSYoshinobu Inoue } 152682cd038dSYoshinobu Inoue sdl = SDL(rt->rt_gateway); 152782cd038dSYoshinobu Inoue if (sdl->sdl_alen != 0) 152882cd038dSYoshinobu Inoue bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 152982cd038dSYoshinobu Inoue 153082cd038dSYoshinobu Inoue return(1); 153182cd038dSYoshinobu Inoue } 1532