diff options
| -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 | } |
