@@ -1401,6 +1401,16 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
void addrconf_dad_failure(struct inet6_ifaddr *ifp)
{
struct inet6_dev *idev = ifp->idev;
+ int ignore;
+
+ spin_lock(&ifp->lock);
+ ignore = (ifp->flags & (IFA_F_DADFAILED|IFA_F_TENTATIVE)) ^
+ IFA_F_TENTATIVE;
+ ifp->flags |= IFA_F_DADFAILED;
+ spin_unlock(&ifp->lock);
+
+ if (ignore)
+ return;
if (net_ratelimit())
printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n",
@@ -2789,7 +2799,10 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
read_lock_bh(&idev->lock);
if (ifp->dead)
goto out;
+
spin_lock_bh(&ifp->lock);
+ if (ifp->flags & IFA_F_DADFAILED)
+ goto unlock_ifp;
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
idev->cnf.accept_dad < 1 ||
@@ -2824,6 +2837,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
ip6_ins_rt(ifp->rt);
addrconf_dad_kick(ifp);
+unlock_ifp:
spin_unlock_bh(&ifp->lock);
out:
read_unlock_bh(&idev->lock);
@@ -2841,6 +2855,11 @@ static void addrconf_dad_timer(unsigned long data)
goto out;
}
spin_lock_bh(&ifp->lock);
+ if (ifp->flags & IFA_F_DADFAILED) {
+ spin_unlock_bh(&ifp->lock);
+ read_unlock_bh(&idev->lock);
+ goto out;
+ }
if (ifp->probes == 0) {
/*
* DAD was successful