diff options
-rw-r--r-- | include/net/if_inet6.h | 12 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 16 |
2 files changed, 19 insertions, 9 deletions
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 13f9fc086d54..f95ff8d9aa47 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h | |||
@@ -32,6 +32,13 @@ | |||
32 | 32 | ||
33 | #ifdef __KERNEL__ | 33 | #ifdef __KERNEL__ |
34 | 34 | ||
35 | enum { | ||
36 | INET6_IFADDR_STATE_DAD, | ||
37 | INET6_IFADDR_STATE_POSTDAD, | ||
38 | INET6_IFADDR_STATE_UP, | ||
39 | INET6_IFADDR_STATE_DEAD, | ||
40 | }; | ||
41 | |||
35 | struct inet6_ifaddr { | 42 | struct inet6_ifaddr { |
36 | struct in6_addr addr; | 43 | struct in6_addr addr; |
37 | __u32 prefix_len; | 44 | __u32 prefix_len; |
@@ -40,6 +47,9 @@ struct inet6_ifaddr { | |||
40 | __u32 prefered_lft; | 47 | __u32 prefered_lft; |
41 | atomic_t refcnt; | 48 | atomic_t refcnt; |
42 | spinlock_t lock; | 49 | spinlock_t lock; |
50 | spinlock_t state_lock; | ||
51 | |||
52 | int state; | ||
43 | 53 | ||
44 | __u8 probes; | 54 | __u8 probes; |
45 | __u8 flags; | 55 | __u8 flags; |
@@ -62,8 +72,6 @@ struct inet6_ifaddr { | |||
62 | struct inet6_ifaddr *ifpub; | 72 | struct inet6_ifaddr *ifpub; |
63 | int regen_count; | 73 | int regen_count; |
64 | #endif | 74 | #endif |
65 | |||
66 | int dead; | ||
67 | struct rcu_head rcu; | 75 | struct rcu_head rcu; |
68 | }; | 76 | }; |
69 | 77 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 75d3b8c1e856..4e5ad9de1679 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -553,7 +553,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) | |||
553 | if (del_timer(&ifp->timer)) | 553 | if (del_timer(&ifp->timer)) |
554 | pr_notice("Timer is still running, when freeing ifa=%p\n", ifp); | 554 | pr_notice("Timer is still running, when freeing ifa=%p\n", ifp); |
555 | 555 | ||
556 | if (!ifp->dead) { | 556 | if (ifp->state != INET6_IFADDR_STATE_DEAD) { |
557 | pr_warning("Freeing alive inet6 address %p\n", ifp); | 557 | pr_warning("Freeing alive inet6 address %p\n", ifp); |
558 | return; | 558 | return; |
559 | } | 559 | } |
@@ -648,6 +648,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
648 | ipv6_addr_copy(&ifa->addr, addr); | 648 | ipv6_addr_copy(&ifa->addr, addr); |
649 | 649 | ||
650 | spin_lock_init(&ifa->lock); | 650 | spin_lock_init(&ifa->lock); |
651 | spin_lock_init(&ifa->state_lock); | ||
651 | init_timer(&ifa->timer); | 652 | init_timer(&ifa->timer); |
652 | INIT_HLIST_NODE(&ifa->addr_lst); | 653 | INIT_HLIST_NODE(&ifa->addr_lst); |
653 | ifa->timer.data = (unsigned long) ifa; | 654 | ifa->timer.data = (unsigned long) ifa; |
@@ -720,7 +721,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) | |||
720 | 721 | ||
721 | hash = ipv6_addr_hash(&ifp->addr); | 722 | hash = ipv6_addr_hash(&ifp->addr); |
722 | 723 | ||
723 | ifp->dead = 1; | 724 | ifp->state = INET6_IFADDR_STATE_DEAD; |
724 | 725 | ||
725 | spin_lock_bh(&addrconf_hash_lock); | 726 | spin_lock_bh(&addrconf_hash_lock); |
726 | hlist_del_init_rcu(&ifp->addr_lst); | 727 | hlist_del_init_rcu(&ifp->addr_lst); |
@@ -2665,7 +2666,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2665 | ifa = list_first_entry(&idev->tempaddr_list, | 2666 | ifa = list_first_entry(&idev->tempaddr_list, |
2666 | struct inet6_ifaddr, tmp_list); | 2667 | struct inet6_ifaddr, tmp_list); |
2667 | list_del(&ifa->tmp_list); | 2668 | list_del(&ifa->tmp_list); |
2668 | ifa->dead = 1; | 2669 | ifa->state = INET6_IFADDR_STATE_DEAD; |
2669 | write_unlock_bh(&idev->lock); | 2670 | write_unlock_bh(&idev->lock); |
2670 | spin_lock_bh(&ifa->lock); | 2671 | spin_lock_bh(&ifa->lock); |
2671 | 2672 | ||
@@ -2707,7 +2708,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2707 | write_unlock_bh(&idev->lock); | 2708 | write_unlock_bh(&idev->lock); |
2708 | } else { | 2709 | } else { |
2709 | list_del(&ifa->if_list); | 2710 | list_del(&ifa->if_list); |
2710 | ifa->dead = 1; | 2711 | ifa->state = INET6_IFADDR_STATE_DEAD; |
2711 | write_unlock_bh(&idev->lock); | 2712 | write_unlock_bh(&idev->lock); |
2712 | 2713 | ||
2713 | /* clear hash table */ | 2714 | /* clear hash table */ |
@@ -2717,7 +2718,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2717 | } | 2718 | } |
2718 | 2719 | ||
2719 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | 2720 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
2720 | if (ifa->dead) | 2721 | if (ifa->state == INET6_IFADDR_STATE_DEAD) |
2721 | atomic_notifier_call_chain(&inet6addr_chain, | 2722 | atomic_notifier_call_chain(&inet6addr_chain, |
2722 | NETDEV_DOWN, ifa); | 2723 | NETDEV_DOWN, ifa); |
2723 | in6_ifa_put(ifa); | 2724 | in6_ifa_put(ifa); |
@@ -2815,7 +2816,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2815 | net_srandom(ifp->addr.s6_addr32[3]); | 2816 | net_srandom(ifp->addr.s6_addr32[3]); |
2816 | 2817 | ||
2817 | read_lock_bh(&idev->lock); | 2818 | read_lock_bh(&idev->lock); |
2818 | if (ifp->dead) | 2819 | if (ifp->state == INET6_IFADDR_STATE_DEAD) |
2819 | goto out; | 2820 | goto out; |
2820 | 2821 | ||
2821 | spin_lock(&ifp->lock); | 2822 | spin_lock(&ifp->lock); |
@@ -4050,7 +4051,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
4050 | addrconf_leave_solict(ifp->idev, &ifp->addr); | 4051 | addrconf_leave_solict(ifp->idev, &ifp->addr); |
4051 | dst_hold(&ifp->rt->u.dst); | 4052 | dst_hold(&ifp->rt->u.dst); |
4052 | 4053 | ||
4053 | if (ifp->dead && ip6_del_rt(ifp->rt)) | 4054 | if (ifp->state == INET6_IFADDR_STATE_DEAD && |
4055 | ip6_del_rt(ifp->rt)) | ||
4054 | dst_free(&ifp->rt->u.dst); | 4056 | dst_free(&ifp->rt->u.dst); |
4055 | break; | 4057 | break; |
4056 | } | 4058 | } |