📄 route.c
字号:
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.
*/
int
rtioctl(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
*/
int
rtrequest(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 int
rt_fixdelete(rn, vp)
struct radix_node *rn;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -