[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: David L Stevens <dlstevens@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
ca9b907d14
commit
8cdaaa15da
@@ -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
|
|||||||
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
|
|||||||
&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,
|
|||||||
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,
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user