route.c

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

C
1,191
字号
			stat = &rtstat.rts_dynamic;		} else {			/*			 * Smash the current notion of the gateway to			 * this destination.  Should check about netmask!!!			 */			rt->rt_flags |= RTF_MODIFIED;			flags |= RTF_MODIFIED;			stat = &rtstat.rts_newgateway;			/*			 * add the key and gateway (in one malloc'd chunk).			 */			rt_setgate(rt, rt_key(rt), gateway);		}	} else		error = EHOSTUNREACH;done:	if (rt) {		if (rtp && !error)			*rtp = rt;		else			rtfree(rt);	}out:	if (error)		rtstat.rts_badredirect++;	else if (stat != NULL)		(*stat)++;	bzero((caddr_t)&info, sizeof(info));	info.rti_info[RTAX_DST] = dst;	info.rti_info[RTAX_GATEWAY] = gateway;	info.rti_info[RTAX_NETMASK] = netmask;	info.rti_info[RTAX_AUTHOR] = src;	rt_missmsg(RTM_REDIRECT, &info, flags, error);}/** Routing table ioctl interface.*/intrtioctl(req, data, p)	int req;	caddr_t data;	struct proc *p;{#ifdef INET    struct ecos_rtentry *rt;    int res;    switch (req) {    case SIOCADDRT:        rt = (struct ecos_rtentry *)data;        res = rtrequest(RTM_ADD,                         &rt->rt_dst,                        &rt->rt_gateway,                        &rt->rt_genmask,                        rt->rt_flags,                        NULL);        return (res);    case SIOCDELRT:        rt = (struct ecos_rtentry *)data;        res = rtrequest(RTM_DELETE,                         &rt->rt_dst,                        &rt->rt_gateway,                        &rt->rt_genmask,                        rt->rt_flags,                        NULL);        return (res);    default:        break;    }	/* Multicast goop, grrr... */#ifdef MROUTING	return mrt_ioctl(req, data);#else	return mrt_ioctl(req, data, p);#endif#else /* INET */	return ENXIO;#endif /* INET */}struct ifaddr *ifa_ifwithroute(flags, dst, gateway)	int flags;	struct sockaddr	*dst, *gateway;{	register struct ifaddr *ifa;	if ((flags & RTF_GATEWAY) == 0) {		/*		 * If we are adding a route to an interface,		 * and the interface is a pt to pt link		 * we should search for the destination		 * as our clue to the interface.  Otherwise		 * we can use the local address.		 */		ifa = 0;		if (flags & RTF_HOST) {			ifa = ifa_ifwithdstaddr(dst);		}		if (ifa == 0)			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 == 0)		ifa = ifa_ifwithnet(gateway);	if (ifa == 0) {		struct rtentry *rt = rtalloc1(dst, 0, 0UL);		if (rt == 0)			return (0);		rt->rt_refcnt--;		if ((ifa = rt->rt_ifa) == 0)			return (0);	}	if (ifa->ifa_addr->sa_family != dst->sa_family) {		struct ifaddr *oifa = ifa;		ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);		if (ifa == 0)			ifa = oifa;	}	return (ifa);}#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))static int rt_fixdelete __P((struct radix_node *, void *));static int rt_fixchange __P((struct radix_node *, void *));struct rtfc_arg {	struct rtentry *rt0;	struct radix_node_head *rnh;};/* * Do appropriate manipulations of a routing tree given * all the bits of info needed */intrtrequest(req, dst, gateway, netmask, flags, ret_nrt)	int req, flags;	struct sockaddr *dst, *gateway, *netmask;	struct rtentry **ret_nrt;{	int s = splnet(); 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; }	/*	 * Find the correct routing tree to use for this Address Family	 */	if ((rnh = rt_tables[dst->sa_family]) == 0)		senderr(ESRCH);	/*	 * If we are adding a host route then we don't want to put	 * a netmask in the tree	 */	if (flags & RTF_HOST)		netmask = 0;	switch (req) {	case RTM_DELETE:		/*		 * Remove the item from the tree and return it.		 * Complain if it is not there and do no more processing.		 */		if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)			senderr(ESRCH);		if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))			panic ("rtrequest delete");		rt = (struct rtentry *)rn;		/*		 * Now search what's left of the subtree for any cloned		 * routes which might have been formed from this node.		 */		if ((rt->rt_flags & (RTF_CLONING | RTF_PRCLONING)) &&		    rt_mask(rt)) {			rnh->rnh_walktree_from(rnh, dst, rt_mask(rt),					       rt_fixdelete, rt);		}		/*		 * Remove any external references we may have.		 * This might result in another rtentry being freed if		 * we held its last reference.		 */		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;		}		/*		 * NB: RTF_UP must be set during the search above,		 * because we might delete the last ref, causing		 * rt to get freed prematurely.		 *  eh? then why not just add a reference?		 * I'm not sure how RTF_UP helps matters. (JRE)		 */		rt->rt_flags &= ~RTF_UP;		/*		 * give the protocol a chance to keep things in sync.		 */		if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)			ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));		/*		 * one more rtentry floating around that is not		 * linked to the routing table.		 */		rttrash++;		/*		 * If the caller wants it, then it can have it,		 * but it's up to it to free the rtentry as we won't be		 * doing it.		 */		if (ret_nrt)			*ret_nrt = rt;		else if (rt->rt_refcnt <= 0) {			rt->rt_refcnt++; /* make a 1->0 transition */			rtfree(rt);		}		break;	case RTM_RESOLVE:		if (ret_nrt == 0 || (rt = *ret_nrt) == 0)			senderr(EINVAL);		ifa = rt->rt_ifa;		flags = rt->rt_flags &		    ~(RTF_CLONING | RTF_PRCLONING | RTF_STATIC);		flags |= RTF_WASCLONED;		gateway = rt->rt_gateway;		if ((netmask = rt->rt_genmask) == 0)			flags |= RTF_HOST;		goto makeroute;	case RTM_ADD:		if ((flags & RTF_GATEWAY) && !gateway)			panic("rtrequest: GATEWAY but no gateway");		if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)			senderr(ENETUNREACH);	makeroute:		R_Malloc(rt, struct rtentry *, sizeof(*rt));		if (rt == 0)			senderr(ENOBUFS);		Bzero(rt, sizeof(*rt));		rt->rt_flags = RTF_UP | flags;		/*		 * Add the gateway. Possibly re-malloc-ing the storage for it		 * also add the rt_gwroute if possible.		 */		if ((error = rt_setgate(rt, dst, gateway)) != 0) {			Free(rt);			senderr(error);		}		/*		 * point to the (possibly newly malloc'd) dest address.		 */		ndst = rt_key(rt);		/*		 * make sure it contains the value we want (masked if needed).		 */		if (netmask) {			rt_maskedcopy(dst, ndst, netmask);		} else			Bcopy(dst, ndst, dst->sa_len);		/*		 * Note that we now have a reference to the ifa.		 * This moved from below so that rnh->rnh_addaddr() can		 * examine the ifa and  ifa->ifa_ifp if it so desires.		 */		ifa->ifa_refcnt++;		rt->rt_ifa = ifa;		rt->rt_ifp = ifa->ifa_ifp;		/* XXX mtu manipulation will be done in rnh_addaddr -- itojun */		rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,					rnh, rt->rt_nodes);		if (rn == 0) {			struct rtentry *rt2;			/*			 * Uh-oh, we already have one of these in the tree.			 * We do a special hack: if the route that's already			 * there was generated by the protocol-cloning			 * mechanism, then we just blow it away and retry			 * the insertion of the new one.			 */			rt2 = rtalloc1(dst, 0, RTF_PRCLONING);			if (rt2 && rt2->rt_parent) {				rtrequest(RTM_DELETE,					  (struct sockaddr *)rt_key(rt2),					  rt2->rt_gateway,					  rt_mask(rt2), rt2->rt_flags, 0);				RTFREE(rt2);				rn = rnh->rnh_addaddr((caddr_t)ndst,						      (caddr_t)netmask,						      rnh, rt->rt_nodes);			} else if (rt2) {				/* undo the extra ref we got */				RTFREE(rt2);			}		}		/*		 * If it still failed to go into the tree,		 * then un-make it (this should be a function)		 */		if (rn == 0) {			if (rt->rt_gwroute)				rtfree(rt->rt_gwroute);			if (rt->rt_ifa) {				IFAFREE(rt->rt_ifa);			}			Free(rt_key(rt));			Free(rt);			senderr(EEXIST);		}		rt->rt_parent = 0;		/*		 * If we got here from RESOLVE, then we are cloning		 * so clone the rest, and note that we		 * are a clone (and increment the parent's references)		 */		if (req == RTM_RESOLVE) {			rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */			if ((*ret_nrt)->rt_flags & (RTF_CLONING | RTF_PRCLONING)) {				rt->rt_parent = (*ret_nrt);				(*ret_nrt)->rt_refcnt++;			}		}		/*		 * if this protocol has something to add to this then		 * allow it to do that as well.		 */		if (ifa->ifa_rtrequest)			ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));		/*		 * We repeat the same procedure from rt_setgate() here because		 * it doesn't fire when we call it there because the node		 * hasn't been added to the tree yet.		 */		if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {			struct rtfc_arg arg;			arg.rnh = rnh;			arg.rt0 = rt;			rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),					       rt_fixchange, &arg);		}		/*		 * actually return a resultant rtentry and		 * give the caller a single reference.		 */		if (ret_nrt) {			*ret_nrt = rt;			rt->rt_refcnt++;		}		break;	}bad:	splx(s);	return (error);}/* * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family'' * (i.e., the routes related to it by the operation of cloning).  This * routine is iterated over all potential former-child-routes by way of * rnh->rnh_walktree_from() above, and those that actually are children of * the late parent (passed in as VP here) are themselves deleted. */static intrt_fixdelete(rn, vp)	struct radix_node *rn;

⌨️ 快捷键说明

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