aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAndreas Hofmeister <andi@collax.com>2011-10-25 23:24:29 -0400
committerDavid S. Miller <davem@davemloft.net>2011-10-30 04:12:36 -0400
commit14ef37b6d00eb5d06704e45989ba4c21e7be7673 (patch)
tree800422d2aa85e190bc6e07e305574d71bf25db24 /net
parente6d265e8504ab4a3368b8645d318b344ee88b280 (diff)
ipv6: fix route lookup in addrconf_prefix_rcv()
The route lookup to find a previously auto-configured route for a prefixes used to use rt6_lookup(), with the prefix from the RA used as an address. However, that kind of lookup ignores routing tables, the prefix length and route flags, so when there were other matching routes, even in different tables and/or with a different prefix length, the wrong route would be manipulated. Now, a new function "addrconf_get_prefix_route()" is used for the route lookup, which searches in RT6_TABLE_PREFIX and takes the prefix-length and route flags into account. Signed-off-by: Andreas Hofmeister <andi@collax.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/addrconf.c43
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,
1713 ip6_route_add(&cfg); 1713 ip6_route_add(&cfg);
1714} 1714}
1715 1715
1716
1717static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
1718 int plen,
1719 const struct net_device *dev,
1720 u32 flags, u32 noflags)
1721{
1722 struct fib6_node *fn;
1723 struct rt6_info *rt = NULL;
1724 struct fib6_table *table;
1725
1726 table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX);
1727 if (table == NULL)
1728 return NULL;
1729
1730 write_lock_bh(&table->tb6_lock);
1731 fn = fib6_locate(&table->tb6_root, pfx, plen, NULL, 0);
1732 if (!fn)
1733 goto out;
1734 for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
1735 if (rt->rt6i_dev->ifindex != dev->ifindex)
1736 continue;
1737 if ((rt->rt6i_flags & flags) != flags)
1738 continue;
1739 if ((noflags != 0) && ((rt->rt6i_flags & flags) != 0))
1740 continue;
1741 dst_hold(&rt->dst);
1742 break;
1743 }
1744out:
1745 write_unlock_bh(&table->tb6_lock);
1746 return rt;
1747}
1748
1749
1716/* Create "default" multicast route to the interface */ 1750/* Create "default" multicast route to the interface */
1717 1751
1718static void addrconf_add_mroute(struct net_device *dev) 1752static void addrconf_add_mroute(struct net_device *dev)
@@ -1842,10 +1876,13 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
1842 if (addrconf_finite_timeout(rt_expires)) 1876 if (addrconf_finite_timeout(rt_expires))
1843 rt_expires *= HZ; 1877 rt_expires *= HZ;
1844 1878
1845 rt = rt6_lookup(net, &pinfo->prefix, NULL, 1879 rt = addrconf_get_prefix_route(&pinfo->prefix,
1846 dev->ifindex, 1); 1880 pinfo->prefix_len,
1881 dev,
1882 RTF_ADDRCONF | RTF_PREFIX_RT,
1883 RTF_GATEWAY | RTF_DEFAULT);
1847 1884
1848 if (rt && addrconf_is_prefix_route(rt)) { 1885 if (rt) {
1849 /* Autoconf prefix route */ 1886 /* Autoconf prefix route */
1850 if (valid_lft == 0) { 1887 if (valid_lft == 0) {
1851 ip6_del_rt(rt); 1888 ip6_del_rt(rt);