version 1.121, 2009/11/03 00:30:11 |
version 1.121.4.4, 2011/04/21 01:42:13 |
|
|
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
|
#include <sys/kmem.h> |
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/callout.h> |
#include <sys/callout.h> |
Line 124 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 125 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#define rtcache_debug() 0 |
#define rtcache_debug() 0 |
#endif /* RTFLUSH_DEBUG */ |
#endif /* RTFLUSH_DEBUG */ |
|
|
struct route_cb route_cb; |
|
struct rtstat rtstat; |
struct rtstat rtstat; |
struct radix_node_head *rt_tables[AF_MAX+1]; |
|
|
|
int rttrash; /* routes not in table but not freed */ |
int rttrash; /* routes not in table but not freed */ |
|
|
Line 253 rt_set_ifa(struct rtentry *rt, struct if |
|
Line 252 rt_set_ifa(struct rtentry *rt, struct if |
|
rt_set_ifa1(rt, ifa); |
rt_set_ifa1(rt, ifa); |
} |
} |
|
|
void |
|
rtable_init(void **table) |
|
{ |
|
struct domain *dom; |
|
DOMAIN_FOREACH(dom) |
|
if (dom->dom_rtattach) |
|
dom->dom_rtattach(&table[dom->dom_family], |
|
dom->dom_rtoffset); |
|
} |
|
|
|
static int |
static int |
route_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, |
route_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, |
void *arg0, void *arg1, void *arg2, void *arg3) |
void *arg0, void *arg1, void *arg2, void *arg3) |
Line 283 route_listener_cb(kauth_cred_t cred, kau |
|
Line 272 route_listener_cb(kauth_cred_t cred, kau |
|
} |
} |
|
|
void |
void |
route_init(void) |
rt_init(void) |
{ |
{ |
|
|
#ifdef RTFLUSH_DEBUG |
#ifdef RTFLUSH_DEBUG |
Line 295 route_init(void) |
|
Line 284 route_init(void) |
|
pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", |
pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", |
NULL, IPL_SOFTNET); |
NULL, IPL_SOFTNET); |
|
|
rt_init(); |
|
rn_init(); /* initialize all zeroes, all ones, mask table */ |
rn_init(); /* initialize all zeroes, all ones, mask table */ |
rtable_init((void **)rt_tables); |
rtbl_init(); |
|
|
route_listener = kauth_listen_scope(KAUTH_SCOPE_NETWORK, |
route_listener = kauth_listen_scope(KAUTH_SCOPE_NETWORK, |
route_listener_cb, NULL); |
route_listener_cb, NULL); |
Line 340 rtcache(struct route *ro) |
|
Line 328 rtcache(struct route *ro) |
|
struct rtentry * |
struct rtentry * |
rtalloc1(const struct sockaddr *dst, int report) |
rtalloc1(const struct sockaddr *dst, int report) |
{ |
{ |
struct radix_node_head *rnh = rt_tables[dst->sa_family]; |
rtbl_t *rtbl = rt_gettable(dst->sa_family); |
struct rtentry *rt; |
struct rtentry *rt; |
struct radix_node *rn; |
|
struct rtentry *newrt = NULL; |
struct rtentry *newrt = NULL; |
struct rt_addrinfo info; |
struct rt_addrinfo info; |
int s = splsoftnet(), err = 0, msgtype = RTM_MISS; |
int s = splsoftnet(), err = 0, msgtype = RTM_MISS; |
|
|
if (rnh && (rn = rnh->rnh_matchaddr(dst, rnh)) && |
if (rtbl != NULL && (rt = rt_matchaddr(rtbl, dst)) != NULL) { |
((rn->rn_flags & RNF_ROOT) == 0)) { |
newrt = rt; |
newrt = rt = (struct rtentry *)rn; |
|
if (report && (rt->rt_flags & RTF_CLONING)) { |
if (report && (rt->rt_flags & RTF_CLONING)) { |
err = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0, |
err = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0, |
&newrt); |
&newrt); |
Line 397 rtfree(struct rtentry *rt) |
|
Line 383 rtfree(struct rtentry *rt) |
|
panic("rtfree"); |
panic("rtfree"); |
rt->rt_refcnt--; |
rt->rt_refcnt--; |
if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { |
if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { |
if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT)) |
rt_assert_inactive(rt); |
panic ("rtfree 2"); |
|
rttrash--; |
rttrash--; |
if (rt->rt_refcnt < 0) { |
if (rt->rt_refcnt < 0) { |
printf("rtfree: %p not freed (neg refs)\n", rt); |
printf("rtfree: %p not freed (neg refs)\n", rt); |
Line 490 rtredirect(const struct sockaddr *dst, c |
|
Line 475 rtredirect(const struct sockaddr *dst, c |
|
if (rt != NULL) |
if (rt != NULL) |
rtfree(rt); |
rtfree(rt); |
flags |= RTF_GATEWAY | RTF_DYNAMIC; |
flags |= RTF_GATEWAY | RTF_DYNAMIC; |
|
memset(&info, 0, sizeof(info)); |
info.rti_info[RTAX_DST] = dst; |
info.rti_info[RTAX_DST] = dst; |
info.rti_info[RTAX_GATEWAY] = gateway; |
info.rti_info[RTAX_GATEWAY] = gateway; |
info.rti_info[RTAX_NETMASK] = netmask; |
info.rti_info[RTAX_NETMASK] = netmask; |
|
|
rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) |
rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) |
{ |
{ |
int s = splsoftnet(); |
int s = splsoftnet(); |
int error = 0; |
int error = 0, rc; |
struct rtentry *rt, *crt; |
struct rtentry *rt, *crt; |
struct radix_node *rn; |
rtbl_t *rtbl; |
struct radix_node_head *rnh; |
struct ifaddr *ifa, *ifa2; |
struct ifaddr *ifa; |
|
struct sockaddr_storage maskeddst; |
struct sockaddr_storage maskeddst; |
const struct sockaddr *dst = info->rti_info[RTAX_DST]; |
const struct sockaddr *dst = info->rti_info[RTAX_DST]; |
const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY]; |
const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY]; |
Line 710 rtrequest1(int req, struct rt_addrinfo * |
|
Line 695 rtrequest1(int req, struct rt_addrinfo * |
|
int flags = info->rti_flags; |
int flags = info->rti_flags; |
#define senderr(x) { error = x ; goto bad; } |
#define senderr(x) { error = x ; goto bad; } |
|
|
if ((rnh = rt_tables[dst->sa_family]) == NULL) |
if ((rtbl = rt_gettable(dst->sa_family)) == NULL) |
senderr(ESRCH); |
senderr(ESRCH); |
if (flags & RTF_HOST) |
if (flags & RTF_HOST) |
netmask = NULL; |
netmask = NULL; |
Line 721 rtrequest1(int req, struct rt_addrinfo * |
|
Line 706 rtrequest1(int req, struct rt_addrinfo * |
|
netmask); |
netmask); |
dst = (struct sockaddr *)&maskeddst; |
dst = (struct sockaddr *)&maskeddst; |
} |
} |
if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == NULL) |
if ((rt = rt_lookup(rtbl, dst, netmask)) == NULL) |
senderr(ESRCH); |
senderr(ESRCH); |
rt = (struct rtentry *)rn; |
|
if ((rt->rt_flags & RTF_CLONING) != 0) { |
if ((rt->rt_flags & RTF_CLONING) != 0) { |
/* clean up any cloned children */ |
/* clean up any cloned children */ |
rtflushclone(dst->sa_family, rt); |
rtflushclone(dst->sa_family, rt); |
} |
} |
if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL) |
if ((rt = rt_deladdr(rtbl, dst, netmask)) == NULL) |
senderr(ESRCH); |
senderr(ESRCH); |
if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) |
|
panic ("rtrequest delete"); |
|
rt = (struct rtentry *)rn; |
|
if (rt->rt_gwroute) { |
if (rt->rt_gwroute) { |
RTFREE(rt->rt_gwroute); |
RTFREE(rt->rt_gwroute); |
rt->rt_gwroute = NULL; |
rt->rt_gwroute = NULL; |
Line 803 rtrequest1(int req, struct rt_addrinfo * |
|
Line 784 rtrequest1(int req, struct rt_addrinfo * |
|
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
} |
} |
rt_set_ifa(rt, ifa); |
rt_set_ifa(rt, ifa); |
|
if (info->rti_info[RTAX_TAG] != NULL) |
|
rt_settag(rt, info->rti_info[RTAX_TAG]); |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
rt->rt_ifp = ifa->ifa_ifp; |
if (info->rti_info[RTAX_IFP] != NULL && |
|
(ifa2 = ifa_ifwithnet(info->rti_info[RTAX_IFP])) != NULL && |
|
ifa2->ifa_ifp != NULL) |
|
rt->rt_ifp = ifa2->ifa_ifp; |
|
else |
|
rt->rt_ifp = ifa->ifa_ifp; |
if (req == RTM_RESOLVE) { |
if (req == RTM_RESOLVE) { |
rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ |
rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ |
rt->rt_parent = *ret_nrt; |
rt->rt_parent = *ret_nrt; |
rt->rt_parent->rt_refcnt++; |
rt->rt_parent->rt_refcnt++; |
} |
} |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
rn = rnh->rnh_addaddr(rt_getkey(rt), netmask, rnh, |
rc = rt_addaddr(rtbl, rt, netmask); |
rt->rt_nodes); |
|
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
if (rn == NULL && (crt = rtalloc1(rt_getkey(rt), 0)) != NULL) { |
if (rc != 0 && (crt = rtalloc1(rt_getkey(rt), 0)) != NULL) { |
/* overwrite cloned route */ |
/* overwrite cloned route */ |
if ((crt->rt_flags & RTF_CLONED) != 0) { |
if ((crt->rt_flags & RTF_CLONED) != 0) { |
rtdeletemsg(crt); |
rtdeletemsg(crt); |
rn = rnh->rnh_addaddr(rt_getkey(rt), |
rc = rt_addaddr(rtbl, rt, netmask); |
netmask, rnh, rt->rt_nodes); |
|
} |
} |
RTFREE(crt); |
RTFREE(crt); |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
} |
} |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
if (rn == NULL) { |
if (rc != 0) { |
IFAFREE(ifa); |
IFAFREE(ifa); |
if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent) |
if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent) |
rtfree(rt->rt_parent); |
rtfree(rt->rt_parent); |
Line 833 rtrequest1(int req, struct rt_addrinfo * |
|
Line 819 rtrequest1(int req, struct rt_addrinfo * |
|
rtfree(rt->rt_gwroute); |
rtfree(rt->rt_gwroute); |
rt_destroy(rt); |
rt_destroy(rt); |
pool_put(&rtentry_pool, rt); |
pool_put(&rtentry_pool, rt); |
senderr(EEXIST); |
senderr(rc); |
} |
} |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); |
if (ifa->ifa_rtrequest) |
if (ifa->ifa_rtrequest) |
Line 855 rtrequest1(int req, struct rt_addrinfo * |
|
Line 841 rtrequest1(int req, struct rt_addrinfo * |
|
netmask); |
netmask); |
dst = (struct sockaddr *)&maskeddst; |
dst = (struct sockaddr *)&maskeddst; |
} |
} |
rn = rnh->rnh_lookup(dst, netmask, rnh); |
if ((rt = rt_lookup(rtbl, dst, netmask)) == NULL) |
if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) |
|
senderr(ESRCH); |
senderr(ESRCH); |
if (ret_nrt != NULL) { |
if (ret_nrt != NULL) { |
rt = (struct rtentry *)rn; |
|
*ret_nrt = rt; |
*ret_nrt = rt; |
rt->rt_refcnt++; |
rt->rt_refcnt++; |
} |
} |
Line 1385 rtcache_setdst(struct route *ro, const s |
|
Line 1369 rtcache_setdst(struct route *ro, const s |
|
return 0; |
return 0; |
} |
} |
|
|
static int |
const struct sockaddr * |
rt_walktree_visitor(struct radix_node *rn, void *v) |
rt_settag(struct rtentry *rt, const struct sockaddr *tag) |
{ |
{ |
struct rtwalk *rw = (struct rtwalk *)v; |
if (rt->rt_tag != tag) { |
|
if (rt->rt_tag != NULL) |
return (*rw->rw_f)((struct rtentry *)rn, rw->rw_v); |
sockaddr_free(rt->rt_tag); |
|
rt->rt_tag = sockaddr_dup(tag, M_NOWAIT); |
|
} |
|
return rt->rt_tag; |
} |
} |
|
|
int |
struct sockaddr * |
rt_walktree(sa_family_t family, int (*f)(struct rtentry *, void *), void *v) |
rt_gettag(struct rtentry *rt) |
{ |
{ |
struct radix_node_head *rnh = rt_tables[family]; |
return rt->rt_tag; |
struct rtwalk rw; |
|
|
|
if (rnh == NULL) |
|
return 0; |
|
|
|
rw.rw_f = f; |
|
rw.rw_v = v; |
|
|
|
return rn_walktree(rnh, rt_walktree_visitor, &rw); |
|
} |
} |