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