route.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 782 行 · 第 1/2 页

C
782
字号
					       rt_fixdelete, rt);		}		if (rt->rt_gwroute) {			rt = rt->rt_gwroute; RTFREE(rt);			(rt = (struct rtentry *)rn)->rt_gwroute = 0;		}		/*		 * NB: RTF_UP must be set during the search above,		 * because we might delete the last ref, causing		 * rt to get freed prematurely.		 */		rt->rt_flags &= ~RTF_UP;		if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)			ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));		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 == 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 (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);		/*		 * 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)) {			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];	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 1;		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 1; /* 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;}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 (cmd == RTM_DELETE) {		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;		}		rt = rtalloc1(dst, 0, 0UL);		if (rt) {			rt->rt_refcnt--;			if (rt->rt_ifa != ifa) {				if (m)					(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)		(void) m_free(m);	if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {		rt_newaddrmsg(cmd, ifa, error, nrt);		if (rt->rt_refcnt <= 0) {			rt->rt_refcnt++;			rtfree(rt);		}	}	if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {		rt->rt_refcnt--;		if (rt->rt_ifa != ifa) {			printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,				rt->rt_ifa);			if (rt->rt_ifa->ifa_rtrequest)			    rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));			IFAFREE(rt->rt_ifa);			rt->rt_ifa = ifa;			rt->rt_ifp = ifa->ifa_ifp;			ifa->ifa_refcnt++;			if (ifa->ifa_rtrequest)			    ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));		}		rt_newaddrmsg(cmd, ifa, error, nrt);	}	return (error);}

⌨️ 快捷键说明

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