aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c38
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
1873void addrconf_dad_failure(struct inet6_ifaddr *ifp) 1873void 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);
1935lock_errdad: 1934lock_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
1951errdad: 1938errdad:
@@ -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