diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 38 |
1 files changed, 23 insertions, 15 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ab3e796596b1..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: |
@@ -3543,7 +3530,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
3543 | /* combine the user config with event to determine if permanent | 3530 | /* combine the user config with event to determine if permanent |
3544 | * addresses are to be removed from address hash table | 3531 | * addresses are to be removed from address hash table |
3545 | */ | 3532 | */ |
3546 | keep_addr = !(how || _keep_addr <= 0); | 3533 | keep_addr = !(how || _keep_addr <= 0 || idev->cnf.disable_ipv6); |
3547 | 3534 | ||
3548 | /* Step 2: clear hash table */ | 3535 | /* Step 2: clear hash table */ |
3549 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { | 3536 | for (i = 0; i < IN6_ADDR_HSIZE; i++) { |
@@ -3599,7 +3586,7 @@ restart: | |||
3599 | /* re-combine the user config with event to determine if permanent | 3586 | /* re-combine the user config with event to determine if permanent |
3600 | * addresses are to be removed from the interface list | 3587 | * addresses are to be removed from the interface list |
3601 | */ | 3588 | */ |
3602 | keep_addr = (!how && _keep_addr > 0); | 3589 | keep_addr = (!how && _keep_addr > 0 && !idev->cnf.disable_ipv6); |
3603 | 3590 | ||
3604 | INIT_LIST_HEAD(&del_list); | 3591 | INIT_LIST_HEAD(&del_list); |
3605 | list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) { | 3592 | list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) { |
@@ -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 | ||