aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2010-10-27 14:16:49 -0400
committerDavid S. Miller <davem@davemloft.net>2010-11-12 16:44:24 -0500
commit2de795707294972f6c34bae9de713e502c431296 (patch)
treebd5ee45aee40d0c4a6a0c7d3c25202fd0f95f3f6 /net/ipv6
parent8f49c2703b33519aaaccc63f571b465b9d2b3a2d (diff)
ipv6: addrconf: don't remove address state on ifdown if the address is being kept
Currently, addrconf_ifdown does not delete statically configured IPv6 addresses when the interface is brought down. The intent is that when the interface comes back up the address will be usable again. However, this doesn't actually work, because the system stops listening on the corresponding solicited-node multicast address, so the address cannot respond to neighbor solicitations and thus receive traffic. Also, the code notifies the rest of the system that the address is being deleted (e.g, RTM_DELADDR), even though it is not. Fix it so that none of this state is updated if the address is being kept on the interface. Tested: Added a statically configured IPv6 address to an interface, started ping, brought link down, brought link up again. When link came up ping kept on going and "ip -6 maddr" showed that the host was still subscribed to there Signed-off-by: Lorenzo Colitti <lorenzo@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf.c24
1 files changed, 8 insertions, 16 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e048ec62d109..b41ce0f0d514 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2740,10 +2740,6 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2740 /* Flag it for later restoration when link comes up */ 2740 /* Flag it for later restoration when link comes up */
2741 ifa->flags |= IFA_F_TENTATIVE; 2741 ifa->flags |= IFA_F_TENTATIVE;
2742 ifa->state = INET6_IFADDR_STATE_DAD; 2742 ifa->state = INET6_IFADDR_STATE_DAD;
2743
2744 write_unlock_bh(&idev->lock);
2745
2746 in6_ifa_hold(ifa);
2747 } else { 2743 } else {
2748 list_del(&ifa->if_list); 2744 list_del(&ifa->if_list);
2749 2745
@@ -2758,19 +2754,15 @@ static int addrconf_ifdown(struct net_device *dev, int how)
2758 ifa->state = INET6_IFADDR_STATE_DEAD; 2754 ifa->state = INET6_IFADDR_STATE_DEAD;
2759 spin_unlock_bh(&ifa->state_lock); 2755 spin_unlock_bh(&ifa->state_lock);
2760 2756
2761 if (state == INET6_IFADDR_STATE_DEAD) 2757 if (state == INET6_IFADDR_STATE_DEAD) {
2762 goto put_ifa; 2758 in6_ifa_put(ifa);
2759 } else {
2760 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2761 atomic_notifier_call_chain(&inet6addr_chain,
2762 NETDEV_DOWN, ifa);
2763 }
2764 write_lock_bh(&idev->lock);
2763 } 2765 }
2764
2765 __ipv6_ifa_notify(RTM_DELADDR, ifa);
2766 if (ifa->state == INET6_IFADDR_STATE_DEAD)
2767 atomic_notifier_call_chain(&inet6addr_chain,
2768 NETDEV_DOWN, ifa);
2769
2770put_ifa:
2771 in6_ifa_put(ifa);
2772
2773 write_lock_bh(&idev->lock);
2774 } 2766 }
2775 2767
2776 list_splice(&keep_list, &idev->addr_list); 2768 list_splice(&keep_list, &idev->addr_list);