aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c35
1 files changed, 24 insertions, 11 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 1593289155ff..b0e1430b64f1 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2646,7 +2646,8 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2646 2646
2647 write_lock_bh(&addrconf_hash_lock); 2647 write_lock_bh(&addrconf_hash_lock);
2648 while ((ifa = *bifa) != NULL) { 2648 while ((ifa = *bifa) != NULL) {
2649 if (ifa->idev == idev) { 2649 if (ifa->idev == idev &&
2650 (how || !(ifa->flags&IFA_F_PERMANENT))) {
2650 *bifa = ifa->lst_next; 2651 *bifa = ifa->lst_next;
2651 ifa->lst_next = NULL; 2652 ifa->lst_next = NULL;
2652 addrconf_del_timer(ifa); 2653 addrconf_del_timer(ifa);
@@ -2686,18 +2687,30 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2686 write_lock_bh(&idev->lock); 2687 write_lock_bh(&idev->lock);
2687 } 2688 }
2688#endif 2689#endif
2689 while ((ifa = idev->addr_list) != NULL) { 2690 bifa = &idev->addr_list;
2690 idev->addr_list = ifa->if_next; 2691 while ((ifa = *bifa) != NULL) {
2691 ifa->if_next = NULL; 2692 if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) {
2692 ifa->dead = 1; 2693 /* Retain permanent address on admin down */
2693 addrconf_del_timer(ifa); 2694 bifa = &ifa->if_next;
2694 write_unlock_bh(&idev->lock); 2695
2696 /* Restart DAD if needed when link comes back up */
2697 if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
2698 idev->cnf.accept_dad <= 0 ||
2699 (ifa->flags & IFA_F_NODAD)))
2700 ifa->flags |= IFA_F_TENTATIVE;
2701 } else {
2702 *bifa = ifa->if_next;
2703 ifa->if_next = NULL;
2695 2704
2696 __ipv6_ifa_notify(RTM_DELADDR, ifa); 2705 ifa->dead = 1;
2697 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); 2706 write_unlock_bh(&idev->lock);
2698 in6_ifa_put(ifa);
2699 2707
2700 write_lock_bh(&idev->lock); 2708 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2709 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
2710 in6_ifa_put(ifa);
2711
2712 write_lock_bh(&idev->lock);
2713 }
2701 } 2714 }
2702 write_unlock_bh(&idev->lock); 2715 write_unlock_bh(&idev->lock);
2703 2716