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 + -
显示快捷键?