Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 232464
b: refs/heads/master
c: 73a8bd7
h: refs/heads/master
v: v3
  • Loading branch information
David S. Miller committed Jan 25, 2011
1 parent 28b10c4 commit f7d6c36
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 49 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: de0368d5fec7b9ef95228510f2edb79610beb448
refs/heads/master: 73a8bd74e2618990dbb218c3d82f53e60acd9af0
81 changes: 33 additions & 48 deletions trunk/net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2661,14 +2661,12 @@ static int addrconf_ifdown(struct net_device *dev, int how)
struct net *net = dev_net(dev);
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
LIST_HEAD(keep_list);
int state;
int state, i;

ASSERT_RTNL();

/* Flush routes if device is being removed or it is not loopback */
if (how || !(dev->flags & IFF_LOOPBACK))
rt6_ifdown(net, dev);
rt6_ifdown(net, dev);
neigh_ifdown(&nd_tbl, dev);

idev = __in6_dev_get(dev);
if (idev == NULL)
Expand All @@ -2689,6 +2687,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)

}

/* Step 2: clear hash table */
for (i = 0; i < IN6_ADDR_HSIZE; i++) {
struct hlist_head *h = &inet6_addr_lst[i];
struct hlist_node *n;

spin_lock_bh(&addrconf_hash_lock);
restart:
hlist_for_each_entry_rcu(ifa, n, h, addr_lst) {
if (ifa->idev == idev) {
hlist_del_init_rcu(&ifa->addr_lst);
addrconf_del_timer(ifa);
goto restart;
}
}
spin_unlock_bh(&addrconf_hash_lock);
}

write_lock_bh(&idev->lock);

/* Step 2: clear flags for stateless addrconf */
Expand Down Expand Up @@ -2722,52 +2737,23 @@ static int addrconf_ifdown(struct net_device *dev, int how)
struct inet6_ifaddr, if_list);
addrconf_del_timer(ifa);

/* If just doing link down, and address is permanent
and not link-local, then retain it. */
if (!how &&
(ifa->flags&IFA_F_PERMANENT) &&
!(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
list_move_tail(&ifa->if_list, &keep_list);

/* If not doing DAD on this address, just keep it. */
if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
idev->cnf.accept_dad <= 0 ||
(ifa->flags & IFA_F_NODAD))
continue;
list_del(&ifa->if_list);

/* If it was tentative already, no need to notify */
if (ifa->flags & IFA_F_TENTATIVE)
continue;
write_unlock_bh(&idev->lock);

/* Flag it for later restoration when link comes up */
ifa->flags |= IFA_F_TENTATIVE;
ifa->state = INET6_IFADDR_STATE_DAD;
} else {
list_del(&ifa->if_list);

/* clear hash table */
spin_lock_bh(&addrconf_hash_lock);
hlist_del_init_rcu(&ifa->addr_lst);
spin_unlock_bh(&addrconf_hash_lock);

write_unlock_bh(&idev->lock);
spin_lock_bh(&ifa->state_lock);
state = ifa->state;
ifa->state = INET6_IFADDR_STATE_DEAD;
spin_unlock_bh(&ifa->state_lock);

if (state != INET6_IFADDR_STATE_DEAD) {
__ipv6_ifa_notify(RTM_DELADDR, ifa);
atomic_notifier_call_chain(&inet6addr_chain,
NETDEV_DOWN, ifa);
}
spin_lock_bh(&ifa->state_lock);
state = ifa->state;
ifa->state = INET6_IFADDR_STATE_DEAD;
spin_unlock_bh(&ifa->state_lock);

in6_ifa_put(ifa);
write_lock_bh(&idev->lock);
if (state != INET6_IFADDR_STATE_DEAD) {
__ipv6_ifa_notify(RTM_DELADDR, ifa);
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
}
}
in6_ifa_put(ifa);

list_splice(&keep_list, &idev->addr_list);
write_lock_bh(&idev->lock);
}

write_unlock_bh(&idev->lock);

Expand Down Expand Up @@ -4156,8 +4142,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
addrconf_leave_solict(ifp->idev, &ifp->addr);
dst_hold(&ifp->rt->dst);

if (ifp->state == INET6_IFADDR_STATE_DEAD &&
ip6_del_rt(ifp->rt))
if (ip6_del_rt(ifp->rt))
dst_free(&ifp->rt->dst);
break;
}
Expand Down

0 comments on commit f7d6c36

Please sign in to comment.