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.c84
1 files changed, 33 insertions, 51 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 5b189c97c2fc..fd6782e3a038 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -420,9 +420,6 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
420 dev->type == ARPHRD_TUNNEL6 || 420 dev->type == ARPHRD_TUNNEL6 ||
421 dev->type == ARPHRD_SIT || 421 dev->type == ARPHRD_SIT ||
422 dev->type == ARPHRD_NONE) { 422 dev->type == ARPHRD_NONE) {
423 printk(KERN_INFO
424 "%s: Disabled Privacy Extensions\n",
425 dev->name);
426 ndev->cnf.use_tempaddr = -1; 423 ndev->cnf.use_tempaddr = -1;
427 } else { 424 } else {
428 in6_dev_hold(ndev); 425 in6_dev_hold(ndev);
@@ -2664,14 +2661,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2664 struct net *net = dev_net(dev); 2661 struct net *net = dev_net(dev);
2665 struct inet6_dev *idev; 2662 struct inet6_dev *idev;
2666 struct inet6_ifaddr *ifa; 2663 struct inet6_ifaddr *ifa;
2667 LIST_HEAD(keep_list); 2664 int state, i;
2668 int state;
2669 2665
2670 ASSERT_RTNL(); 2666 ASSERT_RTNL();
2671 2667
2672 /* Flush routes if device is being removed or it is not loopback */ 2668 rt6_ifdown(net, dev);
2673 if (how || !(dev->flags & IFF_LOOPBACK)) 2669 neigh_ifdown(&nd_tbl, dev);
2674 rt6_ifdown(net, dev);
2675 2670
2676 idev = __in6_dev_get(dev); 2671 idev = __in6_dev_get(dev);
2677 if (idev == NULL) 2672 if (idev == NULL)
@@ -2692,6 +2687,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2692 2687
2693 } 2688 }
2694 2689
2690 /* Step 2: clear hash table */
2691 for (i = 0; i < IN6_ADDR_HSIZE; i++) {
2692 struct hlist_head *h = &inet6_addr_lst[i];
2693 struct hlist_node *n;
2694
2695 spin_lock_bh(&addrconf_hash_lock);
2696 restart:
2697 hlist_for_each_entry_rcu(ifa, n, h, addr_lst) {
2698 if (ifa->idev == idev) {
2699 hlist_del_init_rcu(&ifa->addr_lst);
2700 addrconf_del_timer(ifa);
2701 goto restart;
2702 }
2703 }
2704 spin_unlock_bh(&addrconf_hash_lock);
2705 }
2706
2695 write_lock_bh(&idev->lock); 2707 write_lock_bh(&idev->lock);
2696 2708
2697 /* Step 2: clear flags for stateless addrconf */ 2709 /* Step 2: clear flags for stateless addrconf */
@@ -2725,52 +2737,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2725 struct inet6_ifaddr, if_list); 2737 struct inet6_ifaddr, if_list);
2726 addrconf_del_timer(ifa); 2738 addrconf_del_timer(ifa);
2727 2739
2728 /* If just doing link down, and address is permanent 2740 list_del(&ifa->if_list);
2729 and not link-local, then retain it. */
2730 if (!how &&
2731 (ifa->flags&IFA_F_PERMANENT) &&
2732 !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
2733 list_move_tail(&ifa->if_list, &keep_list);
2734
2735 /* If not doing DAD on this address, just keep it. */
2736 if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
2737 idev->cnf.accept_dad <= 0 ||
2738 (ifa->flags & IFA_F_NODAD))
2739 continue;
2740 2741
2741 /* If it was tentative already, no need to notify */ 2742 write_unlock_bh(&idev->lock);
2742 if (ifa->flags & IFA_F_TENTATIVE)
2743 continue;
2744 2743
2745 /* Flag it for later restoration when link comes up */ 2744 spin_lock_bh(&ifa->state_lock);
2746 ifa->flags |= IFA_F_TENTATIVE; 2745 state = ifa->state;
2747 ifa->state = INET6_IFADDR_STATE_DAD; 2746 ifa->state = INET6_IFADDR_STATE_DEAD;
2748 } else { 2747 spin_unlock_bh(&ifa->state_lock);
2749 list_del(&ifa->if_list);
2750
2751 /* clear hash table */
2752 spin_lock_bh(&addrconf_hash_lock);
2753 hlist_del_init_rcu(&ifa->addr_lst);
2754 spin_unlock_bh(&addrconf_hash_lock);
2755
2756 write_unlock_bh(&idev->lock);
2757 spin_lock_bh(&ifa->state_lock);
2758 state = ifa->state;
2759 ifa->state = INET6_IFADDR_STATE_DEAD;
2760 spin_unlock_bh(&ifa->state_lock);
2761
2762 if (state != INET6_IFADDR_STATE_DEAD) {
2763 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2764 atomic_notifier_call_chain(&inet6addr_chain,
2765 NETDEV_DOWN, ifa);
2766 }
2767 2748
2768 in6_ifa_put(ifa); 2749 if (state != INET6_IFADDR_STATE_DEAD) {
2769 write_lock_bh(&idev->lock); 2750 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2751 atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
2770 } 2752 }
2771 } 2753 in6_ifa_put(ifa);
2772 2754
2773 list_splice(&keep_list, &idev->addr_list); 2755 write_lock_bh(&idev->lock);
2756 }
2774 2757
2775 write_unlock_bh(&idev->lock); 2758 write_unlock_bh(&idev->lock);
2776 2759
@@ -4159,8 +4142,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4159 addrconf_leave_solict(ifp->idev, &ifp->addr); 4142 addrconf_leave_solict(ifp->idev, &ifp->addr);
4160 dst_hold(&ifp->rt->dst); 4143 dst_hold(&ifp->rt->dst);
4161 4144
4162 if (ifp->state == INET6_IFADDR_STATE_DEAD && 4145 if (ip6_del_rt(ifp->rt))
4163 ip6_del_rt(ifp->rt))
4164 dst_free(&ifp->rt->dst); 4146 dst_free(&ifp->rt->dst);
4165 break; 4147 break;
4166 } 4148 }