aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-05-18 18:55:27 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-18 18:55:27 -0400
commitf2344a131bccdbfc5338e17fa71a807dee7944fa (patch)
tree17d00515d1623679592068a304abf8bd88c46ee4 /net/ipv6
parent4c5ff6a6fe794f102479db998c69054319279e3c (diff)
ipv6: Use POSTDAD state
This patch makes use of the new POSTDAD state. This prevents a race between DAD completion and failure. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2e42162c9042..7c769fa81d97 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1406,10 +1406,27 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
1406 ipv6_del_addr(ifp); 1406 ipv6_del_addr(ifp);
1407} 1407}
1408 1408
1409static int addrconf_dad_end(struct inet6_ifaddr *ifp)
1410{
1411 int err = -ENOENT;
1412
1413 spin_lock(&ifp->state_lock);
1414 if (ifp->state == INET6_IFADDR_STATE_DAD) {
1415 ifp->state = INET6_IFADDR_STATE_POSTDAD;
1416 err = 0;
1417 }
1418 spin_unlock(&ifp->state_lock);
1419
1420 return err;
1421}
1422
1409void addrconf_dad_failure(struct inet6_ifaddr *ifp) 1423void addrconf_dad_failure(struct inet6_ifaddr *ifp)
1410{ 1424{
1411 struct inet6_dev *idev = ifp->idev; 1425 struct inet6_dev *idev = ifp->idev;
1412 1426
1427 if (addrconf_dad_end(ifp))
1428 return;
1429
1413 if (net_ratelimit()) 1430 if (net_ratelimit())
1414 printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n", 1431 printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n",
1415 ifp->idev->dev->name, &ifp->addr); 1432 ifp->idev->dev->name, &ifp->addr);
@@ -2712,6 +2729,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2712 2729
2713 /* Flag it for later restoration when link comes up */ 2730 /* Flag it for later restoration when link comes up */
2714 ifa->flags |= IFA_F_TENTATIVE; 2731 ifa->flags |= IFA_F_TENTATIVE;
2732 ifa->state = INET6_IFADDR_STATE_DAD;
2715 2733
2716 write_unlock_bh(&idev->lock); 2734 write_unlock_bh(&idev->lock);
2717 2735
@@ -2883,6 +2901,9 @@ static void addrconf_dad_timer(unsigned long data)
2883 struct inet6_dev *idev = ifp->idev; 2901 struct inet6_dev *idev = ifp->idev;
2884 struct in6_addr mcaddr; 2902 struct in6_addr mcaddr;
2885 2903
2904 if (!ifp->probes && addrconf_dad_end(ifp))
2905 goto out;
2906
2886 read_lock(&idev->lock); 2907 read_lock(&idev->lock);
2887 if (idev->dead || !(idev->if_flags & IF_READY)) { 2908 if (idev->dead || !(idev->if_flags & IF_READY)) {
2888 read_unlock(&idev->lock); 2909 read_unlock(&idev->lock);
@@ -2956,12 +2977,10 @@ static void addrconf_dad_run(struct inet6_dev *idev)
2956 read_lock_bh(&idev->lock); 2977 read_lock_bh(&idev->lock);
2957 list_for_each_entry(ifp, &idev->addr_list, if_list) { 2978 list_for_each_entry(ifp, &idev->addr_list, if_list) {
2958 spin_lock(&ifp->lock); 2979 spin_lock(&ifp->lock);
2959 if (!(ifp->flags & IFA_F_TENTATIVE)) { 2980 if (ifp->flags & IFA_F_TENTATIVE &&
2960 spin_unlock(&ifp->lock); 2981 ifp->state == INET6_IFADDR_STATE_DAD)
2961 continue; 2982 addrconf_dad_kick(ifp);
2962 }
2963 spin_unlock(&ifp->lock); 2983 spin_unlock(&ifp->lock);
2964 addrconf_dad_kick(ifp);
2965 } 2984 }
2966 read_unlock_bh(&idev->lock); 2985 read_unlock_bh(&idev->lock);
2967} 2986}