The same patch as in previous e-mail with a few typos in comments corrected:
Signed-off-by: Michal Ruzicka [EMAIL PROTECTED]
--- linux-2.6.17.8/net/ipv4/igmp.c.orig 2006-08-11 11:50:46.0 +0200
+++ linux-2.6.17.8/net/ipv4/igmp.c 2006-08-16 16:53:08.0 +0200
@@ -1369,13 +1369,15 @@
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = imr-imr_multiaddr.s_addr } }
};
struct rtable *rt;
- struct net_device *dev = NULL;
- struct in_device *idev = NULL;
+ struct net_device *dev;
if (imr-imr_ifindex) {
- idev = inetdev_by_index(imr-imr_ifindex);
- if (idev)
+ struct in_device *idev = inetdev_by_index(imr-imr_ifindex);
+
+ if (idev) {
+ imr-imr_address.s_addr = 0;
__in_dev_put(idev);
+ }
return idev;
}
if (imr-imr_address.s_addr) {
@@ -1383,17 +1385,16 @@
if (!dev)
return NULL;
dev_put(dev);
- }
-
- if (!dev !ip_route_output_key(rt, fl)) {
+ } else if (!ip_route_output_key(rt, fl)) {
dev = rt-u.dst.dev;
ip_rt_put(rt);
- }
- if (dev) {
- imr-imr_ifindex = dev-ifindex;
- idev = __in_dev_get_rtnl(dev);
- }
- return idev;
+ if (!dev)
+ return NULL;
+ } else
+ return NULL;
+
+ imr-imr_ifindex = dev-ifindex;
+ return __in_dev_get_rtnl(dev);
}
/*
@@ -1798,27 +1799,79 @@
u32 ifindex;
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);
-
- *imlp = iml-next;
-
- ip_mc_dec_group(in_dev, group);
- rtnl_unlock();
- sock_kfree_s(sk, iml, sizeof(*iml));
- return 0;
+ in_dev = ip_mc_find_dev(imr);
+ if (ifindex != 0) {
+ /* leave by interface index */
+ for (imlp = inet-mc_list; (iml = *imlp) != NULL; imlp =
iml-next) {
+ if (iml-multi.imr_multiaddr.s_addr != group)
+ continue;
+
+ if (iml-multi.imr_ifindex == ifindex)
+ goto leave;
+ }
+ } else {
+ /* leave by address / multicast group route */
+ struct ip_mc_socklist **cimlp = NULL;
+ u32 address = imr-imr_address.s_addr;
+
+ ifindex = imr-imr_ifindex;
+ for (imlp = inet-mc_list; (iml = *imlp) != NULL; imlp =
iml-next) {
+ if (iml-multi.imr_multiaddr.s_addr != group)
+ continue;
+
+ if (iml-multi.imr_ifindex == ifindex)
+ /* direct match
+* NOTE: We do not have to test for in_dev !=
NULL
+* since we know that ifindex was zero before
call
+* to ip_mc_find_dev() but is non-zero now (as
+* it equals to an interface index which is
never
+* zero). The ip_mc_find_dev() function modifies
+* the ifindex only if it finds an interface
+* (in wich case it returns non-NULL). Thus the
+* in_dev must be non-NULL.
+*/
+ goto leave;
+
+ if (cimlp == NULL iml-multi.imr_address.s_addr ==
address)
+ cimlp = imlp;
+ }
+
+ if (cimlp != NULL) {
+ /* We have found at least one candidate interface
+* for leaving by address but not a direct match.
+* Since there is no way to tell what interface the user
+* wnated to leave the multicast group on we are going
+* to leave it on the first candidate interface found.
+*/
+ iml = *(imlp = cimlp);
+
+ if (in_dev != NULL) {
+ /* If we have found an interface matching the
leave
+* request chances are that the interface which
we
+* are about to leave the multicast group on
still