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.000000000 +0200 +++ linux-2.6.17.8/net/ipv4/igmp.c 2006-08-16 16:53:08.000000000 +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 + * exists. Check if it is the case so as to call + * ip_mc_dec_group() properly. + */ + imr->imr_ifindex = iml->multi.imr_ifindex; + in_dev = ip_mc_find_dev(imr); + } + + goto leave; } } rtnl_unlock(); - return -EADDRNOTAVAIL; + return (in_dev == NULL) ? -ENODEV : -EADDRNOTAVAIL; + +leave: + *imlp = iml->next; + + (void) ip_mc_leave_src(sk, iml, in_dev); + if (in_dev != NULL) + ip_mc_dec_group(in_dev, group); + rtnl_unlock(); + sock_kfree_s(sk, iml, sizeof(*iml)); + return 0; } int ip_mc_source(int add, int omode, struct sock *sk, struct Michal - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html