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

📄 nd6.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			}		}		break;	case RTM_DELETE:		if (!ln)			break;		/* leave from solicited node multicast for proxy ND */		if ((rt->rt_flags & RTF_ANNOUNCE) != 0 &&		    (ifp->if_flags & IFF_MULTICAST) != 0) {			struct in6_addr llsol;			struct in6_multi *in6m;			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;			IN6_LOOKUP_MULTI(llsol, ifp, in6m);			if (in6m)				in6_delmulti(in6m);		}		nd6_inuse--;		ln->ln_next->ln_prev = ln->ln_prev;		ln->ln_prev->ln_next = ln->ln_next;		ln->ln_prev = NULL;		rt->rt_llinfo = 0;		rt->rt_flags &= ~RTF_LLINFO;		if (ln->ln_hold)			m_freem(ln->ln_hold);		Free((caddr_t)ln);	}}intnd6_ioctl(cmd, data, ifp)	u_long cmd;	caddr_t	data;	struct ifnet *ifp;{	struct in6_drlist *drl = (struct in6_drlist *)data;	struct in6_oprlist *oprl = (struct in6_oprlist *)data;	struct in6_ndireq *ndi = (struct in6_ndireq *)data;	struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data;	struct in6_ndifreq *ndif = (struct in6_ndifreq *)data;	struct nd_defrouter *dr;	struct nd_prefix *pr;	struct rtentry *rt;	int i = 0, error = 0;	int s;	switch (cmd) {	case SIOCGDRLST_IN6:		/*		 * obsolete API, use sysctl under net.inet6.icmp6		 */		bzero(drl, sizeof(*drl));#ifdef __NetBSD__		s = splsoftnet();#else		s = splnet();#endif		dr = TAILQ_FIRST(&nd_defrouter);		while (dr && i < DRLSTSIZ) {			drl->defrouter[i].rtaddr = dr->rtaddr;			if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) {				/* XXX: need to this hack for KAME stack */				drl->defrouter[i].rtaddr.s6_addr16[1] = 0;			} else				log(LOG_ERR,				    "default router list contains a "				    "non-linklocal address(%s)\n",				    ip6_sprintf(&drl->defrouter[i].rtaddr));			drl->defrouter[i].flags = dr->flags;			drl->defrouter[i].rtlifetime = dr->rtlifetime;			drl->defrouter[i].expire = dr->expire;			drl->defrouter[i].if_index = dr->ifp->if_index;			i++;			dr = TAILQ_NEXT(dr, dr_entry);		}		splx(s);		break;	case SIOCGPRLST_IN6:		/*		 * obsolete API, use sysctl under net.inet6.icmp6		 *		 * XXX the structure in6_prlist was changed in backward-		 * incompatible manner.  in6_oprlist is used for SIOCGPRLST_IN6,		 * in6_prlist is used for nd6_sysctl() - fill_prlist().		 */		/*		 * XXX meaning of fields, especialy "raflags", is very		 * differnet between RA prefix list and RR/static prefix list.		 * how about separating ioctls into two?		 */		bzero(oprl, sizeof(*oprl));#ifdef __NetBSD__		s = splsoftnet();#else		s = splnet();#endif		pr = nd_prefix.lh_first;		while (pr && i < PRLSTSIZ) {			struct nd_pfxrouter *pfr;			int j;			(void)in6_embedscope(&oprl->prefix[i].prefix,					     &pr->ndpr_prefix);			oprl->prefix[i].raflags = pr->ndpr_raf;			oprl->prefix[i].prefixlen = pr->ndpr_plen;			oprl->prefix[i].vltime = pr->ndpr_vltime;			oprl->prefix[i].pltime = pr->ndpr_pltime;			oprl->prefix[i].if_index = pr->ndpr_ifp->if_index;			if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME)				oprl->prefix[i].expire = 0;			else {				time_t maxexpire;				/* XXX: we assume time_t is signed. */				maxexpire = (-1) &					~(1 << ((sizeof(maxexpire) * 8) - 1));				if (pr->ndpr_vltime <				    maxexpire - pr->ndpr_lastupdate) {					oprl->prefix[i].expire =						 pr->ndpr_lastupdate +						pr->ndpr_vltime;				} else					oprl->prefix[i].expire = maxexpire;			}			pfr = pr->ndpr_advrtrs.lh_first;			j = 0;			while (pfr) {				if (j < DRLSTSIZ) {#define RTRADDR oprl->prefix[i].advrtr[j]					RTRADDR = pfr->router->rtaddr;					if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) {						/* XXX: hack for KAME */						RTRADDR.s6_addr16[1] = 0;					} else						log(LOG_ERR,						    "a router(%s) advertises "						    "a prefix with "						    "non-link local address\n",						    ip6_sprintf(&RTRADDR));#undef RTRADDR				}				j++;				pfr = pfr->pfr_next;			}			oprl->prefix[i].advrtrs = j;			oprl->prefix[i].origin = PR_ORIG_RA;			i++;			pr = pr->ndpr_next;		}		splx(s);		break;	case OSIOCGIFINFO_IN6:		if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {			error = EINVAL;			break;		}		ndi->ndi.linkmtu = nd_ifinfo[ifp->if_index].linkmtu;		ndi->ndi.maxmtu = nd_ifinfo[ifp->if_index].maxmtu;		ndi->ndi.basereachable =		    nd_ifinfo[ifp->if_index].basereachable;		ndi->ndi.reachable = nd_ifinfo[ifp->if_index].reachable;		ndi->ndi.retrans = nd_ifinfo[ifp->if_index].retrans;		ndi->ndi.flags = nd_ifinfo[ifp->if_index].flags;		ndi->ndi.recalctm = nd_ifinfo[ifp->if_index].recalctm;		ndi->ndi.chlim = nd_ifinfo[ifp->if_index].chlim;		ndi->ndi.receivedra = nd_ifinfo[ifp->if_index].receivedra;		break;	case SIOCGIFINFO_IN6:		if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {			error = EINVAL;			break;		}		ndi->ndi = nd_ifinfo[ifp->if_index];		break;	case SIOCSIFINFO_FLAGS:		/* XXX: almost all other fields of ndi->ndi is unused */		if (!nd_ifinfo || i >= nd_ifinfo_indexlim) {			error = EINVAL;			break;		}		nd_ifinfo[ifp->if_index].flags = ndi->ndi.flags;		break;	case SIOCSNDFLUSH_IN6:	/* XXX: the ioctl name is confusing... */		/* sync kernel routing table with the default router list */		defrouter_reset();		defrouter_select();		break;	case SIOCSPFXFLUSH_IN6:	    {		/* flush all the prefix advertised by routers */		struct nd_prefix *pr, *next;#ifdef __NetBSD__		s = splsoftnet();#else		s = splnet();#endif		for (pr = nd_prefix.lh_first; pr; pr = next) {			struct in6_ifaddr *ia, *ia_next;			next = pr->ndpr_next;			if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))				continue; /* XXX */			/* do we really have to remove addresses as well? */			for (ia = in6_ifaddr; ia; ia = ia_next) {				/* ia might be removed.  keep the next ptr. */				ia_next = ia->ia_next;				if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)					continue;				if (ia->ia6_ndpr == pr)					in6_purgeaddr(&ia->ia_ifa);			}			prelist_remove(pr);		}		splx(s);		break;	    }	case SIOCSRTRFLUSH_IN6:	    {		/* flush all the default routers */		struct nd_defrouter *dr, *next;#ifdef __NetBSD__		s = splsoftnet();#else		s = splnet();#endif		defrouter_reset();		for (dr = TAILQ_FIRST(&nd_defrouter); dr; dr = next) {			next = TAILQ_NEXT(dr, dr_entry);			defrtrlist_del(dr);		}		defrouter_select();		splx(s);		break;	    }	case SIOCGNBRINFO_IN6:	    {		struct llinfo_nd6 *ln;		struct in6_addr nb_addr = nbi->addr; /* make local for safety */		/*		 * XXX: KAME specific hack for scoped addresses		 *      XXXX: for other scopes than link-local?		 */		if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) ||		    IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) {			u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2];			if (*idp == 0)				*idp = htons(ifp->if_index);		}#ifdef __NetBSD__		s = splsoftnet();#else		s = splnet();#endif		if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL ||		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) == NULL) {			error = EINVAL;			splx(s);			break;		}		nbi->state = ln->ln_state;		nbi->asked = ln->ln_asked;		nbi->isrouter = ln->ln_router;		nbi->expire = ln->ln_expire;		splx(s);				break;	    }	case SIOCGDEFIFACE_IN6:	/* XXX: should be implemented as a sysctl? */		ndif->ifindex = nd6_defifindex;		break;	case SIOCSDEFIFACE_IN6:	/* XXX: should be implemented as a sysctl? */		return(nd6_setdefaultiface(ndif->ifindex));		break;	}	return(error);}/* * Create neighbor cache entry and cache link-layer address, * on reception of inbound ND6 packets.  (RS/RA/NS/redirect) */struct rtentry *nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code)	struct ifnet *ifp;	struct in6_addr *from;	char *lladdr;	int lladdrlen;	int type;	/* ICMP6 type */	int code;	/* type dependent information */{	struct rtentry *rt = NULL;	struct llinfo_nd6 *ln = NULL;	int is_newentry;	struct sockaddr_dl *sdl = NULL;	int do_update;	int olladdr;	int llchange;	int newstate = 0;#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)	long time_second = time.tv_sec;#endif	if (!ifp)		panic("ifp == NULL in nd6_cache_lladdr");	if (!from)		panic("from == NULL in nd6_cache_lladdr");	/* nothing must be updated for unspecified address */	if (IN6_IS_ADDR_UNSPECIFIED(from))		return NULL;	/*	 * Validation about ifp->if_addrlen and lladdrlen must be done in	 * the caller.	 *	 * XXX If the link does not have link-layer adderss, what should	 * we do? (ifp->if_addrlen == 0)	 * Spec says nothing in sections for RA, RS and NA.  There's small	 * description on it in NS section (RFC 2461 7.2.3).	 */	rt = nd6_lookup(from, 0, ifp);	if (!rt) {#if 0		/* nothing must be done if there's no lladdr */		if (!lladdr || !lladdrlen)			return NULL;#endif		rt = nd6_lookup(from, 1, ifp);		is_newentry = 1;	} else {		/* do nothing if static ndp is set */		if (rt->rt_flags & RTF_STATIC)			return NULL;		is_newentry = 0;	}	if (!rt)		return NULL;	if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) {fail:		(void)nd6_free(rt, 0);		return NULL;	}	ln = (struct llinfo_nd6 *)rt->rt_llinfo;	if (!ln)		goto fail;	if (!rt->rt_gateway)		goto fail;	if (rt->rt_gateway->sa_family != AF_LINK)		goto fail;	sdl = SDL(rt->rt_gateway);	olladdr = (sdl->sdl_alen) ? 1 : 0;	if (olladdr && lladdr) {		if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen))			llchange = 1;		else			llchange = 0;	} else		llchange = 0;	/*	 * newentry olladdr  lladdr  llchange	(*=record)	 *	0	n	n	--	(1)	 *	0	y	n	--	(2)	 *	0	n	y	--	(3) * STALE	 *	0	y	y	n	(4) *	 *	0	y	y	y	(5) * STALE	 *	1	--	n	--	(6)   NOSTATE(= PASSIVE)	 *	1	--	y	--	(7) * STALE	 */	if (lladdr) {		/* (3-5) and (7) */		/*		 * Record source link-layer address		 * XXX is it dependent to ifp->if_type?		 */		sdl->sdl_alen = ifp->if_addrlen;		bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen);	}	if (!is_newentry) {		if ((!olladdr && lladdr)		/* (3) */		 || (olladdr && lladdr && llchange)) {	/* (5) */			do_update = 1;			newstate = ND6_LLINFO_STALE;		} else					/* (1-2,4) */			do_update = 0;	} else {		do_update = 1;		if (!lladdr)				/* (6) */			newstate = ND6_LLINFO_NOSTATE;		else					/* (7) */			newstate = ND6_LLINFO_STALE;	}	if (do_update) {		/*		 * Update the state of the neighbor cache.		 */		ln->ln_state = newstate;		if (ln->ln_state == ND6_LLINFO_STALE) {			/*			 * XXX: since nd6_output() below will cause			 * state tansition to DELAY and reset the timer,			 * we must set the timer now, although it is actually			 * meaningless.			 */			ln->ln_expire = time_second + nd6_gctimer;			if (ln->ln_hold) {				/*				 * we assume ifp is not a p2p here, so just				 * set the 2nd argument as the 1st one.				 */				nd6_output(ifp, ifp, ln->ln_hold,					   (struct sockaddr_in6 *)rt_key(rt),					   rt);				ln->ln_hold = NULL;			}		} else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {			/* probe right away */			ln->ln_expire = time_second;		}	}	/*	 * ICMP6 type dependent behavior.	 *	 * NS: clear IsRouter if new entry	 * RS: clear IsRouter	 * RA: set IsRouter if there's lladdr	 * redir: clear IsRouter if new entry	 *	 * RA case, (1):	 * The spec says that we must set IsRouter in the following cases:	 * - If lladdr exist, set IsRouter.  This means (1-5).	 * - If it is old entry (!newentry), set IsRouter.  This means (7).	 * So, based on the spec, in (1-5) and (7) cases we must set IsRouter.	 * A quetion arises for (1) case.  (1) case has no lladdr in the	 * neighbor cache, this is similar to (6).	 * This case is rare but we figured that we MUST NOT set IsRouter.	 *	 * newentry olladdr  lladdr  llchange	    NS  RS  RA	redir	 *							D R	 *	0	n	n	--	(1)	c   ?     s	 *	0	y	n	--	(2)	c   s     s	 *	0	n	y	--	(3)	c   s     s	 *	0	y	y	n	(4)	c   s     s	 *	0	y	y	y	(5)	c   s     s	 *	1	--	n	--	(6) c	c 	c s	 *	1	--	y	--	(7) c	c   s	c s	 *	 *					(c=clear s=set)	 */	switch (type & 0xff) {	case ND_NEIGHBOR_SOLICIT:		/*		 * New entry must have is_router flag cleared.		 */		if (is_newentry)	/* (6-7) */			ln->ln_router = 0;		break;	case ND_REDIRECT:		/*		 * If the icmp is a redirect to a better router, always set the		 * is_router flag.  Otherwise, if the entry is newly created,		 * clear the flag.  [RFC 2461, sec 8.3]		 */		if (code == ND_REDIRECT_ROUTER)			ln->ln_router = 1;		else if (is_newentry) /* (6-7) */			ln->ln_router = 0;		break;	case ND_ROUTER_SOLICIT:		/*		 * is_router flag must always be cleared.

⌨️ 快捷键说明

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