diff options
Diffstat (limited to 'net/ipv4/igmp.c')
-rw-r--r-- | net/ipv4/igmp.c | 38 |
1 files changed, 22 insertions, 16 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 9f4b752f5a33..8e8117c19e4d 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -1793,29 +1793,35 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | |||
1793 | struct in_device *in_dev; | 1793 | struct in_device *in_dev; |
1794 | u32 group = imr->imr_multiaddr.s_addr; | 1794 | u32 group = imr->imr_multiaddr.s_addr; |
1795 | u32 ifindex; | 1795 | u32 ifindex; |
1796 | int ret = -EADDRNOTAVAIL; | ||
1796 | 1797 | ||
1797 | rtnl_lock(); | 1798 | rtnl_lock(); |
1798 | in_dev = ip_mc_find_dev(imr); | 1799 | in_dev = ip_mc_find_dev(imr); |
1799 | if (!in_dev) { | ||
1800 | rtnl_unlock(); | ||
1801 | return -ENODEV; | ||
1802 | } | ||
1803 | ifindex = imr->imr_ifindex; | 1800 | ifindex = imr->imr_ifindex; |
1804 | for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) { | 1801 | for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) { |
1805 | if (iml->multi.imr_multiaddr.s_addr == group && | 1802 | if (iml->multi.imr_multiaddr.s_addr != group) |
1806 | iml->multi.imr_ifindex == ifindex) { | 1803 | continue; |
1807 | (void) ip_mc_leave_src(sk, iml, in_dev); | 1804 | if (ifindex) { |
1805 | if (iml->multi.imr_ifindex != ifindex) | ||
1806 | continue; | ||
1807 | } else if (imr->imr_address.s_addr && imr->imr_address.s_addr != | ||
1808 | iml->multi.imr_address.s_addr) | ||
1809 | continue; | ||
1810 | |||
1811 | (void) ip_mc_leave_src(sk, iml, in_dev); | ||
1808 | 1812 | ||
1809 | *imlp = iml->next; | 1813 | *imlp = iml->next; |
1810 | 1814 | ||
1815 | if (in_dev) | ||
1811 | ip_mc_dec_group(in_dev, group); | 1816 | ip_mc_dec_group(in_dev, group); |
1812 | rtnl_unlock(); | 1817 | rtnl_unlock(); |
1813 | sock_kfree_s(sk, iml, sizeof(*iml)); | 1818 | sock_kfree_s(sk, iml, sizeof(*iml)); |
1814 | return 0; | 1819 | return 0; |
1815 | } | ||
1816 | } | 1820 | } |
1821 | if (!in_dev) | ||
1822 | ret = -ENODEV; | ||
1817 | rtnl_unlock(); | 1823 | rtnl_unlock(); |
1818 | return -EADDRNOTAVAIL; | 1824 | return ret; |
1819 | } | 1825 | } |
1820 | 1826 | ||
1821 | int ip_mc_source(int add, int omode, struct sock *sk, struct | 1827 | int ip_mc_source(int add, int omode, struct sock *sk, struct |
@@ -2199,13 +2205,13 @@ void ip_mc_drop_socket(struct sock *sk) | |||
2199 | struct in_device *in_dev; | 2205 | struct in_device *in_dev; |
2200 | inet->mc_list = iml->next; | 2206 | inet->mc_list = iml->next; |
2201 | 2207 | ||
2202 | if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != NULL) { | 2208 | in_dev = inetdev_by_index(iml->multi.imr_ifindex); |
2203 | (void) ip_mc_leave_src(sk, iml, in_dev); | 2209 | (void) ip_mc_leave_src(sk, iml, in_dev); |
2210 | if (in_dev != NULL) { | ||
2204 | ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); | 2211 | ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); |
2205 | in_dev_put(in_dev); | 2212 | in_dev_put(in_dev); |
2206 | } | 2213 | } |
2207 | sock_kfree_s(sk, iml, sizeof(*iml)); | 2214 | sock_kfree_s(sk, iml, sizeof(*iml)); |
2208 | |||
2209 | } | 2215 | } |
2210 | rtnl_unlock(); | 2216 | rtnl_unlock(); |
2211 | } | 2217 | } |