Commit a6279458 authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki Committed by David S. Miller

[IPV6] NDISC: Search over all possible rules on receipt of redirect.

Split up function for finding routes for redirects.
Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5e032e32
...@@ -1279,19 +1279,18 @@ static int ip6_route_del(struct fib6_config *cfg) ...@@ -1279,19 +1279,18 @@ static int ip6_route_del(struct fib6_config *cfg)
/* /*
* Handle redirects * Handle redirects
*/ */
void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, struct ip6rd_flowi {
struct in6_addr *saddr, struct flowi fl;
struct neighbour *neigh, u8 *lladdr, int on_link) struct in6_addr gateway;
};
static struct rt6_info *__ip6_route_redirect(struct fib6_table *table,
struct flowi *fl,
int flags)
{ {
struct rt6_info *rt, *nrt = NULL; struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl;
struct rt6_info *rt;
struct fib6_node *fn; struct fib6_node *fn;
struct fib6_table *table;
struct netevent_redirect netevent;
/* TODO: Very lazy, might need to check all tables */
table = fib6_get_table(RT6_TABLE_MAIN);
if (table == NULL)
return;
/* /*
* Get the "current" route for this destination and * Get the "current" route for this destination and
...@@ -1305,7 +1304,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, ...@@ -1305,7 +1304,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
*/ */
read_lock_bh(&table->tb6_lock); read_lock_bh(&table->tb6_lock);
fn = fib6_lookup(&table->tb6_root, dest, src); fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart: restart:
for (rt = fn->leaf; rt; rt = rt->u.next) { for (rt = fn->leaf; rt; rt = rt->u.next) {
/* /*
...@@ -1320,29 +1319,67 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, ...@@ -1320,29 +1319,67 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
continue; continue;
if (!(rt->rt6i_flags & RTF_GATEWAY)) if (!(rt->rt6i_flags & RTF_GATEWAY))
continue; continue;
if (neigh->dev != rt->rt6i_dev) if (fl->oif != rt->rt6i_dev->ifindex)
continue; continue;
if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway))
continue; continue;
break; break;
} }
if (rt)
dst_hold(&rt->u.dst); if (!rt) {
else if (rt6_need_strict(dest)) { if (rt6_need_strict(&fl->fl6_dst)) {
while ((fn = fn->parent) != NULL) { while ((fn = fn->parent) != NULL) {
if (fn->fn_flags & RTN_ROOT) if (fn->fn_flags & RTN_ROOT)
break; break;
if (fn->fn_flags & RTN_RTINFO) if (fn->fn_flags & RTN_RTINFO)
goto restart; goto restart;
}
} }
rt = &ip6_null_entry;
} }
dst_hold(&rt->u.dst);
read_unlock_bh(&table->tb6_lock); read_unlock_bh(&table->tb6_lock);
if (!rt) { return rt;
};
static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
struct in6_addr *src,
struct in6_addr *gateway,
struct net_device *dev)
{
struct ip6rd_flowi rdfl = {
.fl = {
.oif = dev->ifindex,
.nl_u = {
.ip6_u = {
.daddr = *dest,
.saddr = *src,
},
},
},
.gateway = *gateway,
};
int flags = rt6_need_strict(dest) ? RT6_F_STRICT : 0;
return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
}
void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
struct in6_addr *saddr,
struct neighbour *neigh, u8 *lladdr, int on_link)
{
struct rt6_info *rt, *nrt = NULL;
struct netevent_redirect netevent;
rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
if (rt == &ip6_null_entry) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
"for redirect target\n"); "for redirect target\n");
return; goto out;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment