1686cdd19SJun-ichiro itojun Hagino /* $FreeBSD$ */ 2686cdd19SJun-ichiro itojun Hagino /* $KAME: nd6.c,v 1.68 2000/07/02 14:48:02 itojun Exp $ */ 3686cdd19SJun-ichiro itojun Hagino 482cd038dSYoshinobu Inoue /* 582cd038dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 682cd038dSYoshinobu Inoue * All rights reserved. 782cd038dSYoshinobu Inoue * 882cd038dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 982cd038dSYoshinobu Inoue * modification, are permitted provided that the following conditions 1082cd038dSYoshinobu Inoue * are met: 1182cd038dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 1282cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 1382cd038dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 1482cd038dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 1582cd038dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 1682cd038dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 1782cd038dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 1882cd038dSYoshinobu Inoue * without specific prior written permission. 1982cd038dSYoshinobu Inoue * 2082cd038dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2182cd038dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2282cd038dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2382cd038dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2482cd038dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2582cd038dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2682cd038dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2782cd038dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2882cd038dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2982cd038dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3082cd038dSYoshinobu Inoue * SUCH DAMAGE. 3182cd038dSYoshinobu Inoue */ 3282cd038dSYoshinobu Inoue 3382cd038dSYoshinobu Inoue /* 3482cd038dSYoshinobu Inoue * XXX 3582cd038dSYoshinobu Inoue * KAME 970409 note: 3682cd038dSYoshinobu Inoue * BSD/OS version heavily modifies this code, related to llinfo. 3782cd038dSYoshinobu Inoue * Since we don't have BSD/OS version of net/route.c in our hand, 3882cd038dSYoshinobu Inoue * I left the code mostly as it was in 970310. -- itojun 3982cd038dSYoshinobu Inoue */ 4082cd038dSYoshinobu Inoue 41686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h" 42686cdd19SJun-ichiro itojun Hagino #include "opt_inet6.h" 43686cdd19SJun-ichiro itojun Hagino 4482cd038dSYoshinobu Inoue #include <sys/param.h> 4582cd038dSYoshinobu Inoue #include <sys/systm.h> 4682cd038dSYoshinobu Inoue #include <sys/malloc.h> 4782cd038dSYoshinobu Inoue #include <sys/mbuf.h> 4882cd038dSYoshinobu Inoue #include <sys/socket.h> 4982cd038dSYoshinobu Inoue #include <sys/sockio.h> 5082cd038dSYoshinobu Inoue #include <sys/time.h> 5182cd038dSYoshinobu Inoue #include <sys/kernel.h> 52686cdd19SJun-ichiro itojun Hagino #include <sys/protosw.h> 5382cd038dSYoshinobu Inoue #include <sys/errno.h> 5482cd038dSYoshinobu Inoue #include <sys/syslog.h> 5582cd038dSYoshinobu Inoue #include <sys/queue.h> 5682cd038dSYoshinobu Inoue 5782cd038dSYoshinobu Inoue #include <net/if.h> 5882cd038dSYoshinobu Inoue #include <net/if_dl.h> 5982cd038dSYoshinobu Inoue #include <net/if_types.h> 6082cd038dSYoshinobu Inoue #include <net/if_atm.h> 6182cd038dSYoshinobu Inoue #include <net/route.h> 6282cd038dSYoshinobu Inoue 6382cd038dSYoshinobu Inoue #include <netinet/in.h> 6482cd038dSYoshinobu Inoue #include <netinet/if_ether.h> 6582cd038dSYoshinobu Inoue #include <netinet/if_fddi.h> 6682cd038dSYoshinobu Inoue #include <netinet6/in6_var.h> 67686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h> 6882cd038dSYoshinobu Inoue #include <netinet6/ip6_var.h> 6982cd038dSYoshinobu Inoue #include <netinet6/nd6.h> 7082cd038dSYoshinobu Inoue #include <netinet6/in6_prefix.h> 71686cdd19SJun-ichiro itojun Hagino #include <netinet/icmp6.h> 7282cd038dSYoshinobu Inoue 7382cd038dSYoshinobu Inoue #include <net/net_osdep.h> 7482cd038dSYoshinobu Inoue 7582cd038dSYoshinobu Inoue #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */ 7682cd038dSYoshinobu Inoue #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */ 7782cd038dSYoshinobu Inoue 7882cd038dSYoshinobu Inoue #define SIN6(s) ((struct sockaddr_in6 *)s) 7982cd038dSYoshinobu Inoue #define SDL(s) ((struct sockaddr_dl *)s) 8082cd038dSYoshinobu Inoue 8182cd038dSYoshinobu Inoue /* timer values */ 8282cd038dSYoshinobu Inoue int nd6_prune = 1; /* walk list every 1 seconds */ 8382cd038dSYoshinobu Inoue int nd6_delay = 5; /* delay first probe time 5 second */ 8482cd038dSYoshinobu Inoue int nd6_umaxtries = 3; /* maximum unicast query */ 8582cd038dSYoshinobu Inoue int nd6_mmaxtries = 3; /* maximum multicast query */ 8682cd038dSYoshinobu Inoue int nd6_useloopback = 1; /* use loopback interface for local traffic */ 87686cdd19SJun-ichiro itojun Hagino 88686cdd19SJun-ichiro itojun Hagino /* preventing too many loops in ND option parsing */ 89686cdd19SJun-ichiro itojun Hagino int nd6_maxndopt = 10; /* max # of ND options allowed */ 90686cdd19SJun-ichiro itojun Hagino 91686cdd19SJun-ichiro itojun Hagino int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ 9282cd038dSYoshinobu Inoue 9382cd038dSYoshinobu Inoue /* for debugging? */ 9482cd038dSYoshinobu Inoue static int nd6_inuse, nd6_allocated; 9582cd038dSYoshinobu Inoue 9682cd038dSYoshinobu Inoue struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; 97686cdd19SJun-ichiro itojun Hagino static size_t nd_ifinfo_indexlim = 8; 9882cd038dSYoshinobu Inoue struct nd_ifinfo *nd_ifinfo = NULL; 99686cdd19SJun-ichiro itojun Hagino struct nd_drhead nd_defrouter; 10082cd038dSYoshinobu Inoue struct nd_prhead nd_prefix = { 0 }; 10182cd038dSYoshinobu Inoue 10282cd038dSYoshinobu Inoue int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; 10382cd038dSYoshinobu Inoue static struct sockaddr_in6 all1_sa; 10482cd038dSYoshinobu Inoue 10582cd038dSYoshinobu Inoue static void nd6_slowtimo __P((void *)); 10682cd038dSYoshinobu Inoue 10782cd038dSYoshinobu Inoue void 10882cd038dSYoshinobu Inoue nd6_init() 10982cd038dSYoshinobu Inoue { 11082cd038dSYoshinobu Inoue static int nd6_init_done = 0; 11182cd038dSYoshinobu Inoue int i; 11282cd038dSYoshinobu Inoue 11382cd038dSYoshinobu Inoue if (nd6_init_done) { 11482cd038dSYoshinobu Inoue log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); 11582cd038dSYoshinobu Inoue return; 11682cd038dSYoshinobu Inoue } 11782cd038dSYoshinobu Inoue 11882cd038dSYoshinobu Inoue all1_sa.sin6_family = AF_INET6; 11982cd038dSYoshinobu Inoue all1_sa.sin6_len = sizeof(struct sockaddr_in6); 12082cd038dSYoshinobu Inoue for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) 12182cd038dSYoshinobu Inoue all1_sa.sin6_addr.s6_addr[i] = 0xff; 12282cd038dSYoshinobu Inoue 123686cdd19SJun-ichiro itojun Hagino /* initialization of the default router list */ 124686cdd19SJun-ichiro itojun Hagino TAILQ_INIT(&nd_defrouter); 125686cdd19SJun-ichiro itojun Hagino 12682cd038dSYoshinobu Inoue nd6_init_done = 1; 12782cd038dSYoshinobu Inoue 12882cd038dSYoshinobu Inoue /* start timer */ 12982cd038dSYoshinobu Inoue timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); 13082cd038dSYoshinobu Inoue } 13182cd038dSYoshinobu Inoue 13282cd038dSYoshinobu Inoue void 13382cd038dSYoshinobu Inoue nd6_ifattach(ifp) 13482cd038dSYoshinobu Inoue struct ifnet *ifp; 13582cd038dSYoshinobu Inoue { 13682cd038dSYoshinobu Inoue 13782cd038dSYoshinobu Inoue /* 13882cd038dSYoshinobu Inoue * We have some arrays that should be indexed by if_index. 13982cd038dSYoshinobu Inoue * since if_index will grow dynamically, they should grow too. 14082cd038dSYoshinobu Inoue */ 141686cdd19SJun-ichiro itojun Hagino if (nd_ifinfo == NULL || if_index >= nd_ifinfo_indexlim) { 14282cd038dSYoshinobu Inoue size_t n; 14382cd038dSYoshinobu Inoue caddr_t q; 14482cd038dSYoshinobu Inoue 145686cdd19SJun-ichiro itojun Hagino while (if_index >= nd_ifinfo_indexlim) 146686cdd19SJun-ichiro itojun Hagino nd_ifinfo_indexlim <<= 1; 14782cd038dSYoshinobu Inoue 14882cd038dSYoshinobu Inoue /* grow nd_ifinfo */ 149686cdd19SJun-ichiro itojun Hagino n = nd_ifinfo_indexlim * sizeof(struct nd_ifinfo); 15082cd038dSYoshinobu Inoue q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK); 15182cd038dSYoshinobu Inoue bzero(q, n); 15282cd038dSYoshinobu Inoue if (nd_ifinfo) { 15382cd038dSYoshinobu Inoue bcopy((caddr_t)nd_ifinfo, q, n/2); 15482cd038dSYoshinobu Inoue free((caddr_t)nd_ifinfo, M_IP6NDP); 15582cd038dSYoshinobu Inoue } 15682cd038dSYoshinobu Inoue nd_ifinfo = (struct nd_ifinfo *)q; 15782cd038dSYoshinobu Inoue } 15882cd038dSYoshinobu Inoue 15982cd038dSYoshinobu Inoue #define ND nd_ifinfo[ifp->if_index] 160686cdd19SJun-ichiro itojun Hagino 161bf1c6fefSHidetoshi Shimokawa /* 162bf1c6fefSHidetoshi Shimokawa * Don't initialize if called twice. 163bf1c6fefSHidetoshi Shimokawa * XXX: to detect this, we should choose a member that is never set 164bf1c6fefSHidetoshi Shimokawa * before initialization of the ND structure itself. We formaly used 165bf1c6fefSHidetoshi Shimokawa * the linkmtu member, which was not suitable because it could be 166bf1c6fefSHidetoshi Shimokawa * initialized via "ifconfig mtu". 167bf1c6fefSHidetoshi Shimokawa */ 168bf1c6fefSHidetoshi Shimokawa if (ND.basereachable) 169686cdd19SJun-ichiro itojun Hagino return; 170686cdd19SJun-ichiro itojun Hagino 17182cd038dSYoshinobu Inoue ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu; 17282cd038dSYoshinobu Inoue ND.chlim = IPV6_DEFHLIM; 17382cd038dSYoshinobu Inoue ND.basereachable = REACHABLE_TIME; 17482cd038dSYoshinobu Inoue ND.reachable = ND_COMPUTE_RTIME(ND.basereachable); 17582cd038dSYoshinobu Inoue ND.retrans = RETRANS_TIMER; 17682cd038dSYoshinobu Inoue ND.receivedra = 0; 177686cdd19SJun-ichiro itojun Hagino ND.flags = ND6_IFF_PERFORMNUD; 17882cd038dSYoshinobu Inoue nd6_setmtu(ifp); 17982cd038dSYoshinobu Inoue #undef ND 18082cd038dSYoshinobu Inoue } 18182cd038dSYoshinobu Inoue 18282cd038dSYoshinobu Inoue /* 18382cd038dSYoshinobu Inoue * Reset ND level link MTU. This function is called when the physical MTU 18482cd038dSYoshinobu Inoue * changes, which means we might have to adjust the ND level MTU. 18582cd038dSYoshinobu Inoue */ 18682cd038dSYoshinobu Inoue void 18782cd038dSYoshinobu Inoue nd6_setmtu(ifp) 18882cd038dSYoshinobu Inoue struct ifnet *ifp; 18982cd038dSYoshinobu Inoue { 19082cd038dSYoshinobu Inoue #define MIN(a,b) ((a) < (b) ? (a) : (b)) 19182cd038dSYoshinobu Inoue struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; 19282cd038dSYoshinobu Inoue u_long oldmaxmtu = ndi->maxmtu; 19382cd038dSYoshinobu Inoue u_long oldlinkmtu = ndi->linkmtu; 19482cd038dSYoshinobu Inoue 19582cd038dSYoshinobu Inoue switch(ifp->if_type) { 19682cd038dSYoshinobu Inoue case IFT_ARCNET: /* XXX MTU handling needs more work */ 19782cd038dSYoshinobu Inoue ndi->maxmtu = MIN(60480, ifp->if_mtu); 19882cd038dSYoshinobu Inoue break; 19982cd038dSYoshinobu Inoue case IFT_ETHER: 20082cd038dSYoshinobu Inoue ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); 20182cd038dSYoshinobu Inoue break; 20282cd038dSYoshinobu Inoue case IFT_FDDI: 20382cd038dSYoshinobu Inoue ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu); 20482cd038dSYoshinobu Inoue break; 20582cd038dSYoshinobu Inoue case IFT_ATM: 20682cd038dSYoshinobu Inoue ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); 20782cd038dSYoshinobu Inoue break; 20882cd038dSYoshinobu Inoue default: 20982cd038dSYoshinobu Inoue ndi->maxmtu = ifp->if_mtu; 21082cd038dSYoshinobu Inoue break; 21182cd038dSYoshinobu Inoue } 21282cd038dSYoshinobu Inoue 21382cd038dSYoshinobu Inoue if (oldmaxmtu != ndi->maxmtu) { 21482cd038dSYoshinobu Inoue /* 21582cd038dSYoshinobu Inoue * If the ND level MTU is not set yet, or if the maxmtu 21682cd038dSYoshinobu Inoue * is reset to a smaller value than the ND level MTU, 21782cd038dSYoshinobu Inoue * also reset the ND level MTU. 21882cd038dSYoshinobu Inoue */ 21982cd038dSYoshinobu Inoue if (ndi->linkmtu == 0 || 22082cd038dSYoshinobu Inoue ndi->maxmtu < ndi->linkmtu) { 22182cd038dSYoshinobu Inoue ndi->linkmtu = ndi->maxmtu; 22282cd038dSYoshinobu Inoue /* also adjust in6_maxmtu if necessary. */ 22382cd038dSYoshinobu Inoue if (oldlinkmtu == 0) { 22482cd038dSYoshinobu Inoue /* 22582cd038dSYoshinobu Inoue * XXX: the case analysis is grotty, but 22682cd038dSYoshinobu Inoue * it is not efficient to call in6_setmaxmtu() 22782cd038dSYoshinobu Inoue * here when we are during the initialization 22882cd038dSYoshinobu Inoue * procedure. 22982cd038dSYoshinobu Inoue */ 23082cd038dSYoshinobu Inoue if (in6_maxmtu < ndi->linkmtu) 23182cd038dSYoshinobu Inoue in6_maxmtu = ndi->linkmtu; 23282cd038dSYoshinobu Inoue } else 23382cd038dSYoshinobu Inoue in6_setmaxmtu(); 23482cd038dSYoshinobu Inoue } 23582cd038dSYoshinobu Inoue } 23682cd038dSYoshinobu Inoue #undef MIN 23782cd038dSYoshinobu Inoue } 23882cd038dSYoshinobu Inoue 23982cd038dSYoshinobu Inoue void 24082cd038dSYoshinobu Inoue nd6_option_init(opt, icmp6len, ndopts) 24182cd038dSYoshinobu Inoue void *opt; 24282cd038dSYoshinobu Inoue int icmp6len; 24382cd038dSYoshinobu Inoue union nd_opts *ndopts; 24482cd038dSYoshinobu Inoue { 24582cd038dSYoshinobu Inoue bzero(ndopts, sizeof(*ndopts)); 24682cd038dSYoshinobu Inoue ndopts->nd_opts_search = (struct nd_opt_hdr *)opt; 24782cd038dSYoshinobu Inoue ndopts->nd_opts_last 24882cd038dSYoshinobu Inoue = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len); 24982cd038dSYoshinobu Inoue 25082cd038dSYoshinobu Inoue if (icmp6len == 0) { 25182cd038dSYoshinobu Inoue ndopts->nd_opts_done = 1; 25282cd038dSYoshinobu Inoue ndopts->nd_opts_search = NULL; 25382cd038dSYoshinobu Inoue } 25482cd038dSYoshinobu Inoue } 25582cd038dSYoshinobu Inoue 25682cd038dSYoshinobu Inoue /* 25782cd038dSYoshinobu Inoue * Take one ND option. 25882cd038dSYoshinobu Inoue */ 25982cd038dSYoshinobu Inoue struct nd_opt_hdr * 26082cd038dSYoshinobu Inoue nd6_option(ndopts) 26182cd038dSYoshinobu Inoue union nd_opts *ndopts; 26282cd038dSYoshinobu Inoue { 26382cd038dSYoshinobu Inoue struct nd_opt_hdr *nd_opt; 26482cd038dSYoshinobu Inoue int olen; 26582cd038dSYoshinobu Inoue 26682cd038dSYoshinobu Inoue if (!ndopts) 26782cd038dSYoshinobu Inoue panic("ndopts == NULL in nd6_option\n"); 26882cd038dSYoshinobu Inoue if (!ndopts->nd_opts_last) 26982cd038dSYoshinobu Inoue panic("uninitialized ndopts in nd6_option\n"); 27082cd038dSYoshinobu Inoue if (!ndopts->nd_opts_search) 27182cd038dSYoshinobu Inoue return NULL; 27282cd038dSYoshinobu Inoue if (ndopts->nd_opts_done) 27382cd038dSYoshinobu Inoue return NULL; 27482cd038dSYoshinobu Inoue 27582cd038dSYoshinobu Inoue nd_opt = ndopts->nd_opts_search; 27682cd038dSYoshinobu Inoue 27719391949SKris Kennaway /* make sure nd_opt_len is inside the buffer */ 27819391949SKris Kennaway if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) { 27919391949SKris Kennaway bzero(ndopts, sizeof(*ndopts)); 28019391949SKris Kennaway return NULL; 28119391949SKris Kennaway } 28219391949SKris Kennaway 28382cd038dSYoshinobu Inoue olen = nd_opt->nd_opt_len << 3; 28482cd038dSYoshinobu Inoue if (olen == 0) { 28582cd038dSYoshinobu Inoue /* 28682cd038dSYoshinobu Inoue * Message validation requires that all included 28782cd038dSYoshinobu Inoue * options have a length that is greater than zero. 28882cd038dSYoshinobu Inoue */ 28982cd038dSYoshinobu Inoue bzero(ndopts, sizeof(*ndopts)); 29082cd038dSYoshinobu Inoue return NULL; 29182cd038dSYoshinobu Inoue } 29282cd038dSYoshinobu Inoue 29382cd038dSYoshinobu Inoue ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); 29419391949SKris Kennaway if (ndopts->nd_opts_search > ndopts->nd_opts_last) { 29519391949SKris Kennaway /* option overruns the end of buffer, invalid */ 29619391949SKris Kennaway bzero(ndopts, sizeof(*ndopts)); 29719391949SKris Kennaway return NULL; 29819391949SKris Kennaway } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) { 29919391949SKris Kennaway /* reached the end of options chain */ 30082cd038dSYoshinobu Inoue ndopts->nd_opts_done = 1; 30182cd038dSYoshinobu Inoue ndopts->nd_opts_search = NULL; 30282cd038dSYoshinobu Inoue } 30382cd038dSYoshinobu Inoue return nd_opt; 30482cd038dSYoshinobu Inoue } 30582cd038dSYoshinobu Inoue 30682cd038dSYoshinobu Inoue /* 30782cd038dSYoshinobu Inoue * Parse multiple ND options. 30882cd038dSYoshinobu Inoue * This function is much easier to use, for ND routines that do not need 30982cd038dSYoshinobu Inoue * multiple options of the same type. 31082cd038dSYoshinobu Inoue */ 31182cd038dSYoshinobu Inoue int 31282cd038dSYoshinobu Inoue nd6_options(ndopts) 31382cd038dSYoshinobu Inoue union nd_opts *ndopts; 31482cd038dSYoshinobu Inoue { 31582cd038dSYoshinobu Inoue struct nd_opt_hdr *nd_opt; 31682cd038dSYoshinobu Inoue int i = 0; 31782cd038dSYoshinobu Inoue 31882cd038dSYoshinobu Inoue if (!ndopts) 31982cd038dSYoshinobu Inoue panic("ndopts == NULL in nd6_options\n"); 32082cd038dSYoshinobu Inoue if (!ndopts->nd_opts_last) 32182cd038dSYoshinobu Inoue panic("uninitialized ndopts in nd6_options\n"); 32282cd038dSYoshinobu Inoue if (!ndopts->nd_opts_search) 32382cd038dSYoshinobu Inoue return 0; 32482cd038dSYoshinobu Inoue 32582cd038dSYoshinobu Inoue while (1) { 32682cd038dSYoshinobu Inoue nd_opt = nd6_option(ndopts); 32782cd038dSYoshinobu Inoue if (!nd_opt && !ndopts->nd_opts_last) { 32882cd038dSYoshinobu Inoue /* 32982cd038dSYoshinobu Inoue * Message validation requires that all included 33082cd038dSYoshinobu Inoue * options have a length that is greater than zero. 33182cd038dSYoshinobu Inoue */ 33282cd038dSYoshinobu Inoue bzero(ndopts, sizeof(*ndopts)); 33382cd038dSYoshinobu Inoue return -1; 33482cd038dSYoshinobu Inoue } 33582cd038dSYoshinobu Inoue 33682cd038dSYoshinobu Inoue if (!nd_opt) 33782cd038dSYoshinobu Inoue goto skip1; 33882cd038dSYoshinobu Inoue 33982cd038dSYoshinobu Inoue switch (nd_opt->nd_opt_type) { 34082cd038dSYoshinobu Inoue case ND_OPT_SOURCE_LINKADDR: 34182cd038dSYoshinobu Inoue case ND_OPT_TARGET_LINKADDR: 34282cd038dSYoshinobu Inoue case ND_OPT_MTU: 34382cd038dSYoshinobu Inoue case ND_OPT_REDIRECTED_HEADER: 34482cd038dSYoshinobu Inoue if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { 34582cd038dSYoshinobu Inoue printf("duplicated ND6 option found " 34682cd038dSYoshinobu Inoue "(type=%d)\n", nd_opt->nd_opt_type); 34782cd038dSYoshinobu Inoue /* XXX bark? */ 34882cd038dSYoshinobu Inoue } else { 34982cd038dSYoshinobu Inoue ndopts->nd_opt_array[nd_opt->nd_opt_type] 35082cd038dSYoshinobu Inoue = nd_opt; 35182cd038dSYoshinobu Inoue } 35282cd038dSYoshinobu Inoue break; 35382cd038dSYoshinobu Inoue case ND_OPT_PREFIX_INFORMATION: 35482cd038dSYoshinobu Inoue if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) { 35582cd038dSYoshinobu Inoue ndopts->nd_opt_array[nd_opt->nd_opt_type] 35682cd038dSYoshinobu Inoue = nd_opt; 35782cd038dSYoshinobu Inoue } 35882cd038dSYoshinobu Inoue ndopts->nd_opts_pi_end = 35982cd038dSYoshinobu Inoue (struct nd_opt_prefix_info *)nd_opt; 36082cd038dSYoshinobu Inoue break; 36182cd038dSYoshinobu Inoue default: 36282cd038dSYoshinobu Inoue /* 36382cd038dSYoshinobu Inoue * Unknown options must be silently ignored, 36482cd038dSYoshinobu Inoue * to accomodate future extension to the protocol. 36582cd038dSYoshinobu Inoue */ 366686cdd19SJun-ichiro itojun Hagino log(LOG_DEBUG, 36782cd038dSYoshinobu Inoue "nd6_options: unsupported option %d - " 36882cd038dSYoshinobu Inoue "option ignored\n", nd_opt->nd_opt_type); 36982cd038dSYoshinobu Inoue } 37082cd038dSYoshinobu Inoue 37182cd038dSYoshinobu Inoue skip1: 37282cd038dSYoshinobu Inoue i++; 373686cdd19SJun-ichiro itojun Hagino if (i > nd6_maxndopt) { 374686cdd19SJun-ichiro itojun Hagino icmp6stat.icp6s_nd_toomanyopt++; 37582cd038dSYoshinobu Inoue printf("too many loop in nd opt\n"); 37682cd038dSYoshinobu Inoue break; 37782cd038dSYoshinobu Inoue } 37882cd038dSYoshinobu Inoue 37982cd038dSYoshinobu Inoue if (ndopts->nd_opts_done) 38082cd038dSYoshinobu Inoue break; 38182cd038dSYoshinobu Inoue } 38282cd038dSYoshinobu Inoue 38382cd038dSYoshinobu Inoue return 0; 38482cd038dSYoshinobu Inoue } 38582cd038dSYoshinobu Inoue 38682cd038dSYoshinobu Inoue /* 38782cd038dSYoshinobu Inoue * ND6 timer routine to expire default route list and prefix list 38882cd038dSYoshinobu Inoue */ 38982cd038dSYoshinobu Inoue void 39082cd038dSYoshinobu Inoue nd6_timer(ignored_arg) 39182cd038dSYoshinobu Inoue void *ignored_arg; 39282cd038dSYoshinobu Inoue { 39382cd038dSYoshinobu Inoue int s; 39482cd038dSYoshinobu Inoue register struct llinfo_nd6 *ln; 39582cd038dSYoshinobu Inoue register struct nd_defrouter *dr; 39682cd038dSYoshinobu Inoue register struct nd_prefix *pr; 39782cd038dSYoshinobu Inoue 39882cd038dSYoshinobu Inoue s = splnet(); 39982cd038dSYoshinobu Inoue timeout(nd6_timer, (caddr_t)0, nd6_prune * hz); 40082cd038dSYoshinobu Inoue 40182cd038dSYoshinobu Inoue ln = llinfo_nd6.ln_next; 40282cd038dSYoshinobu Inoue /* XXX BSD/OS separates this code -- itojun */ 40382cd038dSYoshinobu Inoue while (ln && ln != &llinfo_nd6) { 40482cd038dSYoshinobu Inoue struct rtentry *rt; 40582cd038dSYoshinobu Inoue struct ifnet *ifp; 40682cd038dSYoshinobu Inoue struct sockaddr_in6 *dst; 40782cd038dSYoshinobu Inoue struct llinfo_nd6 *next = ln->ln_next; 408686cdd19SJun-ichiro itojun Hagino /* XXX: used for the DELAY case only: */ 409686cdd19SJun-ichiro itojun Hagino struct nd_ifinfo *ndi = NULL; 41082cd038dSYoshinobu Inoue 41182cd038dSYoshinobu Inoue if ((rt = ln->ln_rt) == NULL) { 41282cd038dSYoshinobu Inoue ln = next; 41382cd038dSYoshinobu Inoue continue; 41482cd038dSYoshinobu Inoue } 41582cd038dSYoshinobu Inoue if ((ifp = rt->rt_ifp) == NULL) { 41682cd038dSYoshinobu Inoue ln = next; 41782cd038dSYoshinobu Inoue continue; 41882cd038dSYoshinobu Inoue } 419686cdd19SJun-ichiro itojun Hagino ndi = &nd_ifinfo[ifp->if_index]; 42082cd038dSYoshinobu Inoue dst = (struct sockaddr_in6 *)rt_key(rt); 42182cd038dSYoshinobu Inoue 42282cd038dSYoshinobu Inoue if (ln->ln_expire > time_second) { 42382cd038dSYoshinobu Inoue ln = next; 42482cd038dSYoshinobu Inoue continue; 42582cd038dSYoshinobu Inoue } 42682cd038dSYoshinobu Inoue 42782cd038dSYoshinobu Inoue /* sanity check */ 42882cd038dSYoshinobu Inoue if (!rt) 42982cd038dSYoshinobu Inoue panic("rt=0 in nd6_timer(ln=%p)\n", ln); 430686cdd19SJun-ichiro itojun Hagino if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln) 431686cdd19SJun-ichiro itojun Hagino panic("rt_llinfo(%p) is not equal to ln(%p)\n", 432686cdd19SJun-ichiro itojun Hagino rt->rt_llinfo, ln); 43382cd038dSYoshinobu Inoue if (!dst) 43482cd038dSYoshinobu Inoue panic("dst=0 in nd6_timer(ln=%p)\n", ln); 43582cd038dSYoshinobu Inoue 43682cd038dSYoshinobu Inoue switch (ln->ln_state) { 43782cd038dSYoshinobu Inoue case ND6_LLINFO_INCOMPLETE: 43882cd038dSYoshinobu Inoue if (ln->ln_asked < nd6_mmaxtries) { 43982cd038dSYoshinobu Inoue ln->ln_asked++; 44082cd038dSYoshinobu Inoue ln->ln_expire = time_second + 44182cd038dSYoshinobu Inoue nd_ifinfo[ifp->if_index].retrans / 1000; 44282cd038dSYoshinobu Inoue nd6_ns_output(ifp, NULL, &dst->sin6_addr, 44382cd038dSYoshinobu Inoue ln, 0); 44482cd038dSYoshinobu Inoue } else { 44582cd038dSYoshinobu Inoue struct mbuf *m = ln->ln_hold; 44682cd038dSYoshinobu Inoue if (m) { 44782cd038dSYoshinobu Inoue if (rt->rt_ifp) { 44882cd038dSYoshinobu Inoue /* 44982cd038dSYoshinobu Inoue * Fake rcvif to make ICMP error 45082cd038dSYoshinobu Inoue * more helpful in diagnosing 45182cd038dSYoshinobu Inoue * for the receiver. 45282cd038dSYoshinobu Inoue * XXX: should we consider 45382cd038dSYoshinobu Inoue * older rcvif? 45482cd038dSYoshinobu Inoue */ 45582cd038dSYoshinobu Inoue m->m_pkthdr.rcvif = rt->rt_ifp; 45682cd038dSYoshinobu Inoue } 45782cd038dSYoshinobu Inoue icmp6_error(m, ICMP6_DST_UNREACH, 45882cd038dSYoshinobu Inoue ICMP6_DST_UNREACH_ADDR, 0); 45982cd038dSYoshinobu Inoue ln->ln_hold = NULL; 46082cd038dSYoshinobu Inoue } 46182cd038dSYoshinobu Inoue nd6_free(rt); 46282cd038dSYoshinobu Inoue } 46382cd038dSYoshinobu Inoue break; 46482cd038dSYoshinobu Inoue case ND6_LLINFO_REACHABLE: 465686cdd19SJun-ichiro itojun Hagino if (ln->ln_expire) 46682cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_STALE; 46782cd038dSYoshinobu Inoue break; 46882cd038dSYoshinobu Inoue /* 46982cd038dSYoshinobu Inoue * ND6_LLINFO_STALE state requires nothing for timer 47082cd038dSYoshinobu Inoue * routine. 47182cd038dSYoshinobu Inoue */ 47282cd038dSYoshinobu Inoue case ND6_LLINFO_DELAY: 473686cdd19SJun-ichiro itojun Hagino if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) { 474686cdd19SJun-ichiro itojun Hagino /* We need NUD */ 47582cd038dSYoshinobu Inoue ln->ln_asked = 1; 47682cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_PROBE; 47782cd038dSYoshinobu Inoue ln->ln_expire = time_second + 478686cdd19SJun-ichiro itojun Hagino ndi->retrans / 1000; 479686cdd19SJun-ichiro itojun Hagino nd6_ns_output(ifp, &dst->sin6_addr, 480686cdd19SJun-ichiro itojun Hagino &dst->sin6_addr, 48182cd038dSYoshinobu Inoue ln, 0); 482686cdd19SJun-ichiro itojun Hagino } else 483686cdd19SJun-ichiro itojun Hagino ln->ln_state = ND6_LLINFO_STALE; /* XXX */ 48482cd038dSYoshinobu Inoue break; 48582cd038dSYoshinobu Inoue case ND6_LLINFO_PROBE: 48682cd038dSYoshinobu Inoue if (ln->ln_asked < nd6_umaxtries) { 48782cd038dSYoshinobu Inoue ln->ln_asked++; 48882cd038dSYoshinobu Inoue ln->ln_expire = time_second + 48982cd038dSYoshinobu Inoue nd_ifinfo[ifp->if_index].retrans / 1000; 49082cd038dSYoshinobu Inoue nd6_ns_output(ifp, &dst->sin6_addr, 49182cd038dSYoshinobu Inoue &dst->sin6_addr, ln, 0); 49282cd038dSYoshinobu Inoue } else { 49382cd038dSYoshinobu Inoue nd6_free(rt); 49482cd038dSYoshinobu Inoue } 49582cd038dSYoshinobu Inoue break; 49682cd038dSYoshinobu Inoue case ND6_LLINFO_WAITDELETE: 49782cd038dSYoshinobu Inoue nd6_free(rt); 49882cd038dSYoshinobu Inoue break; 49982cd038dSYoshinobu Inoue } 50082cd038dSYoshinobu Inoue ln = next; 50182cd038dSYoshinobu Inoue } 50282cd038dSYoshinobu Inoue 50382cd038dSYoshinobu Inoue /* expire */ 504686cdd19SJun-ichiro itojun Hagino dr = TAILQ_FIRST(&nd_defrouter); 50582cd038dSYoshinobu Inoue while (dr) { 50682cd038dSYoshinobu Inoue if (dr->expire && dr->expire < time_second) { 50782cd038dSYoshinobu Inoue struct nd_defrouter *t; 508686cdd19SJun-ichiro itojun Hagino t = TAILQ_NEXT(dr, dr_entry); 50982cd038dSYoshinobu Inoue defrtrlist_del(dr); 51082cd038dSYoshinobu Inoue dr = t; 511686cdd19SJun-ichiro itojun Hagino } else { 512686cdd19SJun-ichiro itojun Hagino dr = TAILQ_NEXT(dr, dr_entry); 51382cd038dSYoshinobu Inoue } 514686cdd19SJun-ichiro itojun Hagino } 515686cdd19SJun-ichiro itojun Hagino pr = nd_prefix.lh_first; 51682cd038dSYoshinobu Inoue while (pr) { 51782cd038dSYoshinobu Inoue struct in6_ifaddr *ia6; 51882cd038dSYoshinobu Inoue struct in6_addrlifetime *lt6; 51982cd038dSYoshinobu Inoue 52082cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 52182cd038dSYoshinobu Inoue ia6 = NULL; 52282cd038dSYoshinobu Inoue else 52382cd038dSYoshinobu Inoue ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); 52482cd038dSYoshinobu Inoue 52582cd038dSYoshinobu Inoue if (ia6) { 52682cd038dSYoshinobu Inoue /* check address lifetime */ 52782cd038dSYoshinobu Inoue lt6 = &ia6->ia6_lifetime; 52882cd038dSYoshinobu Inoue if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second) 52982cd038dSYoshinobu Inoue ia6->ia6_flags |= IN6_IFF_DEPRECATED; 53082cd038dSYoshinobu Inoue if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) { 53182cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 53282cd038dSYoshinobu Inoue in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 53382cd038dSYoshinobu Inoue /* xxx ND_OPT_PI_FLAG_ONLINK processing */ 53482cd038dSYoshinobu Inoue } 53582cd038dSYoshinobu Inoue } 53682cd038dSYoshinobu Inoue 53782cd038dSYoshinobu Inoue /* 53882cd038dSYoshinobu Inoue * check prefix lifetime. 53982cd038dSYoshinobu Inoue * since pltime is just for autoconf, pltime processing for 54082cd038dSYoshinobu Inoue * prefix is not necessary. 54182cd038dSYoshinobu Inoue * 54282cd038dSYoshinobu Inoue * we offset expire time by NDPR_KEEP_EXPIRE, so that we 54382cd038dSYoshinobu Inoue * can use the old prefix information to validate the 54482cd038dSYoshinobu Inoue * next prefix information to come. See prelist_update() 54582cd038dSYoshinobu Inoue * for actual validation. 54682cd038dSYoshinobu Inoue */ 54782cd038dSYoshinobu Inoue if (pr->ndpr_expire 54882cd038dSYoshinobu Inoue && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { 54982cd038dSYoshinobu Inoue struct nd_prefix *t; 550686cdd19SJun-ichiro itojun Hagino t = pr->ndpr_next; 55182cd038dSYoshinobu Inoue 55282cd038dSYoshinobu Inoue /* 55382cd038dSYoshinobu Inoue * address expiration and prefix expiration are 55482cd038dSYoshinobu Inoue * separate. NEVER perform in6_ifdel here. 55582cd038dSYoshinobu Inoue */ 55682cd038dSYoshinobu Inoue 55782cd038dSYoshinobu Inoue prelist_remove(pr); 55882cd038dSYoshinobu Inoue pr = t; 55982cd038dSYoshinobu Inoue } else 560686cdd19SJun-ichiro itojun Hagino pr = pr->ndpr_next; 56182cd038dSYoshinobu Inoue } 56282cd038dSYoshinobu Inoue splx(s); 56382cd038dSYoshinobu Inoue } 56482cd038dSYoshinobu Inoue 565686cdd19SJun-ichiro itojun Hagino /* 566686cdd19SJun-ichiro itojun Hagino * Nuke neighbor cache/prefix/default router management table, right before 567686cdd19SJun-ichiro itojun Hagino * ifp goes away. 568686cdd19SJun-ichiro itojun Hagino */ 569686cdd19SJun-ichiro itojun Hagino void 570686cdd19SJun-ichiro itojun Hagino nd6_purge(ifp) 571686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 572686cdd19SJun-ichiro itojun Hagino { 573686cdd19SJun-ichiro itojun Hagino struct llinfo_nd6 *ln, *nln; 574686cdd19SJun-ichiro itojun Hagino struct nd_defrouter *dr, *ndr, drany; 575686cdd19SJun-ichiro itojun Hagino struct nd_prefix *pr, *npr; 576686cdd19SJun-ichiro itojun Hagino 577686cdd19SJun-ichiro itojun Hagino /* Nuke default router list entries toward ifp */ 578686cdd19SJun-ichiro itojun Hagino if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { 579686cdd19SJun-ichiro itojun Hagino /* 580686cdd19SJun-ichiro itojun Hagino * The first entry of the list may be stored in 581686cdd19SJun-ichiro itojun Hagino * the routing table, so we'll delete it later. 582686cdd19SJun-ichiro itojun Hagino */ 583686cdd19SJun-ichiro itojun Hagino for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = ndr) { 584686cdd19SJun-ichiro itojun Hagino ndr = TAILQ_NEXT(dr, dr_entry); 585686cdd19SJun-ichiro itojun Hagino if (dr->ifp == ifp) 586686cdd19SJun-ichiro itojun Hagino defrtrlist_del(dr); 587686cdd19SJun-ichiro itojun Hagino } 588686cdd19SJun-ichiro itojun Hagino dr = TAILQ_FIRST(&nd_defrouter); 589686cdd19SJun-ichiro itojun Hagino if (dr->ifp == ifp) 590686cdd19SJun-ichiro itojun Hagino defrtrlist_del(dr); 591686cdd19SJun-ichiro itojun Hagino } 592686cdd19SJun-ichiro itojun Hagino 593686cdd19SJun-ichiro itojun Hagino /* Nuke prefix list entries toward ifp */ 594686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = npr) { 595686cdd19SJun-ichiro itojun Hagino npr = pr->ndpr_next; 596686cdd19SJun-ichiro itojun Hagino if (pr->ndpr_ifp == ifp) { 597686cdd19SJun-ichiro itojun Hagino if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 598686cdd19SJun-ichiro itojun Hagino in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 599686cdd19SJun-ichiro itojun Hagino prelist_remove(pr); 600686cdd19SJun-ichiro itojun Hagino } 601686cdd19SJun-ichiro itojun Hagino } 602686cdd19SJun-ichiro itojun Hagino 603686cdd19SJun-ichiro itojun Hagino /* cancel default outgoing interface setting */ 604686cdd19SJun-ichiro itojun Hagino if (nd6_defifindex == ifp->if_index) 605686cdd19SJun-ichiro itojun Hagino nd6_setdefaultiface(0); 606686cdd19SJun-ichiro itojun Hagino 607686cdd19SJun-ichiro itojun Hagino /* refresh default router list */ 608686cdd19SJun-ichiro itojun Hagino bzero(&drany, sizeof(drany)); 609686cdd19SJun-ichiro itojun Hagino defrouter_delreq(&drany, 0); 610686cdd19SJun-ichiro itojun Hagino defrouter_select(); 611686cdd19SJun-ichiro itojun Hagino 612686cdd19SJun-ichiro itojun Hagino /* 613686cdd19SJun-ichiro itojun Hagino * Nuke neighbor cache entries for the ifp. 614686cdd19SJun-ichiro itojun Hagino * Note that rt->rt_ifp may not be the same as ifp, 615686cdd19SJun-ichiro itojun Hagino * due to KAME goto ours hack. See RTM_RESOLVE case in 616686cdd19SJun-ichiro itojun Hagino * nd6_rtrequest(), and ip6_input(). 617686cdd19SJun-ichiro itojun Hagino */ 618686cdd19SJun-ichiro itojun Hagino ln = llinfo_nd6.ln_next; 619686cdd19SJun-ichiro itojun Hagino while (ln && ln != &llinfo_nd6) { 620686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 621686cdd19SJun-ichiro itojun Hagino struct sockaddr_dl *sdl; 622686cdd19SJun-ichiro itojun Hagino 623686cdd19SJun-ichiro itojun Hagino nln = ln->ln_next; 624686cdd19SJun-ichiro itojun Hagino rt = ln->ln_rt; 625686cdd19SJun-ichiro itojun Hagino if (rt && rt->rt_gateway && 626686cdd19SJun-ichiro itojun Hagino rt->rt_gateway->sa_family == AF_LINK) { 627686cdd19SJun-ichiro itojun Hagino sdl = (struct sockaddr_dl *)rt->rt_gateway; 628686cdd19SJun-ichiro itojun Hagino if (sdl->sdl_index == ifp->if_index) 629686cdd19SJun-ichiro itojun Hagino nd6_free(rt); 630686cdd19SJun-ichiro itojun Hagino } 631686cdd19SJun-ichiro itojun Hagino ln = nln; 632686cdd19SJun-ichiro itojun Hagino } 633686cdd19SJun-ichiro itojun Hagino 634686cdd19SJun-ichiro itojun Hagino /* 635686cdd19SJun-ichiro itojun Hagino * Neighbor cache entry for interface route will be retained 636686cdd19SJun-ichiro itojun Hagino * with ND6_LLINFO_WAITDELETE state, by nd6_free(). Nuke it. 637686cdd19SJun-ichiro itojun Hagino */ 638686cdd19SJun-ichiro itojun Hagino ln = llinfo_nd6.ln_next; 639686cdd19SJun-ichiro itojun Hagino while (ln && ln != &llinfo_nd6) { 640686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 641686cdd19SJun-ichiro itojun Hagino struct sockaddr_dl *sdl; 642686cdd19SJun-ichiro itojun Hagino 643686cdd19SJun-ichiro itojun Hagino nln = ln->ln_next; 644686cdd19SJun-ichiro itojun Hagino rt = ln->ln_rt; 645686cdd19SJun-ichiro itojun Hagino if (rt && rt->rt_gateway && 646686cdd19SJun-ichiro itojun Hagino rt->rt_gateway->sa_family == AF_LINK) { 647686cdd19SJun-ichiro itojun Hagino sdl = (struct sockaddr_dl *)rt->rt_gateway; 648686cdd19SJun-ichiro itojun Hagino if (sdl->sdl_index == ifp->if_index) { 649686cdd19SJun-ichiro itojun Hagino rtrequest(RTM_DELETE, rt_key(rt), 650686cdd19SJun-ichiro itojun Hagino (struct sockaddr *)0, rt_mask(rt), 0, 651686cdd19SJun-ichiro itojun Hagino (struct rtentry **)0); 652686cdd19SJun-ichiro itojun Hagino } 653686cdd19SJun-ichiro itojun Hagino } 654686cdd19SJun-ichiro itojun Hagino ln = nln; 655686cdd19SJun-ichiro itojun Hagino } 656686cdd19SJun-ichiro itojun Hagino } 657686cdd19SJun-ichiro itojun Hagino 65882cd038dSYoshinobu Inoue struct rtentry * 65982cd038dSYoshinobu Inoue nd6_lookup(addr6, create, ifp) 66082cd038dSYoshinobu Inoue struct in6_addr *addr6; 66182cd038dSYoshinobu Inoue int create; 66282cd038dSYoshinobu Inoue struct ifnet *ifp; 66382cd038dSYoshinobu Inoue { 66482cd038dSYoshinobu Inoue struct rtentry *rt; 66582cd038dSYoshinobu Inoue struct sockaddr_in6 sin6; 66682cd038dSYoshinobu Inoue 66782cd038dSYoshinobu Inoue bzero(&sin6, sizeof(sin6)); 66882cd038dSYoshinobu Inoue sin6.sin6_len = sizeof(struct sockaddr_in6); 66982cd038dSYoshinobu Inoue sin6.sin6_family = AF_INET6; 67082cd038dSYoshinobu Inoue sin6.sin6_addr = *addr6; 671686cdd19SJun-ichiro itojun Hagino #ifdef SCOPEDROUTING 672686cdd19SJun-ichiro itojun Hagino sin6.sin6_scope_id = in6_addr2scopeid(ifp, addr6); 673686cdd19SJun-ichiro itojun Hagino #endif 67482cd038dSYoshinobu Inoue rt = rtalloc1((struct sockaddr *)&sin6, create, 0UL); 67582cd038dSYoshinobu Inoue if (rt && (rt->rt_flags & RTF_LLINFO) == 0) { 67682cd038dSYoshinobu Inoue /* 67782cd038dSYoshinobu Inoue * This is the case for the default route. 67882cd038dSYoshinobu Inoue * If we want to create a neighbor cache for the address, we 67982cd038dSYoshinobu Inoue * should free the route for the destination and allocate an 68082cd038dSYoshinobu Inoue * interface route. 68182cd038dSYoshinobu Inoue */ 68282cd038dSYoshinobu Inoue if (create) { 68382cd038dSYoshinobu Inoue RTFREE(rt); 68482cd038dSYoshinobu Inoue rt = 0; 68582cd038dSYoshinobu Inoue } 68682cd038dSYoshinobu Inoue } 68782cd038dSYoshinobu Inoue if (!rt) { 68882cd038dSYoshinobu Inoue if (create && ifp) { 689686cdd19SJun-ichiro itojun Hagino int e; 690686cdd19SJun-ichiro itojun Hagino 69182cd038dSYoshinobu Inoue /* 69282cd038dSYoshinobu Inoue * If no route is available and create is set, 69382cd038dSYoshinobu Inoue * we allocate a host route for the destination 69482cd038dSYoshinobu Inoue * and treat it like an interface route. 69582cd038dSYoshinobu Inoue * This hack is necessary for a neighbor which can't 69682cd038dSYoshinobu Inoue * be covered by our own prefix. 69782cd038dSYoshinobu Inoue */ 69882cd038dSYoshinobu Inoue struct ifaddr *ifa = 69982cd038dSYoshinobu Inoue ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); 70082cd038dSYoshinobu Inoue if (ifa == NULL) 70182cd038dSYoshinobu Inoue return(NULL); 70282cd038dSYoshinobu Inoue 70382cd038dSYoshinobu Inoue /* 70482cd038dSYoshinobu Inoue * Create a new route. RTF_LLINFO is necessary 70582cd038dSYoshinobu Inoue * to create a Neighbor Cache entry for the 70682cd038dSYoshinobu Inoue * destination in nd6_rtrequest which will be 70782cd038dSYoshinobu Inoue * called in rtequest via ifa->ifa_rtrequest. 70882cd038dSYoshinobu Inoue */ 709686cdd19SJun-ichiro itojun Hagino if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, 71082cd038dSYoshinobu Inoue ifa->ifa_addr, 71182cd038dSYoshinobu Inoue (struct sockaddr *)&all1_sa, 71282cd038dSYoshinobu Inoue (ifa->ifa_flags | 713686cdd19SJun-ichiro itojun Hagino RTF_HOST | RTF_LLINFO) & 714686cdd19SJun-ichiro itojun Hagino ~RTF_CLONING, 715686cdd19SJun-ichiro itojun Hagino &rt)) != 0) 71682cd038dSYoshinobu Inoue log(LOG_ERR, 71782cd038dSYoshinobu Inoue "nd6_lookup: failed to add route for a " 718686cdd19SJun-ichiro itojun Hagino "neighbor(%s), errno=%d\n", 719686cdd19SJun-ichiro itojun Hagino ip6_sprintf(addr6), e); 72082cd038dSYoshinobu Inoue if (rt == NULL) 72182cd038dSYoshinobu Inoue return(NULL); 72282cd038dSYoshinobu Inoue if (rt->rt_llinfo) { 72382cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = 72482cd038dSYoshinobu Inoue (struct llinfo_nd6 *)rt->rt_llinfo; 72582cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_NOSTATE; 72682cd038dSYoshinobu Inoue } 72782cd038dSYoshinobu Inoue } else 72882cd038dSYoshinobu Inoue return(NULL); 72982cd038dSYoshinobu Inoue } 73082cd038dSYoshinobu Inoue rt->rt_refcnt--; 73182cd038dSYoshinobu Inoue /* 73282cd038dSYoshinobu Inoue * Validation for the entry. 73382cd038dSYoshinobu Inoue * XXX: we can't use rt->rt_ifp to check for the interface, since 73482cd038dSYoshinobu Inoue * it might be the loopback interface if the entry is for our 73582cd038dSYoshinobu Inoue * own address on a non-loopback interface. Instead, we should 73682cd038dSYoshinobu Inoue * use rt->rt_ifa->ifa_ifp, which would specify the REAL interface. 73782cd038dSYoshinobu Inoue */ 73882cd038dSYoshinobu Inoue if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || 73982cd038dSYoshinobu Inoue rt->rt_gateway->sa_family != AF_LINK || 74082cd038dSYoshinobu Inoue (ifp && rt->rt_ifa->ifa_ifp != ifp)) { 74182cd038dSYoshinobu Inoue if (create) { 74282cd038dSYoshinobu Inoue log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", 74382cd038dSYoshinobu Inoue ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); 74482cd038dSYoshinobu Inoue /* xxx more logs... kazu */ 74582cd038dSYoshinobu Inoue } 74682cd038dSYoshinobu Inoue return(0); 74782cd038dSYoshinobu Inoue } 74882cd038dSYoshinobu Inoue return(rt); 74982cd038dSYoshinobu Inoue } 75082cd038dSYoshinobu Inoue 75182cd038dSYoshinobu Inoue /* 75282cd038dSYoshinobu Inoue * Detect if a given IPv6 address identifies a neighbor on a given link. 75382cd038dSYoshinobu Inoue * XXX: should take care of the destination of a p2p link? 75482cd038dSYoshinobu Inoue */ 75582cd038dSYoshinobu Inoue int 75682cd038dSYoshinobu Inoue nd6_is_addr_neighbor(addr, ifp) 757686cdd19SJun-ichiro itojun Hagino struct sockaddr_in6 *addr; 75882cd038dSYoshinobu Inoue struct ifnet *ifp; 75982cd038dSYoshinobu Inoue { 76082cd038dSYoshinobu Inoue register struct ifaddr *ifa; 76182cd038dSYoshinobu Inoue int i; 76282cd038dSYoshinobu Inoue 76382cd038dSYoshinobu Inoue #define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr) 76482cd038dSYoshinobu Inoue #define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr) 76582cd038dSYoshinobu Inoue 766686cdd19SJun-ichiro itojun Hagino /* 767686cdd19SJun-ichiro itojun Hagino * A link-local address is always a neighbor. 768686cdd19SJun-ichiro itojun Hagino * XXX: we should use the sin6_scope_id field rather than the embedded 769686cdd19SJun-ichiro itojun Hagino * interface index. 770686cdd19SJun-ichiro itojun Hagino */ 771686cdd19SJun-ichiro itojun Hagino if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) && 772686cdd19SJun-ichiro itojun Hagino ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]) == ifp->if_index) 77382cd038dSYoshinobu Inoue return(1); 77482cd038dSYoshinobu Inoue 77582cd038dSYoshinobu Inoue /* 77682cd038dSYoshinobu Inoue * If the address matches one of our addresses, 77782cd038dSYoshinobu Inoue * it should be a neighbor. 77882cd038dSYoshinobu Inoue */ 779686cdd19SJun-ichiro itojun Hagino for (ifa = ifp->if_addrlist.tqh_first; 780686cdd19SJun-ichiro itojun Hagino ifa; 781686cdd19SJun-ichiro itojun Hagino ifa = ifa->ifa_list.tqe_next) 78282cd038dSYoshinobu Inoue { 78382cd038dSYoshinobu Inoue if (ifa->ifa_addr->sa_family != AF_INET6) 78482cd038dSYoshinobu Inoue next: continue; 78582cd038dSYoshinobu Inoue 78682cd038dSYoshinobu Inoue for (i = 0; i < 4; i++) { 787686cdd19SJun-ichiro itojun Hagino if ((IFADDR6(ifa).s6_addr32[i] ^ 788686cdd19SJun-ichiro itojun Hagino addr->sin6_addr.s6_addr32[i]) & 78982cd038dSYoshinobu Inoue IFMASK6(ifa).s6_addr32[i]) 79082cd038dSYoshinobu Inoue goto next; 79182cd038dSYoshinobu Inoue } 79282cd038dSYoshinobu Inoue return(1); 79382cd038dSYoshinobu Inoue } 79482cd038dSYoshinobu Inoue 79582cd038dSYoshinobu Inoue /* 79682cd038dSYoshinobu Inoue * Even if the address matches none of our addresses, it might be 79782cd038dSYoshinobu Inoue * in the neighbor cache. 79882cd038dSYoshinobu Inoue */ 799686cdd19SJun-ichiro itojun Hagino if (nd6_lookup(&addr->sin6_addr, 0, ifp)) 80082cd038dSYoshinobu Inoue return(1); 80182cd038dSYoshinobu Inoue 80282cd038dSYoshinobu Inoue return(0); 80382cd038dSYoshinobu Inoue #undef IFADDR6 80482cd038dSYoshinobu Inoue #undef IFMASK6 80582cd038dSYoshinobu Inoue } 80682cd038dSYoshinobu Inoue 80782cd038dSYoshinobu Inoue /* 80882cd038dSYoshinobu Inoue * Free an nd6 llinfo entry. 80982cd038dSYoshinobu Inoue */ 81082cd038dSYoshinobu Inoue void 81182cd038dSYoshinobu Inoue nd6_free(rt) 81282cd038dSYoshinobu Inoue struct rtentry *rt; 81382cd038dSYoshinobu Inoue { 81482cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; 81582cd038dSYoshinobu Inoue struct sockaddr_dl *sdl; 816686cdd19SJun-ichiro itojun Hagino struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; 81782cd038dSYoshinobu Inoue struct nd_defrouter *dr; 81882cd038dSYoshinobu Inoue 81982cd038dSYoshinobu Inoue /* 820686cdd19SJun-ichiro itojun Hagino * Clear all destination cache entries for the neighbor. 821686cdd19SJun-ichiro itojun Hagino * XXX: is it better to restrict this to hosts? 82282cd038dSYoshinobu Inoue */ 823686cdd19SJun-ichiro itojun Hagino pfctlinput(PRC_HOSTDEAD, rt_key(rt)); 824686cdd19SJun-ichiro itojun Hagino 825686cdd19SJun-ichiro itojun Hagino if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ 826686cdd19SJun-ichiro itojun Hagino int s; 827686cdd19SJun-ichiro itojun Hagino s = splnet(); 828686cdd19SJun-ichiro itojun Hagino dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 829686cdd19SJun-ichiro itojun Hagino rt->rt_ifp); 830686cdd19SJun-ichiro itojun Hagino if (ln->ln_router || dr) { 831686cdd19SJun-ichiro itojun Hagino /* 832686cdd19SJun-ichiro itojun Hagino * rt6_flush must be called whether or not the neighbor 833686cdd19SJun-ichiro itojun Hagino * is in the Default Router List. 834686cdd19SJun-ichiro itojun Hagino * See a corresponding comment in nd6_na_input(). 835686cdd19SJun-ichiro itojun Hagino */ 836686cdd19SJun-ichiro itojun Hagino rt6_flush(&in6, rt->rt_ifp); 837686cdd19SJun-ichiro itojun Hagino } 838686cdd19SJun-ichiro itojun Hagino 839686cdd19SJun-ichiro itojun Hagino if (dr) { 840686cdd19SJun-ichiro itojun Hagino /* 841686cdd19SJun-ichiro itojun Hagino * Unreachablity of a router might affect the default 842686cdd19SJun-ichiro itojun Hagino * router selection and on-link detection of advertised 843686cdd19SJun-ichiro itojun Hagino * prefixes. 844686cdd19SJun-ichiro itojun Hagino */ 845686cdd19SJun-ichiro itojun Hagino 846686cdd19SJun-ichiro itojun Hagino /* 847686cdd19SJun-ichiro itojun Hagino * Temporarily fake the state to choose a new default 848686cdd19SJun-ichiro itojun Hagino * router and to perform on-link determination of 849686cdd19SJun-ichiro itojun Hagino * prefixes coreectly. 850686cdd19SJun-ichiro itojun Hagino * Below the state will be set correctly, 851686cdd19SJun-ichiro itojun Hagino * or the entry itself will be deleted. 852686cdd19SJun-ichiro itojun Hagino */ 853686cdd19SJun-ichiro itojun Hagino ln->ln_state = ND6_LLINFO_INCOMPLETE; 854686cdd19SJun-ichiro itojun Hagino 855686cdd19SJun-ichiro itojun Hagino if (dr == TAILQ_FIRST(&nd_defrouter)) { 856686cdd19SJun-ichiro itojun Hagino /* 857686cdd19SJun-ichiro itojun Hagino * It is used as the current default router, 858686cdd19SJun-ichiro itojun Hagino * so we have to move it to the end of the 859686cdd19SJun-ichiro itojun Hagino * list and choose a new one. 860686cdd19SJun-ichiro itojun Hagino * XXX: it is not very efficient if this is 861686cdd19SJun-ichiro itojun Hagino * the only router. 862686cdd19SJun-ichiro itojun Hagino */ 863686cdd19SJun-ichiro itojun Hagino TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 864686cdd19SJun-ichiro itojun Hagino TAILQ_INSERT_TAIL(&nd_defrouter, dr, dr_entry); 865686cdd19SJun-ichiro itojun Hagino 866686cdd19SJun-ichiro itojun Hagino defrouter_select(); 867686cdd19SJun-ichiro itojun Hagino } 868686cdd19SJun-ichiro itojun Hagino pfxlist_onlink_check(); 86982cd038dSYoshinobu Inoue } 87082cd038dSYoshinobu Inoue splx(s); 87182cd038dSYoshinobu Inoue } 87282cd038dSYoshinobu Inoue 87382cd038dSYoshinobu Inoue if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && 87482cd038dSYoshinobu Inoue sdl->sdl_family == AF_LINK) { 87582cd038dSYoshinobu Inoue sdl->sdl_alen = 0; 87682cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_WAITDELETE; 87782cd038dSYoshinobu Inoue ln->ln_asked = 0; 87882cd038dSYoshinobu Inoue rt->rt_flags &= ~RTF_REJECT; 87982cd038dSYoshinobu Inoue return; 88082cd038dSYoshinobu Inoue } 881686cdd19SJun-ichiro itojun Hagino 882686cdd19SJun-ichiro itojun Hagino rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, 883686cdd19SJun-ichiro itojun Hagino rt_mask(rt), 0, (struct rtentry **)0); 88482cd038dSYoshinobu Inoue } 88582cd038dSYoshinobu Inoue 88682cd038dSYoshinobu Inoue /* 88782cd038dSYoshinobu Inoue * Upper-layer reachability hint for Neighbor Unreachability Detection. 88882cd038dSYoshinobu Inoue * 88982cd038dSYoshinobu Inoue * XXX cost-effective metods? 89082cd038dSYoshinobu Inoue */ 89182cd038dSYoshinobu Inoue void 892686cdd19SJun-ichiro itojun Hagino nd6_nud_hint(rt, dst6, force) 89382cd038dSYoshinobu Inoue struct rtentry *rt; 89482cd038dSYoshinobu Inoue struct in6_addr *dst6; 895686cdd19SJun-ichiro itojun Hagino int force; 89682cd038dSYoshinobu Inoue { 89782cd038dSYoshinobu Inoue struct llinfo_nd6 *ln; 89882cd038dSYoshinobu Inoue 89982cd038dSYoshinobu Inoue /* 90082cd038dSYoshinobu Inoue * If the caller specified "rt", use that. Otherwise, resolve the 90182cd038dSYoshinobu Inoue * routing table by supplied "dst6". 90282cd038dSYoshinobu Inoue */ 90382cd038dSYoshinobu Inoue if (!rt) { 90482cd038dSYoshinobu Inoue if (!dst6) 90582cd038dSYoshinobu Inoue return; 90682cd038dSYoshinobu Inoue if (!(rt = nd6_lookup(dst6, 0, NULL))) 90782cd038dSYoshinobu Inoue return; 90882cd038dSYoshinobu Inoue } 90982cd038dSYoshinobu Inoue 910686cdd19SJun-ichiro itojun Hagino if ((rt->rt_flags & RTF_GATEWAY) != 0 || 911686cdd19SJun-ichiro itojun Hagino (rt->rt_flags & RTF_LLINFO) == 0 || 912686cdd19SJun-ichiro itojun Hagino !rt->rt_llinfo || !rt->rt_gateway || 913686cdd19SJun-ichiro itojun Hagino rt->rt_gateway->sa_family != AF_LINK) { 91482cd038dSYoshinobu Inoue /* This is not a host route. */ 91582cd038dSYoshinobu Inoue return; 91682cd038dSYoshinobu Inoue } 91782cd038dSYoshinobu Inoue 91882cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 919ad8d5711SMunechika SUMIKAWA if (ln->ln_state < ND6_LLINFO_REACHABLE) 92082cd038dSYoshinobu Inoue return; 92182cd038dSYoshinobu Inoue 922686cdd19SJun-ichiro itojun Hagino /* 923686cdd19SJun-ichiro itojun Hagino * if we get upper-layer reachability confirmation many times, 924686cdd19SJun-ichiro itojun Hagino * it is possible we have false information. 925686cdd19SJun-ichiro itojun Hagino */ 926686cdd19SJun-ichiro itojun Hagino if (!force) { 927686cdd19SJun-ichiro itojun Hagino ln->ln_byhint++; 928686cdd19SJun-ichiro itojun Hagino if (ln->ln_byhint > nd6_maxnudhint) 929686cdd19SJun-ichiro itojun Hagino return; 930686cdd19SJun-ichiro itojun Hagino } 931686cdd19SJun-ichiro itojun Hagino 93282cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_REACHABLE; 93382cd038dSYoshinobu Inoue if (ln->ln_expire) 93482cd038dSYoshinobu Inoue ln->ln_expire = time_second + 93582cd038dSYoshinobu Inoue nd_ifinfo[rt->rt_ifp->if_index].reachable; 93682cd038dSYoshinobu Inoue } 93782cd038dSYoshinobu Inoue 938686cdd19SJun-ichiro itojun Hagino #ifdef OLDIP6OUTPUT 939686cdd19SJun-ichiro itojun Hagino /* 940686cdd19SJun-ichiro itojun Hagino * Resolve an IP6 address into an ethernet address. If success, 941686cdd19SJun-ichiro itojun Hagino * desten is filled in. If there is no entry in ndptab, 942686cdd19SJun-ichiro itojun Hagino * set one up and multicast a solicitation for the IP6 address. 943686cdd19SJun-ichiro itojun Hagino * Hold onto this mbuf and resend it once the address 944686cdd19SJun-ichiro itojun Hagino * is finally resolved. A return value of 1 indicates 945686cdd19SJun-ichiro itojun Hagino * that desten has been filled in and the packet should be sent 946686cdd19SJun-ichiro itojun Hagino * normally; a 0 return indicates that the packet has been 947686cdd19SJun-ichiro itojun Hagino * taken over here, either now or for later transmission. 948686cdd19SJun-ichiro itojun Hagino */ 949686cdd19SJun-ichiro itojun Hagino int 950686cdd19SJun-ichiro itojun Hagino nd6_resolve(ifp, rt, m, dst, desten) 951686cdd19SJun-ichiro itojun Hagino struct ifnet *ifp; 952686cdd19SJun-ichiro itojun Hagino struct rtentry *rt; 953686cdd19SJun-ichiro itojun Hagino struct mbuf *m; 954686cdd19SJun-ichiro itojun Hagino struct sockaddr *dst; 955686cdd19SJun-ichiro itojun Hagino u_char *desten; 956686cdd19SJun-ichiro itojun Hagino { 957686cdd19SJun-ichiro itojun Hagino struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; 958686cdd19SJun-ichiro itojun Hagino struct sockaddr_dl *sdl; 959686cdd19SJun-ichiro itojun Hagino 960686cdd19SJun-ichiro itojun Hagino if (m->m_flags & M_MCAST) { 961686cdd19SJun-ichiro itojun Hagino switch (ifp->if_type) { 962686cdd19SJun-ichiro itojun Hagino case IFT_ETHER: 963686cdd19SJun-ichiro itojun Hagino case IFT_FDDI: 964686cdd19SJun-ichiro itojun Hagino ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, 965686cdd19SJun-ichiro itojun Hagino desten); 966686cdd19SJun-ichiro itojun Hagino return(1); 967686cdd19SJun-ichiro itojun Hagino break; 968686cdd19SJun-ichiro itojun Hagino case IFT_ARCNET: 969686cdd19SJun-ichiro itojun Hagino *desten = 0; 970686cdd19SJun-ichiro itojun Hagino return(1); 971686cdd19SJun-ichiro itojun Hagino break; 972686cdd19SJun-ichiro itojun Hagino default: 973686cdd19SJun-ichiro itojun Hagino return(0); 974686cdd19SJun-ichiro itojun Hagino } 975686cdd19SJun-ichiro itojun Hagino } 976686cdd19SJun-ichiro itojun Hagino if (rt && (rt->rt_flags & RTF_LLINFO) != 0) 977686cdd19SJun-ichiro itojun Hagino ln = (struct llinfo_nd6 *)rt->rt_llinfo; 978686cdd19SJun-ichiro itojun Hagino else { 979686cdd19SJun-ichiro itojun Hagino if ((rt = nd6_lookup(&(SIN6(dst)->sin6_addr), 1, ifp)) != NULL) 980686cdd19SJun-ichiro itojun Hagino ln = (struct llinfo_nd6 *)rt->rt_llinfo; 981686cdd19SJun-ichiro itojun Hagino } 982686cdd19SJun-ichiro itojun Hagino if (!ln || !rt) { 983686cdd19SJun-ichiro itojun Hagino log(LOG_DEBUG, "nd6_resolve: can't allocate llinfo for %s\n", 984686cdd19SJun-ichiro itojun Hagino ip6_sprintf(&(SIN6(dst)->sin6_addr))); 985686cdd19SJun-ichiro itojun Hagino m_freem(m); 986686cdd19SJun-ichiro itojun Hagino return(0); 987686cdd19SJun-ichiro itojun Hagino } 988686cdd19SJun-ichiro itojun Hagino sdl = SDL(rt->rt_gateway); 989686cdd19SJun-ichiro itojun Hagino /* 990686cdd19SJun-ichiro itojun Hagino * Ckeck the address family and length is valid, the address 991686cdd19SJun-ichiro itojun Hagino * is resolved; otherwise, try to resolve. 992686cdd19SJun-ichiro itojun Hagino */ 993686cdd19SJun-ichiro itojun Hagino if (ln->ln_state >= ND6_LLINFO_REACHABLE 994686cdd19SJun-ichiro itojun Hagino && sdl->sdl_family == AF_LINK 995686cdd19SJun-ichiro itojun Hagino && sdl->sdl_alen != 0) { 996686cdd19SJun-ichiro itojun Hagino bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 997686cdd19SJun-ichiro itojun Hagino if (ln->ln_state == ND6_LLINFO_STALE) { 998686cdd19SJun-ichiro itojun Hagino ln->ln_asked = 0; 999686cdd19SJun-ichiro itojun Hagino ln->ln_state = ND6_LLINFO_DELAY; 1000686cdd19SJun-ichiro itojun Hagino ln->ln_expire = time_second + nd6_delay; 1001686cdd19SJun-ichiro itojun Hagino } 1002686cdd19SJun-ichiro itojun Hagino return(1); 1003686cdd19SJun-ichiro itojun Hagino } 1004686cdd19SJun-ichiro itojun Hagino /* 1005686cdd19SJun-ichiro itojun Hagino * There is an ndp entry, but no ethernet address 1006686cdd19SJun-ichiro itojun Hagino * response yet. Replace the held mbuf with this 1007686cdd19SJun-ichiro itojun Hagino * latest one. 1008686cdd19SJun-ichiro itojun Hagino * 1009686cdd19SJun-ichiro itojun Hagino * XXX Does the code conform to rate-limiting rule? 1010686cdd19SJun-ichiro itojun Hagino * (RFC 2461 7.2.2) 1011686cdd19SJun-ichiro itojun Hagino */ 1012686cdd19SJun-ichiro itojun Hagino if (ln->ln_state == ND6_LLINFO_WAITDELETE || 1013686cdd19SJun-ichiro itojun Hagino ln->ln_state == ND6_LLINFO_NOSTATE) 1014686cdd19SJun-ichiro itojun Hagino ln->ln_state = ND6_LLINFO_INCOMPLETE; 1015686cdd19SJun-ichiro itojun Hagino if (ln->ln_hold) 1016686cdd19SJun-ichiro itojun Hagino m_freem(ln->ln_hold); 1017686cdd19SJun-ichiro itojun Hagino ln->ln_hold = m; 1018686cdd19SJun-ichiro itojun Hagino if (ln->ln_expire) { 1019686cdd19SJun-ichiro itojun Hagino rt->rt_flags &= ~RTF_REJECT; 1020686cdd19SJun-ichiro itojun Hagino if (ln->ln_asked < nd6_mmaxtries && 1021686cdd19SJun-ichiro itojun Hagino ln->ln_expire < time_second) { 1022686cdd19SJun-ichiro itojun Hagino ln->ln_asked++; 1023686cdd19SJun-ichiro itojun Hagino ln->ln_expire = time_second + 1024686cdd19SJun-ichiro itojun Hagino nd_ifinfo[ifp->if_index].retrans / 1000; 1025686cdd19SJun-ichiro itojun Hagino nd6_ns_output(ifp, NULL, &(SIN6(dst)->sin6_addr), 1026686cdd19SJun-ichiro itojun Hagino ln, 0); 1027686cdd19SJun-ichiro itojun Hagino } 1028686cdd19SJun-ichiro itojun Hagino } 1029686cdd19SJun-ichiro itojun Hagino return(0); 1030686cdd19SJun-ichiro itojun Hagino } 1031686cdd19SJun-ichiro itojun Hagino #endif /* OLDIP6OUTPUT */ 1032686cdd19SJun-ichiro itojun Hagino 103382cd038dSYoshinobu Inoue void 103482cd038dSYoshinobu Inoue nd6_rtrequest(req, rt, sa) 103582cd038dSYoshinobu Inoue int req; 103682cd038dSYoshinobu Inoue struct rtentry *rt; 103782cd038dSYoshinobu Inoue struct sockaddr *sa; /* xxx unused */ 103882cd038dSYoshinobu Inoue { 103982cd038dSYoshinobu Inoue struct sockaddr *gate = rt->rt_gateway; 104082cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; 104182cd038dSYoshinobu Inoue static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 104282cd038dSYoshinobu Inoue struct ifnet *ifp = rt->rt_ifp; 104382cd038dSYoshinobu Inoue struct ifaddr *ifa; 104482cd038dSYoshinobu Inoue 104582cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_GATEWAY) 104682cd038dSYoshinobu Inoue return; 104782cd038dSYoshinobu Inoue 104882cd038dSYoshinobu Inoue switch (req) { 104982cd038dSYoshinobu Inoue case RTM_ADD: 105082cd038dSYoshinobu Inoue /* 105182cd038dSYoshinobu Inoue * There is no backward compatibility :) 105282cd038dSYoshinobu Inoue * 105382cd038dSYoshinobu Inoue * if ((rt->rt_flags & RTF_HOST) == 0 && 105482cd038dSYoshinobu Inoue * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 105582cd038dSYoshinobu Inoue * rt->rt_flags |= RTF_CLONING; 105682cd038dSYoshinobu Inoue */ 1057686cdd19SJun-ichiro itojun Hagino if (rt->rt_flags & (RTF_CLONING | RTF_LLINFO)) { 105882cd038dSYoshinobu Inoue /* 105982cd038dSYoshinobu Inoue * Case 1: This route should come from 106082cd038dSYoshinobu Inoue * a route to interface. RTF_LLINFO flag is set 106182cd038dSYoshinobu Inoue * for a host route whose destination should be 106282cd038dSYoshinobu Inoue * treated as on-link. 106382cd038dSYoshinobu Inoue */ 106482cd038dSYoshinobu Inoue rt_setgate(rt, rt_key(rt), 106582cd038dSYoshinobu Inoue (struct sockaddr *)&null_sdl); 106682cd038dSYoshinobu Inoue gate = rt->rt_gateway; 106782cd038dSYoshinobu Inoue SDL(gate)->sdl_type = ifp->if_type; 106882cd038dSYoshinobu Inoue SDL(gate)->sdl_index = ifp->if_index; 106982cd038dSYoshinobu Inoue if (ln) 107082cd038dSYoshinobu Inoue ln->ln_expire = time_second; 1071686cdd19SJun-ichiro itojun Hagino #if 1 107282cd038dSYoshinobu Inoue if (ln && ln->ln_expire == 0) { 107382cd038dSYoshinobu Inoue /* cludge for desktops */ 1074686cdd19SJun-ichiro itojun Hagino #if 0 1075686cdd19SJun-ichiro itojun Hagino printf("nd6_request: time.tv_sec is zero; " 1076686cdd19SJun-ichiro itojun Hagino "treat it as 1\n"); 1077686cdd19SJun-ichiro itojun Hagino #endif 107882cd038dSYoshinobu Inoue ln->ln_expire = 1; 107982cd038dSYoshinobu Inoue } 1080686cdd19SJun-ichiro itojun Hagino #endif 108182cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_CLONING) 108282cd038dSYoshinobu Inoue break; 108382cd038dSYoshinobu Inoue } 1084686cdd19SJun-ichiro itojun Hagino /* 1085686cdd19SJun-ichiro itojun Hagino * In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here. 1086686cdd19SJun-ichiro itojun Hagino * We don't do that here since llinfo is not ready yet. 1087686cdd19SJun-ichiro itojun Hagino * 1088686cdd19SJun-ichiro itojun Hagino * There are also couple of other things to be discussed: 1089686cdd19SJun-ichiro itojun Hagino * - unsolicited NA code needs improvement beforehand 1090686cdd19SJun-ichiro itojun Hagino * - RFC2461 says we MAY send multicast unsolicited NA 1091686cdd19SJun-ichiro itojun Hagino * (7.2.6 paragraph 4), however, it also says that we 1092686cdd19SJun-ichiro itojun Hagino * SHOULD provide a mechanism to prevent multicast NA storm. 1093686cdd19SJun-ichiro itojun Hagino * we don't have anything like it right now. 1094686cdd19SJun-ichiro itojun Hagino * note that the mechanism need a mutual agreement 1095686cdd19SJun-ichiro itojun Hagino * between proxies, which means that we need to implement 1096686cdd19SJun-ichiro itojun Hagino * a new protocol, or new kludge. 1097686cdd19SJun-ichiro itojun Hagino * - from RFC2461 6.2.4, host MUST NOT send unsolicited NA. 1098686cdd19SJun-ichiro itojun Hagino * we need to check ip6forwarding before sending it. 1099686cdd19SJun-ichiro itojun Hagino * (or should we allow proxy ND configuration only for 1100686cdd19SJun-ichiro itojun Hagino * routers? there's no mention about proxy ND from hosts) 1101686cdd19SJun-ichiro itojun Hagino */ 1102686cdd19SJun-ichiro itojun Hagino #if 0 1103686cdd19SJun-ichiro itojun Hagino /* XXX it does not work */ 110482cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_ANNOUNCE) 110582cd038dSYoshinobu Inoue nd6_na_output(ifp, 110682cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr, 110782cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr, 110882cd038dSYoshinobu Inoue ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1109686cdd19SJun-ichiro itojun Hagino 1, NULL); 1110686cdd19SJun-ichiro itojun Hagino #endif 111182cd038dSYoshinobu Inoue /* FALLTHROUGH */ 111282cd038dSYoshinobu Inoue case RTM_RESOLVE: 1113686cdd19SJun-ichiro itojun Hagino if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 1114686cdd19SJun-ichiro itojun Hagino /* 1115686cdd19SJun-ichiro itojun Hagino * Address resolution isn't necessary for a point to 1116686cdd19SJun-ichiro itojun Hagino * point link, so we can skip this test for a p2p link. 1117686cdd19SJun-ichiro itojun Hagino */ 111882cd038dSYoshinobu Inoue if (gate->sa_family != AF_LINK || 111982cd038dSYoshinobu Inoue gate->sa_len < sizeof(null_sdl)) { 1120686cdd19SJun-ichiro itojun Hagino log(LOG_DEBUG, 1121686cdd19SJun-ichiro itojun Hagino "nd6_rtrequest: bad gateway value\n"); 112282cd038dSYoshinobu Inoue break; 112382cd038dSYoshinobu Inoue } 112482cd038dSYoshinobu Inoue SDL(gate)->sdl_type = ifp->if_type; 112582cd038dSYoshinobu Inoue SDL(gate)->sdl_index = ifp->if_index; 1126686cdd19SJun-ichiro itojun Hagino } 1127686cdd19SJun-ichiro itojun Hagino if (ln != NULL) 112882cd038dSYoshinobu Inoue break; /* This happens on a route change */ 112982cd038dSYoshinobu Inoue /* 113082cd038dSYoshinobu Inoue * Case 2: This route may come from cloning, or a manual route 113182cd038dSYoshinobu Inoue * add with a LL address. 113282cd038dSYoshinobu Inoue */ 113382cd038dSYoshinobu Inoue R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln)); 113482cd038dSYoshinobu Inoue rt->rt_llinfo = (caddr_t)ln; 113582cd038dSYoshinobu Inoue if (!ln) { 113682cd038dSYoshinobu Inoue log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); 113782cd038dSYoshinobu Inoue break; 113882cd038dSYoshinobu Inoue } 113982cd038dSYoshinobu Inoue nd6_inuse++; 114082cd038dSYoshinobu Inoue nd6_allocated++; 114182cd038dSYoshinobu Inoue Bzero(ln, sizeof(*ln)); 114282cd038dSYoshinobu Inoue ln->ln_rt = rt; 114382cd038dSYoshinobu Inoue /* this is required for "ndp" command. - shin */ 114482cd038dSYoshinobu Inoue if (req == RTM_ADD) { 114582cd038dSYoshinobu Inoue /* 114682cd038dSYoshinobu Inoue * gate should have some valid AF_LINK entry, 114782cd038dSYoshinobu Inoue * and ln->ln_expire should have some lifetime 114882cd038dSYoshinobu Inoue * which is specified by ndp command. 114982cd038dSYoshinobu Inoue */ 115082cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_REACHABLE; 1151686cdd19SJun-ichiro itojun Hagino ln->ln_byhint = 0; 115282cd038dSYoshinobu Inoue } else { 115382cd038dSYoshinobu Inoue /* 115482cd038dSYoshinobu Inoue * When req == RTM_RESOLVE, rt is created and 115582cd038dSYoshinobu Inoue * initialized in rtrequest(), so rt_expire is 0. 115682cd038dSYoshinobu Inoue */ 1157686cdd19SJun-ichiro itojun Hagino ln->ln_state = ND6_LLINFO_NOSTATE; 115882cd038dSYoshinobu Inoue ln->ln_expire = time_second; 115982cd038dSYoshinobu Inoue } 116082cd038dSYoshinobu Inoue rt->rt_flags |= RTF_LLINFO; 116182cd038dSYoshinobu Inoue ln->ln_next = llinfo_nd6.ln_next; 116282cd038dSYoshinobu Inoue llinfo_nd6.ln_next = ln; 116382cd038dSYoshinobu Inoue ln->ln_prev = &llinfo_nd6; 116482cd038dSYoshinobu Inoue ln->ln_next->ln_prev = ln; 116582cd038dSYoshinobu Inoue 116682cd038dSYoshinobu Inoue /* 116782cd038dSYoshinobu Inoue * check if rt_key(rt) is one of my address assigned 116882cd038dSYoshinobu Inoue * to the interface. 116982cd038dSYoshinobu Inoue */ 117082cd038dSYoshinobu Inoue ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, 117182cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr); 117282cd038dSYoshinobu Inoue if (ifa) { 117382cd038dSYoshinobu Inoue caddr_t macp = nd6_ifptomac(ifp); 117482cd038dSYoshinobu Inoue ln->ln_expire = 0; 117582cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_REACHABLE; 1176686cdd19SJun-ichiro itojun Hagino ln->ln_byhint = 0; 117782cd038dSYoshinobu Inoue if (macp) { 117882cd038dSYoshinobu Inoue Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); 117982cd038dSYoshinobu Inoue SDL(gate)->sdl_alen = ifp->if_addrlen; 118082cd038dSYoshinobu Inoue } 118182cd038dSYoshinobu Inoue if (nd6_useloopback) { 118282cd038dSYoshinobu Inoue rt->rt_ifp = &loif[0]; /*XXX*/ 118382cd038dSYoshinobu Inoue /* 118482cd038dSYoshinobu Inoue * Make sure rt_ifa be equal to the ifaddr 118582cd038dSYoshinobu Inoue * corresponding to the address. 118682cd038dSYoshinobu Inoue * We need this because when we refer 118782cd038dSYoshinobu Inoue * rt_ifa->ia6_flags in ip6_input, we assume 118882cd038dSYoshinobu Inoue * that the rt_ifa points to the address instead 118982cd038dSYoshinobu Inoue * of the loopback address. 119082cd038dSYoshinobu Inoue */ 119182cd038dSYoshinobu Inoue if (ifa != rt->rt_ifa) { 1192686cdd19SJun-ichiro itojun Hagino IFAFREE(rt->rt_ifa); 119382cd038dSYoshinobu Inoue ifa->ifa_refcnt++; 119482cd038dSYoshinobu Inoue rt->rt_ifa = ifa; 119582cd038dSYoshinobu Inoue } 119682cd038dSYoshinobu Inoue } 1197686cdd19SJun-ichiro itojun Hagino } else if (rt->rt_flags & RTF_ANNOUNCE) { 1198686cdd19SJun-ichiro itojun Hagino ln->ln_expire = 0; 1199686cdd19SJun-ichiro itojun Hagino ln->ln_state = ND6_LLINFO_REACHABLE; 1200686cdd19SJun-ichiro itojun Hagino ln->ln_byhint = 0; 1201686cdd19SJun-ichiro itojun Hagino 1202686cdd19SJun-ichiro itojun Hagino /* join solicited node multicast for proxy ND */ 1203686cdd19SJun-ichiro itojun Hagino if (ifp->if_flags & IFF_MULTICAST) { 1204686cdd19SJun-ichiro itojun Hagino struct in6_addr llsol; 1205686cdd19SJun-ichiro itojun Hagino int error; 1206686cdd19SJun-ichiro itojun Hagino 1207686cdd19SJun-ichiro itojun Hagino llsol = SIN6(rt_key(rt))->sin6_addr; 1208686cdd19SJun-ichiro itojun Hagino llsol.s6_addr16[0] = htons(0xff02); 1209686cdd19SJun-ichiro itojun Hagino llsol.s6_addr16[1] = htons(ifp->if_index); 1210686cdd19SJun-ichiro itojun Hagino llsol.s6_addr32[1] = 0; 1211686cdd19SJun-ichiro itojun Hagino llsol.s6_addr32[2] = htonl(1); 1212686cdd19SJun-ichiro itojun Hagino llsol.s6_addr8[12] = 0xff; 1213686cdd19SJun-ichiro itojun Hagino 1214686cdd19SJun-ichiro itojun Hagino (void)in6_addmulti(&llsol, ifp, &error); 1215686cdd19SJun-ichiro itojun Hagino if (error) 1216686cdd19SJun-ichiro itojun Hagino printf( 1217686cdd19SJun-ichiro itojun Hagino "nd6_rtrequest: could not join solicited node multicast (errno=%d)\n", error); 1218686cdd19SJun-ichiro itojun Hagino } 121982cd038dSYoshinobu Inoue } 122082cd038dSYoshinobu Inoue break; 122182cd038dSYoshinobu Inoue 122282cd038dSYoshinobu Inoue case RTM_DELETE: 122382cd038dSYoshinobu Inoue if (!ln) 122482cd038dSYoshinobu Inoue break; 1225686cdd19SJun-ichiro itojun Hagino /* leave from solicited node multicast for proxy ND */ 1226686cdd19SJun-ichiro itojun Hagino if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && 1227686cdd19SJun-ichiro itojun Hagino (ifp->if_flags & IFF_MULTICAST) != 0) { 1228686cdd19SJun-ichiro itojun Hagino struct in6_addr llsol; 1229686cdd19SJun-ichiro itojun Hagino struct in6_multi *in6m; 1230686cdd19SJun-ichiro itojun Hagino 1231686cdd19SJun-ichiro itojun Hagino llsol = SIN6(rt_key(rt))->sin6_addr; 1232686cdd19SJun-ichiro itojun Hagino llsol.s6_addr16[0] = htons(0xff02); 1233686cdd19SJun-ichiro itojun Hagino llsol.s6_addr16[1] = htons(ifp->if_index); 1234686cdd19SJun-ichiro itojun Hagino llsol.s6_addr32[1] = 0; 1235686cdd19SJun-ichiro itojun Hagino llsol.s6_addr32[2] = htonl(1); 1236686cdd19SJun-ichiro itojun Hagino llsol.s6_addr8[12] = 0xff; 1237686cdd19SJun-ichiro itojun Hagino 1238686cdd19SJun-ichiro itojun Hagino IN6_LOOKUP_MULTI(llsol, ifp, in6m); 1239686cdd19SJun-ichiro itojun Hagino if (in6m) 1240686cdd19SJun-ichiro itojun Hagino in6_delmulti(in6m); 1241686cdd19SJun-ichiro itojun Hagino } 124282cd038dSYoshinobu Inoue nd6_inuse--; 124382cd038dSYoshinobu Inoue ln->ln_next->ln_prev = ln->ln_prev; 124482cd038dSYoshinobu Inoue ln->ln_prev->ln_next = ln->ln_next; 124582cd038dSYoshinobu Inoue ln->ln_prev = NULL; 124682cd038dSYoshinobu Inoue rt->rt_llinfo = 0; 124782cd038dSYoshinobu Inoue rt->rt_flags &= ~RTF_LLINFO; 124882cd038dSYoshinobu Inoue if (ln->ln_hold) 124982cd038dSYoshinobu Inoue m_freem(ln->ln_hold); 125082cd038dSYoshinobu Inoue Free((caddr_t)ln); 125182cd038dSYoshinobu Inoue } 125282cd038dSYoshinobu Inoue } 125382cd038dSYoshinobu Inoue 125482cd038dSYoshinobu Inoue void 125582cd038dSYoshinobu Inoue nd6_p2p_rtrequest(req, rt, sa) 125682cd038dSYoshinobu Inoue int req; 125782cd038dSYoshinobu Inoue struct rtentry *rt; 125882cd038dSYoshinobu Inoue struct sockaddr *sa; /* xxx unused */ 125982cd038dSYoshinobu Inoue { 126082cd038dSYoshinobu Inoue struct sockaddr *gate = rt->rt_gateway; 126182cd038dSYoshinobu Inoue static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 126282cd038dSYoshinobu Inoue struct ifnet *ifp = rt->rt_ifp; 126382cd038dSYoshinobu Inoue struct ifaddr *ifa; 126482cd038dSYoshinobu Inoue 126582cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_GATEWAY) 126682cd038dSYoshinobu Inoue return; 126782cd038dSYoshinobu Inoue 126882cd038dSYoshinobu Inoue switch (req) { 126982cd038dSYoshinobu Inoue case RTM_ADD: 127082cd038dSYoshinobu Inoue /* 127182cd038dSYoshinobu Inoue * There is no backward compatibility :) 127282cd038dSYoshinobu Inoue * 127382cd038dSYoshinobu Inoue * if ((rt->rt_flags & RTF_HOST) == 0 && 127482cd038dSYoshinobu Inoue * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 127582cd038dSYoshinobu Inoue * rt->rt_flags |= RTF_CLONING; 127682cd038dSYoshinobu Inoue */ 127782cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_CLONING) { 127882cd038dSYoshinobu Inoue /* 127982cd038dSYoshinobu Inoue * Case 1: This route should come from 128082cd038dSYoshinobu Inoue * a route to interface. 128182cd038dSYoshinobu Inoue */ 128282cd038dSYoshinobu Inoue rt_setgate(rt, rt_key(rt), 128382cd038dSYoshinobu Inoue (struct sockaddr *)&null_sdl); 128482cd038dSYoshinobu Inoue gate = rt->rt_gateway; 128582cd038dSYoshinobu Inoue SDL(gate)->sdl_type = ifp->if_type; 128682cd038dSYoshinobu Inoue SDL(gate)->sdl_index = ifp->if_index; 128782cd038dSYoshinobu Inoue break; 128882cd038dSYoshinobu Inoue } 128982cd038dSYoshinobu Inoue /* Announce a new entry if requested. */ 129082cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_ANNOUNCE) 129182cd038dSYoshinobu Inoue nd6_na_output(ifp, 129282cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr, 129382cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr, 129482cd038dSYoshinobu Inoue ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1295686cdd19SJun-ichiro itojun Hagino 1, NULL); 129682cd038dSYoshinobu Inoue /* FALLTHROUGH */ 129782cd038dSYoshinobu Inoue case RTM_RESOLVE: 129882cd038dSYoshinobu Inoue /* 129982cd038dSYoshinobu Inoue * check if rt_key(rt) is one of my address assigned 130082cd038dSYoshinobu Inoue * to the interface. 130182cd038dSYoshinobu Inoue */ 130282cd038dSYoshinobu Inoue ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, 130382cd038dSYoshinobu Inoue &SIN6(rt_key(rt))->sin6_addr); 130482cd038dSYoshinobu Inoue if (ifa) { 130582cd038dSYoshinobu Inoue if (nd6_useloopback) { 130682cd038dSYoshinobu Inoue rt->rt_ifp = &loif[0]; /*XXX*/ 130782cd038dSYoshinobu Inoue } 130882cd038dSYoshinobu Inoue } 130982cd038dSYoshinobu Inoue break; 131082cd038dSYoshinobu Inoue } 131182cd038dSYoshinobu Inoue } 131282cd038dSYoshinobu Inoue 131382cd038dSYoshinobu Inoue int 131482cd038dSYoshinobu Inoue nd6_ioctl(cmd, data, ifp) 131582cd038dSYoshinobu Inoue u_long cmd; 131682cd038dSYoshinobu Inoue caddr_t data; 131782cd038dSYoshinobu Inoue struct ifnet *ifp; 131882cd038dSYoshinobu Inoue { 131982cd038dSYoshinobu Inoue struct in6_drlist *drl = (struct in6_drlist *)data; 132082cd038dSYoshinobu Inoue struct in6_prlist *prl = (struct in6_prlist *)data; 132182cd038dSYoshinobu Inoue struct in6_ndireq *ndi = (struct in6_ndireq *)data; 132282cd038dSYoshinobu Inoue struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; 1323686cdd19SJun-ichiro itojun Hagino struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; 132482cd038dSYoshinobu Inoue struct nd_defrouter *dr, any; 132582cd038dSYoshinobu Inoue struct nd_prefix *pr; 132682cd038dSYoshinobu Inoue struct rtentry *rt; 132782cd038dSYoshinobu Inoue int i = 0, error = 0; 132882cd038dSYoshinobu Inoue int s; 132982cd038dSYoshinobu Inoue 133082cd038dSYoshinobu Inoue switch (cmd) { 133182cd038dSYoshinobu Inoue case SIOCGDRLST_IN6: 133282cd038dSYoshinobu Inoue bzero(drl, sizeof(*drl)); 133382cd038dSYoshinobu Inoue s = splnet(); 1334686cdd19SJun-ichiro itojun Hagino dr = TAILQ_FIRST(&nd_defrouter); 133582cd038dSYoshinobu Inoue while (dr && i < DRLSTSIZ) { 133682cd038dSYoshinobu Inoue drl->defrouter[i].rtaddr = dr->rtaddr; 133782cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { 133882cd038dSYoshinobu Inoue /* XXX: need to this hack for KAME stack */ 133982cd038dSYoshinobu Inoue drl->defrouter[i].rtaddr.s6_addr16[1] = 0; 134082cd038dSYoshinobu Inoue } else 134182cd038dSYoshinobu Inoue log(LOG_ERR, 134282cd038dSYoshinobu Inoue "default router list contains a " 134382cd038dSYoshinobu Inoue "non-linklocal address(%s)\n", 134482cd038dSYoshinobu Inoue ip6_sprintf(&drl->defrouter[i].rtaddr)); 134582cd038dSYoshinobu Inoue 134682cd038dSYoshinobu Inoue drl->defrouter[i].flags = dr->flags; 134782cd038dSYoshinobu Inoue drl->defrouter[i].rtlifetime = dr->rtlifetime; 134882cd038dSYoshinobu Inoue drl->defrouter[i].expire = dr->expire; 134982cd038dSYoshinobu Inoue drl->defrouter[i].if_index = dr->ifp->if_index; 135082cd038dSYoshinobu Inoue i++; 1351686cdd19SJun-ichiro itojun Hagino dr = TAILQ_NEXT(dr, dr_entry); 135282cd038dSYoshinobu Inoue } 135382cd038dSYoshinobu Inoue splx(s); 135482cd038dSYoshinobu Inoue break; 135582cd038dSYoshinobu Inoue case SIOCGPRLST_IN6: 1356686cdd19SJun-ichiro itojun Hagino /* 1357686cdd19SJun-ichiro itojun Hagino * XXX meaning of fields, especialy "raflags", is very 1358686cdd19SJun-ichiro itojun Hagino * differnet between RA prefix list and RR/static prefix list. 1359686cdd19SJun-ichiro itojun Hagino * how about separating ioctls into two? 1360686cdd19SJun-ichiro itojun Hagino */ 136182cd038dSYoshinobu Inoue bzero(prl, sizeof(*prl)); 136282cd038dSYoshinobu Inoue s = splnet(); 1363686cdd19SJun-ichiro itojun Hagino pr = nd_prefix.lh_first; 136482cd038dSYoshinobu Inoue while (pr && i < PRLSTSIZ) { 136582cd038dSYoshinobu Inoue struct nd_pfxrouter *pfr; 136682cd038dSYoshinobu Inoue int j; 136782cd038dSYoshinobu Inoue 136882cd038dSYoshinobu Inoue prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; 136982cd038dSYoshinobu Inoue prl->prefix[i].raflags = pr->ndpr_raf; 137082cd038dSYoshinobu Inoue prl->prefix[i].prefixlen = pr->ndpr_plen; 137182cd038dSYoshinobu Inoue prl->prefix[i].vltime = pr->ndpr_vltime; 137282cd038dSYoshinobu Inoue prl->prefix[i].pltime = pr->ndpr_pltime; 137382cd038dSYoshinobu Inoue prl->prefix[i].if_index = pr->ndpr_ifp->if_index; 137482cd038dSYoshinobu Inoue prl->prefix[i].expire = pr->ndpr_expire; 137582cd038dSYoshinobu Inoue 1376686cdd19SJun-ichiro itojun Hagino pfr = pr->ndpr_advrtrs.lh_first; 137782cd038dSYoshinobu Inoue j = 0; 137882cd038dSYoshinobu Inoue while(pfr) { 137982cd038dSYoshinobu Inoue if (j < DRLSTSIZ) { 138082cd038dSYoshinobu Inoue #define RTRADDR prl->prefix[i].advrtr[j] 138182cd038dSYoshinobu Inoue RTRADDR = pfr->router->rtaddr; 138282cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) { 138382cd038dSYoshinobu Inoue /* XXX: hack for KAME */ 138482cd038dSYoshinobu Inoue RTRADDR.s6_addr16[1] = 0; 138582cd038dSYoshinobu Inoue } else 138682cd038dSYoshinobu Inoue log(LOG_ERR, 138782cd038dSYoshinobu Inoue "a router(%s) advertises " 138882cd038dSYoshinobu Inoue "a prefix with " 138982cd038dSYoshinobu Inoue "non-link local address\n", 139082cd038dSYoshinobu Inoue ip6_sprintf(&RTRADDR)); 139182cd038dSYoshinobu Inoue #undef RTRADDR 139282cd038dSYoshinobu Inoue } 139382cd038dSYoshinobu Inoue j++; 1394686cdd19SJun-ichiro itojun Hagino pfr = pfr->pfr_next; 139582cd038dSYoshinobu Inoue } 139682cd038dSYoshinobu Inoue prl->prefix[i].advrtrs = j; 1397686cdd19SJun-ichiro itojun Hagino prl->prefix[i].origin = PR_ORIG_RA; 139882cd038dSYoshinobu Inoue 139982cd038dSYoshinobu Inoue i++; 1400686cdd19SJun-ichiro itojun Hagino pr = pr->ndpr_next; 140182cd038dSYoshinobu Inoue } 140282cd038dSYoshinobu Inoue { 140382cd038dSYoshinobu Inoue struct rr_prefix *rpp; 140482cd038dSYoshinobu Inoue 140582cd038dSYoshinobu Inoue for (rpp = LIST_FIRST(&rr_prefix); rpp; 140682cd038dSYoshinobu Inoue rpp = LIST_NEXT(rpp, rp_entry)) { 140782cd038dSYoshinobu Inoue if (i >= PRLSTSIZ) 140882cd038dSYoshinobu Inoue break; 140982cd038dSYoshinobu Inoue prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; 141082cd038dSYoshinobu Inoue prl->prefix[i].raflags = rpp->rp_raf; 141182cd038dSYoshinobu Inoue prl->prefix[i].prefixlen = rpp->rp_plen; 141282cd038dSYoshinobu Inoue prl->prefix[i].vltime = rpp->rp_vltime; 141382cd038dSYoshinobu Inoue prl->prefix[i].pltime = rpp->rp_pltime; 141482cd038dSYoshinobu Inoue prl->prefix[i].if_index = rpp->rp_ifp->if_index; 141582cd038dSYoshinobu Inoue prl->prefix[i].expire = rpp->rp_expire; 141682cd038dSYoshinobu Inoue prl->prefix[i].advrtrs = 0; 1417686cdd19SJun-ichiro itojun Hagino prl->prefix[i].origin = rpp->rp_origin; 141882cd038dSYoshinobu Inoue i++; 141982cd038dSYoshinobu Inoue } 142082cd038dSYoshinobu Inoue } 1421686cdd19SJun-ichiro itojun Hagino splx(s); 142282cd038dSYoshinobu Inoue 142382cd038dSYoshinobu Inoue break; 142482cd038dSYoshinobu Inoue case SIOCGIFINFO_IN6: 1425686cdd19SJun-ichiro itojun Hagino if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { 1426686cdd19SJun-ichiro itojun Hagino error = EINVAL; 1427686cdd19SJun-ichiro itojun Hagino break; 1428686cdd19SJun-ichiro itojun Hagino } 142982cd038dSYoshinobu Inoue ndi->ndi = nd_ifinfo[ifp->if_index]; 143082cd038dSYoshinobu Inoue break; 1431686cdd19SJun-ichiro itojun Hagino case SIOCSIFINFO_FLAGS: 1432686cdd19SJun-ichiro itojun Hagino /* XXX: almost all other fields of ndi->ndi is unused */ 1433686cdd19SJun-ichiro itojun Hagino if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { 1434686cdd19SJun-ichiro itojun Hagino error = EINVAL; 1435686cdd19SJun-ichiro itojun Hagino break; 1436686cdd19SJun-ichiro itojun Hagino } 1437686cdd19SJun-ichiro itojun Hagino nd_ifinfo[ifp->if_index].flags = ndi->ndi.flags; 1438686cdd19SJun-ichiro itojun Hagino break; 1439686cdd19SJun-ichiro itojun Hagino case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ 144082cd038dSYoshinobu Inoue /* flush default router list */ 144182cd038dSYoshinobu Inoue /* 144282cd038dSYoshinobu Inoue * xxx sumikawa: should not delete route if default 144382cd038dSYoshinobu Inoue * route equals to the top of default router list 144482cd038dSYoshinobu Inoue */ 144582cd038dSYoshinobu Inoue bzero(&any, sizeof(any)); 144682cd038dSYoshinobu Inoue defrouter_delreq(&any, 0); 1447686cdd19SJun-ichiro itojun Hagino defrouter_select(); 144882cd038dSYoshinobu Inoue /* xxx sumikawa: flush prefix list */ 144982cd038dSYoshinobu Inoue break; 145082cd038dSYoshinobu Inoue case SIOCSPFXFLUSH_IN6: 145182cd038dSYoshinobu Inoue { 145282cd038dSYoshinobu Inoue /* flush all the prefix advertised by routers */ 145382cd038dSYoshinobu Inoue struct nd_prefix *pr, *next; 145482cd038dSYoshinobu Inoue 145582cd038dSYoshinobu Inoue s = splnet(); 1456686cdd19SJun-ichiro itojun Hagino for (pr = nd_prefix.lh_first; pr; pr = next) { 1457686cdd19SJun-ichiro itojun Hagino next = pr->ndpr_next; 145882cd038dSYoshinobu Inoue if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 145982cd038dSYoshinobu Inoue in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 146082cd038dSYoshinobu Inoue prelist_remove(pr); 146182cd038dSYoshinobu Inoue } 146282cd038dSYoshinobu Inoue splx(s); 146382cd038dSYoshinobu Inoue break; 146482cd038dSYoshinobu Inoue } 146582cd038dSYoshinobu Inoue case SIOCSRTRFLUSH_IN6: 146682cd038dSYoshinobu Inoue { 146782cd038dSYoshinobu Inoue /* flush all the default routers */ 146882cd038dSYoshinobu Inoue struct nd_defrouter *dr, *next; 146982cd038dSYoshinobu Inoue 147082cd038dSYoshinobu Inoue s = splnet(); 1471686cdd19SJun-ichiro itojun Hagino if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { 147282cd038dSYoshinobu Inoue /* 147382cd038dSYoshinobu Inoue * The first entry of the list may be stored in 147482cd038dSYoshinobu Inoue * the routing table, so we'll delete it later. 147582cd038dSYoshinobu Inoue */ 1476686cdd19SJun-ichiro itojun Hagino for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = next) { 1477686cdd19SJun-ichiro itojun Hagino next = TAILQ_NEXT(dr, dr_entry); 147882cd038dSYoshinobu Inoue defrtrlist_del(dr); 147982cd038dSYoshinobu Inoue } 1480686cdd19SJun-ichiro itojun Hagino defrtrlist_del(TAILQ_FIRST(&nd_defrouter)); 148182cd038dSYoshinobu Inoue } 148282cd038dSYoshinobu Inoue splx(s); 148382cd038dSYoshinobu Inoue break; 148482cd038dSYoshinobu Inoue } 148582cd038dSYoshinobu Inoue case SIOCGNBRINFO_IN6: 148682cd038dSYoshinobu Inoue { 148782cd038dSYoshinobu Inoue struct llinfo_nd6 *ln; 148882cd038dSYoshinobu Inoue struct in6_addr nb_addr = nbi->addr; /* make local for safety */ 148982cd038dSYoshinobu Inoue 149082cd038dSYoshinobu Inoue /* 149182cd038dSYoshinobu Inoue * XXX: KAME specific hack for scoped addresses 149282cd038dSYoshinobu Inoue * XXXX: for other scopes than link-local? 149382cd038dSYoshinobu Inoue */ 149482cd038dSYoshinobu Inoue if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) || 149582cd038dSYoshinobu Inoue IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) { 149682cd038dSYoshinobu Inoue u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2]; 149782cd038dSYoshinobu Inoue 149882cd038dSYoshinobu Inoue if (*idp == 0) 149982cd038dSYoshinobu Inoue *idp = htons(ifp->if_index); 150082cd038dSYoshinobu Inoue } 150182cd038dSYoshinobu Inoue 150282cd038dSYoshinobu Inoue s = splnet(); 150382cd038dSYoshinobu Inoue if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { 150482cd038dSYoshinobu Inoue error = EINVAL; 1505686cdd19SJun-ichiro itojun Hagino splx(s); 150682cd038dSYoshinobu Inoue break; 150782cd038dSYoshinobu Inoue } 150882cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 150982cd038dSYoshinobu Inoue nbi->state = ln->ln_state; 151082cd038dSYoshinobu Inoue nbi->asked = ln->ln_asked; 151182cd038dSYoshinobu Inoue nbi->isrouter = ln->ln_router; 151282cd038dSYoshinobu Inoue nbi->expire = ln->ln_expire; 151382cd038dSYoshinobu Inoue splx(s); 151482cd038dSYoshinobu Inoue 151582cd038dSYoshinobu Inoue break; 151682cd038dSYoshinobu Inoue } 1517686cdd19SJun-ichiro itojun Hagino case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ 1518686cdd19SJun-ichiro itojun Hagino ndif->ifindex = nd6_defifindex; 1519686cdd19SJun-ichiro itojun Hagino break; 1520686cdd19SJun-ichiro itojun Hagino case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ 1521686cdd19SJun-ichiro itojun Hagino return(nd6_setdefaultiface(ndif->ifindex)); 1522686cdd19SJun-ichiro itojun Hagino break; 152382cd038dSYoshinobu Inoue } 152482cd038dSYoshinobu Inoue return(error); 152582cd038dSYoshinobu Inoue } 152682cd038dSYoshinobu Inoue 152782cd038dSYoshinobu Inoue /* 152882cd038dSYoshinobu Inoue * Create neighbor cache entry and cache link-layer address, 152982cd038dSYoshinobu Inoue * on reception of inbound ND6 packets. (RS/RA/NS/redirect) 153082cd038dSYoshinobu Inoue */ 153182cd038dSYoshinobu Inoue struct rtentry * 153282cd038dSYoshinobu Inoue nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) 153382cd038dSYoshinobu Inoue struct ifnet *ifp; 153482cd038dSYoshinobu Inoue struct in6_addr *from; 153582cd038dSYoshinobu Inoue char *lladdr; 153682cd038dSYoshinobu Inoue int lladdrlen; 153782cd038dSYoshinobu Inoue int type; /* ICMP6 type */ 153882cd038dSYoshinobu Inoue int code; /* type dependent information */ 153982cd038dSYoshinobu Inoue { 154082cd038dSYoshinobu Inoue struct rtentry *rt = NULL; 154182cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = NULL; 154282cd038dSYoshinobu Inoue int is_newentry; 154382cd038dSYoshinobu Inoue struct sockaddr_dl *sdl = NULL; 154482cd038dSYoshinobu Inoue int do_update; 154582cd038dSYoshinobu Inoue int olladdr; 154682cd038dSYoshinobu Inoue int llchange; 154782cd038dSYoshinobu Inoue int newstate = 0; 154882cd038dSYoshinobu Inoue 154982cd038dSYoshinobu Inoue if (!ifp) 155082cd038dSYoshinobu Inoue panic("ifp == NULL in nd6_cache_lladdr"); 155182cd038dSYoshinobu Inoue if (!from) 155282cd038dSYoshinobu Inoue panic("from == NULL in nd6_cache_lladdr"); 155382cd038dSYoshinobu Inoue 155482cd038dSYoshinobu Inoue /* nothing must be updated for unspecified address */ 155582cd038dSYoshinobu Inoue if (IN6_IS_ADDR_UNSPECIFIED(from)) 155682cd038dSYoshinobu Inoue return NULL; 155782cd038dSYoshinobu Inoue 155882cd038dSYoshinobu Inoue /* 155982cd038dSYoshinobu Inoue * Validation about ifp->if_addrlen and lladdrlen must be done in 156082cd038dSYoshinobu Inoue * the caller. 156182cd038dSYoshinobu Inoue * 156282cd038dSYoshinobu Inoue * XXX If the link does not have link-layer adderss, what should 156382cd038dSYoshinobu Inoue * we do? (ifp->if_addrlen == 0) 156482cd038dSYoshinobu Inoue * Spec says nothing in sections for RA, RS and NA. There's small 156582cd038dSYoshinobu Inoue * description on it in NS section (RFC 2461 7.2.3). 156682cd038dSYoshinobu Inoue */ 156782cd038dSYoshinobu Inoue 156882cd038dSYoshinobu Inoue rt = nd6_lookup(from, 0, ifp); 156982cd038dSYoshinobu Inoue if (!rt) { 1570686cdd19SJun-ichiro itojun Hagino #if 0 1571686cdd19SJun-ichiro itojun Hagino /* nothing must be done if there's no lladdr */ 1572686cdd19SJun-ichiro itojun Hagino if (!lladdr || !lladdrlen) 1573686cdd19SJun-ichiro itojun Hagino return NULL; 1574686cdd19SJun-ichiro itojun Hagino #endif 1575686cdd19SJun-ichiro itojun Hagino 157682cd038dSYoshinobu Inoue rt = nd6_lookup(from, 1, ifp); 157782cd038dSYoshinobu Inoue is_newentry = 1; 157882cd038dSYoshinobu Inoue } else 157982cd038dSYoshinobu Inoue is_newentry = 0; 158082cd038dSYoshinobu Inoue 158182cd038dSYoshinobu Inoue if (!rt) 158282cd038dSYoshinobu Inoue return NULL; 158382cd038dSYoshinobu Inoue if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { 158482cd038dSYoshinobu Inoue fail: 158582cd038dSYoshinobu Inoue nd6_free(rt); 158682cd038dSYoshinobu Inoue return NULL; 158782cd038dSYoshinobu Inoue } 158882cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 158982cd038dSYoshinobu Inoue if (!ln) 159082cd038dSYoshinobu Inoue goto fail; 159182cd038dSYoshinobu Inoue if (!rt->rt_gateway) 159282cd038dSYoshinobu Inoue goto fail; 159382cd038dSYoshinobu Inoue if (rt->rt_gateway->sa_family != AF_LINK) 159482cd038dSYoshinobu Inoue goto fail; 159582cd038dSYoshinobu Inoue sdl = SDL(rt->rt_gateway); 159682cd038dSYoshinobu Inoue 159782cd038dSYoshinobu Inoue olladdr = (sdl->sdl_alen) ? 1 : 0; 159882cd038dSYoshinobu Inoue if (olladdr && lladdr) { 159982cd038dSYoshinobu Inoue if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen)) 160082cd038dSYoshinobu Inoue llchange = 1; 160182cd038dSYoshinobu Inoue else 160282cd038dSYoshinobu Inoue llchange = 0; 160382cd038dSYoshinobu Inoue } else 160482cd038dSYoshinobu Inoue llchange = 0; 160582cd038dSYoshinobu Inoue 160682cd038dSYoshinobu Inoue /* 160782cd038dSYoshinobu Inoue * newentry olladdr lladdr llchange (*=record) 160882cd038dSYoshinobu Inoue * 0 n n -- (1) 160982cd038dSYoshinobu Inoue * 0 y n -- (2) 161082cd038dSYoshinobu Inoue * 0 n y -- (3) * STALE 161182cd038dSYoshinobu Inoue * 0 y y n (4) * 161282cd038dSYoshinobu Inoue * 0 y y y (5) * STALE 161382cd038dSYoshinobu Inoue * 1 -- n -- (6) NOSTATE(= PASSIVE) 161482cd038dSYoshinobu Inoue * 1 -- y -- (7) * STALE 161582cd038dSYoshinobu Inoue */ 161682cd038dSYoshinobu Inoue 161782cd038dSYoshinobu Inoue if (lladdr) { /*(3-5) and (7)*/ 161882cd038dSYoshinobu Inoue /* 161982cd038dSYoshinobu Inoue * Record source link-layer address 162082cd038dSYoshinobu Inoue * XXX is it dependent to ifp->if_type? 162182cd038dSYoshinobu Inoue */ 162282cd038dSYoshinobu Inoue sdl->sdl_alen = ifp->if_addrlen; 162382cd038dSYoshinobu Inoue bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); 162482cd038dSYoshinobu Inoue } 162582cd038dSYoshinobu Inoue 162682cd038dSYoshinobu Inoue if (!is_newentry) { 162782cd038dSYoshinobu Inoue if ((!olladdr && lladdr) /*(3)*/ 162882cd038dSYoshinobu Inoue || (olladdr && lladdr && llchange)) { /*(5)*/ 162982cd038dSYoshinobu Inoue do_update = 1; 163082cd038dSYoshinobu Inoue newstate = ND6_LLINFO_STALE; 163182cd038dSYoshinobu Inoue } else /*(1-2,4)*/ 163282cd038dSYoshinobu Inoue do_update = 0; 163382cd038dSYoshinobu Inoue } else { 163482cd038dSYoshinobu Inoue do_update = 1; 163582cd038dSYoshinobu Inoue if (!lladdr) /*(6)*/ 163682cd038dSYoshinobu Inoue newstate = ND6_LLINFO_NOSTATE; 163782cd038dSYoshinobu Inoue else /*(7)*/ 163882cd038dSYoshinobu Inoue newstate = ND6_LLINFO_STALE; 163982cd038dSYoshinobu Inoue } 164082cd038dSYoshinobu Inoue 164182cd038dSYoshinobu Inoue if (do_update) { 164282cd038dSYoshinobu Inoue /* 164382cd038dSYoshinobu Inoue * Update the state of the neighbor cache. 164482cd038dSYoshinobu Inoue */ 164582cd038dSYoshinobu Inoue ln->ln_state = newstate; 164682cd038dSYoshinobu Inoue 164782cd038dSYoshinobu Inoue if (ln->ln_state == ND6_LLINFO_STALE) { 164882cd038dSYoshinobu Inoue rt->rt_flags &= ~RTF_REJECT; 164982cd038dSYoshinobu Inoue if (ln->ln_hold) { 1650686cdd19SJun-ichiro itojun Hagino #ifdef OLDIP6OUTPUT 1651686cdd19SJun-ichiro itojun Hagino (*ifp->if_output)(ifp, ln->ln_hold, 1652686cdd19SJun-ichiro itojun Hagino rt_key(rt), rt); 1653686cdd19SJun-ichiro itojun Hagino #else 1654686cdd19SJun-ichiro itojun Hagino /* 1655686cdd19SJun-ichiro itojun Hagino * we assume ifp is not a p2p here, so just 1656686cdd19SJun-ichiro itojun Hagino * set the 2nd argument as the 1st one. 1657686cdd19SJun-ichiro itojun Hagino */ 1658686cdd19SJun-ichiro itojun Hagino nd6_output(ifp, ifp, ln->ln_hold, 165982cd038dSYoshinobu Inoue (struct sockaddr_in6 *)rt_key(rt), 166082cd038dSYoshinobu Inoue rt); 1661686cdd19SJun-ichiro itojun Hagino #endif 166282cd038dSYoshinobu Inoue ln->ln_hold = 0; 166382cd038dSYoshinobu Inoue } 166482cd038dSYoshinobu Inoue } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { 166582cd038dSYoshinobu Inoue /* probe right away */ 166682cd038dSYoshinobu Inoue ln->ln_expire = time_second; 166782cd038dSYoshinobu Inoue } 166882cd038dSYoshinobu Inoue } 166982cd038dSYoshinobu Inoue 167082cd038dSYoshinobu Inoue /* 167182cd038dSYoshinobu Inoue * ICMP6 type dependent behavior. 167282cd038dSYoshinobu Inoue * 167382cd038dSYoshinobu Inoue * NS: clear IsRouter if new entry 167482cd038dSYoshinobu Inoue * RS: clear IsRouter 167582cd038dSYoshinobu Inoue * RA: set IsRouter if there's lladdr 167682cd038dSYoshinobu Inoue * redir: clear IsRouter if new entry 167782cd038dSYoshinobu Inoue * 167882cd038dSYoshinobu Inoue * RA case, (1): 167982cd038dSYoshinobu Inoue * The spec says that we must set IsRouter in the following cases: 168082cd038dSYoshinobu Inoue * - If lladdr exist, set IsRouter. This means (1-5). 168182cd038dSYoshinobu Inoue * - If it is old entry (!newentry), set IsRouter. This means (7). 168282cd038dSYoshinobu Inoue * So, based on the spec, in (1-5) and (7) cases we must set IsRouter. 168382cd038dSYoshinobu Inoue * A quetion arises for (1) case. (1) case has no lladdr in the 168482cd038dSYoshinobu Inoue * neighbor cache, this is similar to (6). 168582cd038dSYoshinobu Inoue * This case is rare but we figured that we MUST NOT set IsRouter. 168682cd038dSYoshinobu Inoue * 168782cd038dSYoshinobu Inoue * newentry olladdr lladdr llchange NS RS RA redir 168882cd038dSYoshinobu Inoue * D R 168982cd038dSYoshinobu Inoue * 0 n n -- (1) c ? s 169082cd038dSYoshinobu Inoue * 0 y n -- (2) c s s 169182cd038dSYoshinobu Inoue * 0 n y -- (3) c s s 169282cd038dSYoshinobu Inoue * 0 y y n (4) c s s 169382cd038dSYoshinobu Inoue * 0 y y y (5) c s s 169482cd038dSYoshinobu Inoue * 1 -- n -- (6) c c c s 169582cd038dSYoshinobu Inoue * 1 -- y -- (7) c c s c s 169682cd038dSYoshinobu Inoue * 169782cd038dSYoshinobu Inoue * (c=clear s=set) 169882cd038dSYoshinobu Inoue */ 169982cd038dSYoshinobu Inoue switch (type & 0xff) { 170082cd038dSYoshinobu Inoue case ND_NEIGHBOR_SOLICIT: 170182cd038dSYoshinobu Inoue /* 170282cd038dSYoshinobu Inoue * New entry must have is_router flag cleared. 170382cd038dSYoshinobu Inoue */ 170482cd038dSYoshinobu Inoue if (is_newentry) /*(6-7)*/ 170582cd038dSYoshinobu Inoue ln->ln_router = 0; 170682cd038dSYoshinobu Inoue break; 170782cd038dSYoshinobu Inoue case ND_REDIRECT: 170882cd038dSYoshinobu Inoue /* 170982cd038dSYoshinobu Inoue * If the icmp is a redirect to a better router, always set the 171082cd038dSYoshinobu Inoue * is_router flag. Otherwise, if the entry is newly created, 171182cd038dSYoshinobu Inoue * clear the flag. [RFC 2461, sec 8.3] 171282cd038dSYoshinobu Inoue */ 171382cd038dSYoshinobu Inoue if (code == ND_REDIRECT_ROUTER) 171482cd038dSYoshinobu Inoue ln->ln_router = 1; 171582cd038dSYoshinobu Inoue else if (is_newentry) /*(6-7)*/ 171682cd038dSYoshinobu Inoue ln->ln_router = 0; 171782cd038dSYoshinobu Inoue break; 171882cd038dSYoshinobu Inoue case ND_ROUTER_SOLICIT: 171982cd038dSYoshinobu Inoue /* 172082cd038dSYoshinobu Inoue * is_router flag must always be cleared. 172182cd038dSYoshinobu Inoue */ 172282cd038dSYoshinobu Inoue ln->ln_router = 0; 172382cd038dSYoshinobu Inoue break; 172482cd038dSYoshinobu Inoue case ND_ROUTER_ADVERT: 172582cd038dSYoshinobu Inoue /* 172682cd038dSYoshinobu Inoue * Mark an entry with lladdr as a router. 172782cd038dSYoshinobu Inoue */ 172882cd038dSYoshinobu Inoue if ((!is_newentry && (olladdr || lladdr)) /*(2-5)*/ 172982cd038dSYoshinobu Inoue || (is_newentry && lladdr)) { /*(7)*/ 173082cd038dSYoshinobu Inoue ln->ln_router = 1; 173182cd038dSYoshinobu Inoue } 173282cd038dSYoshinobu Inoue break; 173382cd038dSYoshinobu Inoue } 173482cd038dSYoshinobu Inoue 173582cd038dSYoshinobu Inoue return rt; 173682cd038dSYoshinobu Inoue } 173782cd038dSYoshinobu Inoue 173882cd038dSYoshinobu Inoue static void 173982cd038dSYoshinobu Inoue nd6_slowtimo(ignored_arg) 174082cd038dSYoshinobu Inoue void *ignored_arg; 174182cd038dSYoshinobu Inoue { 174282cd038dSYoshinobu Inoue int s = splnet(); 174382cd038dSYoshinobu Inoue register int i; 174482cd038dSYoshinobu Inoue register struct nd_ifinfo *nd6if; 174582cd038dSYoshinobu Inoue 174682cd038dSYoshinobu Inoue timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); 174782cd038dSYoshinobu Inoue for (i = 1; i < if_index + 1; i++) { 1748686cdd19SJun-ichiro itojun Hagino if (!nd_ifinfo || i >= nd_ifinfo_indexlim) 1749686cdd19SJun-ichiro itojun Hagino continue; 175082cd038dSYoshinobu Inoue nd6if = &nd_ifinfo[i]; 175182cd038dSYoshinobu Inoue if (nd6if->basereachable && /* already initialized */ 175282cd038dSYoshinobu Inoue (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { 175382cd038dSYoshinobu Inoue /* 175482cd038dSYoshinobu Inoue * Since reachable time rarely changes by router 175582cd038dSYoshinobu Inoue * advertisements, we SHOULD insure that a new random 175682cd038dSYoshinobu Inoue * value gets recomputed at least once every few hours. 175782cd038dSYoshinobu Inoue * (RFC 2461, 6.3.4) 175882cd038dSYoshinobu Inoue */ 175982cd038dSYoshinobu Inoue nd6if->recalctm = nd6_recalc_reachtm_interval; 176082cd038dSYoshinobu Inoue nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable); 176182cd038dSYoshinobu Inoue } 176282cd038dSYoshinobu Inoue } 176382cd038dSYoshinobu Inoue splx(s); 176482cd038dSYoshinobu Inoue } 176582cd038dSYoshinobu Inoue 176682cd038dSYoshinobu Inoue #define senderr(e) { error = (e); goto bad;} 176782cd038dSYoshinobu Inoue int 1768686cdd19SJun-ichiro itojun Hagino nd6_output(ifp, origifp, m0, dst, rt0) 176982cd038dSYoshinobu Inoue register struct ifnet *ifp; 1770686cdd19SJun-ichiro itojun Hagino struct ifnet *origifp; 177182cd038dSYoshinobu Inoue struct mbuf *m0; 177282cd038dSYoshinobu Inoue struct sockaddr_in6 *dst; 177382cd038dSYoshinobu Inoue struct rtentry *rt0; 177482cd038dSYoshinobu Inoue { 177582cd038dSYoshinobu Inoue register struct mbuf *m = m0; 177682cd038dSYoshinobu Inoue register struct rtentry *rt = rt0; 1777686cdd19SJun-ichiro itojun Hagino struct sockaddr_in6 *gw6 = NULL; 177882cd038dSYoshinobu Inoue struct llinfo_nd6 *ln = NULL; 177982cd038dSYoshinobu Inoue int error = 0; 178082cd038dSYoshinobu Inoue 178182cd038dSYoshinobu Inoue if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) 178282cd038dSYoshinobu Inoue goto sendpkt; 178382cd038dSYoshinobu Inoue 178482cd038dSYoshinobu Inoue /* 178582cd038dSYoshinobu Inoue * XXX: we currently do not make neighbor cache on any interface 1786686cdd19SJun-ichiro itojun Hagino * other than ARCnet, Ethernet, FDDI and GIF. 1787686cdd19SJun-ichiro itojun Hagino * 1788686cdd19SJun-ichiro itojun Hagino * draft-ietf-ngtrans-mech-06.txt says: 1789686cdd19SJun-ichiro itojun Hagino * - unidirectional tunnels needs no ND 179082cd038dSYoshinobu Inoue */ 179182cd038dSYoshinobu Inoue switch (ifp->if_type) { 179282cd038dSYoshinobu Inoue case IFT_ARCNET: 179382cd038dSYoshinobu Inoue case IFT_ETHER: 179482cd038dSYoshinobu Inoue case IFT_FDDI: 1795686cdd19SJun-ichiro itojun Hagino case IFT_GIF: /* XXX need more cases? */ 179682cd038dSYoshinobu Inoue break; 179782cd038dSYoshinobu Inoue default: 179882cd038dSYoshinobu Inoue goto sendpkt; 179982cd038dSYoshinobu Inoue } 180082cd038dSYoshinobu Inoue 180182cd038dSYoshinobu Inoue /* 180282cd038dSYoshinobu Inoue * next hop determination. This routine is derived from ether_outpout. 180382cd038dSYoshinobu Inoue */ 180482cd038dSYoshinobu Inoue if (rt) { 180582cd038dSYoshinobu Inoue if ((rt->rt_flags & RTF_UP) == 0) { 180682cd038dSYoshinobu Inoue if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1, 0UL)) != 180782cd038dSYoshinobu Inoue NULL) 180882cd038dSYoshinobu Inoue { 180982cd038dSYoshinobu Inoue rt->rt_refcnt--; 1810686cdd19SJun-ichiro itojun Hagino if (rt->rt_ifp != ifp) { 1811686cdd19SJun-ichiro itojun Hagino /* XXX: loop care? */ 1812686cdd19SJun-ichiro itojun Hagino return nd6_output(ifp, origifp, m0, 1813686cdd19SJun-ichiro itojun Hagino dst, rt); 1814686cdd19SJun-ichiro itojun Hagino } 181582cd038dSYoshinobu Inoue } else 181682cd038dSYoshinobu Inoue senderr(EHOSTUNREACH); 181782cd038dSYoshinobu Inoue } 1818686cdd19SJun-ichiro itojun Hagino 181982cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_GATEWAY) { 1820686cdd19SJun-ichiro itojun Hagino gw6 = (struct sockaddr_in6 *)rt->rt_gateway; 1821686cdd19SJun-ichiro itojun Hagino 1822686cdd19SJun-ichiro itojun Hagino /* 1823686cdd19SJun-ichiro itojun Hagino * We skip link-layer address resolution and NUD 1824686cdd19SJun-ichiro itojun Hagino * if the gateway is not a neighbor from ND point 1825686cdd19SJun-ichiro itojun Hagino * of view, regardless the value of the value of 1826686cdd19SJun-ichiro itojun Hagino * nd_ifinfo.flags. 1827686cdd19SJun-ichiro itojun Hagino * The second condition is a bit tricky: we skip 1828686cdd19SJun-ichiro itojun Hagino * if the gateway is our own address, which is 1829686cdd19SJun-ichiro itojun Hagino * sometimes used to install a route to a p2p link. 1830686cdd19SJun-ichiro itojun Hagino */ 1831686cdd19SJun-ichiro itojun Hagino if (!nd6_is_addr_neighbor(gw6, ifp) || 1832686cdd19SJun-ichiro itojun Hagino in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { 1833686cdd19SJun-ichiro itojun Hagino if (rt->rt_flags & RTF_REJECT) 1834686cdd19SJun-ichiro itojun Hagino senderr(EHOSTDOWN); 1835686cdd19SJun-ichiro itojun Hagino 1836686cdd19SJun-ichiro itojun Hagino /* 1837686cdd19SJun-ichiro itojun Hagino * We allow this kind of tricky route only 1838686cdd19SJun-ichiro itojun Hagino * when the outgoing interface is p2p. 1839686cdd19SJun-ichiro itojun Hagino * XXX: we may need a more generic rule here. 1840686cdd19SJun-ichiro itojun Hagino */ 1841686cdd19SJun-ichiro itojun Hagino if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 1842686cdd19SJun-ichiro itojun Hagino senderr(EHOSTUNREACH); 1843686cdd19SJun-ichiro itojun Hagino 1844686cdd19SJun-ichiro itojun Hagino goto sendpkt; 1845686cdd19SJun-ichiro itojun Hagino } 1846686cdd19SJun-ichiro itojun Hagino 184782cd038dSYoshinobu Inoue if (rt->rt_gwroute == 0) 184882cd038dSYoshinobu Inoue goto lookup; 184982cd038dSYoshinobu Inoue if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 185082cd038dSYoshinobu Inoue rtfree(rt); rt = rt0; 185182cd038dSYoshinobu Inoue lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); 185282cd038dSYoshinobu Inoue if ((rt = rt->rt_gwroute) == 0) 185382cd038dSYoshinobu Inoue senderr(EHOSTUNREACH); 185482cd038dSYoshinobu Inoue } 185582cd038dSYoshinobu Inoue } 185682cd038dSYoshinobu Inoue if (rt->rt_flags & RTF_REJECT) 185782cd038dSYoshinobu Inoue senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 185882cd038dSYoshinobu Inoue } 185982cd038dSYoshinobu Inoue 186082cd038dSYoshinobu Inoue /* 186182cd038dSYoshinobu Inoue * Address resolution or Neighbor Unreachability Detection 186282cd038dSYoshinobu Inoue * for the next hop. 186382cd038dSYoshinobu Inoue * At this point, the destination of the packet must be a unicast 186482cd038dSYoshinobu Inoue * or an anycast address(i.e. not a multicast). 186582cd038dSYoshinobu Inoue */ 186682cd038dSYoshinobu Inoue 186782cd038dSYoshinobu Inoue /* Look up the neighbor cache for the nexthop */ 186882cd038dSYoshinobu Inoue if (rt && (rt->rt_flags & RTF_LLINFO) != 0) 186982cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 187082cd038dSYoshinobu Inoue else { 1871686cdd19SJun-ichiro itojun Hagino /* 1872686cdd19SJun-ichiro itojun Hagino * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), 1873686cdd19SJun-ichiro itojun Hagino * the condition below is not very efficient. But we believe 1874686cdd19SJun-ichiro itojun Hagino * it is tolerable, because this should be a rare case. 1875686cdd19SJun-ichiro itojun Hagino */ 1876686cdd19SJun-ichiro itojun Hagino if (nd6_is_addr_neighbor(dst, ifp) && 1877686cdd19SJun-ichiro itojun Hagino (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) 187882cd038dSYoshinobu Inoue ln = (struct llinfo_nd6 *)rt->rt_llinfo; 187982cd038dSYoshinobu Inoue } 188082cd038dSYoshinobu Inoue if (!ln || !rt) { 1881686cdd19SJun-ichiro itojun Hagino if ((ifp->if_flags & IFF_POINTOPOINT) == 0 && 1882686cdd19SJun-ichiro itojun Hagino !(nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD)) { 1883686cdd19SJun-ichiro itojun Hagino log(LOG_DEBUG, 1884686cdd19SJun-ichiro itojun Hagino "nd6_output: can't allocate llinfo for %s " 188582cd038dSYoshinobu Inoue "(ln=%p, rt=%p)\n", 188682cd038dSYoshinobu Inoue ip6_sprintf(&dst->sin6_addr), ln, rt); 188782cd038dSYoshinobu Inoue senderr(EIO); /* XXX: good error? */ 188882cd038dSYoshinobu Inoue } 188982cd038dSYoshinobu Inoue 1890686cdd19SJun-ichiro itojun Hagino goto sendpkt; /* send anyway */ 1891686cdd19SJun-ichiro itojun Hagino } 1892686cdd19SJun-ichiro itojun Hagino 1893686cdd19SJun-ichiro itojun Hagino /* We don't have to do link-layer address resolution on a p2p link. */ 1894686cdd19SJun-ichiro itojun Hagino if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 1895686cdd19SJun-ichiro itojun Hagino ln->ln_state < ND6_LLINFO_REACHABLE) 1896686cdd19SJun-ichiro itojun Hagino ln->ln_state = ND6_LLINFO_STALE; 189782cd038dSYoshinobu Inoue 189882cd038dSYoshinobu Inoue /* 189982cd038dSYoshinobu Inoue * The first time we send a packet to a neighbor whose entry is 190082cd038dSYoshinobu Inoue * STALE, we have to change the state to DELAY and a sets a timer to 190182cd038dSYoshinobu Inoue * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do 190282cd038dSYoshinobu Inoue * neighbor unreachability detection on expiration. 190382cd038dSYoshinobu Inoue * (RFC 2461 7.3.3) 190482cd038dSYoshinobu Inoue */ 190582cd038dSYoshinobu Inoue if (ln->ln_state == ND6_LLINFO_STALE) { 190682cd038dSYoshinobu Inoue ln->ln_asked = 0; 190782cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_DELAY; 190882cd038dSYoshinobu Inoue ln->ln_expire = time_second + nd6_delay; 190982cd038dSYoshinobu Inoue } 191082cd038dSYoshinobu Inoue 191182cd038dSYoshinobu Inoue /* 191282cd038dSYoshinobu Inoue * If the neighbor cache entry has a state other than INCOMPLETE 191382cd038dSYoshinobu Inoue * (i.e. its link-layer address is already reloved), just 191482cd038dSYoshinobu Inoue * send the packet. 191582cd038dSYoshinobu Inoue */ 191682cd038dSYoshinobu Inoue if (ln->ln_state > ND6_LLINFO_INCOMPLETE) 191782cd038dSYoshinobu Inoue goto sendpkt; 191882cd038dSYoshinobu Inoue 191982cd038dSYoshinobu Inoue /* 192082cd038dSYoshinobu Inoue * There is a neighbor cache entry, but no ethernet address 192182cd038dSYoshinobu Inoue * response yet. Replace the held mbuf (if any) with this 192282cd038dSYoshinobu Inoue * latest one. 192382cd038dSYoshinobu Inoue * 192482cd038dSYoshinobu Inoue * XXX Does the code conform to rate-limiting rule? 192582cd038dSYoshinobu Inoue * (RFC 2461 7.2.2) 192682cd038dSYoshinobu Inoue */ 192782cd038dSYoshinobu Inoue if (ln->ln_state == ND6_LLINFO_WAITDELETE || 192882cd038dSYoshinobu Inoue ln->ln_state == ND6_LLINFO_NOSTATE) 192982cd038dSYoshinobu Inoue ln->ln_state = ND6_LLINFO_INCOMPLETE; 193082cd038dSYoshinobu Inoue if (ln->ln_hold) 193182cd038dSYoshinobu Inoue m_freem(ln->ln_hold); 193282cd038dSYoshinobu Inoue ln->ln_hold = m; 193382cd038dSYoshinobu Inoue if (ln->ln_expire) { 193482cd038dSYoshinobu Inoue rt->rt_flags &= ~RTF_REJECT; 193582cd038dSYoshinobu Inoue if (ln->ln_asked < nd6_mmaxtries && 193682cd038dSYoshinobu Inoue ln->ln_expire < time_second) { 193782cd038dSYoshinobu Inoue ln->ln_asked++; 193882cd038dSYoshinobu Inoue ln->ln_expire = time_second + 193982cd038dSYoshinobu Inoue nd_ifinfo[ifp->if_index].retrans / 1000; 194082cd038dSYoshinobu Inoue nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); 194182cd038dSYoshinobu Inoue } 194282cd038dSYoshinobu Inoue } 194382cd038dSYoshinobu Inoue return(0); 194482cd038dSYoshinobu Inoue 194582cd038dSYoshinobu Inoue sendpkt: 1946686cdd19SJun-ichiro itojun Hagino 1947686cdd19SJun-ichiro itojun Hagino #ifdef FAKE_LOOPBACK_IF 1948686cdd19SJun-ichiro itojun Hagino if (ifp->if_flags & IFF_LOOPBACK) { 1949686cdd19SJun-ichiro itojun Hagino return((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, 1950686cdd19SJun-ichiro itojun Hagino rt)); 1951686cdd19SJun-ichiro itojun Hagino } 1952686cdd19SJun-ichiro itojun Hagino #endif 195382cd038dSYoshinobu Inoue return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); 195482cd038dSYoshinobu Inoue 195582cd038dSYoshinobu Inoue bad: 195682cd038dSYoshinobu Inoue if (m) 195782cd038dSYoshinobu Inoue m_freem(m); 195882cd038dSYoshinobu Inoue return (error); 195982cd038dSYoshinobu Inoue } 196082cd038dSYoshinobu Inoue #undef senderr 196182cd038dSYoshinobu Inoue 196282cd038dSYoshinobu Inoue int 196382cd038dSYoshinobu Inoue nd6_storelladdr(ifp, rt, m, dst, desten) 196482cd038dSYoshinobu Inoue struct ifnet *ifp; 196582cd038dSYoshinobu Inoue struct rtentry *rt; 196682cd038dSYoshinobu Inoue struct mbuf *m; 196782cd038dSYoshinobu Inoue struct sockaddr *dst; 196882cd038dSYoshinobu Inoue u_char *desten; 196982cd038dSYoshinobu Inoue { 197082cd038dSYoshinobu Inoue struct sockaddr_dl *sdl; 197182cd038dSYoshinobu Inoue 197282cd038dSYoshinobu Inoue if (m->m_flags & M_MCAST) { 197382cd038dSYoshinobu Inoue switch (ifp->if_type) { 197482cd038dSYoshinobu Inoue case IFT_ETHER: 197582cd038dSYoshinobu Inoue case IFT_FDDI: 197682cd038dSYoshinobu Inoue ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, 197782cd038dSYoshinobu Inoue desten); 197882cd038dSYoshinobu Inoue return(1); 197982cd038dSYoshinobu Inoue break; 198082cd038dSYoshinobu Inoue case IFT_ARCNET: 198182cd038dSYoshinobu Inoue *desten = 0; 198282cd038dSYoshinobu Inoue return(1); 198382cd038dSYoshinobu Inoue default: 198482cd038dSYoshinobu Inoue return(0); 198582cd038dSYoshinobu Inoue } 198682cd038dSYoshinobu Inoue } 198782cd038dSYoshinobu Inoue 198882cd038dSYoshinobu Inoue if (rt == NULL || 198982cd038dSYoshinobu Inoue rt->rt_gateway->sa_family != AF_LINK) { 199082cd038dSYoshinobu Inoue printf("nd6_storelladdr: something odd happens\n"); 199182cd038dSYoshinobu Inoue return(0); 199282cd038dSYoshinobu Inoue } 199382cd038dSYoshinobu Inoue sdl = SDL(rt->rt_gateway); 1994686cdd19SJun-ichiro itojun Hagino if (sdl->sdl_alen == 0) { 1995686cdd19SJun-ichiro itojun Hagino /* this should be impossible, but we bark here for debugging */ 1996686cdd19SJun-ichiro itojun Hagino printf("nd6_storelladdr: sdl_alen == 0\n"); 1997686cdd19SJun-ichiro itojun Hagino return(0); 1998686cdd19SJun-ichiro itojun Hagino } 199982cd038dSYoshinobu Inoue 2000686cdd19SJun-ichiro itojun Hagino bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 200182cd038dSYoshinobu Inoue return(1); 200282cd038dSYoshinobu Inoue } 2003