route.c

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

C
1,078
字号
		if (flags & RTF_HOST) 			ifa = ifa_ifwithdstaddr(dst);		if (ifa == NULL)			ifa = ifa_ifwithaddr(gateway);	} else {		/*		 * If we are adding a route to a remote net		 * or host, the gateway may still be on the		 * other end of a pt to pt link.		 */		ifa = ifa_ifwithdstaddr(gateway);	}	if (ifa == NULL)		ifa = ifa_ifwithnet(gateway);	if (ifa == NULL) {		struct rtentry *rt = rtalloc1(gateway, 0);		if (rt == NULL)			return (NULL);		rt->rt_refcnt--;		/* The gateway must be local if the same address family. */		if (!(flags & RTF_TUNNEL) && (rt->rt_flags & RTF_GATEWAY) && 		    rt_key(rt)->sa_family == dst->sa_family)			return (0);		if ((ifa = rt->rt_ifa) == NULL)			return (NULL);	}	if (ifa->ifa_addr->sa_family != dst->sa_family) {		struct ifaddr *oifa = ifa;		ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);		if (ifa == NULL)			ifa = oifa;	}	return (ifa);}#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))const char *_rt_cmd(int req){    switch (req)    {    case RTM_DELETE:        return "DELETE";    case RTM_RESOLVE:        return "RESOLVE";    case RTM_ADD:        return "ADD";    default:        return "???";    }}intrtrequest(req, dst, gateway, netmask, flags, ret_nrt)	int req, flags;	struct sockaddr *dst, *gateway, *netmask;	struct rtentry **ret_nrt;{	int s = splsoftnet(); int error = 0;	register struct rtentry *rt;	register struct radix_node *rn;	register struct radix_node_head *rnh;	struct ifaddr *ifa;	struct sockaddr *ndst;#define senderr(x) { error = x ; goto bad; }	if ((rnh = rt_tables[dst->sa_family]) == 0)		senderr(EAFNOSUPPORT);	if (flags & RTF_HOST)		netmask = 0;	switch (req) {	case RTM_DELETE:		if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL)			senderr(ESRCH);		if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))			panic ("rtrequest delete");		rt = (struct rtentry *)rn;		rt->rt_flags &= ~RTF_UP;		if (rt->rt_gwroute) {		    if (rt != rt->rt_gwroute)			RTFREE( rt->rt_gwroute ); // Free it up as normal		    else			rt->rt_refcnt--; // Just dec the refcount - freeing					 // it here would be premature		    rt->rt_gwroute = NULL;		}		if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)			ifa->ifa_rtrequest(RTM_DELETE, rt, SA(NULL));		rttrash++;		if (ret_nrt)			*ret_nrt = rt;		else if (rt->rt_refcnt <= 0) {			rt->rt_refcnt++;			rtfree(rt);		}		break;	case RTM_RESOLVE:		if (ret_nrt == NULL || (rt = *ret_nrt) == NULL)			senderr(EINVAL);		ifa = rt->rt_ifa;		flags = rt->rt_flags & ~RTF_CLONING;		gateway = rt->rt_gateway;		if ((netmask = rt->rt_genmask) == NULL)			flags |= RTF_HOST;		goto makeroute;	case RTM_ADD:		if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == NULL)			senderr(ENETUNREACH);		/* The interface found in the previous statement may		 * be overridden later by rt_setif.  See the code		 * for case RTM_ADD in rtsock.c:route_output.		 */	makeroute:		R_Malloc(rt, struct rtentry *, sizeof(*rt));		if (rt == NULL)			senderr(ENOBUFS);		Bzero(rt, sizeof(*rt));		rt->rt_flags = RTF_UP | flags;		LIST_INIT(&rt->rt_timer);		if (rt_setgate(rt, dst, gateway)) {			Free(rt);			senderr(ENOBUFS);		}		ndst = rt_key(rt);		if (netmask) {			rt_maskedcopy(dst, ndst, netmask);		} else			Bcopy(dst, ndst, dst->sa_len);if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { /* XXX */  rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu;}		rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,					rnh, rt->rt_nodes);		if (rn == NULL) {			if (rt->rt_gwroute)				rtfree(rt->rt_gwroute);			Free(rt_key(rt));			Free(rt);			senderr(EEXIST);		}		ifa->ifa_refcnt++;		rt->rt_ifa = ifa;		rt->rt_ifp = ifa->ifa_ifp;		if (req == RTM_RESOLVE) {			/*			 * Copy both metrics and a back pointer to the cloned			 * route's parent.			 */			rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */			rt->rt_parent = *ret_nrt;	 /* Back ptr. to parent. */		}		if (ifa->ifa_rtrequest)			ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : NULL));		if (ret_nrt) {			*ret_nrt = rt;			rt->rt_refcnt++;		}#ifdef INET6		/* If we have a v4_in_v4 or a v4_in_v6 tunnel route		 * then do some tunnel state (e.g. security state)		 * initialization.		 *		 * Since IPV6 packets flow down this path, we don't		 * want it using ipv4_tunnelsetup(rt) (since they		 * have their own ipv6_tunnel_parent/child()		 * routines which are called ipv6_rtrequest().)		 *		 * Thus, we check to see if the packet is to a v4		 * destination.		 */		if (dst->sa_family == AF_INET && (rt->rt_flags & RTF_TUNNEL))			ipv4_tunnelsetup(rt);#endif /* INET6 */		break;	}bad:	splx(s);	return (error);}/* * Set up any tunnel states (e.g. security) information * for v4_in_v4 or v4_in_v6 tunnel routes. */voidipv4_tunnelsetup(rt)	register struct rtentry *rt;{	/* XXX */}intrt_setgate(rt0, dst, gate)	struct rtentry *rt0;	struct sockaddr *dst, *gate;{	caddr_t new, old;	int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);	register struct rtentry *rt = rt0;	if (rt->rt_gateway == NULL || glen > ROUNDUP(rt->rt_gateway->sa_len)) {		old = (caddr_t)rt_key(rt);		R_Malloc(new, caddr_t, dlen + glen);		if (new == NULL)			return 1;		rt->rt_nodes->rn_key = new;	} else {		new = rt->rt_nodes->rn_key;		old = NULL;	}	Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);	if (old) {		Bcopy(dst, new, dlen);		Free(old);	}	if (rt->rt_gwroute != NULL) {		rt = rt->rt_gwroute;		RTFREE(rt);		rt = rt0;		rt->rt_gwroute = NULL;	}	if (rt->rt_flags & RTF_GATEWAY) {		rt->rt_gwroute = rtalloc1(gate, 1);	}	return 0;}voidrt_maskedcopy(src, dst, netmask)	struct sockaddr *src, *dst, *netmask;{	register u_char *cp1 = (u_char *)src;	register u_char *cp2 = (u_char *)dst;	register u_char *cp3 = (u_char *)netmask;	u_char *cplim = cp2 + *cp3;	u_char *cplim2 = cp2 + *cp1;	*cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */	cp3 += 2;	if (cplim > cplim2)		cplim = cplim2;	while (cp2 < cplim)		*cp2++ = *cp1++ & *cp3++;	if (cp2 < cplim2)		bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));}/* * Set up a routing table entry, normally * for an interface. */intrtinit(ifa, cmd, flags)	register struct ifaddr *ifa;	int cmd, flags;{	register struct rtentry *rt;	register struct sockaddr *dst;	register struct sockaddr *deldst;	struct mbuf *m = NULL;	struct rtentry *nrt = NULL;	int error;	dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;	if (cmd == RTM_DELETE) {		if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {			m = m_get(M_DONTWAIT, MT_SONAME);			if (m == NULL)				return(ENOBUFS);			deldst = mtod(m, struct sockaddr *);			rt_maskedcopy(dst, deldst, ifa->ifa_netmask);			dst = deldst;		}		if ((rt = rtalloc1(dst, 0)) != NULL) {			rt->rt_refcnt--;			if (rt->rt_ifa != ifa) {				if (m != NULL)					(void) m_free(m);				return (flags & RTF_HOST ? EHOSTUNREACH							: ENETUNREACH);			}		}	}	error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,			flags | ifa->ifa_flags, &nrt);	if (m != NULL)		(void) m_free(m);	if (cmd == RTM_DELETE && error == 0 && (rt = nrt) != NULL) {		rt_newaddrmsg(cmd, ifa, error, nrt);		if (rt->rt_refcnt <= 0) {			rt->rt_refcnt++;			rtfree(rt);		}	}	if (cmd == RTM_ADD && error == 0 && (rt = nrt) != NULL) {		rt->rt_refcnt--;#ifdef INET6		/* Initialize Path MTU for IPv6 interface route */		if (ifa->ifa_addr->sa_family == AF_INET6 &&		    !rt->rt_rmx.rmx_mtu)			rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu;#endif /* INET6 */		if (rt->rt_ifa != ifa) {#ifdef __ECOS			diag_printf("rtinit: wrong ifa (%x) was (%x)\n",			       ifa, rt->rt_ifa);#else			printf("rtinit: wrong ifa (%x) was (%x)\n",			       ifa, rt->rt_ifa);#endif			if (rt->rt_ifa->ifa_rtrequest)				rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt,				    SA(NULL));			IFAFREE(rt->rt_ifa);			rt->rt_ifa = ifa;			rt->rt_ifp = ifa->ifa_ifp;			rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu;	/*XXX*/			ifa->ifa_refcnt++;			if (ifa->ifa_rtrequest)				ifa->ifa_rtrequest(RTM_ADD, rt, SA(NULL));		}		rt_newaddrmsg(cmd, ifa, error, nrt);	}	return (error);}/* * Route timer routines.  These routes allow functions to be called * for various routes at any time.  This is useful in supporting * path MTU discovery and redirect route deletion. * * This is similar to some BSDI internal functions, but it provides * for multiple queues for efficiency's sake... */LIST_HEAD(, rttimer_queue) rttimer_queue_head;static int rt_init_done = 0;#define RTTIMER_CALLOUT(r)	{				\	if (r->rtt_func != NULL) {				\		(*r->rtt_func)(r->rtt_rt, r);			\	} else {						\		rtrequest((int) RTM_DELETE,			\			  (struct sockaddr *)rt_key(r->rtt_rt),	\			  0, 0, 0, 0);				\	}							\}/*  * Some subtle order problems with domain initialization mean that * we cannot count on this being run from rt_init before various * protocol initializations are done.  Therefore, we make sure * that this is run when the first queue is added... */void	 rt_timer_init(){#ifndef __ECOS	assert(rt_init_done == 0);#endif#if 0	pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl",	    0, NULL, NULL, M_RTABLE);#endif	LIST_INIT(&rttimer_queue_head);	timeout(rt_timer_timer, NULL, hz);  /* every second */	rt_init_done = 1;}struct rttimer_queue *rt_timer_queue_create(timeout)	u_int	timeout;{	struct rttimer_queue *rtq;	if (rt_init_done == 0)		rt_timer_init();	R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);	if (rtq == NULL)		return (NULL);			rtq->rtq_timeout = timeout;	TAILQ_INIT(&rtq->rtq_head);	LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);	return (rtq);}voidrt_timer_queue_change(rtq, timeout)	struct rttimer_queue *rtq;	long timeout;{	rtq->rtq_timeout = timeout;}voidrt_timer_queue_destroy(rtq, destroy)	struct rttimer_queue *rtq;	int destroy;{	struct rttimer *r;	while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {		LIST_REMOVE(r, rtt_link);		TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);		if (destroy)			RTTIMER_CALLOUT(r);#if 0		pool_put(&rttimer_pool, r);#else		free(r, M_RTABLE);#endif	}	LIST_REMOVE(rtq, rtq_link);	/*	 * Caller is responsible for freeing the rttimer_queue structure.	 */}void     rt_timer_remove_all(rt)	struct rtentry *rt;{	struct rttimer *r;	while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {		LIST_REMOVE(r, rtt_link);		TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);#if 0		pool_put(&rttimer_pool, r);#else		free(r, M_RTABLE);#endif	}}int      rt_timer_add(rt, func, queue)	struct rtentry *rt;	void(*func) __P((struct rtentry *, struct rttimer *));	struct rttimer_queue *queue;{	struct rttimer *r;	long current_time;	int s;	s = splclock();#ifdef __ECOS        get_mono_time();#endif	current_time = mono_time.tv_sec;	splx(s);	/*	 * If there's already a timer with this action, destroy it before	 * we add a new one.	 */	for (r = LIST_FIRST(&rt->rt_timer); r != NULL;	     r = LIST_NEXT(r, rtt_link)) {		if (r->rtt_func == func) {			LIST_REMOVE(r, rtt_link);			TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);#if 0			pool_put(&rttimer_pool, r);#else			free(r, M_RTABLE);#endif			break;  /* only one per list, so we can quit... */		}	}#if 0	r = pool_get(&rttimer_pool, PR_NOWAIT);#else	r = (struct rttimer *)malloc(sizeof(*r), M_RTABLE, M_NOWAIT);#endif	if (r == NULL)		return (ENOBUFS);	r->rtt_rt = rt;	r->rtt_time = current_time;	r->rtt_func = func;	r->rtt_queue = queue;	LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);	TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);		return (0);}/* ARGSUSED */voidrt_timer_timer(arg)	void *arg;{	struct rttimer_queue *rtq;	struct rttimer *r;	long current_time;	int s;	s = splclock();#ifdef __ECOS        get_mono_time();#endif	current_time = mono_time.tv_sec;	splx(s);	s = splsoftnet();	for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL; 	     rtq = LIST_NEXT(rtq, rtq_link)) {		while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&		    (r->rtt_time + rtq->rtq_timeout) < current_time) {			LIST_REMOVE(r, rtt_link);			TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);			RTTIMER_CALLOUT(r);#if 0			pool_put(&rttimer_pool, r);#else			free(r, M_RTABLE);#endif		}	}	splx(s);	timeout(rt_timer_timer, NULL, hz);  /* every second */}

⌨️ 快捷键说明

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