⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nd6.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		} else			return(NULL);	}	rt->rt_refcnt--;	/*	 * Validation for the entry.	 * XXX: we can't use rt->rt_ifp to check for the interface, since	 *      it might be the loopback interface if the entry is for our	 *      own address on a non-loopback interface. Instead, we should	 *      use rt->rt_ifa->ifa_ifp, which would specify the REAL interface.	 */	if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||	    rt->rt_gateway->sa_family != AF_LINK ||	    (ifp && rt->rt_ifa->ifa_ifp != ifp)) {		if (create) {			log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n",			    ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec");		}		return(0);	}	return(rt);}/* * Detect if a given IPv6 address identifies a neighbor on a given link. * XXX: should take care of the destination of a p2p link? */intnd6_is_addr_neighbor(addr, ifp)	struct sockaddr_in6 *addr;	struct ifnet *ifp;{	struct nd_prefix *pr;	struct rtentry *rt;	int i;#define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr)#define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr)	/*	 * A link-local address is always a neighbor.	 * XXX: we should use the sin6_scope_id field rather than the embedded	 * interface index.	 * XXX: a link does not necessarily specify a single interface.	 */	if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) &&	    ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]) == ifp->if_index)		return(1);	/*	 * If the address matches one of our on-link prefixes, it should be a	 * neighbor.	 */	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {		if (pr->ndpr_ifp != ifp)			continue;		if (!(pr->ndpr_stateflags & NDPRF_ONLINK))			continue;		for (i = 0; i < 4; i++) {			if ((pr->ndpr_mask.s6_addr32[i] &			     addr->sin6_addr.s6_addr32[i]) !=			    pr->ndpr_prefix.sin6_addr.s6_addr32[i])				break;		}		if (i == 4)	/* full match */			return(1);	}	/*	 * If the default router list is empty, all addresses are regarded	 * as on-link, and thus, as a neighbor.	 * XXX: we restrict the condition to hosts, because routers usually do	 * not have the "default router list".	 */	if (!ip6_forwarding && TAILQ_FIRST(&nd_defrouter) == NULL &&	    nd6_defifindex == ifp->if_index) {		return(1);	}	/*	 * Even if the address matches none of our addresses, it might be	 * in the neighbor cache.	 */	if ((rt = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL &&	    rt->rt_llinfo != NULL)		return(1);	return(0);#undef IFADDR6#undef IFMASK6}/* * Free an nd6 llinfo entry. * Since the function would cause significant changes in the kernel, DO NOT * make it global, unless you have a strong reason for the change, and are sure * that the change is safe. */static struct llinfo_nd6 *nd6_free(rt, gc)	struct rtentry *rt;	int gc;{	struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next;	struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr;	struct nd_defrouter *dr;	/*	 * we used to have pfctlinput(PRC_HOSTDEAD) here.	 * even though it is not harmful, it was not really necessary.	 */	if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */		int s;#ifdef __NetBSD__		s = splsoftnet();#else		s = splnet();#endif		dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,				      rt->rt_ifp);		if (dr != NULL && dr->expire &&		    ln->ln_state == ND6_LLINFO_STALE && gc) {			/*			 * If the reason for the deletion is just garbage			 * collection, and the neighbor is an active default			 * router, do not delete it.  Instead, reset the GC			 * timer using the router's lifetime.			 * Simply deleting the entry would affect default			 * router selection, which is not necessarily a good			 * thing, especially when we're using router preference			 * values.			 * XXX: the check for ln_state would be redundant,			 *      but we intentionally keep it just in case.			 */			ln->ln_expire = dr->expire;			splx(s);			return(ln->ln_next);		}		if (ln->ln_router || dr) {			/*			 * rt6_flush must be called whether or not the neighbor			 * is in the Default Router List.			 * See a corresponding comment in nd6_na_input().			 */			rt6_flush(&in6, rt->rt_ifp);		}		if (dr) {			/*			 * Unreachablity of a router might affect the default			 * router selection and on-link detection of advertised			 * prefixes.			 */			/*			 * Temporarily fake the state to choose a new default			 * router and to perform on-link determination of			 * prefixes correctly.			 * Below the state will be set correctly,			 * or the entry itself will be deleted.			 */			ln->ln_state = ND6_LLINFO_INCOMPLETE;			/*			 * Since defrouter_select() does not affect the			 * on-link determination and MIP6 needs the check			 * before the default router selection, we perform			 * the check now.			 */			pfxlist_onlink_check();			/*			 * refresh default router list			 */			defrouter_select();		}		splx(s);	}	/*	 * Before deleting the entry, remember the next entry as the	 * return value.  We need this because pfxlist_onlink_check() above	 * might have freed other entries (particularly the old next entry) as	 * a side effect (XXX).	 */	next = ln->ln_next;	/*	 * Detach the route from the routing tree and the list of neighbor	 * caches, and disable the route entry not to be used in already	 * cached routes.	 */	rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,		  rt_mask(rt), 0, (struct rtentry **)0);	return(next);}/* * Upper-layer reachability hint for Neighbor Unreachability Detection. * * XXX cost-effective metods? */voidnd6_nud_hint(rt, dst6, force)	struct rtentry *rt;	struct in6_addr *dst6;	int force;{	struct llinfo_nd6 *ln;#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)	long time_second = time.tv_sec;#endif	/*	 * If the caller specified "rt", use that.  Otherwise, resolve the	 * routing table by supplied "dst6".	 */	if (!rt) {		if (!dst6)			return;		if (!(rt = nd6_lookup(dst6, 0, NULL)))			return;	}	if ((rt->rt_flags & RTF_GATEWAY) != 0 ||	    (rt->rt_flags & RTF_LLINFO) == 0 ||	    !rt->rt_llinfo || !rt->rt_gateway ||	    rt->rt_gateway->sa_family != AF_LINK) {		/* This is not a host route. */		return;	}	ln = (struct llinfo_nd6 *)rt->rt_llinfo;	if (ln->ln_state < ND6_LLINFO_REACHABLE)		return;	/*	 * if we get upper-layer reachability confirmation many times,	 * it is possible we have false information.	 */	if (!force) {		ln->ln_byhint++;		if (ln->ln_byhint > nd6_maxnudhint)			return;	}	ln->ln_state = ND6_LLINFO_REACHABLE;	if (ln->ln_expire)		ln->ln_expire = time_second +			nd_ifinfo[rt->rt_ifp->if_index].reachable;}void#if (defined(__bsdi__) && _BSDI_VERSION >= 199802) || defined(__NetBSD__) || defined(__OpenBSD__)nd6_rtrequest(req, rt, info)	int	req;	struct rtentry *rt;	struct rt_addrinfo *info; /* xxx unused */#elsend6_rtrequest(req, rt, sa)	int	req;	struct rtentry *rt;	struct sockaddr *sa; /* xxx unused */#endif{	struct sockaddr *gate = rt->rt_gateway;	struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo;	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};	struct ifnet *ifp = rt->rt_ifp;	struct ifaddr *ifa;#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)	long time_second = time.tv_sec;#endif	if ((rt->rt_flags & RTF_GATEWAY))		return;	if (nd6_need_cache(ifp) == 0 && (rt->rt_flags & RTF_HOST) == 0) {		/*		 * This is probably an interface direct route for a link		 * which does not need neighbor caches (e.g. fe80::%lo0/64).		 * We do not need special treatment below for such a route.		 * Moreover, the RTF_LLINFO flag which would be set below		 * would annoy the ndp(8) command.		 */		return;	}	if (req == RTM_RESOLVE &&	    !nd6_is_addr_neighbor((struct sockaddr_in6 *)rt_key(rt), ifp)) {		/*		 * FreeBSD and BSD/OS often make a cloned host route based		 * on a less-specific route (e.g. the default route).		 * If the less specific route does not have a "gateway"		 * (this is the case when the route just goes to a p2p		 * interface), we'll mistakenly make a neighbor cache for		 * the host route, and will see strange neighbor solicitation		 * for the corresponding destination.  In order to avoid the		 * confusion, we check if the destination of the route is		 * a neighbor in terms of neighbor discovery, and stop the		 * process if not.  Additionally, we remove the LLINFO flag		 * so that ndp(8) will not try to get the neighbor information		 * of the destination.		 */		rt->rt_flags &= ~RTF_LLINFO;		return;	}	switch (req) {	case RTM_ADD:		/*		 * There is no backward compatibility :)		 *		 * if ((rt->rt_flags & RTF_HOST) == 0 &&		 *     SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)		 *	   rt->rt_flags |= RTF_CLONING;		 */		if (rt->rt_flags & (RTF_CLONING | RTF_LLINFO)) {			/*			 * Case 1: This route should come from			 * a route to interface.  RTF_LLINFO flag is set			 * for a host route whose destination should be			 * treated as on-link.			 */			rt_setgate(rt, rt_key(rt),				   (struct sockaddr *)&null_sdl);			gate = rt->rt_gateway;			SDL(gate)->sdl_type = ifp->if_type;			SDL(gate)->sdl_index = ifp->if_index;			if (ln)				ln->ln_expire = time_second;#if 1			if (ln && ln->ln_expire == 0) {				/* kludge for desktops */#if 0				printf("nd6_rtequest: time.tv_sec is zero; "				       "treat it as 1\n");#endif				ln->ln_expire = 1;			}#endif			if ((rt->rt_flags & RTF_CLONING))				break;		}		/*		 * In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here.		 * We don't do that here since llinfo is not ready yet.		 *		 * There are also couple of other things to be discussed:		 * - unsolicited NA code needs improvement beforehand		 * - RFC2461 says we MAY send multicast unsolicited NA		 *   (7.2.6 paragraph 4), however, it also says that we		 *   SHOULD provide a mechanism to prevent multicast NA storm.		 *   we don't have anything like it right now.		 *   note that the mechanism needs a mutual agreement		 *   between proxies, which means that we need to implement		 *   a new protocol, or a new kludge.		 * - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA.		 *   we need to check ip6forwarding before sending it.		 *   (or should we allow proxy ND configuration only for		 *   routers?  there's no mention about proxy ND from hosts)		 */#if 0		/* XXX it does not work */		if (rt->rt_flags & RTF_ANNOUNCE)			nd6_na_output(ifp,			      &SIN6(rt_key(rt))->sin6_addr,			      &SIN6(rt_key(rt))->sin6_addr,			      ip6_forwarding ? ND_NA_FLAG_ROUTER : 0,			      1, NULL);#endif		/* FALLTHROUGH */	case RTM_RESOLVE:		if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) {			/*			 * Address resolution isn't necessary for a point to			 * point link, so we can skip this test for a p2p link.			 */			if (gate->sa_family != AF_LINK ||			    gate->sa_len < sizeof(null_sdl)) {				log(LOG_DEBUG,				    "nd6_rtrequest: bad gateway value: %s\n",				    if_name(ifp));				break;			}			SDL(gate)->sdl_type = ifp->if_type;			SDL(gate)->sdl_index = ifp->if_index;		}		if (ln != NULL)			break;	/* This happens on a route change */		/*		 * Case 2: This route may come from cloning, or a manual route		 * add with a LL address.		 */		R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln));		rt->rt_llinfo = (caddr_t)ln;		if (!ln) {			log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n");			break;		}		nd6_inuse++;		nd6_allocated++;		Bzero(ln, sizeof(*ln));		ln->ln_rt = rt;		/* this is required for "ndp" command. - shin */		if (req == RTM_ADD) {		        /*			 * gate should have some valid AF_LINK entry,			 * and ln->ln_expire should have some lifetime			 * which is specified by ndp command.			 */			ln->ln_state = ND6_LLINFO_REACHABLE;			ln->ln_byhint = 0;		} else {		        /*			 * When req == RTM_RESOLVE, rt is created and			 * initialized in rtrequest(), so rt_expire is 0.			 */			ln->ln_state = ND6_LLINFO_NOSTATE;			ln->ln_expire = time_second;		}		rt->rt_flags |= RTF_LLINFO;		ln->ln_next = llinfo_nd6.ln_next;		llinfo_nd6.ln_next = ln;		ln->ln_prev = &llinfo_nd6;		ln->ln_next->ln_prev = ln;		/*		 * check if rt_key(rt) is one of my address assigned		 * to the interface.		 */		ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp,					  &SIN6(rt_key(rt))->sin6_addr);		if (ifa) {			caddr_t macp = nd6_ifptomac(ifp);			ln->ln_expire = 0;			ln->ln_state = ND6_LLINFO_REACHABLE;			ln->ln_byhint = 0;			if (macp) {				Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen);				SDL(gate)->sdl_alen = ifp->if_addrlen;			}			if (nd6_useloopback) {#ifdef __bsdi__#if _BSDI_VERSION >= 199802				extern struct ifnet *loifp;				rt->rt_ifp = loifp;	/* XXX */#else				extern struct ifnet loif;				rt->rt_ifp = &loif;	/* XXX */#endif#elif defined(__OpenBSD__)				rt->rt_ifp = lo0ifp;	/* XXX */#else				rt->rt_ifp = &loif[0];	/* XXX */#endif				/*				 * Make sure rt_ifa be equal to the ifaddr				 * corresponding to the address.				 * We need this because when we refer				 * rt_ifa->ia6_flags in ip6_input, we assume				 * that the rt_ifa points to the address instead				 * of the loopback address.				 */				if (ifa != rt->rt_ifa) {					IFAFREE(rt->rt_ifa);					IFAREF(ifa);					rt->rt_ifa = ifa;				}			}		} else if (rt->rt_flags & RTF_ANNOUNCE) {			ln->ln_expire = 0;			ln->ln_state = ND6_LLINFO_REACHABLE;			ln->ln_byhint = 0;			/* join solicited node multicast for proxy ND */			if (ifp->if_flags & IFF_MULTICAST) {				struct in6_addr llsol;				int error;				llsol = SIN6(rt_key(rt))->sin6_addr;				llsol.s6_addr16[0] = htons(0xff02);				llsol.s6_addr16[1] = htons(ifp->if_index);				llsol.s6_addr32[1] = 0;				llsol.s6_addr32[2] = htonl(1);				llsol.s6_addr8[12] = 0xff;				if (!in6_addmulti(&llsol, ifp, &error)) {					nd6log((LOG_ERR, "%s: failed to join "					    "%s (errno=%d)\n", if_name(ifp),					    ip6_sprintf(&llsol), error));				}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -