aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/igmp.c11
-rw-r--r--net/ipv6/mcast.c10
2 files changed, 19 insertions, 2 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index dbbfa09de4e8..7af3146939dc 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1849,13 +1849,14 @@ done:
1849 1849
1850int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) 1850int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
1851{ 1851{
1852 int err; 1852 int err = 0;
1853 struct ip_mreqn imr; 1853 struct ip_mreqn imr;
1854 u32 addr = msf->imsf_multiaddr; 1854 u32 addr = msf->imsf_multiaddr;
1855 struct ip_mc_socklist *pmc; 1855 struct ip_mc_socklist *pmc;
1856 struct in_device *in_dev; 1856 struct in_device *in_dev;
1857 struct inet_sock *inet = inet_sk(sk); 1857 struct inet_sock *inet = inet_sk(sk);
1858 struct ip_sf_socklist *newpsl, *psl; 1858 struct ip_sf_socklist *newpsl, *psl;
1859 int leavegroup = 0;
1859 1860
1860 if (!MULTICAST(addr)) 1861 if (!MULTICAST(addr))
1861 return -EINVAL; 1862 return -EINVAL;
@@ -1875,6 +1876,12 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
1875 goto done; 1876 goto done;
1876 } 1877 }
1877 1878
1879 /* special case - (INCLUDE, empty) == LEAVE_GROUP */
1880 if (msf->imsf_fmode == MCAST_INCLUDE && msf->imsf_numsrc == 0) {
1881 leavegroup = 1;
1882 goto done;
1883 }
1884
1878 for (pmc=inet->mc_list; pmc; pmc=pmc->next) { 1885 for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
1879 if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && 1886 if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&
1880 pmc->multi.imr_ifindex == imr.imr_ifindex) 1887 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 err = 0; 1922 err = 0;
1916done: 1923done:
1917 rtnl_shunlock(); 1924 rtnl_shunlock();
1925 if (leavegroup)
1926 err = ip_mc_leave_group(sk, &imr);
1918 return err; 1927 return err;
1919} 1928}
1920 1929
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 9db4581d0d79..398c982625f8 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -281,7 +281,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
281 } 281 }
282 write_unlock_bh(&ipv6_sk_mc_lock); 282 write_unlock_bh(&ipv6_sk_mc_lock);
283 283
284 return -ENOENT; 284 return -EADDRNOTAVAIL;
285} 285}
286 286
287static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) 287static 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 struct inet6_dev *idev; 492 struct inet6_dev *idev;
493 struct ipv6_pinfo *inet6 = inet6_sk(sk); 493 struct ipv6_pinfo *inet6 = inet6_sk(sk);
494 struct ip6_sf_socklist *newpsl, *psl; 494 struct ip6_sf_socklist *newpsl, *psl;
495 int leavegroup = 0;
495 int i, err; 496 int i, err;
496 497
497 group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; 498 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 return -ENODEV; 509 return -ENODEV;
509 dev = idev->dev; 510 dev = idev->dev;
510 511
512 if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
513 leavegroup = 1;
514 goto done;
515 }
516
511 for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) { 517 for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
512 if (pmc->ifindex != gsf->gf_interface) 518 if (pmc->ifindex != gsf->gf_interface)
513 continue; 519 continue;
@@ -554,6 +560,8 @@ done:
554 read_unlock_bh(&idev->lock); 560 read_unlock_bh(&idev->lock);
555 in6_dev_put(idev); 561 in6_dev_put(idev);
556 dev_put(dev); 562 dev_put(dev);
563 if (leavegroup)
564 err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
557 return err; 565 return err;
558} 566}
559 567