nd6_rtr.c

来自「eCos操作系统源码」· C语言 代码 · 共 2,371 行 · 第 1/5 页

C
2,371
字号
			nd6log((LOG_INFO, "nd6_ra_input: mtu option "			    "mtu=%d sent from %s; maxmtu unknown, "			    "ignoring\n",			    mtu, ip6_sprintf(&ip6->ip6_src)));		}	} skip:		/*	 * Source link layer address	 */    {	char *lladdr = NULL;	int lladdrlen = 0;		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_ra_input: lladdrlen mismatch for %s "		    "(if %d, RA packet %d)\n",			ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2));		goto bad;	}	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);	/*	 * Installing a link-layer address might change the state of the	 * router's neighbor cache, which might also affect our on-link	 * detection of adveritsed prefixes.	 */	pfxlist_onlink_check();    } freeit:	m_freem(m);	return; bad:	icmp6stat.icp6s_badra++;	m_freem(m);}/* * default router list proccessing sub routines *//* tell the change to user processes watching the routing socket. */static voidnd6_rtmsg(cmd, rt)	int cmd;	struct rtentry *rt;{	struct rt_addrinfo info;	bzero((caddr_t)&info, sizeof(info));#if (defined(__bsdi__) && _BSDI_VERSION >= 199802) /* BSDI4 */	/* maybe this is unnecessary */	info.rti_flags = rt->rt_flags;#endif	info.rti_info[RTAX_DST] = rt_key(rt);	info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;	info.rti_info[RTAX_NETMASK] = rt_mask(rt);#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)	info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addrlist->ifa_addr;#else	info.rti_info[RTAX_IFP] =		(struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist);#endif	info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;	rt_missmsg(cmd, &info, rt->rt_flags, 0);}voiddefrouter_addreq(new)	struct nd_defrouter *new;{	struct sockaddr_in6 def, mask, gate;	struct rtentry *newrt = NULL;	int s;	int error;	Bzero(&def, sizeof(def));	Bzero(&mask, sizeof(mask));	Bzero(&gate, sizeof(gate));	def.sin6_len = mask.sin6_len = gate.sin6_len		= sizeof(struct sockaddr_in6);	def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;	gate.sin6_addr = new->rtaddr;#ifdef __NetBSD__	s = splsoftnet();#else	s = splnet();#endif	error = rtrequest(RTM_ADD, (struct sockaddr *)&def,		(struct sockaddr *)&gate, (struct sockaddr *)&mask,		RTF_GATEWAY, &newrt);	if (newrt) {		nd6_rtmsg(RTM_ADD, newrt); /* tell user process */		newrt->rt_refcnt--;	}	if (error == 0)		new->installed = 1;	splx(s);	return;}/* Add a route to a given interface as default */static voiddefrouter_addifreq(ifp)	struct ifnet *ifp;{	struct sockaddr_in6 def, mask;	struct ifaddr *ifa;	struct rtentry *newrt = NULL;	int error, flags;#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)	struct rt_addrinfo info;#endif	/* remove one if we have already installed one */	if (nd6_defif_installed)		defrouter_delifreq();	bzero(&def, sizeof(def));	bzero(&mask, sizeof(mask));	def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);	def.sin6_family = mask.sin6_family = AF_INET6;	/*	 * Search for an ifaddr beloging to the specified interface.	 * XXX: An IPv6 address are required to be assigned on the interface.	 */	if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) {		nd6log((LOG_ERR,	/* better error? */		    "defrouter_addifreq: failed to find an ifaddr "		    "to install a route to interface %s\n",		    if_name(ifp)));		return;	}	flags = ifa->ifa_flags;#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)	bzero(&info, sizeof(info));	info.rti_info[RTAX_DST] = (struct sockaddr *)&def;	info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)ifa->ifa_addr;	info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask;	info.rti_info[RTAX_IFA] = (struct sockaddr *)ifa->ifa_addr;	info.rti_flags = flags;	error = rtrequest1(RTM_ADD, &info, &newrt);#else	error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr,			  (struct sockaddr *)&mask, flags, &newrt);#endif	if (error != 0) {		nd6log((LOG_ERR,		    "defrouter_addifreq: failed to install a route to "		    "interface %s (errno = %d)\n",		    if_name(ifp), error));		if (newrt)	/* maybe unnecessary, but do it for safety */			newrt->rt_refcnt--;	} else {		if (newrt) {			nd6_rtmsg(RTM_ADD, newrt);			newrt->rt_refcnt--;		}	}	nd6_defif_installed = ifa;	IFAREF(ifa);}/* Remove a default route points to interface */static voiddefrouter_delifreq(){	struct sockaddr_in6 def, mask;	struct rtentry *oldrt = NULL;	if (!nd6_defif_installed)		return;	Bzero(&def, sizeof(def));	Bzero(&mask, sizeof(mask));	def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);	def.sin6_family = mask.sin6_family = AF_INET6;	rtrequest(RTM_DELETE, (struct sockaddr *)&def,	    (struct sockaddr *)nd6_defif_installed->ifa_addr,	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);	if (oldrt) {		nd6_rtmsg(RTM_DELETE, oldrt);		if (oldrt->rt_refcnt <= 0) {			/*			 * XXX: borrowed from the RTM_DELETE case of			 * rtrequest().			 */			oldrt->rt_refcnt++;			rtfree(oldrt);		}	}	IFAFREE(nd6_defif_installed);	nd6_defif_installed = NULL;}struct nd_defrouter *defrouter_lookup(addr, ifp)	struct in6_addr *addr;	struct ifnet *ifp;{	struct nd_defrouter *dr;	for (dr = TAILQ_FIRST(&nd_defrouter); dr;	     dr = TAILQ_NEXT(dr, dr_entry)) {		if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))			return(dr);	}	return(NULL);		/* search failed */}voiddefrtrlist_del(dr)	struct nd_defrouter *dr;{	struct nd_defrouter *deldr = NULL;	struct nd_prefix *pr;	/*	 * Flush all the routing table entries that use the router	 * as a next hop.	 */	if (!ip6_forwarding && ip6_accept_rtadv) {		/* above is a good condition? */		rt6_flush(&dr->rtaddr, dr->ifp);	}	if (dr->installed) {		deldr = dr;		defrouter_delreq(dr);	}	TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);	/*	 * Also delete all the pointers to the router in each prefix lists.	 */	for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {		struct nd_pfxrouter *pfxrtr;		if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)			pfxrtr_del(pfxrtr);	}	pfxlist_onlink_check();	/*	 * If the router is the primary one, choose a new one.	 * Note that defrouter_select() will remove the current gateway	 * from the routing table.	 */	if (deldr)		defrouter_select();	free(dr, M_IP6NDP);}/* * Remove the default route for a given router. * This is just a subroutine function for defrouter_select(), and should * not be called from anywhere else. */static voiddefrouter_delreq(dr)	struct nd_defrouter *dr;{	struct sockaddr_in6 def, mask, gw;	struct rtentry *oldrt = NULL;	Bzero(&def, sizeof(def));	Bzero(&mask, sizeof(mask));	Bzero(&gw, sizeof(gw));	def.sin6_len = mask.sin6_len = gw.sin6_len =	    sizeof(struct sockaddr_in6);	def.sin6_family = mask.sin6_family = gw.sin6_family = AF_INET6;	if (dr)		gw.sin6_addr = dr->rtaddr;	rtrequest(RTM_DELETE, (struct sockaddr *)&def,	    dr ? (struct sockaddr *)&gw : NULL,	    (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);	if (oldrt) {		nd6_rtmsg(RTM_DELETE, oldrt);		if (oldrt->rt_refcnt <= 0) {			/*			 * XXX: borrowed from the RTM_DELETE case of			 * rtrequest().			 */			oldrt->rt_refcnt++;			rtfree(oldrt);		}	}	if (dr)		dr->installed = 0;}/* * remove all default routes from default router list */voiddefrouter_reset(){	struct nd_defrouter *dr;	for (dr = TAILQ_FIRST(&nd_defrouter); dr;	     dr = TAILQ_NEXT(dr, dr_entry))		defrouter_delreq(dr);	defrouter_delifreq();	/*	 * XXX should we also nuke any default routers in the kernel, by 	 * going through them by rtalloc1()?	 */}/* * Default Router Selection according to Section 6.3.6 of RFC 2461 and * draft-ietf-ipngwg-router-selection: * 1) Routers that are reachable or probably reachable should be preferred. *    If we have more than one (probably) reachable router, prefer ones *    with the highest router preference. * 2) When no routers on the list are known to be reachable or *    probably reachable, routers SHOULD be selected in a round-robin *    fashion, regardless of router preference values. * 3) If the Default Router List is empty, assume that all *    destinations are on-link. * * We assume nd_defrouter is sorted by router preference value. * Since the code below covers both with and without router preference cases, * we do not need to classify the cases by ifdef. * * At this moment, we do not try to install more than one default router, * even when the multipath routing is available, because we're not sure about * the benefits for stub hosts comparing to the risk of making the code * complicated and the possibility of introducing bugs. */voiddefrouter_select(){#ifdef __NetBSD__	int s = splsoftnet();#else	int s = splnet();#endif	struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;	struct rtentry *rt = NULL;	struct llinfo_nd6 *ln = NULL;	/*	 * This function should be called only when acting as an autoconfigured	 * host.  Although the remaining part of this function is not effective	 * if the node is not an autoconfigured host, we explicitly exclude	 * such cases here for safety.	 */	if (ip6_forwarding || !ip6_accept_rtadv) {		nd6log((LOG_WARNING,		    "defrouter_select: called unexpectedly (forwarding=%d, "		    "accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv));		splx(s);		return;	}	/*	 * Let's handle easy case (3) first:	 * If default router list is empty, we should probably install	 * an interface route and assume that all destinations are on-link.	 */	if (!TAILQ_FIRST(&nd_defrouter)) {		/*		 * XXX: The specification does not say this mechanism should		 * be restricted to hosts, but this would be not useful		 * (even harmful) for routers.		 * This test is meaningless due to a test at the beginning of		 * the function, but we intentionally keep it to make the note		 * clear.		 */		if (!ip6_forwarding) {			if (nd6_defifp) {				/*				 * Install a route to the default interface				 * as default route.				 */				defrouter_addifreq(nd6_defifp);			} else {				/*				 * purge the existing route.				 * XXX: is this really correct?				 */				defrouter_delifreq();				nd6log((LOG_INFO, "defrouter_select: "				    "there's no default router and no default"				    " interface\n"));			}		}		splx(s);		return;	}	/*	 * If we have a default route for the default interface, delete it.	 * Note that the existence of the route is checked in the delete	 * function.	 */	defrouter_delifreq();	/*	 * Search for a (probably) reachable router from the list.	 * We just pick up the first reachable one (if any), assuming that	 * the ordering rule of the list described in defrtrlist_update().	 */	for (dr = TAILQ_FIRST(&nd_defrouter); dr;	     dr = TAILQ_NEXT(dr, dr_entry)) {		if (!selected_dr &&		    (rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&		    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&		    ND6_IS_LLINFO_PROBREACH(ln)) {			selected_dr = dr;		}		if (dr->installed && !installed_dr)			installed_dr = dr;		else if (dr->installed && installed_dr) {			/* this should not happen.  warn for diagnosis. */			log(LOG_ERR, "defrouter_select: more than one router"			    " is installed\n");		}	}	/*	 * If none of the default routers was found to be reachable,	 * round-robin the list regardless of preference.	 * Otherwise, if we have an installed router, check if the selected	 * (reachable) router should really be preferred to the installed one.	 * We only prefer the new router when the old one is not reachable	 * or when the new one has a really higher preference value.	 */	if (!selected_dr) {		if (!installed_dr || !TAILQ_NEXT(installed_dr, dr_entry))			selected_dr = TAILQ_FIRST(&nd_defrouter);		else 			selected_dr = TAILQ_NEXT(installed_dr, dr_entry);	} else if (installed_dr &&		   (rt = nd6_lookup(&installed_dr->rtaddr, 0,				    installed_dr->ifp)) &&		   (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&		   ND6_IS_LLINFO_PROBREACH(ln) &&		   rtpref(selected_dr) <= rtpref(installed_dr)) {			selected_dr = installed_dr;	}	/*	 * If the selected router is different than the installed one,	 * remove the installed router and install the selected one.	 * Note that the selected router is never NULL here.	 */

⌨️ 快捷键说明

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