summaryrefslogtreecommitdiffstats
path: root/net/ipv6/ipv6_sockglue.c
diff options
context:
space:
mode:
authorDavid L Stevens <dlstevens@us.ibm.com>2005-06-21 13:58:25 -0700
committerDavid S. Miller <davem@davemloft.net>2005-06-21 13:58:25 -0700
commitc9e3e8b6958e02230079e6817862ea2968509866 (patch)
tree296b30b9e208d37b1cdfa6d40ad785abb1487bd9 /net/ipv6/ipv6_sockglue.c
parent0d51aa80a9b1db43920c0770c3bb842dd823c005 (diff)
downloadlinux-c9e3e8b6958e02230079e6817862ea2968509866.tar.gz
linux-c9e3e8b6958e02230079e6817862ea2968509866.tar.bz2
linux-c9e3e8b6958e02230079e6817862ea2968509866.zip
[IPV6]: multicast join and misc
Here is a simplified version of the patch to fix a bug in IPv6 multicasting. It: 1) adds existence check & EADDRINUSE error for regular joins 2) adds an exception for EADDRINUSE in the source-specific multicast join (where a prior join is ok) 3) adds a missing/needed read_lock on sock_mc_list; would've raced with destroying the socket on interface down without 4) adds a "leave group" in the (INCLUDE, empty) source filter case. This frees unneeded socket buffer memory, but also prevents an inappropriate interaction among the 8 socket options that mess with this. Some would fail as if in the group when you aren't really. Item #4 had a locking bug in the last version of this patch; rather than removing the idev->lock read lock only, I've simplified it to remove all lock state in the path and treat it as a direct "leave group" call for the (INCLUDE,empty) case it covers. Tested on an MP machine. :-) Much thanks to HoerdtMickael <hoerdt@clarinet.u-strasbg.fr> who reported the original bug. Signed-off-by: David L Stevens <dlstevens@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r--net/ipv6/ipv6_sockglue.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 279ab86be662..f3ef4c38d315 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -423,11 +423,12 @@ done:
psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
retv = ipv6_sock_mc_join(sk, greqs.gsr_interface,
&psin6->sin6_addr);
- if (retv)
+ /* prior join w/ different source is ok */
+ if (retv && retv != -EADDRINUSE)
break;
omode = MCAST_INCLUDE;
add = 1;
- } else /*IP_DROP_SOURCE_MEMBERSHIP */ {
+ } else /* MCAST_LEAVE_SOURCE_GROUP */ {
omode = MCAST_INCLUDE;
add = 0;
}