diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2010-05-18 18:55:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-18 18:55:27 -0400 |
commit | f2344a131bccdbfc5338e17fa71a807dee7944fa (patch) | |
tree | 17d00515d1623679592068a304abf8bd88c46ee4 /net/ipv6/addrconf.c | |
parent | 4c5ff6a6fe794f102479db998c69054319279e3c (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/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 29 |
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 | ||
1409 | static 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 | |||
1409 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1423 | void 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 | } |