> Michal,
>         This looks correct, but I think a better way to do it is:
> 
>         in_dev = inetdev_by_index(...)
>         (void) ip_mc_leave_src()
>         if (in_dev) {
>                 ip_mc_dec_group()
>                 in_dev_put()
>         }
> 
>         That way, sflist internal details aren't visible at this
> level, and ip_mc_leave_src() collapses to the sock_kfree_s()
> when in_dev is NULL.

You are absolutely right, I just failed to notice that -ENODEV return value
from ip_mc_del_src()/ip_mc_leave_src() is ignored.
Here comes the patch:

--- linux-2.6.17.8/net/ipv4/igmp.c.orig 2006-08-11 11:45:56.000000000 +0200
+++ linux-2.6.17.8/net/ipv4/igmp.c      2006-08-11 11:51:56.000000000 +0200
@@ -2202,13 +2202,13 @@
                struct in_device *in_dev;
                inet->mc_list = iml->next;
 
-               if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != 
NULL) {
-                       (void) ip_mc_leave_src(sk, iml, in_dev);
+               in_dev = inetdev_by_index(iml->multi.imr_ifindex);
+               (void) ip_mc_leave_src(sk, iml, in_dev);
+               if (in_dev != NULL) {
                        ip_mc_dec_group(in_dev, 
iml->multi.imr_multiaddr.s_addr);
                        in_dev_put(in_dev);
                }
                sock_kfree_s(sk, iml, sizeof(*iml));
-
        }
        rtnl_unlock();
 }


>         Also, ip_mc_leave_group() has the same issue; looks
> like it just needs the "if (in_dev)" removed before the call to
> ip_mc_leave_src().

In fact it is a slightly different issue, there is no leak in this
function. Rather the function completely fails to leave a multicast
group joined on an interface that does not exist any more. Actually
this is how I discovered the bug as I was tracking down a problem
with ripd daemon of routing software quagga which failed to join
a multicast group (with -ENOBUFS) on an interface after there were
several (20 to be precise which corresponds to the default value
[IP_MAX_MEMBERSHIPS] of sysctl_igmp_max_memberships) interfaces
added/removed.
Here comes a patch for that:

--- linux-2.6.17.8/net/ipv4/igmp.c.leak 2006-08-11 11:50:46.000000000 +0200
+++ linux-2.6.17.8/net/ipv4/igmp.c      2006-08-11 11:52:33.000000000 +0200
@@ -1799,19 +1799,15 @@
 
        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);
+                       (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;


>                                         +-DLS
> 

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