diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/addrconf.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e39239e6426e..d0611a5de45f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1713,6 +1713,40 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, ip6_route_add(&cfg); } + +static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, + int plen, + const struct net_device *dev, + u32 flags, u32 noflags) +{ + struct fib6_node *fn; + struct rt6_info *rt = NULL; + struct fib6_table *table; + + table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX); + if (table == NULL) + return NULL; + + write_lock_bh(&table->tb6_lock); + fn = fib6_locate(&table->tb6_root, pfx, plen, NULL, 0); + if (!fn) + goto out; + for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { + if (rt->rt6i_dev->ifindex != dev->ifindex) + continue; + if ((rt->rt6i_flags & flags) != flags) + continue; + if ((noflags != 0) && ((rt->rt6i_flags & flags) != 0)) + continue; + dst_hold(&rt->dst); + break; + } +out: + write_unlock_bh(&table->tb6_lock); + return rt; +} + + /* Create "default" multicast route to the interface */ static void addrconf_add_mroute(struct net_device *dev) @@ -1842,10 +1876,13 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) if (addrconf_finite_timeout(rt_expires)) rt_expires *= HZ; - rt = rt6_lookup(net, &pinfo->prefix, NULL, - dev->ifindex, 1); + rt = addrconf_get_prefix_route(&pinfo->prefix, + pinfo->prefix_len, + dev, + RTF_ADDRCONF | RTF_PREFIX_RT, + RTF_GATEWAY | RTF_DEFAULT); - if (rt && addrconf_is_prefix_route(rt)) { + if (rt) { /* Autoconf prefix route */ if (valid_lft == 0) { ip6_del_rt(rt); |