Commit 9951f036 authored by David L Stevens's avatar David L Stevens Committed by David S. Miller

[IPV4]: (INCLUDE,empty)/leave-group equivalence for full-state MSF APIs & errno fix

1) Adds (INCLUDE, empty)/leave-group equivalence to the full-state 
   multicast source filter APIs (IPv4 and IPv6)

2) Fixes an incorrect errno in the IPv6 leave-group (ENOENT should be
   EADDRNOTAVAIL)
Signed-off-by: default avatarDavid L Stevens <dlstevens@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 917f2f10
...@@ -1849,13 +1849,14 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct ...@@ -1849,13 +1849,14 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
{ {
int err; int err = 0;
struct ip_mreqn imr; struct ip_mreqn imr;
u32 addr = msf->imsf_multiaddr; u32 addr = msf->imsf_multiaddr;
struct ip_mc_socklist *pmc; struct ip_mc_socklist *pmc;
struct in_device *in_dev; struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
struct ip_sf_socklist *newpsl, *psl; struct ip_sf_socklist *newpsl, *psl;
int leavegroup = 0;
if (!MULTICAST(addr)) if (!MULTICAST(addr))
return -EINVAL; return -EINVAL;
...@@ -1875,6 +1876,12 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) ...@@ -1875,6 +1876,12 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
goto done; goto done;
} }
/* special case - (INCLUDE, empty) == LEAVE_GROUP */
if (msf->imsf_fmode == MCAST_INCLUDE && msf->imsf_numsrc == 0) {
leavegroup = 1;
goto done;
}
for (pmc=inet->mc_list; pmc; pmc=pmc->next) { for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&
pmc->multi.imr_ifindex == imr.imr_ifindex) pmc->multi.imr_ifindex == imr.imr_ifindex)
...@@ -1915,6 +1922,8 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) ...@@ -1915,6 +1922,8 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
err = 0; err = 0;
done: done:
rtnl_shunlock(); rtnl_shunlock();
if (leavegroup)
err = ip_mc_leave_group(sk, &imr);
return err; return err;
} }
......
...@@ -281,7 +281,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) ...@@ -281,7 +281,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
} }
write_unlock_bh(&ipv6_sk_mc_lock); write_unlock_bh(&ipv6_sk_mc_lock);
return -ENOENT; return -EADDRNOTAVAIL;
} }
static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex)
...@@ -492,6 +492,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) ...@@ -492,6 +492,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
struct inet6_dev *idev; struct inet6_dev *idev;
struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct ip6_sf_socklist *newpsl, *psl; struct ip6_sf_socklist *newpsl, *psl;
int leavegroup = 0;
int i, err; int i, err;
group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
...@@ -508,6 +509,11 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) ...@@ -508,6 +509,11 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
return -ENODEV; return -ENODEV;
dev = idev->dev; dev = idev->dev;
if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
leavegroup = 1;
goto done;
}
for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
if (pmc->ifindex != gsf->gf_interface) if (pmc->ifindex != gsf->gf_interface)
continue; continue;
...@@ -554,6 +560,8 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) ...@@ -554,6 +560,8 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
in6_dev_put(idev); in6_dev_put(idev);
dev_put(dev); dev_put(dev);
if (leavegroup)
err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
return err; return err;
} }
......
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