diff options
| -rw-r--r-- | net/ipv4/igmp.c | 11 | ||||
| -rw-r--r-- | net/ipv6/mcast.c | 10 |
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 | ||
| 1850 | int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | 1850 | int 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; |
| 1916 | done: | 1923 | done: |
| 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 | ||
| 287 | static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) | 287 | 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 | 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 | ||
