diff options
author | David L Stevens <dlstevens@us.ibm.com> | 2006-08-18 01:27:39 +0200 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-08-18 01:29:57 +0200 |
commit | acd6e00b8e4db542cb6bc9ddfbb4e18bbe29ce4d (patch) | |
tree | f644e1ee2a5d85b1d680897105ad8f38a562cfc1 /net/ipv4/igmp.c | |
parent | [NET]: Disallow whitespace in network device names. (diff) | |
download | linux-acd6e00b8e4db542cb6bc9ddfbb4e18bbe29ce4d.tar.xz linux-acd6e00b8e4db542cb6bc9ddfbb4e18bbe29ce4d.zip |
[MCAST]: Fix filter leak on device removal.
This fixes source filter leakage when a device is removed and a
process leaves the group thereafter.
This also includes corresponding fixes for IPv6 multicast source
filters on device removal.
Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/igmp.c')
-rw-r--r-- | net/ipv4/igmp.c | 32 |
1 files changed, 19 insertions, 13 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index e981369ebe13..8e8117c19e4d 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1793,29 +1793,35 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) struct in_device *in_dev; u32 group = imr->imr_multiaddr.s_addr; u32 ifindex; + int ret = -EADDRNOTAVAIL; rtnl_lock(); in_dev = ip_mc_find_dev(imr); - if (!in_dev) { - rtnl_unlock(); - return -ENODEV; - } ifindex = imr->imr_ifindex; for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) { - if (iml->multi.imr_multiaddr.s_addr == group && - iml->multi.imr_ifindex == ifindex) { - (void) ip_mc_leave_src(sk, iml, in_dev); + if (iml->multi.imr_multiaddr.s_addr != group) + continue; + if (ifindex) { + if (iml->multi.imr_ifindex != ifindex) + continue; + } else if (imr->imr_address.s_addr && imr->imr_address.s_addr != + iml->multi.imr_address.s_addr) + continue; - *imlp = iml->next; + (void) ip_mc_leave_src(sk, iml, in_dev); + *imlp = iml->next; + + if (in_dev) ip_mc_dec_group(in_dev, group); - rtnl_unlock(); - sock_kfree_s(sk, iml, sizeof(*iml)); - return 0; - } + rtnl_unlock(); + sock_kfree_s(sk, iml, sizeof(*iml)); + return 0; } + if (!in_dev) + ret = -ENODEV; rtnl_unlock(); - return -EADDRNOTAVAIL; + return ret; } int ip_mc_source(int add, int omode, struct sock *sk, struct |