aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorstephen hemminger <shemminger@vyatta.com>2010-02-08 14:48:05 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-12 15:28:01 -0500
commitdc2b99f71ef477a31020511876ab4403fb7c4420 (patch)
treecb30c11a7eb13d2ad004ee168135282aac434791 /net/ipv6/addrconf.c
parentc0ad98453f23b98f73a1f1be2a75303a6c0dee4c (diff)
IPv6: keep permanent addresses on admin down
Permanent IPV6 addresses should not be removed when the link is set to admin down, only when device is removed. When link is lost permanent addresses should be marked as tentative so that when link comes back they are subject to duplicate address detection (if DAD was enabled for that address). Other routing systems keep manually configured IPv6 addresses when link is set down. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-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