#include <linux/route.h>
#include <linux/inetdevice.h>
#include <linux/init.h>
+#include <linux/slab.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
hash = ipv6_addr_hash(addr);
hlist_add_head_rcu(&ifa->addr_lst, &inet6_addr_lst[hash]);
- in6_ifa_hold(ifa);
spin_unlock(&addrconf_hash_lock);
write_lock(&idev->lock);
spin_lock_bh(&addrconf_hash_lock);
hlist_del_init_rcu(&ifp->addr_lst);
- __in6_ifa_put(ifp);
spin_unlock_bh(&addrconf_hash_lock);
write_lock_bh(&idev->lock);
/* Flag it for later restoration when link comes up */
ifa->flags |= IFA_F_TENTATIVE;
in6_ifa_hold(ifa);
+ write_unlock_bh(&idev->lock);
} else {
list_del(&ifa->if_list);
ifa->dead = 1;
- }
- write_unlock_bh(&idev->lock);
+ write_unlock_bh(&idev->lock);
- /* clear hash table */
- spin_lock_bh(&addrconf_hash_lock);
- hlist_del_init_rcu(&ifa->addr_lst);
- __in6_ifa_put(ifa);
- spin_unlock_bh(&addrconf_hash_lock);
+ /* clear hash table */
+ spin_lock_bh(&addrconf_hash_lock);
+ hlist_del_init_rcu(&ifa->addr_lst);
+ spin_unlock_bh(&addrconf_hash_lock);
+ }
__ipv6_ifa_notify(RTM_DELADDR, ifa);
- atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
+ if (ifa->dead)
+ atomic_notifier_call_chain(&inet6addr_chain,
+ NETDEV_DOWN, ifa);
in6_ifa_put(ifa);
write_lock_bh(&idev->lock);
hlist_for_each_entry_rcu(dev, node, head, index_hlist) {
if (idx < s_idx)
goto cont;
- if (idx > s_idx)
+ if (h > s_h || idx > s_idx)
s_ip_idx = 0;
ip_idx = 0;
idev = __in6_dev_get(dev);
addrconf_leave_anycast(ifp);
addrconf_leave_solict(ifp->idev, &ifp->addr);
dst_hold(&ifp->rt->u.dst);
- if (ip6_del_rt(ifp->rt))
+
+ if (ifp->dead && ip6_del_rt(ifp->rt))
dst_free(&ifp->rt->u.dst);
break;
}