|
@@ -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);
|