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

📄 nd6.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		 */		ln->ln_router = 0;		break;	case ND_ROUTER_ADVERT:		/*		 * Mark an entry with lladdr as a router.		 */		if ((!is_newentry && (olladdr || lladdr))	/* (2-5) */		 || (is_newentry && lladdr)) {			/* (7) */			ln->ln_router = 1;		}		break;	}	/*	 * When the link-layer address of a router changes, select the	 * best router again.  In particular, when the neighbor entry is newly	 * created, it might affect the selection policy.	 * Question: can we restrict the first condition to the "is_newentry"	 * case?	 * XXX: when we hear an RA from a new router with the link-layer	 * address option, defrouter_select() is called twice, since	 * defrtrlist_update called the function as well.  However, I believe	 * we can compromise the overhead, since it only happens the first	 * time.	 * XXX: although defrouter_select() should not have a bad effect	 * for those are not autoconfigured hosts, we explicitly avoid such	 * cases for safety.	 */	if (do_update && ln->ln_router && !ip6_forwarding && ip6_accept_rtadv)		defrouter_select();	return rt;}static voidnd6_slowtimo(ignored_arg)    void *ignored_arg;{#ifdef __NetBSD__	int s = splsoftnet();#else	int s = splnet();#endif	int i;	struct nd_ifinfo *nd6if;#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	for (i = 1; i < if_index + 1; i++) {		if (!nd_ifinfo || i >= nd_ifinfo_indexlim)			continue;		nd6if = &nd_ifinfo[i];		if (nd6if->basereachable && /* already initialized */		    (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) {			/*			 * Since reachable time rarely changes by router			 * advertisements, we SHOULD insure that a new random			 * value gets recomputed at least once every few hours.			 * (RFC 2461, 6.3.4)			 */			nd6if->recalctm = nd6_recalc_reachtm_interval;			nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable);		}	}	splx(s);}#define senderr(e) { error = (e); goto bad;}intnd6_output(ifp, origifp, m0, dst, rt0)	struct ifnet *ifp;	struct ifnet *origifp;	struct mbuf *m0;	struct sockaddr_in6 *dst;	struct rtentry *rt0;{	struct mbuf *m = m0;	struct rtentry *rt = rt0;	struct sockaddr_in6 *gw6 = NULL;	struct llinfo_nd6 *ln = NULL;	int error = 0;#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)	long time_second = time.tv_sec;#endif#if defined(__OpenBSD__) && defined(IPSEC)	struct m_tag *mtag;#endif /* IPSEC */	if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))		goto sendpkt;	if (nd6_need_cache(ifp) == 0)		goto sendpkt;	/*	 * next hop determination.  This routine is derived from ether_outpout.	 */	if (rt) {		if ((rt->rt_flags & RTF_UP) == 0) {#ifdef __FreeBSD__			if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1, 0UL)) !=				NULL)#else			if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) !=				NULL)#endif			{				rt->rt_refcnt--;				if (rt->rt_ifp != ifp) {					/* XXX: loop care? */					return nd6_output(ifp, origifp, m0,							  dst, rt);				}			} else				senderr(EHOSTUNREACH);		}		if (rt->rt_flags & RTF_GATEWAY) {			gw6 = (struct sockaddr_in6 *)rt->rt_gateway;			/*			 * We skip link-layer address resolution and NUD			 * if the gateway is not a neighbor from ND point			 * of view, regardless of the value of nd_ifinfo.flags.			 * The second condition is a bit tricky; we skip			 * if the gateway is our own address, which is			 * sometimes used to install a route to a p2p link.			 */			if (!nd6_is_addr_neighbor(gw6, ifp) ||			    in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) {				/*				 * We allow this kind of tricky route only				 * when the outgoing interface is p2p.				 * XXX: we may need a more generic rule here.				 */				if ((ifp->if_flags & IFF_POINTOPOINT) == 0)					senderr(EHOSTUNREACH);				goto sendpkt;			}			if (rt->rt_gwroute == 0)				goto lookup;			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {				rtfree(rt); rt = rt0;			lookup:#ifdef __FreeBSD__				rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL);#else				rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);#endif				if ((rt = rt->rt_gwroute) == 0)					senderr(EHOSTUNREACH);#if defined(__bsdi__) || defined(__NetBSD__)				/* the "G" test below also prevents rt == rt0 */				if ((rt->rt_flags & RTF_GATEWAY) ||				    (rt->rt_ifp != ifp)) {					rt->rt_refcnt--;					rt0->rt_gwroute = 0;					senderr(EHOSTUNREACH);				}#endif			}		}	}	/*	 * Address resolution or Neighbor Unreachability Detection	 * for the next hop.	 * At this point, the destination of the packet must be a unicast	 * or an anycast address(i.e. not a multicast).	 */	/* Look up the neighbor cache for the nexthop */	if (rt && (rt->rt_flags & RTF_LLINFO) != 0)		ln = (struct llinfo_nd6 *)rt->rt_llinfo;	else {		/*		 * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),		 * the condition below is not very efficient.  But we believe		 * it is tolerable, because this should be a rare case.		 */		if (nd6_is_addr_neighbor(dst, ifp) &&		    (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL)			ln = (struct llinfo_nd6 *)rt->rt_llinfo;	}	if (!ln || !rt) {		if ((ifp->if_flags & IFF_POINTOPOINT) == 0 &&		    !(nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD)) {			log(LOG_DEBUG,			    "nd6_output: can't allocate llinfo for %s "			    "(ln=%p, rt=%p)\n",			    ip6_sprintf(&dst->sin6_addr), ln, rt);			senderr(EIO);	/* XXX: good error? */		}		goto sendpkt;	/* send anyway */	}	/* We don't have to do link-layer address resolution on a p2p link. */	if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&	    ln->ln_state < ND6_LLINFO_REACHABLE) {		ln->ln_state = ND6_LLINFO_STALE;		ln->ln_expire = time_second + nd6_gctimer;	}	/*	 * The first time we send a packet to a neighbor whose entry is	 * STALE, we have to change the state to DELAY and a sets a timer to	 * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do	 * neighbor unreachability detection on expiration.	 * (RFC 2461 7.3.3)	 */	if (ln->ln_state == ND6_LLINFO_STALE) {		ln->ln_asked = 0;		ln->ln_state = ND6_LLINFO_DELAY;		ln->ln_expire = time_second + nd6_delay;	}	/*	 * If the neighbor cache entry has a state other than INCOMPLETE	 * (i.e. its link-layer address is already resolved), just	 * send the packet.	 */	if (ln->ln_state > ND6_LLINFO_INCOMPLETE)		goto sendpkt;	/*	 * There is a neighbor cache entry, but no ethernet address	 * response yet.  Replace the held mbuf (if any) with this	 * latest one.	 * This code conforms to the rate-limiting rule described in Section	 * 7.2.2 of RFC 2461, because the timer is set correctly after sending	 * an NS below.	 */	if (ln->ln_state == ND6_LLINFO_NOSTATE)		ln->ln_state = ND6_LLINFO_INCOMPLETE;	if (ln->ln_hold)		m_freem(ln->ln_hold);	ln->ln_hold = m;	if (ln->ln_expire) {		if (ln->ln_asked < nd6_mmaxtries &&		    ln->ln_expire < time_second) {			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);		}	}	return(0);	  sendpkt:#if defined(__OpenBSD__) && defined(IPSEC)	/*	 * If the packet needs outgoing IPsec crypto processing and the	 * interface doesn't support it, drop it.	 */	mtag = m_tag_find(m, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL);#endif /* IPSEC */	if ((ifp->if_flags & IFF_LOOPBACK) != 0) {#if defined(__OpenBSD__) && defined(IPSEC)		if (mtag != NULL &&		    (origifp->if_capabilities & IFCAP_IPSEC) == 0) {			/* Tell IPsec to do its own crypto. */			ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));			error = EACCES;			goto bad;		}#endif /* IPSEC */		return((*ifp->if_output)(origifp, m, (struct sockaddr *)dst,					 rt));	}#if defined(__OpenBSD__) && defined(IPSEC)	if (mtag != NULL &&	    (ifp->if_capabilities & IFCAP_IPSEC) == 0) {		/* Tell IPsec to do its own crypto. */		ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));		error = EACCES;		goto bad;	}#endif /* IPSEC */	return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt));  bad:	if (m)		m_freem(m);	return (error);}	#undef senderrintnd6_need_cache(ifp)	struct ifnet *ifp;{	/*	 * XXX: we currently do not make neighbor cache on any interface	 * other than ARCnet, Ethernet, FDDI and GIF.	 *	 * RFC2893 says:	 * - unidirectional tunnels needs no ND	 */	switch (ifp->if_type) {	case IFT_ARCNET:	case IFT_ETHER:	case IFT_FDDI:	case IFT_IEEE1394:#ifdef IFT_PROPVIRTUAL	case IFT_PROPVIRTUAL:#endif#ifdef IFT_L2VLAN	case IFT_L2VLAN:#endif#ifdef IFT_IEEE80211	case IFT_IEEE80211:#endif	case IFT_GIF:		/* XXX need more cases? */		return(1);	default:		return(0);	}}intnd6_storelladdr(ifp, rt, m, dst, desten)	struct ifnet *ifp;	struct rtentry *rt;	struct mbuf *m;	struct sockaddr *dst;	u_char *desten;{	int i;	struct sockaddr_dl *sdl;	if (m->m_flags & M_MCAST) {		switch (ifp->if_type) {		case IFT_ETHER:		case IFT_FDDI:#ifdef IFT_PROPVIRTUAL		case IFT_PROPVIRTUAL:#endif#ifdef IFT_L2VLAN		case IFT_L2VLAN:#endif#ifdef IFT_IEEE80211		case IFT_IEEE80211:#endif			ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr,						 desten);			return(1);		case IFT_IEEE1394:			/*			 * netbsd can use if_broadcastaddr, but we don't do so			 * to reduce # of ifdef.			 */			for (i = 0; i < ifp->if_addrlen; i++)				desten[i] = ~0;			return(1);		case IFT_ARCNET:			*desten = 0;			return(1);		default:			m_freem(m);			return(0);		}	}	if (rt == NULL) {		/* this could happen, if we could not allocate memory */		m_freem(m);		return(0);	}	if (rt->rt_gateway->sa_family != AF_LINK) {		printf("nd6_storelladdr: something odd happens\n");		m_freem(m);		return(0);	}	sdl = SDL(rt->rt_gateway);	if (sdl->sdl_alen == 0) {		/* this should be impossible, but we bark here for debugging */		printf("nd6_storelladdr: sdl_alen == 0, dst=%s, if=%s\n",		       ip6_sprintf(&SIN6(dst)->sin6_addr), if_name(ifp));		m_freem(m);		return(0);	}	bcopy(LLADDR(sdl), desten, sdl->sdl_alen);	return(1);}#ifdef CYGPKG_NET_FREEBSD_SYSCTLstatic int nd6_sysctl_drlist(SYSCTL_HANDLER_ARGS);static int nd6_sysctl_prlist(SYSCTL_HANDLER_ARGS);#endif#ifdef SYSCTL_DECLSYSCTL_DECL(_net_inet6_icmp6);#endifSYSCTL_NODE(_net_inet6_icmp6, ICMPV6CTL_ND6_DRLIST, nd6_drlist,	CTLFLAG_RD, nd6_sysctl_drlist, "");SYSCTL_NODE(_net_inet6_icmp6, ICMPV6CTL_ND6_PRLIST, nd6_prlist,	CTLFLAG_RD, nd6_sysctl_prlist, "");#ifdef CYGPKG_NET_FREEBSD_SYSCTLstatic intnd6_sysctl_drlist(SYSCTL_HANDLER_ARGS){	int error;	char buf[1024];	struct in6_defrouter *d, *de;	struct nd_defrouter *dr;	if (req->newptr)		return EPERM;	error = 0;	for (dr = TAILQ_FIRST(&nd_defrouter);	     dr;	     dr = TAILQ_NEXT(dr, dr_entry)) {		d = (struct in6_defrouter *)buf;		de = (struct in6_defrouter *)(buf + sizeof(buf));		if (d + 1 <= de) {			bzero(d, sizeof(*d));			d->rtaddr.sin6_family = AF_INET6;			d->rtaddr.sin6_len = sizeof(d->rtaddr);			if (in6_recoverscope(&d->rtaddr, &dr->rtaddr,			    dr->ifp) != 0)				log(LOG_ERR,				    "scope error in "				    "default router list (%s)\n",				    ip6_sprintf(&dr->rtaddr));			d->flags = dr->flags;			d->rtlifetime = dr->rtlifetime;			d->expire = dr->expire;			d->if_index = dr->ifp->if_index;		} else			panic("buffer too short");		error = SYSCTL_OUT(req, buf, sizeof(*d));		if (error)			break;	}	return error;}static intnd6_sysctl_prlist(SYSCTL_HANDLER_ARGS){	int error;	char buf[1024];	struct in6_prefix *p, *pe;	struct nd_prefix *pr;	if (req->newptr)		return EPERM;	error = 0;	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {		u_short advrtrs=0;		size_t advance;		struct sockaddr_in6 *sin6, *s6;		struct nd_pfxrouter *pfr;		p = (struct in6_prefix *)buf;		pe = (struct in6_prefix *)(buf + sizeof(buf));		if (p + 1 <= pe) {			bzero(p, sizeof(*p));			sin6 = (struct sockaddr_in6 *)(p + 1);			p->prefix = pr->ndpr_prefix;			if (in6_recoverscope(&p->prefix,			    &p->prefix.sin6_addr, pr->ndpr_ifp) != 0)				log(LOG_ERR,				    "scope error in prefix list (%s)\n",				    ip6_sprintf(&p->prefix.sin6_addr));			p->raflags = pr->ndpr_raf;			p->prefixlen = pr->ndpr_plen;			p->vltime = pr->ndpr_vltime;			p->pltime = pr->ndpr_pltime;			p->if_index = pr->ndpr_ifp->if_index;			p->expire = pr->ndpr_expire;			p->refcnt = pr->ndpr_refcnt;			p->flags = pr->ndpr_stateflags;			p->origin = PR_ORIG_RA;			advrtrs = 0;			for (pfr = pr->ndpr_advrtrs.lh_first;			     pfr;			     pfr = pfr->pfr_next) {				if ((void *)&sin6[advrtrs + 1] >

⌨️ 快捷键说明

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