Commit d7e6c32e authored by David S. Miller's avatar David S. Miller

[IPV6]: Fix dangling multicast device references.

When addrconf_ifdown() calls ipv6_mc_destroy_dev(), it has NULL'd
out dev->ip6_ptr, which means all in6_dev_get() calls will fail.
So pass an explicit idev into ipv6_dev_mc_dec() in this case so
that we don't leak the all-nodes multicast address reference to the
idev.
parent 3aa4ac18
...@@ -854,15 +854,10 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) ...@@ -854,15 +854,10 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
/* /*
* device multicast group del * device multicast group del
*/ */
int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr) static int __ipv6_dev_mc_dec(struct net_device *dev, struct inet6_dev *idev, struct in6_addr *addr)
{ {
struct inet6_dev *idev;
struct ifmcaddr6 *ma, **map; struct ifmcaddr6 *ma, **map;
idev = in6_dev_get(dev);
if (idev == NULL)
return -ENODEV;
write_lock_bh(&idev->lock); write_lock_bh(&idev->lock);
for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) { for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {
if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) { if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) {
...@@ -873,20 +868,32 @@ int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr) ...@@ -873,20 +868,32 @@ int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
igmp6_group_dropped(ma); igmp6_group_dropped(ma);
ma_put(ma); ma_put(ma);
in6_dev_put(idev);
return 0; return 0;
} }
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
in6_dev_put(idev);
return 0; return 0;
} }
} }
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
in6_dev_put(idev);
return -ENOENT; return -ENOENT;
} }
int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
{
struct inet6_dev *idev = in6_dev_get(dev);
int err;
if (!idev)
return -ENODEV;
err = __ipv6_dev_mc_dec(dev, idev, addr);
in6_dev_put(idev);
return err;
}
/* /*
* check if the interface/address pair is valid * check if the interface/address pair is valid
*/ */
...@@ -2024,7 +2031,12 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) ...@@ -2024,7 +2031,12 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
/* Delete all-nodes address. */ /* Delete all-nodes address. */
ipv6_addr_all_nodes(&maddr); ipv6_addr_all_nodes(&maddr);
ipv6_dev_mc_dec(idev->dev, &maddr);
/* We cannot call ipv6_dev_mc_dec() directly, our caller in
* addrconf.c has NULL'd out dev->ip6_ptr so in6_dev_get() will
* fail.
*/
__ipv6_dev_mc_dec(idev->dev, idev, &maddr);
write_lock_bh(&idev->lock); write_lock_bh(&idev->lock);
while ((i = idev->mc_list) != NULL) { while ((i = idev->mc_list) != NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment