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.c46
1 files changed, 29 insertions, 17 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 5f582f385abb..7a4bf7671285 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2649,11 +2649,11 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2649 write_lock_bh(&addrconf_hash_lock); 2649 write_lock_bh(&addrconf_hash_lock);
2650 while ((ifa = *bifa) != NULL) { 2650 while ((ifa = *bifa) != NULL) {
2651 if (ifa->idev == idev && 2651 if (ifa->idev == idev &&
2652 (how || !(ifa->flags&IFA_F_PERMANENT))) { 2652 (how || !(ifa->flags&IFA_F_PERMANENT) ||
2653 ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
2653 *bifa = ifa->lst_next; 2654 *bifa = ifa->lst_next;
2654 ifa->lst_next = NULL; 2655 ifa->lst_next = NULL;
2655 addrconf_del_timer(ifa); 2656 __in6_ifa_put(ifa);
2656 in6_ifa_put(ifa);
2657 continue; 2657 continue;
2658 } 2658 }
2659 bifa = &ifa->lst_next; 2659 bifa = &ifa->lst_next;
@@ -2691,28 +2691,40 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2691#endif 2691#endif
2692 bifa = &idev->addr_list; 2692 bifa = &idev->addr_list;
2693 while ((ifa = *bifa) != NULL) { 2693 while ((ifa = *bifa) != NULL) {
2694 if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) { 2694 addrconf_del_timer(ifa);
2695 /* Retain permanent address on admin down */ 2695
2696 /* If just doing link down, and address is permanent
2697 and not link-local, then retain it. */
2698 if (how == 0 &&
2699 (ifa->flags&IFA_F_PERMANENT) &&
2700 !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
2696 bifa = &ifa->if_next; 2701 bifa = &ifa->if_next;
2697 2702
2698 /* Restart DAD if needed when link comes back up */ 2703 /* If not doing DAD on this address, just keep it. */
2699 if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || 2704 if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
2700 idev->cnf.accept_dad <= 0 || 2705 idev->cnf.accept_dad <= 0 ||
2701 (ifa->flags & IFA_F_NODAD))) 2706 (ifa->flags & IFA_F_NODAD))
2702 ifa->flags |= IFA_F_TENTATIVE; 2707 continue;
2708
2709 /* If it was tentative already, no need to notify */
2710 if (ifa->flags & IFA_F_TENTATIVE)
2711 continue;
2712
2713 /* Flag it for later restoration when link comes up */
2714 ifa->flags |= IFA_F_TENTATIVE;
2715 in6_ifa_hold(ifa);
2703 } else { 2716 } else {
2704 *bifa = ifa->if_next; 2717 *bifa = ifa->if_next;
2705 ifa->if_next = NULL; 2718 ifa->if_next = NULL;
2706
2707 ifa->dead = 1; 2719 ifa->dead = 1;
2708 write_unlock_bh(&idev->lock); 2720 }
2721 write_unlock_bh(&idev->lock);
2709 2722
2710 __ipv6_ifa_notify(RTM_DELADDR, ifa); 2723 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2711 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); 2724 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
2712 in6_ifa_put(ifa); 2725 in6_ifa_put(ifa);
2713 2726
2714 write_lock_bh(&idev->lock); 2727 write_lock_bh(&idev->lock);
2715 }
2716 } 2728 }
2717 write_unlock_bh(&idev->lock); 2729 write_unlock_bh(&idev->lock);
2718 2730