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

📄 nd6.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	struct in6_ifaddr *ia6, *nia6;	struct in6_addrlifetime *lt6;	#ifdef __NetBSD__	s = splsoftnet();#else	s = splnet();#endif#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)	callout_reset(&nd6_timer_ch, nd6_prune * hz,	    nd6_timer, NULL);#elif defined(__OpenBSD__)	timeout_set(&nd6_timer_ch, nd6_timer, NULL);	timeout_add(&nd6_timer_ch, nd6_prune * hz);#else	timeout(nd6_timer, (caddr_t)0, nd6_prune * hz);#endif	ln = llinfo_nd6.ln_next;	while (ln && ln != &llinfo_nd6) {		struct rtentry *rt;		struct sockaddr_in6 *dst;		struct llinfo_nd6 *next = ln->ln_next;		/* XXX: used for the DELAY case only: */		struct nd_ifinfo *ndi = NULL;		if ((rt = ln->ln_rt) == NULL) {			ln = next;			continue;		}		if ((ifp = rt->rt_ifp) == NULL) {			ln = next;			continue;		}		ndi = &nd_ifinfo[ifp->if_index];		dst = (struct sockaddr_in6 *)rt_key(rt);		if (ln->ln_expire > time_second) {			ln = next;			continue;		}		/* sanity check */		if (!rt)			panic("rt=0 in nd6_timer(ln=%p)\n", ln);		if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln)			panic("rt_llinfo(%p) is not equal to ln(%p)\n",			      rt->rt_llinfo, ln);		if (!dst)			panic("dst=0 in nd6_timer(ln=%p)\n", ln);		switch (ln->ln_state) {		case ND6_LLINFO_INCOMPLETE:			if (ln->ln_asked < nd6_mmaxtries) {				ln->ln_asked++;				ln->ln_expire = time_second +					nd_ifinfo[ifp->if_index].retrans / 1000;				nd6_ns_output(ifp, NULL, &dst->sin6_addr,					ln, 0);			} else {				struct mbuf *m = ln->ln_hold;				if (m) {					struct ip6_hdr *ip6_in;					struct sockaddr_in6 sin6_in;					int64_t szoneid, dzoneid;					/*					 * Fake rcvif to make the ICMP error					 * more helpful in diagnosing for the					 * receiver.					 * XXX: should we consider					 * older rcvif?					 */					m->m_pkthdr.rcvif = rt->rt_ifp;					/*					 * XXX: for scoped addresses, we should					 * disambiguate the zone.  We should					 * perhaps hang sockaddr_in6 as aux					 * data in the mbuf.					 */					ip6_in = mtod(m, struct ip6_hdr *);					szoneid = in6_addr2zoneid(rt->rt_ifp,								  &ip6_in->ip6_src);					dzoneid = in6_addr2zoneid(rt->rt_ifp,								  &ip6_in->ip6_dst);					if (szoneid < 0 || dzoneid < 0) {						/* impossible... */						m_freem(m);					} else {						bzero(&sin6_in,						      sizeof(sin6_in));						sin6_in.sin6_addr = ip6_in->ip6_src;						sin6_in.sin6_scope_id = szoneid;						in6_embedscope(&ip6_in->ip6_src,							       &sin6_in);						bzero(&sin6_in,						      sizeof(sin6_in));						sin6_in.sin6_addr = ip6_in->ip6_dst;						sin6_in.sin6_scope_id = dzoneid;						in6_embedscope(&ip6_in->ip6_dst,							       &sin6_in);						icmp6_error(m,							    ICMP6_DST_UNREACH,							    ICMP6_DST_UNREACH_ADDR, 0);					}					ln->ln_hold = NULL;				}				next = nd6_free(rt, 0);			}			break;		case ND6_LLINFO_REACHABLE:			if (ln->ln_expire) {				ln->ln_state = ND6_LLINFO_STALE;				ln->ln_expire = time_second + nd6_gctimer;			}			break;		case ND6_LLINFO_STALE:			/* Garbage Collection(RFC 2461 5.3) */			if (ln->ln_expire)				next = nd6_free(rt, 1);			break;		case ND6_LLINFO_DELAY:			if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) {				/* We need NUD */				ln->ln_asked = 1;				ln->ln_state = ND6_LLINFO_PROBE;				ln->ln_expire = time_second +					ndi->retrans / 1000;				nd6_ns_output(ifp, &dst->sin6_addr,					      &dst->sin6_addr,					      ln, 0);			} else {				ln->ln_state = ND6_LLINFO_STALE; /* XXX */				ln->ln_expire = time_second + nd6_gctimer;			}			break;		case ND6_LLINFO_PROBE:			if (ln->ln_asked < nd6_umaxtries) {				ln->ln_asked++;				ln->ln_expire = time_second +					nd_ifinfo[ifp->if_index].retrans / 1000;				nd6_ns_output(ifp, &dst->sin6_addr,					       &dst->sin6_addr, ln, 0);			} else {				next = nd6_free(rt, 0);			}			break;		}		ln = next;	}		/* expire default router list */	dr = TAILQ_FIRST(&nd_defrouter);	while (dr) {		if (dr->expire && dr->expire < time_second) {			struct nd_defrouter *t;			t = TAILQ_NEXT(dr, dr_entry);			defrtrlist_del(dr);			dr = t;		} else {			dr = TAILQ_NEXT(dr, dr_entry);		}	}	/*	 * expire interface addresses.	 * in the past the loop was inside prefix expiry processing.	 * However, from a stricter speci-confrmance standpoint, we should	 * rather separate address lifetimes and prefix lifetimes.	 */  addrloop:	for (ia6 = in6_ifaddr; ia6; ia6 = nia6) {		nia6 = ia6->ia_next;		/* check address lifetime */		lt6 = &ia6->ia6_lifetime;		if (IFA6_IS_INVALID(ia6)) {			int regen = 0;			/*			 * If the expiring address is temporary, try			 * regenerating a new one.  This would be useful when			 * we suspended a laptop PC, then turned it on after a			 * period that could invalidate all temporary			 * addresses.  Although we may have to restart the			 * loop (see below), it must be after purging the			 * address.  Otherwise, we'd see an infinite loop of			 * regeneration. 			 */			if (ip6_use_tempaddr &&			    (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) {				if (regen_tmpaddr(ia6) == 0)					regen = 1;			}			in6_purgeaddr(&ia6->ia_ifa);			if (regen)				goto addrloop; /* XXX: see below */		}		if (IFA6_IS_DEPRECATED(ia6)) {			int oldflags = ia6->ia6_flags;			ia6->ia6_flags |= IN6_IFF_DEPRECATED;			/*			 * If a temporary address has just become deprecated,			 * regenerate a new one if possible.			 */			if (ip6_use_tempaddr &&			    (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&			    (oldflags & IN6_IFF_DEPRECATED) == 0) {				if (regen_tmpaddr(ia6) == 0) {					/*					 * A new temporary address is					 * generated.					 * XXX: this means the address chain					 * has changed while we are still in					 * the loop.  Although the change					 * would not cause disaster (because					 * it's not a deletion, but an					 * addition,) we'd rather restart the					 * loop just for safety.  Or does this 					 * significantly reduce performance??					 */					goto addrloop;				}			}		} else {			/*			 * A new RA might have made a deprecated address			 * preferred.			 */			ia6->ia6_flags &= ~IN6_IFF_DEPRECATED;		}	}	/* expire prefix list */	pr = nd_prefix.lh_first;	while (pr) {		/*		 * check prefix lifetime.		 * since pltime is just for autoconf, pltime processing for		 * prefix is not necessary.		 */		if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME &&		    time_second - pr->ndpr_lastupdate > pr->ndpr_vltime) {			struct nd_prefix *t;			t = pr->ndpr_next;			/*			 * address expiration and prefix expiration are			 * separate.  NEVER perform in6_purgeaddr here.			 */			prelist_remove(pr);			pr = t;		} else			pr = pr->ndpr_next;	}	splx(s);}static intregen_tmpaddr(ia6)	struct in6_ifaddr *ia6; /* deprecated/invalidated temporary address */{	struct ifaddr *ifa;	struct ifnet *ifp;	struct in6_ifaddr *public_ifa6 = NULL;	ifp = ia6->ia_ifa.ifa_ifp;#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)#else	for (ifa = ifp->if_addrlist.tqh_first; ifa;	     ifa = ifa->ifa_list.tqe_next)#endif	{		struct in6_ifaddr *it6;		if (ifa->ifa_addr->sa_family != AF_INET6)			continue;		it6 = (struct in6_ifaddr *)ifa;		/* ignore no autoconf addresses. */		if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0)			continue;		/* ignore autoconf addresses with different prefixes. */		if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr)			continue;		/*		 * Now we are looking at an autoconf address with the same		 * prefix as ours.  If the address is temporary and is still		 * preferred, do not create another one.  It would be rare, but		 * could happen, for example, when we resume a laptop PC after		 * a long period.		 */		if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 &&		    !IFA6_IS_DEPRECATED(it6)) {			public_ifa6 = NULL;			break;		}		/*		 * This is a public autoconf address that has the same prefix		 * as ours.  If it is preferred, keep it.  We can't break the		 * loop here, because there may be a still-preferred temporary		 * address with the prefix.		 */		if (!IFA6_IS_DEPRECATED(it6))		    public_ifa6 = it6;	}	if (public_ifa6 != NULL) {		int e;		if ((e = in6_tmpifadd(public_ifa6, 0)) != 0) {			log(LOG_NOTICE, "regen_tmpaddr: failed to create a new"			    " tmp addr,errno=%d\n", e);			return(-1);		}		return(0);	}	return(-1);}/* * Nuke neighbor cache/prefix/default router management table, right before * ifp goes away. */voidnd6_purge(ifp)	struct ifnet *ifp;{	struct llinfo_nd6 *ln, *nln;	struct nd_defrouter *dr, *ndr;	struct nd_prefix *pr, *npr;	/*	 * Nuke default router list entries toward ifp.	 * We defer removal of default router list entries that is installed	 * in the routing table, in order to keep additional side effects as	 * small as possible.	 */	for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) {		ndr = TAILQ_NEXT(dr, dr_entry);		if (dr->installed)			continue;		if (dr->ifp == ifp)			defrtrlist_del(dr);	}	for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = ndr) {		ndr = TAILQ_NEXT(dr, dr_entry);		if (!dr->installed)			continue;		if (dr->ifp == ifp)			defrtrlist_del(dr);	}	/* Nuke prefix list entries toward ifp */	for (pr = nd_prefix.lh_first; pr; pr = npr) {		npr = pr->ndpr_next;		if (pr->ndpr_ifp == ifp) {			/*			 * Previously, pr->ndpr_addr is removed as well,			 * but I strongly believe we don't have to do it.			 * nd6_purge() is only called from in6_ifdetach(),			 * which removes all the associated interface addresses			 * by itself.			 * (jinmei@kame.net 20010129)			 */			prelist_remove(pr);		}	}	/* cancel default outgoing interface setting */	if (nd6_defifindex == ifp->if_index)		nd6_setdefaultiface(0);	if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */		/* refresh default router list */		defrouter_select();	}	/*	 * Nuke neighbor cache entries for the ifp.	 * Note that rt->rt_ifp may not be the same as ifp,	 * due to KAME goto ours hack.  See RTM_RESOLVE case in	 * nd6_rtrequest(), and ip6_input().	 */	ln = llinfo_nd6.ln_next;	while (ln && ln != &llinfo_nd6) {		struct rtentry *rt;		struct sockaddr_dl *sdl;		nln = ln->ln_next;		rt = ln->ln_rt;		if (rt && rt->rt_gateway &&		    rt->rt_gateway->sa_family == AF_LINK) {			sdl = (struct sockaddr_dl *)rt->rt_gateway;			if (sdl->sdl_index == ifp->if_index)				nln = nd6_free(rt, 0);		}		ln = nln;	}}struct rtentry *nd6_lookup(addr6, create, ifp)	struct in6_addr *addr6;	int create;	struct ifnet *ifp;{	struct rtentry *rt;	struct sockaddr_in6 sin6;#ifdef SCOPEDROUTING	int64_t zoneid;#endif	bzero(&sin6, sizeof(sin6));	sin6.sin6_len = sizeof(struct sockaddr_in6);	sin6.sin6_family = AF_INET6;	sin6.sin6_addr = *addr6;#ifdef SCOPEDROUTING	if ((zoneid = in6_addr2zoneid(ifp, addr6)) < 0)		return(NULL);	sin6.sin6_scope_id = zoneid;#endif	rt = rtalloc1((struct sockaddr *)&sin6, create#ifdef __FreeBSD__		      , 0UL#endif /* __FreeBSD__ */		      );	if (rt && (rt->rt_flags & RTF_LLINFO) == 0) {		/*		 * This is the case for the default route.		 * If we want to create a neighbor cache for the address, we		 * should free the route for the destination and allocate an		 * interface route.		 */		if (create) {			RTFREE(rt);			rt = 0;		}	}	if (!rt) {		if (create && ifp) {			int e;			/*			 * If no route is available and create is set,			 * we allocate a host route for the destination			 * and treat it like an interface route.			 * This hack is necessary for a neighbor which can't			 * be covered by our own prefix.			 */			struct ifaddr *ifa =				ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp);			if (ifa == NULL)				return(NULL);			/*			 * Create a new route.  RTF_LLINFO is necessary			 * to create a Neighbor Cache entry for the			 * destination in nd6_rtrequest which will be			 * called in rtrequest via ifa->ifa_rtrequest.			 */			if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6,					   ifa->ifa_addr,					   (struct sockaddr *)&all1_sa,					   (ifa->ifa_flags |					    RTF_HOST | RTF_LLINFO) &					   ~RTF_CLONING,					   &rt)) != 0) {#if 0				log(LOG_ERR,				    "nd6_lookup: failed to add route for a "				    "neighbor(%s), errno=%d\n",				    ip6_sprintf(addr6), e);#endif				return(NULL);			}			if (rt == NULL)				return(NULL);			if (rt->rt_llinfo) {				struct llinfo_nd6 *ln =					(struct llinfo_nd6 *)rt->rt_llinfo;				ln->ln_state = ND6_LLINFO_NOSTATE;			}

⌨️ 快捷键说明

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