Commit 8cdaaa15 authored by David L Stevens's avatar David L Stevens Committed by David S. Miller

[IPV4]: multicast API "join" issues

1) Changes IP_ADD_SOURCE_MEMBERSHIP and MCAST_JOIN_SOURCE_GROUP to ignore
   EADDRINUSE errors on a "courtesy join" -- prior membership or not
   is ok for these.

2) Adds "leave group" equivalence of (INCLUDE, empty) filters in the 
   delta-based API. Without this, mixing delta-based API calls that
   end in an (INCLUDE, empty) filter would not allow a subsequent
   regular IP_ADD_MEMBERSHIP. It also frees socket buffer memory that
   isn't needed for both the multicast group record and source filter.
Signed-off-by: default avatarDavid L Stevens <dlstevens@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ca9b907d
...@@ -1724,6 +1724,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct ...@@ -1724,6 +1724,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
struct in_device *in_dev = NULL; struct in_device *in_dev = NULL;
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
struct ip_sf_socklist *psl; struct ip_sf_socklist *psl;
int leavegroup = 0;
int i, j, rv; int i, j, rv;
if (!MULTICAST(addr)) if (!MULTICAST(addr))
...@@ -1775,6 +1776,12 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct ...@@ -1775,6 +1776,12 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
if (rv) /* source not found */ if (rv) /* source not found */
goto done; goto done;
/* special case - (INCLUDE, empty) == LEAVE_GROUP */
if (psl->sl_count == 1 && omode == MCAST_INCLUDE) {
leavegroup = 1;
goto done;
}
/* update the interface filter */ /* update the interface filter */
ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1, ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1,
&mreqs->imr_sourceaddr, 1); &mreqs->imr_sourceaddr, 1);
...@@ -1831,6 +1838,8 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct ...@@ -1831,6 +1838,8 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
&mreqs->imr_sourceaddr, 1); &mreqs->imr_sourceaddr, 1);
done: done:
rtnl_shunlock(); rtnl_shunlock();
if (leavegroup)
return ip_mc_leave_group(sk, &imr);
return err; return err;
} }
......
...@@ -677,11 +677,11 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, ...@@ -677,11 +677,11 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
mreq.imr_address.s_addr = mreqs.imr_interface; mreq.imr_address.s_addr = mreqs.imr_interface;
mreq.imr_ifindex = 0; mreq.imr_ifindex = 0;
err = ip_mc_join_group(sk, &mreq); err = ip_mc_join_group(sk, &mreq);
if (err) if (err && err != -EADDRINUSE)
break; break;
omode = MCAST_INCLUDE; omode = MCAST_INCLUDE;
add = 1; add = 1;
} else /*IP_DROP_SOURCE_MEMBERSHIP */ { } else /* IP_DROP_SOURCE_MEMBERSHIP */ {
omode = MCAST_INCLUDE; omode = MCAST_INCLUDE;
add = 0; add = 0;
} }
...@@ -754,7 +754,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, ...@@ -754,7 +754,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
mreq.imr_address.s_addr = 0; mreq.imr_address.s_addr = 0;
mreq.imr_ifindex = greqs.gsr_interface; mreq.imr_ifindex = greqs.gsr_interface;
err = ip_mc_join_group(sk, &mreq); err = ip_mc_join_group(sk, &mreq);
if (err) if (err && err != -EADDRINUSE)
break; break;
greqs.gsr_interface = mreq.imr_ifindex; greqs.gsr_interface = mreq.imr_ifindex;
omode = MCAST_INCLUDE; omode = MCAST_INCLUDE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment