📄 nd6.c
字号:
//==========================================================================//// src/sys/netinet6/nd6.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/* $KAME: nd6.c,v 1.221 2001/12/18 02:23:45 itojun Exp $ *//* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * XXX * KAME 970409 note: * BSD/OS version heavily modifies this code, related to llinfo. * Since we don't have BSD/OS version of net/route.c in our hand, * I left the code mostly as it was in 970310. -- itojun */#include <sys/param.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <sys/protosw.h>#include <sys/errno.h>#include <sys/queue.h>#include <sys/sysctl.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_types.h>#include <net/route.h>#include <netinet/in.h>#ifndef __NetBSD__#include <netinet/if_ether.h>#ifdef __bsdi__#include <net/if_fddi.h>#endif#ifdef __OpenBSD__#include <netinet/ip_ipsp.h>#endif#else /* __NetBSD__ */#include <net/if_ether.h>#include <netinet/if_inarp.h>#include <net/if_fddi.h>#endif /* __NetBSD__ */#include <netinet6/in6_var.h>#include <netinet/ip6.h>#include <netinet6/ip6_var.h>#include <netinet6/nd6.h>#include <netinet/icmp6.h>#if defined(__NetBSD__)extern struct ifnet loif[NLOOP];#endif#define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */#define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */#define SIN6(s) ((struct sockaddr_in6 *)s)#define SDL(s) ((struct sockaddr_dl *)s)/* timer values */int nd6_prune = 1; /* walk list every 1 seconds */int nd6_delay = 5; /* delay first probe time 5 second */int nd6_umaxtries = 3; /* maximum unicast query */int nd6_mmaxtries = 3; /* maximum multicast query */int nd6_useloopback = 1; /* use loopback interface for local traffic */int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer *//* preventing too many loops in ND option parsing */int nd6_maxndopt = 10; /* max # of ND options allowed */int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */int nd6_debug = 1;/* for debugging? */static int nd6_inuse, nd6_allocated;struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6};static size_t nd_ifinfo_indexlim = 8;struct nd_ifinfo *nd_ifinfo = NULL;struct nd_drhead nd_defrouter;struct nd_prhead nd_prefix = { 0 };int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL;static struct sockaddr_in6 all1_sa;static void nd6_slowtimo __P((void *));static int regen_tmpaddr __P((struct in6_ifaddr *));static struct llinfo_nd6 *nd6_free __P((struct rtentry *, int));#ifdef __NetBSD__struct callout nd6_slowtimo_ch = CALLOUT_INITIALIZER;struct callout nd6_timer_ch = CALLOUT_INITIALIZER;extern struct callout in6_tmpaddrtimer_ch;#elif (defined(__FreeBSD__) && __FreeBSD__ >= 3)struct callout nd6_slowtimo_ch;struct callout nd6_timer_ch;extern struct callout in6_tmpaddrtimer_ch;#elif defined(__OpenBSD__)struct timeout nd6_slowtimo_ch;struct timeout nd6_timer_ch;extern struct timeout in6_tmpaddrtimer_ch;#endifvoidnd6_init(){ static int nd6_init_done = 0; int i; if (nd6_init_done) { log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); return; } all1_sa.sin6_family = AF_INET6; all1_sa.sin6_len = sizeof(struct sockaddr_in6); for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) all1_sa.sin6_addr.s6_addr[i] = 0xff; /* initialization of the default router list */ TAILQ_INIT(&nd_defrouter); nd6_init_done = 1; /* start timer */#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3) callout_reset(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz, nd6_slowtimo, NULL);#elif defined(__OpenBSD__) timeout_set(&nd6_slowtimo_ch, nd6_slowtimo, NULL); timeout_add(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz);#else timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz);#endif}voidnd6_ifattach(ifp) struct ifnet *ifp;{ /* * We have some arrays that should be indexed by if_index. * since if_index will grow dynamically, they should grow too. */ if (nd_ifinfo == NULL || if_index >= nd_ifinfo_indexlim) { size_t n; caddr_t q; while (if_index >= nd_ifinfo_indexlim) nd_ifinfo_indexlim <<= 1; /* grow nd_ifinfo */ n = nd_ifinfo_indexlim * sizeof(struct nd_ifinfo); q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK); bzero(q, n); if (nd_ifinfo) { bcopy((caddr_t)nd_ifinfo, q, n/2); free((caddr_t)nd_ifinfo, M_IP6NDP); } nd_ifinfo = (struct nd_ifinfo *)q; }#define ND nd_ifinfo[ifp->if_index] /* * Don't initialize if called twice. * XXX: to detect this, we should choose a member that is never set * before initialization of the ND structure itself. We formaly used * the linkmtu member, which was not suitable because it could be * initialized via "ifconfig mtu". */ if (ND.basereachable) return;#ifdef DIAGNOSTIC#if defined(__FreeBSD__) && __FreeBSD__ >= 5 if (!ifnet_byindex(ifp->if_index)) panic("nd6_ifattach: ifnet_byindex is NULL");#else if (!ifindex2ifnet[ifp->if_index]) panic("nd6_ifattach: ifindex2ifnet is NULL");#endif#endif#if defined(__FreeBSD__) && __FreeBSD__ >= 5 ND.linkmtu = ifnet_byindex(ifp->if_index)->if_mtu;#else ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu;#endif ND.chlim = IPV6_DEFHLIM; ND.basereachable = REACHABLE_TIME; ND.reachable = ND_COMPUTE_RTIME(ND.basereachable); ND.retrans = RETRANS_TIMER; ND.receivedra = 0; /* * Note that the default value of ip6_accept_rtadv is 0, which means * we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV * here. */ ND.flags = ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV; nd6_setmtu(ifp);#undef ND}/* * Reset ND level link MTU. This function is called when the physical MTU * changes, which means we might have to adjust the ND level MTU. */voidnd6_setmtu(ifp) struct ifnet *ifp;{#ifndef MIN#define MIN(a,b) ((a) < (b) ? (a) : (b))#endif struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; u_long oldmaxmtu = ndi->maxmtu; u_long oldlinkmtu = ndi->linkmtu; switch (ifp->if_type) { case IFT_ARCNET: /* XXX MTU handling needs more work */ ndi->maxmtu = MIN(60480, ifp->if_mtu); break; case IFT_ETHER: ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); break;#if defined(__FreeBSD__) || defined(__bsdi__) case IFT_FDDI:#if 0 // FIXME#if defined(__bsdi__) && _BSDI_VERSION >= 199802 ndi->maxmtu = MIN(FDDIMTU, ifp->if_mtu);#else ndi->maxmtu = MIN(FDDIIPMTU, ifp->if_mtu);#endif#endif break;#endif#if !(defined(__bsdi__) && _BSDI_VERSION >= 199802) case IFT_ATM:#if 0 // FIXME ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu);#endif break;#endif case IFT_IEEE1394: /* XXX should be IEEE1394MTU(1500) */ ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); break;#ifdef IFT_IEEE80211 case IFT_IEEE80211: /* XXX should be IEEE80211MTU(1500) */ ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); break;#endif default: ndi->maxmtu = ifp->if_mtu; break; } if (oldmaxmtu != ndi->maxmtu) { /* * If the ND level MTU is not set yet, or if the maxmtu * is reset to a smaller value than the ND level MTU, * also reset the ND level MTU. */ if (ndi->linkmtu == 0 || ndi->maxmtu < ndi->linkmtu) { ndi->linkmtu = ndi->maxmtu; /* also adjust in6_maxmtu if necessary. */ if (oldlinkmtu == 0) { /* * XXX: the case analysis is grotty, but * it is not efficient to call in6_setmaxmtu() * here when we are during the initialization * procedure. */ if (in6_maxmtu < ndi->linkmtu) in6_maxmtu = ndi->linkmtu; } else in6_setmaxmtu(); } }#undef MIN}voidnd6_option_init(opt, icmp6len, ndopts) void *opt; int icmp6len; union nd_opts *ndopts;{ bzero(ndopts, sizeof(*ndopts)); ndopts->nd_opts_search = (struct nd_opt_hdr *)opt; ndopts->nd_opts_last = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len); if (icmp6len == 0) { ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; }}/* * Take one ND option. */struct nd_opt_hdr *nd6_option(ndopts) union nd_opts *ndopts;{ struct nd_opt_hdr *nd_opt; int olen; if (!ndopts) panic("ndopts == NULL in nd6_option\n"); if (!ndopts->nd_opts_last) panic("uninitialized ndopts in nd6_option\n"); if (!ndopts->nd_opts_search) return NULL; if (ndopts->nd_opts_done) return NULL; nd_opt = ndopts->nd_opts_search; /* make sure nd_opt_len is inside the buffer */ if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) { bzero(ndopts, sizeof(*ndopts)); return NULL; } olen = nd_opt->nd_opt_len << 3; if (olen == 0) { /* * Message validation requires that all included * options have a length that is greater than zero. */ bzero(ndopts, sizeof(*ndopts)); return NULL; } ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); if (ndopts->nd_opts_search > ndopts->nd_opts_last) { /* option overruns the end of buffer, invalid */ bzero(ndopts, sizeof(*ndopts)); return NULL; } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) { /* reached the end of options chain */ ndopts->nd_opts_done = 1; ndopts->nd_opts_search = NULL; } return nd_opt;}/* * Parse multiple ND options. * This function is much easier to use, for ND routines that do not need * multiple options of the same type. */intnd6_options(ndopts) union nd_opts *ndopts;{ struct nd_opt_hdr *nd_opt; int i = 0; if (!ndopts) panic("ndopts == NULL in nd6_options\n"); if (!ndopts->nd_opts_last) panic("uninitialized ndopts in nd6_options\n"); if (!ndopts->nd_opts_search) return 0; while (1) { nd_opt = nd6_option(ndopts); if (!nd_opt && !ndopts->nd_opts_last) { /* * Message validation requires that all included * options have a length that is greater than zero. */ icmp6stat.icp6s_nd_badopt++; bzero(ndopts, sizeof(*ndopts)); return -1; } if (!nd_opt) goto skip1; switch (nd_opt->nd_opt_type) { case ND_OPT_SOURCE_LINKADDR: case ND_OPT_TARGET_LINKADDR: case ND_OPT_MTU: case ND_OPT_REDIRECTED_HEADER: case ND_OPT_ADVINTERVAL: case ND_OPT_SOURCE_ADDRLIST: case ND_OPT_TARGET_ADDRLIST: if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { nd6log((LOG_INFO, "duplicated ND6 option found (type=%d)\n", nd_opt->nd_opt_type)); /* XXX bark? */ } else { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } break; case ND_OPT_PREFIX_INFORMATION: if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; } ndopts->nd_opts_pi_end = (struct nd_opt_prefix_info *)nd_opt; break; case ND_OPT_HOMEAGENT_INFO: break; default: /* * Unknown options must be silently ignored, * to accomodate future extension to the protocol. */ nd6log((LOG_DEBUG, "nd6_options: unsupported option %d - " "option ignored\n", nd_opt->nd_opt_type)); }skip1: i++; if (i > nd6_maxndopt) { icmp6stat.icp6s_nd_toomanyopt++; nd6log((LOG_INFO, "too many loop in nd opt\n")); break; } if (ndopts->nd_opts_done) break; } return 0;}/* * ND6 timer routine to expire default route list and prefix list */voidnd6_timer(ignored_arg) void *ignored_arg;{ int s; struct llinfo_nd6 *ln; struct nd_defrouter *dr; struct nd_prefix *pr;#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec;#endif struct ifnet *ifp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -