nd6_rtr.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,371 行 · 第 1/5 页
C
2,371 行
//==========================================================================//// src/sys/netinet6/nd6_rtr.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_rtr.c,v 1.187 2001/12/18 02:01:25 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. */#include <sys/param.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <sys/time.h>#include <sys/errno.h>#include <sys/queue.h>#ifdef __OpenBSD__#include <dev/rndvar.h>#endif#include <net/if.h>#include <net/if_types.h>#include <net/if_dl.h>#include <net/route.h>#include <net/radix.h>#include <netinet/in.h>#include <netinet6/in6_var.h>#include <netinet6/in6_ifattach.h>#include <netinet/ip6.h>#include <netinet6/ip6_var.h>#include <netinet6/nd6.h>#include <netinet/icmp6.h>#include <netinet6/scope6_var.h>#ifdef MIP6#include <netinet6/mip6.h>#endif /* MIP6 */#define SDL(s) ((struct sockaddr_dl *)s)static int rtpref __P((struct nd_defrouter *));static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));static struct in6_ifaddr *in6_ifadd __P((struct nd_prefix *));static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *, struct nd_defrouter *));static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));static void pfxrtr_del __P((struct nd_pfxrouter *));static struct nd_pfxrouter *find_pfxlist_reachable_router __P((struct nd_prefix *));static void defrouter_delreq __P((struct nd_defrouter *));static void defrouter_addifreq __P((struct ifnet *));static void defrouter_delifreq __P((void));static void nd6_rtmsg __P((int, struct rtentry *));static void in6_init_address_ltimes __P((struct nd_prefix *ndpr, struct in6_addrlifetime *lt6));static int rt6_deleteroute __P((struct radix_node *, void *));extern int nd6_recalc_reachtm_interval;static struct ifnet *nd6_defifp;int nd6_defifindex;static struct ifaddr *nd6_defif_installed = NULL;int ip6_use_tempaddr = 0;int ip6_desync_factor;u_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME;u_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME;int ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE;/* RTPREF_MEDIUM has to be 0! */#define RTPREF_HIGH 1#define RTPREF_MEDIUM 0#define RTPREF_LOW (-1)#define RTPREF_INVALID (-2)/* * Receive Router Solicitation Message - just for routers. * Router solicitation/advertisement is mostly managed by userland program * (rtadvd) so here we have no function like nd6_ra_output(). * * Based on RFC 2461 */voidnd6_rs_input(m, off, icmp6len) struct mbuf *m; int off, icmp6len;{ struct ifnet *ifp = m->m_pkthdr.rcvif; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_router_solicit *nd_rs; struct in6_addr saddr6 = ip6->ip6_src;#if 0 struct in6_addr daddr6 = ip6->ip6_dst;#endif char *lladdr = NULL; int lladdrlen = 0;#if 0 struct sockaddr_dl *sdl = (struct sockaddr_dl *)NULL; struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; struct rtentry *rt = NULL; int is_newentry;#endif union nd_opts ndopts; /* If I'm not a router, ignore it. */ if (ip6_accept_rtadv != 0 || ip6_forwarding != 1) goto freeit; /* Sanity checks */ if (ip6->ip6_hlim != 255) { nd6log((LOG_ERR, "nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n", ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); goto bad; } /* * Don't update the neighbor cache, if src = ::. * This indicates that the src has no IP address assigned yet. */ if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) goto freeit;#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, icmp6len,); nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off);#else IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); if (nd_rs == NULL) { icmp6stat.icp6s_tooshort++; return; }#endif icmp6len -= sizeof(*nd_rs); nd6_option_init(nd_rs + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { nd6log((LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n")); /* nd6_options have incremented stats */ goto freeit; } if (ndopts.nd_opts_src_lladdr) { lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; } if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { nd6log((LOG_INFO, "nd6_rs_input: lladdrlen mismatch for %s " "(if %d, RS packet %d)\n", ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2)); goto bad; } nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); freeit: m_freem(m); return; bad: icmp6stat.icp6s_badrs++; m_freem(m);}/* * Receive Router Advertisement Message. * * Based on RFC 2461 * TODO: on-link bit on prefix information * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing */voidnd6_ra_input(m, off, icmp6len) struct mbuf *m; int off, icmp6len;{ struct ifnet *ifp = m->m_pkthdr.rcvif; struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_router_advert *nd_ra; struct in6_addr saddr6 = ip6->ip6_src;#if 0 struct in6_addr daddr6 = ip6->ip6_dst; int flags; /* = nd_ra->nd_ra_flags_reserved; */ int is_managed = ((flags & ND_RA_FLAG_MANAGED) != 0); int is_other = ((flags & ND_RA_FLAG_OTHER) != 0);#endif union nd_opts ndopts; struct nd_defrouter *dr; /* * We only accept RAs only when * the system-wide variable allows the acceptance, and * per-interface variable allows RAs on the receiving interface. */ if (ip6_accept_rtadv == 0) goto freeit; if (!(nd_ifinfo[ifp->if_index].flags & ND6_IFF_ACCEPT_RTADV)) goto freeit; if (ip6->ip6_hlim != 255) { nd6log((LOG_ERR, "nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n", ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), if_name(ifp))); goto bad; } if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { nd6log((LOG_ERR, "nd6_ra_input: src %s is not link-local\n", ip6_sprintf(&saddr6))); goto bad; }#ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, icmp6len,); nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off);#else IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); if (nd_ra == NULL) { icmp6stat.icp6s_tooshort++; return; }#endif icmp6len -= sizeof(*nd_ra); nd6_option_init(nd_ra + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { nd6log((LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n")); /* nd6_options have incremented stats */ goto freeit; } { struct nd_defrouter dr0; u_int32_t advreachable = nd_ra->nd_ra_reachable;#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec;#endif Bzero(&dr0, sizeof(dr0)); dr0.rtaddr = saddr6; dr0.flags = nd_ra->nd_ra_flags_reserved; dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); dr0.expire = time_second + dr0.rtlifetime; dr0.ifp = ifp; dr0.advint = 0; /* Mobile IPv6 */ dr0.advint_expire = 0; /* Mobile IPv6 */ dr0.advints_lost = 0; /* Mobile IPv6 */ /* unspecified or not? (RFC 2461 6.3.4) */ if (advreachable) { NTOHL(advreachable); if (advreachable <= MAX_REACHABLE_TIME && ndi->basereachable != advreachable) { ndi->basereachable = advreachable; ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */ } } if (nd_ra->nd_ra_retransmit) ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); if (nd_ra->nd_ra_curhoplimit) ndi->chlim = nd_ra->nd_ra_curhoplimit; dr = defrtrlist_update(&dr0); } /* * prefix */ if (ndopts.nd_opts_pi) { struct nd_opt_hdr *pt; struct nd_opt_prefix_info *pi = NULL; struct nd_prefix pr;#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) long time_second = time.tv_sec;#endif for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; pt = (struct nd_opt_hdr *)((caddr_t)pt + (pt->nd_opt_len << 3))) { if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) continue; pi = (struct nd_opt_prefix_info *)pt; if (pi->nd_opt_pi_len != 4) { nd6log((LOG_INFO, "nd6_ra_input: invalid option " "len %d for prefix information option, " "ignored\n", pi->nd_opt_pi_len)); continue; } if (128 < pi->nd_opt_pi_prefix_len) { nd6log((LOG_INFO, "nd6_ra_input: invalid prefix " "len %d for prefix information option, " "ignored\n", pi->nd_opt_pi_prefix_len)); continue; } if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { nd6log((LOG_INFO, "nd6_ra_input: invalid prefix " "%s, ignored\n", ip6_sprintf(&pi->nd_opt_pi_prefix))); continue; } /* aggregatable unicast address, rfc2374 */ if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20 && pi->nd_opt_pi_prefix_len != 64) { nd6log((LOG_INFO, "nd6_ra_input: invalid prefixlen " "%d for rfc2374 prefix %s, ignored\n", pi->nd_opt_pi_prefix_len, ip6_sprintf(&pi->nd_opt_pi_prefix))); continue; } bzero(&pr, sizeof(pr)); pr.ndpr_prefix.sin6_family = AF_INET6; pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix); pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix; pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif; pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) ? 1 : 0;#ifdef MIP6 pr.ndpr_raf_router = (pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER) ? 1 : 0;#endif /* MIP6 */ pr.ndpr_plen = pi->nd_opt_pi_prefix_len; pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time); pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time); pr.ndpr_lastupdate = time_second; if (in6_init_prefix_ltimes(&pr)) continue; /* prefix lifetime init failed */#ifdef MIP6 if (MIP6_IS_MN) { if (mip6_prefix_list_update(&saddr6, &pr, dr, m)) { mip6log((LOG_ERR, "%s:%d: " "prefix info processing " "failed\n", __FILE__, __LINE__)); goto freeit; } }#endif /* MIP6 */ (void)prelist_update(&pr, dr, m); } }#ifdef MIP6 if (MIP6_IS_MN) { /* check reachability of all routers. */ mip6_probe_routers(); } /* update home agent list. */ if ((MIP6_IS_MN || MIP6_IS_HA) && dr && (dr->flags & ND_RA_FLAG_HOME_AGENT)) { if (mip6_ha_list_update_hainfo(&mip6_ha_list, dr, ndopts.nd_opts_hai)) { mip6log((LOG_ERR, "%s:%d: global HA list update failed\n", __FILE__, __LINE__)); } } if (dr == NULL) { struct mip6_ha *mha; /* the home agent is shutting down. */ mha = mip6_ha_list_find_withaddr(&mip6_ha_list, &saddr6); if (mha) { if (mip6_ha_list_remove(&mip6_ha_list, mha)) { mip6log((LOG_ERR, "%s:%d: HA entry remove failed.\n", __FILE__, __LINE__)); } } }#endif /* MIP6 */ /* * MTU */ if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { u_int32_t mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); /* lower bound */ if (mtu < IPV6_MMTU) { nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option " "mtu=%d sent from %s, ignoring\n", mtu, ip6_sprintf(&ip6->ip6_src))); goto skip; } /* upper bound */ if (ndi->maxmtu) { if (mtu <= ndi->maxmtu) { int change = (ndi->linkmtu != mtu); ndi->linkmtu = mtu; if (change) /* in6_maxmtu may change */ in6_setmaxmtu(); } else { nd6log((LOG_INFO, "nd6_ra_input: bogus mtu " "mtu=%d sent from %s; " "exceeds maxmtu %d, ignoring\n", mtu, ip6_sprintf(&ip6->ip6_src), ndi->maxmtu)); } } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?