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

📄 route.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
			ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));		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;		if ((error = rt_setgate(rt, dst, gateway))) {			Free(rt);			senderr(error);		}		ndst = rt_key(rt);		if (netmask) {			rt_maskedcopy(dst, ndst, netmask);		} else			Bcopy(dst, ndst, dst->sa_len);		/*		 * This moved from below so that rnh->rnh_addaddr() can		 * examine the ifa and ifp if it so desires.		 */		ifa->ifa_refcnt++;		rt->rt_ifa = ifa;		rt->rt_ifp = ifa->ifa_ifp;		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) {				RTFREE(rt2);			}		}		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 (req == RTM_RESOLVE) {			rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */			if ((*ret_nrt)->rt_flags & RTF_PRCLONING) {				rt->rt_parent = (*ret_nrt);				(*ret_nrt)->rt_refcnt++;			}		}		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);		}		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(struct radix_node *rn, void *vp){	struct rtentry *rt = (struct rtentry *)rn;	struct rtentry *rt0 = vp;	if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) {		return rtrequest(RTM_DELETE, rt_key(rt),				 (struct sockaddr *)0, rt_mask(rt),				 rt->rt_flags, (struct rtentry **)0);	}	return 0;}/* * This routine is called from rt_setgate() to do the analogous thing for * adds and changes.  There is the added complication in this case of a * middle insert; i.e., insertion of a new network route between an older * network route and (cloned) host routes.  For this reason, a simple check * of rt->rt_parent is insufficient; each candidate route must be tested * against the (mask, value) of the new route (passed as before in vp) * to see if the new route matches it.  Unfortunately, this has the obnoxious * property of also triggering for insertion /above/ a pre-existing network * route and clones.  Sigh.  This may be fixed some day. * * XXX - it may be possible to do fixdelete() for changes and reserve this * routine just for adds.  I'm not sure why I thought it was necessary to do * changes this way. */#ifdef DEBUGint rtfcdebug = 0;#endifstatic intrt_fixchange(struct radix_node *rn, void *vp){	struct rtentry *rt = (struct rtentry *)rn;	struct rtfc_arg *ap = vp;	struct rtentry *rt0 = ap->rt0;	struct radix_node_head *rnh = ap->rnh;	u_char *xk1, *xm1, *xk2;	int i, len;#ifdef DEBUG	if (rtfcdebug)		printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0);#endif	if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) {#ifdef DEBUG		if(rtfcdebug) printf("no parent or pinned\n");#endif		return 0;	}	if (rt->rt_parent == rt0) {#ifdef DEBUG		if(rtfcdebug) printf("parent match\n");#endif		return rtrequest(RTM_DELETE, rt_key(rt),				 (struct sockaddr *)0, rt_mask(rt),				 rt->rt_flags, (struct rtentry **)0);	}	/*	 * There probably is a function somewhere which does this...	 * if not, there should be.	 */	len = imin(((struct sockaddr *)rt_key(rt0))->sa_len,		   ((struct sockaddr *)rt_key(rt))->sa_len);	xk1 = (u_char *)rt_key(rt0);	xm1 = (u_char *)rt_mask(rt0);	xk2 = (u_char *)rt_key(rt);	for (i = rnh->rnh_treetop->rn_off; i < len; i++) {		if ((xk2[i] & xm1[i]) != xk1[i]) {#ifdef DEBUG			if(rtfcdebug) printf("no match\n");#endif			return 0;		}	}	/*	 * OK, this node is a clone, and matches the node currently being	 * changed/added under the node's mask.  So, get rid of it.	 */#ifdef DEBUG	if(rtfcdebug) printf("deleting\n");#endif	return rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,			 rt_mask(rt), rt->rt_flags, (struct rtentry **)0);}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;	struct radix_node_head *rnh = rt_tables[dst->sa_family];	/*	 * A host route with the destination equal to the gateway	 * will interfere with keeping LLINFO in the routing	 * table, so disallow it.	 */	if (((rt0->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_LLINFO)) ==					(RTF_HOST|RTF_GATEWAY)) &&	    (dst->sa_len == gate->sa_len) &&	    (bcmp(dst, gate, dst->sa_len) == 0)) {		/*		 * The route might already exist if this is an RTM_CHANGE		 * or a routing redirect, so try to delete it.		 */		if (rt_key(rt0))			rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt0),			    rt0->rt_gateway, rt_mask(rt0), rt0->rt_flags, 0);		return EADDRNOTAVAIL;	}	if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {		old = (caddr_t)rt_key(rt);		R_Malloc(new, caddr_t, dlen + glen);		if (new == 0)			return ENOBUFS;		rt->rt_nodes->rn_key = new;	} else {		new = rt->rt_nodes->rn_key;		old = 0;	}	Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);	if (old) {		Bcopy(dst, new, dlen);		Free(old);	}	if (rt->rt_gwroute) {		rt = rt->rt_gwroute; RTFREE(rt);		rt = rt0; rt->rt_gwroute = 0;	}	/*	 * Cloning loop avoidance:	 * In the presence of protocol-cloning and bad configuration,	 * it is possible to get stuck in bottomless mutual recursion	 * (rtrequest rt_setgate rtalloc1).  We avoid this by not allowing	 * protocol-cloning to operate for gateways (which is probably the	 * correct choice anyway), and avoid the resulting reference loops	 * by disallowing any route to run through itself as a gateway.	 * This is obviuosly mandatory when we get rt->rt_output().	 */	if (rt->rt_flags & RTF_GATEWAY) {		rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING);		if (rt->rt_gwroute == rt) {			RTFREE(rt->rt_gwroute);			rt->rt_gwroute = 0;			return EDQUOT; /* failure */		}	}	/*	 * This isn't going to do anything useful for host routes, so	 * don't bother.  Also make sure we have a reasonable mask	 * (we don't yet have one during adds).	 */	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);	}	return 0;}static 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 = 0;	struct rtentry *nrt = 0;	int error;	dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;	/*	 * If it's a delete, check that if it exists, it's on the correct	 * interface or we might scrub a route to another ifa which would	 * be confusing at best and possibly worse.	 */	if (cmd == RTM_DELETE) {		/* 		 * It's a delete, so it should already exist..		 * If it's a net, mask off the host bits		 * (Assuming we have a mask)		 */		if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {			m = m_get(M_WAIT, MT_SONAME);			deldst = mtod(m, struct sockaddr *);			rt_maskedcopy(dst, deldst, ifa->ifa_netmask);			dst = deldst;		}		/*		 * Get an rtentry that is in the routing tree and		 * contains the correct info. (if this fails we can't get there).		 * We set "report" to FALSE so that if it doesn't exist,		 * it doesn't report an error or clone a route, etc. etc.		 */		rt = rtalloc1(dst, 0, 0UL);		if (rt) {			/*			 * Ok so we found the rtentry. it has an extra reference			 * for us at this stage. we won't need that so			 * lop that off now.			 */			rt->rt_refcnt--;			if (rt->rt_ifa != ifa) {				/*				 * If the interface in the rtentry doesn't match				 * the interface we are using, then we don't				 * want to delete it, so return an error.				 * This seems to be the only point of 				 * this whole RTM_DELETE clause.				 */				if (m)					(void) m_free(m);				return (flags & RTF_HOST ? EHOSTUNREACH							: ENETUNREACH);			}		}		/* XXX */#if 0		else {			/* 			 * One would think that as we are deleting, and we know			 * it doesn't exist, we could just return at this point			 * with an "ELSE" clause, but apparently not..			 */			return (flags & RTF_HOST ? EHOSTUNREACH							: ENETUNREACH);		}#endif	}	/*	 * Do the actual request	 */	error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,			flags | ifa->ifa_flags, &nrt);	if (m)		(void) m_free(m);	/*	 * If we are deleting, and we found an entry, then	 * it's been removed from the tree.. now throw it away.	 */	if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {		/*		 * notify any listenning routing agents of the change		 */		rt_newaddrmsg(cmd, ifa, error, nrt);		if (rt->rt_refcnt <= 0) {			rt->rt_refcnt++; /* need a 1->0 transition to free */			rtfree(rt);		}	}	/*	 * We are adding, and we have a returned routing entry.	 * We need to sanity check the result.	 */	if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {		/*		 * We just wanted to add it.. we don't actually need a reference		 */		rt->rt_refcnt--;		/*		 * If it came back with an unexpected interface, then it must 		 * have already existed or something. (XXX)		 */		if (rt->rt_ifa != ifa) {			printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,				rt->rt_ifa);			/*			 * Ask that the route we got back be removed			 * from the routing tables as we are trying			 * to supersede it.			 */			if (rt->rt_ifa->ifa_rtrequest)			    rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));			/* 			 * Remove the referenve to the it's ifaddr.			 */			IFAFREE(rt->rt_ifa);			/*			 * And substitute in references to the ifaddr			 * we are adding.			 */			rt->rt_ifa = ifa;			rt->rt_ifp = ifa->ifa_ifp;			ifa->ifa_refcnt++;			/*			 * Now add it to the routing table			 * XXX could we have just left it?			 * as it might have been in the right place..			 */			if (ifa->ifa_rtrequest)			    ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));		}		/*		 * notify any listenning routing agents of the change		 */		rt_newaddrmsg(cmd, ifa, error, nrt);	}	return (error);}

⌨️ 快捷键说明

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