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

Reply via email to