[IPV4]: multicast API "join" issues
This patch corrects a few problems with the IP_ADD_MEMBERSHIP socket option: 1) The existing code makes an attempt at reference counting joins when using the ip_mreqn/imr_ifindex interface. Joining the same group on the same socket is an error, whatever the API. This leads to unexpected results when mixing ip_mreqn by index with ip_mreqn by address, ip_mreq, or other API's. For example, ip_mreq followed by ip_mreqn of the same group will "work" while the same two reversed will not. Fixed to always return EADDRINUSE on a duplicate join and removed the (now unused) reference count in ip_mc_socklist. 2) The group-search list in ip_mc_join_group() is comparing a full ip_mreqn structure and all of it must match for it to find the group. This doesn't correctly match a group that was joined with ip_mreq or ip_mreqn with an address (with or without an index). It also doesn't match groups that are joined by different addresses on the same interface. All of these are the same multicast group, which is identified by group address and interface index. Fixed the check to correctly match groups so we don't get duplicate group entries on the ip_mc_socklist. 3) The old code allocates a multicast address before searching for duplicates requiring it to free in various error cases. This patch moves the allocate until after the search and igmp_max_memberships check, so never a need to allocate, then free an entry. Signed-off-by: David L Stevens <dlstevens@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4c866aa798
commit
ca9b907d14
2 changed files with 12 additions and 24 deletions
|
@ -148,7 +148,6 @@ struct ip_sf_socklist
|
|||
struct ip_mc_socklist
|
||||
{
|
||||
struct ip_mc_socklist *next;
|
||||
int count;
|
||||
struct ip_mreqn multi;
|
||||
unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */
|
||||
struct ip_sf_socklist *sflist;
|
||||
|
|
|
@ -1615,9 +1615,10 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
|
|||
{
|
||||
int err;
|
||||
u32 addr = imr->imr_multiaddr.s_addr;
|
||||
struct ip_mc_socklist *iml, *i;
|
||||
struct ip_mc_socklist *iml=NULL, *i;
|
||||
struct in_device *in_dev;
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
int ifindex;
|
||||
int count = 0;
|
||||
|
||||
if (!MULTICAST(addr))
|
||||
|
@ -1633,37 +1634,30 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
|
|||
goto done;
|
||||
}
|
||||
|
||||
iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
|
||||
|
||||
err = -EADDRINUSE;
|
||||
ifindex = imr->imr_ifindex;
|
||||
for (i = inet->mc_list; i; i = i->next) {
|
||||
if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) {
|
||||
/* New style additions are reference counted */
|
||||
if (imr->imr_address.s_addr == 0) {
|
||||
i->count++;
|
||||
err = 0;
|
||||
}
|
||||
if (i->multi.imr_multiaddr.s_addr == addr &&
|
||||
i->multi.imr_ifindex == ifindex)
|
||||
goto done;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
err = -ENOBUFS;
|
||||
if (iml == NULL || count >= sysctl_igmp_max_memberships)
|
||||
if (count >= sysctl_igmp_max_memberships)
|
||||
goto done;
|
||||
iml = (struct ip_mc_socklist *)sock_kmalloc(sk,sizeof(*iml),GFP_KERNEL);
|
||||
if (iml == NULL)
|
||||
goto done;
|
||||
|
||||
memcpy(&iml->multi, imr, sizeof(*imr));
|
||||
iml->next = inet->mc_list;
|
||||
iml->count = 1;
|
||||
iml->sflist = NULL;
|
||||
iml->sfmode = MCAST_EXCLUDE;
|
||||
inet->mc_list = iml;
|
||||
ip_mc_inc_group(in_dev, addr);
|
||||
iml = NULL;
|
||||
err = 0;
|
||||
|
||||
done:
|
||||
rtnl_shunlock();
|
||||
if (iml)
|
||||
sock_kfree_s(sk, iml, sizeof(*iml));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1704,12 +1698,6 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
|
|||
in_dev = inetdev_by_index(iml->multi.imr_ifindex);
|
||||
if (in_dev)
|
||||
(void) ip_mc_leave_src(sk, iml, in_dev);
|
||||
if (--iml->count) {
|
||||
rtnl_unlock();
|
||||
if (in_dev)
|
||||
in_dev_put(in_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*imlp = iml->next;
|
||||
|
||||
|
@ -1755,7 +1743,8 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
|
|||
err = -EADDRNOTAVAIL;
|
||||
|
||||
for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
|
||||
if (memcmp(&pmc->multi, mreqs, 2*sizeof(__u32)) == 0)
|
||||
if (pmc->multi.imr_multiaddr.s_addr == imr.imr_multiaddr.s_addr
|
||||
&& pmc->multi.imr_ifindex == imr.imr_ifindex)
|
||||
break;
|
||||
}
|
||||
if (!pmc) /* must have a prior join */
|
||||
|
|
Loading…
Reference in a new issue