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 + -
显示快捷键?