Here's a patch to fix source filter leakage when a device is removed and a process leaves the group thereafter. (2nd part of prior discussion)
This patch also includes corresponding fixes for IPv6 multicast source filters on device removal (1st & 2nd parts of prior discussion, for IPv6). +-DLS [in-line for viewing, attached for applying] Signed-off-by: David L Stevens <[EMAIL PROTECTED]> diff -ruNp linux-2.6.17.8/net/ipv4/igmp.c linux-2.6.17.8-dls/net/ipv4/igmp.c --- linux-2.6.17.8/net/ipv4/igmp.c 2006-08-06 21:18:54.000000000 -0700 +++ linux-2.6.17.8-dls/net/ipv4/igmp.c 2006-08-15 16:30:18.000000000 -0700 @@ -1796,29 +1796,35 @@ int ip_mc_leave_group(struct sock *sk, s 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; + + (void) ip_mc_leave_src(sk, iml, in_dev); - *imlp = iml->next; + *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 diff -ruNp linux-2.6.17.8/net/ipv6/mcast.c linux-2.6.17.8-dls/net/ipv6/mcast.c --- linux-2.6.17.8/net/ipv6/mcast.c 2006-08-06 21:18:54.000000000 -0700 +++ linux-2.6.17.8-dls/net/ipv6/mcast.c 2006-08-15 15:51:53.000000000 -0700 @@ -269,13 +269,14 @@ int ipv6_sock_mc_drop(struct sock *sk, i if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) { struct inet6_dev *idev = in6_dev_get(dev); + (void) ip6_mc_leave_src(sk, mc_lst, idev); if (idev) { - (void) ip6_mc_leave_src(sk,mc_lst,idev); __ipv6_dev_mc_dec(idev, &mc_lst->addr); in6_dev_put(idev); } dev_put(dev); - } + } else + (void) ip6_mc_leave_src(sk, mc_lst, NULL); sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); return 0; } @@ -335,13 +336,14 @@ void ipv6_sock_mc_close(struct sock *sk) if (dev) { struct inet6_dev *idev = in6_dev_get(dev); + (void) ip6_mc_leave_src(sk, mc_lst, idev); if (idev) { - (void) ip6_mc_leave_src(sk, mc_lst, idev); __ipv6_dev_mc_dec(idev, &mc_lst->addr); in6_dev_put(idev); } dev_put(dev); - } + } else + (void) ip6_mc_leave_src(sk, mc_lst, NULL); sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
mcd.patch
Description: Binary data