diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 35 |
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 | ||