diff options
-rw-r--r-- | net/ipv6/addrconf.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index df8425fcbc2c..f418d2eaeddd 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -1872,7 +1872,6 @@ static int addrconf_dad_end(struct inet6_ifaddr *ifp) | |||
1872 | 1872 | ||
1873 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1873 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) |
1874 | { | 1874 | { |
1875 | struct in6_addr addr; | ||
1876 | struct inet6_dev *idev = ifp->idev; | 1875 | struct inet6_dev *idev = ifp->idev; |
1877 | struct net *net = dev_net(ifp->idev->dev); | 1876 | struct net *net = dev_net(ifp->idev->dev); |
1878 | 1877 | ||
@@ -1934,18 +1933,6 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1934 | in6_ifa_put(ifp2); | 1933 | in6_ifa_put(ifp2); |
1935 | lock_errdad: | 1934 | lock_errdad: |
1936 | spin_lock_bh(&ifp->lock); | 1935 | spin_lock_bh(&ifp->lock); |
1937 | } else if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { | ||
1938 | addr.s6_addr32[0] = htonl(0xfe800000); | ||
1939 | addr.s6_addr32[1] = 0; | ||
1940 | |||
1941 | if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) && | ||
1942 | ipv6_addr_equal(&ifp->addr, &addr)) { | ||
1943 | /* DAD failed for link-local based on MAC address */ | ||
1944 | idev->cnf.disable_ipv6 = 1; | ||
1945 | |||
1946 | pr_info("%s: IPv6 being disabled!\n", | ||
1947 | ifp->idev->dev->name); | ||
1948 | } | ||
1949 | } | 1936 | } |
1950 | 1937 | ||
1951 | errdad: | 1938 | errdad: |
@@ -3821,6 +3808,7 @@ static void addrconf_dad_work(struct work_struct *w) | |||
3821 | dad_work); | 3808 | dad_work); |
3822 | struct inet6_dev *idev = ifp->idev; | 3809 | struct inet6_dev *idev = ifp->idev; |
3823 | struct in6_addr mcaddr; | 3810 | struct in6_addr mcaddr; |
3811 | bool disable_ipv6 = false; | ||
3824 | 3812 | ||
3825 | enum { | 3813 | enum { |
3826 | DAD_PROCESS, | 3814 | DAD_PROCESS, |
@@ -3837,6 +3825,24 @@ static void addrconf_dad_work(struct work_struct *w) | |||
3837 | } else if (ifp->state == INET6_IFADDR_STATE_ERRDAD) { | 3825 | } else if (ifp->state == INET6_IFADDR_STATE_ERRDAD) { |
3838 | action = DAD_ABORT; | 3826 | action = DAD_ABORT; |
3839 | ifp->state = INET6_IFADDR_STATE_POSTDAD; | 3827 | ifp->state = INET6_IFADDR_STATE_POSTDAD; |
3828 | |||
3829 | if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6 && | ||
3830 | !(ifp->flags & IFA_F_STABLE_PRIVACY)) { | ||
3831 | struct in6_addr addr; | ||
3832 | |||
3833 | addr.s6_addr32[0] = htonl(0xfe800000); | ||
3834 | addr.s6_addr32[1] = 0; | ||
3835 | |||
3836 | if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) && | ||
3837 | ipv6_addr_equal(&ifp->addr, &addr)) { | ||
3838 | /* DAD failed for link-local based on MAC */ | ||
3839 | idev->cnf.disable_ipv6 = 1; | ||
3840 | |||
3841 | pr_info("%s: IPv6 being disabled!\n", | ||
3842 | ifp->idev->dev->name); | ||
3843 | disable_ipv6 = true; | ||
3844 | } | ||
3845 | } | ||
3840 | } | 3846 | } |
3841 | spin_unlock_bh(&ifp->lock); | 3847 | spin_unlock_bh(&ifp->lock); |
3842 | 3848 | ||
@@ -3845,6 +3851,8 @@ static void addrconf_dad_work(struct work_struct *w) | |||
3845 | goto out; | 3851 | goto out; |
3846 | } else if (action == DAD_ABORT) { | 3852 | } else if (action == DAD_ABORT) { |
3847 | addrconf_dad_stop(ifp, 1); | 3853 | addrconf_dad_stop(ifp, 1); |
3854 | if (disable_ipv6) | ||
3855 | addrconf_ifdown(idev->dev, 0); | ||
3848 | goto out; | 3856 | goto out; |
3849 | } | 3857 | } |
3850 | 3858 | ||