diff options
Diffstat (limited to 'net/ipv4/igmp.c')
| -rw-r--r-- | net/ipv4/igmp.c | 138 |
1 files changed, 94 insertions, 44 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 76c08402c933..2a4bb76f2132 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
| @@ -71,6 +71,7 @@ | |||
| 71 | */ | 71 | */ |
| 72 | 72 | ||
| 73 | #include <linux/module.h> | 73 | #include <linux/module.h> |
| 74 | #include <linux/slab.h> | ||
| 74 | #include <asm/uaccess.h> | 75 | #include <asm/uaccess.h> |
| 75 | #include <asm/system.h> | 76 | #include <asm/system.h> |
| 76 | #include <linux/types.h> | 77 | #include <linux/types.h> |
| @@ -311,7 +312,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) | |||
| 311 | return NULL; | 312 | return NULL; |
| 312 | } | 313 | } |
| 313 | 314 | ||
| 314 | skb_dst_set(skb, &rt->u.dst); | 315 | skb_dst_set(skb, &rt->dst); |
| 315 | skb->dev = dev; | 316 | skb->dev = dev; |
| 316 | 317 | ||
| 317 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | 318 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); |
| @@ -329,7 +330,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size) | |||
| 329 | pip->saddr = rt->rt_src; | 330 | pip->saddr = rt->rt_src; |
| 330 | pip->protocol = IPPROTO_IGMP; | 331 | pip->protocol = IPPROTO_IGMP; |
| 331 | pip->tot_len = 0; /* filled in later */ | 332 | pip->tot_len = 0; /* filled in later */ |
| 332 | ip_select_ident(pip, &rt->u.dst, NULL); | 333 | ip_select_ident(pip, &rt->dst, NULL); |
| 333 | ((u8*)&pip[1])[0] = IPOPT_RA; | 334 | ((u8*)&pip[1])[0] = IPOPT_RA; |
| 334 | ((u8*)&pip[1])[1] = 4; | 335 | ((u8*)&pip[1])[1] = 4; |
| 335 | ((u8*)&pip[1])[2] = 0; | 336 | ((u8*)&pip[1])[2] = 0; |
| @@ -659,7 +660,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, | |||
| 659 | return -1; | 660 | return -1; |
| 660 | } | 661 | } |
| 661 | 662 | ||
| 662 | skb_dst_set(skb, &rt->u.dst); | 663 | skb_dst_set(skb, &rt->dst); |
| 663 | 664 | ||
| 664 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | 665 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); |
| 665 | 666 | ||
| @@ -675,7 +676,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, | |||
| 675 | iph->daddr = dst; | 676 | iph->daddr = dst; |
| 676 | iph->saddr = rt->rt_src; | 677 | iph->saddr = rt->rt_src; |
| 677 | iph->protocol = IPPROTO_IGMP; | 678 | iph->protocol = IPPROTO_IGMP; |
| 678 | ip_select_ident(iph, &rt->u.dst, NULL); | 679 | ip_select_ident(iph, &rt->dst, NULL); |
| 679 | ((u8*)&iph[1])[0] = IPOPT_RA; | 680 | ((u8*)&iph[1])[0] = IPOPT_RA; |
| 680 | ((u8*)&iph[1])[1] = 4; | 681 | ((u8*)&iph[1])[1] = 4; |
| 681 | ((u8*)&iph[1])[2] = 0; | 682 | ((u8*)&iph[1])[2] = 0; |
| @@ -855,6 +856,18 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | |||
| 855 | igmpv3_clear_delrec(in_dev); | 856 | igmpv3_clear_delrec(in_dev); |
| 856 | } else if (len < 12) { | 857 | } else if (len < 12) { |
| 857 | return; /* ignore bogus packet; freed by caller */ | 858 | return; /* ignore bogus packet; freed by caller */ |
| 859 | } else if (IGMP_V1_SEEN(in_dev)) { | ||
| 860 | /* This is a v3 query with v1 queriers present */ | ||
| 861 | max_delay = IGMP_Query_Response_Interval; | ||
| 862 | group = 0; | ||
| 863 | } else if (IGMP_V2_SEEN(in_dev)) { | ||
| 864 | /* this is a v3 query with v2 queriers present; | ||
| 865 | * Interpretation of the max_delay code is problematic here. | ||
| 866 | * A real v2 host would use ih_code directly, while v3 has a | ||
| 867 | * different encoding. We use the v3 encoding as more likely | ||
| 868 | * to be intended in a v3 query. | ||
| 869 | */ | ||
| 870 | max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE); | ||
| 858 | } else { /* v3 */ | 871 | } else { /* v3 */ |
| 859 | if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) | 872 | if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) |
| 860 | return; | 873 | return; |
| @@ -915,18 +928,19 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, | |||
| 915 | read_unlock(&in_dev->mc_list_lock); | 928 | read_unlock(&in_dev->mc_list_lock); |
| 916 | } | 929 | } |
| 917 | 930 | ||
| 931 | /* called in rcu_read_lock() section */ | ||
| 918 | int igmp_rcv(struct sk_buff *skb) | 932 | int igmp_rcv(struct sk_buff *skb) |
| 919 | { | 933 | { |
| 920 | /* This basically follows the spec line by line -- see RFC1112 */ | 934 | /* This basically follows the spec line by line -- see RFC1112 */ |
| 921 | struct igmphdr *ih; | 935 | struct igmphdr *ih; |
| 922 | struct in_device *in_dev = in_dev_get(skb->dev); | 936 | struct in_device *in_dev = __in_dev_get_rcu(skb->dev); |
| 923 | int len = skb->len; | 937 | int len = skb->len; |
| 924 | 938 | ||
| 925 | if (in_dev == NULL) | 939 | if (in_dev == NULL) |
| 926 | goto drop; | 940 | goto drop; |
| 927 | 941 | ||
| 928 | if (!pskb_may_pull(skb, sizeof(struct igmphdr))) | 942 | if (!pskb_may_pull(skb, sizeof(struct igmphdr))) |
| 929 | goto drop_ref; | 943 | goto drop; |
| 930 | 944 | ||
| 931 | switch (skb->ip_summed) { | 945 | switch (skb->ip_summed) { |
| 932 | case CHECKSUM_COMPLETE: | 946 | case CHECKSUM_COMPLETE: |
| @@ -936,7 +950,7 @@ int igmp_rcv(struct sk_buff *skb) | |||
| 936 | case CHECKSUM_NONE: | 950 | case CHECKSUM_NONE: |
| 937 | skb->csum = 0; | 951 | skb->csum = 0; |
| 938 | if (__skb_checksum_complete(skb)) | 952 | if (__skb_checksum_complete(skb)) |
| 939 | goto drop_ref; | 953 | goto drop; |
| 940 | } | 954 | } |
| 941 | 955 | ||
| 942 | ih = igmp_hdr(skb); | 956 | ih = igmp_hdr(skb); |
| @@ -946,7 +960,6 @@ int igmp_rcv(struct sk_buff *skb) | |||
| 946 | break; | 960 | break; |
| 947 | case IGMP_HOST_MEMBERSHIP_REPORT: | 961 | case IGMP_HOST_MEMBERSHIP_REPORT: |
| 948 | case IGMPV2_HOST_MEMBERSHIP_REPORT: | 962 | case IGMPV2_HOST_MEMBERSHIP_REPORT: |
| 949 | case IGMPV3_HOST_MEMBERSHIP_REPORT: | ||
| 950 | /* Is it our report looped back? */ | 963 | /* Is it our report looped back? */ |
| 951 | if (skb_rtable(skb)->fl.iif == 0) | 964 | if (skb_rtable(skb)->fl.iif == 0) |
| 952 | break; | 965 | break; |
| @@ -957,9 +970,9 @@ int igmp_rcv(struct sk_buff *skb) | |||
| 957 | break; | 970 | break; |
| 958 | case IGMP_PIM: | 971 | case IGMP_PIM: |
| 959 | #ifdef CONFIG_IP_PIMSM_V1 | 972 | #ifdef CONFIG_IP_PIMSM_V1 |
| 960 | in_dev_put(in_dev); | ||
| 961 | return pim_rcv_v1(skb); | 973 | return pim_rcv_v1(skb); |
| 962 | #endif | 974 | #endif |
| 975 | case IGMPV3_HOST_MEMBERSHIP_REPORT: | ||
| 963 | case IGMP_DVMRP: | 976 | case IGMP_DVMRP: |
| 964 | case IGMP_TRACE: | 977 | case IGMP_TRACE: |
| 965 | case IGMP_HOST_LEAVE_MESSAGE: | 978 | case IGMP_HOST_LEAVE_MESSAGE: |
| @@ -970,8 +983,6 @@ int igmp_rcv(struct sk_buff *skb) | |||
| 970 | break; | 983 | break; |
| 971 | } | 984 | } |
| 972 | 985 | ||
| 973 | drop_ref: | ||
| 974 | in_dev_put(in_dev); | ||
| 975 | drop: | 986 | drop: |
| 976 | kfree_skb(skb); | 987 | kfree_skb(skb); |
| 977 | return 0; | 988 | return 0; |
| @@ -997,7 +1008,7 @@ static void ip_mc_filter_add(struct in_device *in_dev, __be32 addr) | |||
| 997 | --ANK | 1008 | --ANK |
| 998 | */ | 1009 | */ |
| 999 | if (arp_mc_map(addr, buf, dev, 0) == 0) | 1010 | if (arp_mc_map(addr, buf, dev, 0) == 0) |
| 1000 | dev_mc_add(dev, buf, dev->addr_len, 0); | 1011 | dev_mc_add(dev, buf); |
| 1001 | } | 1012 | } |
| 1002 | 1013 | ||
| 1003 | /* | 1014 | /* |
| @@ -1010,7 +1021,7 @@ static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr) | |||
| 1010 | struct net_device *dev = in_dev->dev; | 1021 | struct net_device *dev = in_dev->dev; |
| 1011 | 1022 | ||
| 1012 | if (arp_mc_map(addr, buf, dev, 0) == 0) | 1023 | if (arp_mc_map(addr, buf, dev, 0) == 0) |
| 1013 | dev_mc_delete(dev, buf, dev->addr_len, 0); | 1024 | dev_mc_del(dev, buf); |
| 1014 | } | 1025 | } |
| 1015 | 1026 | ||
| 1016 | #ifdef CONFIG_IP_MULTICAST | 1027 | #ifdef CONFIG_IP_MULTICAST |
| @@ -1245,6 +1256,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) | |||
| 1245 | out: | 1256 | out: |
| 1246 | return; | 1257 | return; |
| 1247 | } | 1258 | } |
| 1259 | EXPORT_SYMBOL(ip_mc_inc_group); | ||
| 1248 | 1260 | ||
| 1249 | /* | 1261 | /* |
| 1250 | * Resend IGMP JOIN report; used for bonding. | 1262 | * Resend IGMP JOIN report; used for bonding. |
| @@ -1267,6 +1279,7 @@ void ip_mc_rejoin_group(struct ip_mc_list *im) | |||
| 1267 | igmp_ifc_event(in_dev); | 1279 | igmp_ifc_event(in_dev); |
| 1268 | #endif | 1280 | #endif |
| 1269 | } | 1281 | } |
| 1282 | EXPORT_SYMBOL(ip_mc_rejoin_group); | ||
| 1270 | 1283 | ||
| 1271 | /* | 1284 | /* |
| 1272 | * A socket has left a multicast group on device dev | 1285 | * A socket has left a multicast group on device dev |
| @@ -1297,6 +1310,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) | |||
| 1297 | } | 1310 | } |
| 1298 | } | 1311 | } |
| 1299 | } | 1312 | } |
| 1313 | EXPORT_SYMBOL(ip_mc_dec_group); | ||
| 1300 | 1314 | ||
| 1301 | /* Device changing type */ | 1315 | /* Device changing type */ |
| 1302 | 1316 | ||
| @@ -1426,7 +1440,7 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) | |||
| 1426 | } | 1440 | } |
| 1427 | 1441 | ||
| 1428 | if (!dev && !ip_route_output_key(net, &rt, &fl)) { | 1442 | if (!dev && !ip_route_output_key(net, &rt, &fl)) { |
| 1429 | dev = rt->u.dst.dev; | 1443 | dev = rt->dst.dev; |
| 1430 | ip_rt_put(rt); | 1444 | ip_rt_put(rt); |
| 1431 | } | 1445 | } |
| 1432 | if (dev) { | 1446 | if (dev) { |
| @@ -1645,8 +1659,7 @@ static int sf_setstate(struct ip_mc_list *pmc) | |||
| 1645 | if (dpsf->sf_inaddr == psf->sf_inaddr) | 1659 | if (dpsf->sf_inaddr == psf->sf_inaddr) |
| 1646 | break; | 1660 | break; |
| 1647 | if (!dpsf) { | 1661 | if (!dpsf) { |
| 1648 | dpsf = (struct ip_sf_list *) | 1662 | dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC); |
| 1649 | kmalloc(sizeof(*dpsf), GFP_ATOMIC); | ||
| 1650 | if (!dpsf) | 1663 | if (!dpsf) |
| 1651 | continue; | 1664 | continue; |
| 1652 | *dpsf = *psf; | 1665 | *dpsf = *psf; |
| @@ -1799,32 +1812,55 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | |||
| 1799 | iml->next = inet->mc_list; | 1812 | iml->next = inet->mc_list; |
| 1800 | iml->sflist = NULL; | 1813 | iml->sflist = NULL; |
| 1801 | iml->sfmode = MCAST_EXCLUDE; | 1814 | iml->sfmode = MCAST_EXCLUDE; |
| 1802 | inet->mc_list = iml; | 1815 | rcu_assign_pointer(inet->mc_list, iml); |
| 1803 | ip_mc_inc_group(in_dev, addr); | 1816 | ip_mc_inc_group(in_dev, addr); |
| 1804 | err = 0; | 1817 | err = 0; |
| 1805 | done: | 1818 | done: |
| 1806 | rtnl_unlock(); | 1819 | rtnl_unlock(); |
| 1807 | return err; | 1820 | return err; |
| 1808 | } | 1821 | } |
| 1822 | EXPORT_SYMBOL(ip_mc_join_group); | ||
| 1823 | |||
| 1824 | static void ip_sf_socklist_reclaim(struct rcu_head *rp) | ||
| 1825 | { | ||
| 1826 | struct ip_sf_socklist *psf; | ||
| 1827 | |||
| 1828 | psf = container_of(rp, struct ip_sf_socklist, rcu); | ||
| 1829 | /* sk_omem_alloc should have been decreased by the caller*/ | ||
| 1830 | kfree(psf); | ||
| 1831 | } | ||
| 1809 | 1832 | ||
| 1810 | static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, | 1833 | static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, |
| 1811 | struct in_device *in_dev) | 1834 | struct in_device *in_dev) |
| 1812 | { | 1835 | { |
| 1836 | struct ip_sf_socklist *psf = iml->sflist; | ||
| 1813 | int err; | 1837 | int err; |
| 1814 | 1838 | ||
| 1815 | if (iml->sflist == NULL) { | 1839 | if (psf == NULL) { |
| 1816 | /* any-source empty exclude case */ | 1840 | /* any-source empty exclude case */ |
| 1817 | return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, | 1841 | return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, |
| 1818 | iml->sfmode, 0, NULL, 0); | 1842 | iml->sfmode, 0, NULL, 0); |
| 1819 | } | 1843 | } |
| 1820 | err = ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, | 1844 | err = ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, |
| 1821 | iml->sfmode, iml->sflist->sl_count, | 1845 | iml->sfmode, psf->sl_count, psf->sl_addr, 0); |
| 1822 | iml->sflist->sl_addr, 0); | 1846 | rcu_assign_pointer(iml->sflist, NULL); |
| 1823 | sock_kfree_s(sk, iml->sflist, IP_SFLSIZE(iml->sflist->sl_max)); | 1847 | /* decrease mem now to avoid the memleak warning */ |
| 1824 | iml->sflist = NULL; | 1848 | atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc); |
| 1849 | call_rcu(&psf->rcu, ip_sf_socklist_reclaim); | ||
| 1825 | return err; | 1850 | return err; |
| 1826 | } | 1851 | } |
| 1827 | 1852 | ||
| 1853 | |||
| 1854 | static void ip_mc_socklist_reclaim(struct rcu_head *rp) | ||
| 1855 | { | ||
| 1856 | struct ip_mc_socklist *iml; | ||
| 1857 | |||
| 1858 | iml = container_of(rp, struct ip_mc_socklist, rcu); | ||
| 1859 | /* sk_omem_alloc should have been decreased by the caller*/ | ||
| 1860 | kfree(iml); | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | |||
| 1828 | /* | 1864 | /* |
| 1829 | * Ask a socket to leave a group. | 1865 | * Ask a socket to leave a group. |
| 1830 | */ | 1866 | */ |
| @@ -1854,12 +1890,14 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | |||
| 1854 | 1890 | ||
| 1855 | (void) ip_mc_leave_src(sk, iml, in_dev); | 1891 | (void) ip_mc_leave_src(sk, iml, in_dev); |
| 1856 | 1892 | ||
| 1857 | *imlp = iml->next; | 1893 | rcu_assign_pointer(*imlp, iml->next); |
| 1858 | 1894 | ||
| 1859 | if (in_dev) | 1895 | if (in_dev) |
| 1860 | ip_mc_dec_group(in_dev, group); | 1896 | ip_mc_dec_group(in_dev, group); |
| 1861 | rtnl_unlock(); | 1897 | rtnl_unlock(); |
| 1862 | sock_kfree_s(sk, iml, sizeof(*iml)); | 1898 | /* decrease mem now to avoid the memleak warning */ |
| 1899 | atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); | ||
| 1900 | call_rcu(&iml->rcu, ip_mc_socklist_reclaim); | ||
| 1863 | return 0; | 1901 | return 0; |
| 1864 | } | 1902 | } |
| 1865 | if (!in_dev) | 1903 | if (!in_dev) |
| @@ -1974,9 +2012,12 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
| 1974 | if (psl) { | 2012 | if (psl) { |
| 1975 | for (i=0; i<psl->sl_count; i++) | 2013 | for (i=0; i<psl->sl_count; i++) |
| 1976 | newpsl->sl_addr[i] = psl->sl_addr[i]; | 2014 | newpsl->sl_addr[i] = psl->sl_addr[i]; |
| 1977 | sock_kfree_s(sk, psl, IP_SFLSIZE(psl->sl_max)); | 2015 | /* decrease mem now to avoid the memleak warning */ |
| 2016 | atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); | ||
| 2017 | call_rcu(&psl->rcu, ip_sf_socklist_reclaim); | ||
| 1978 | } | 2018 | } |
| 1979 | pmc->sflist = psl = newpsl; | 2019 | rcu_assign_pointer(pmc->sflist, newpsl); |
| 2020 | psl = newpsl; | ||
| 1980 | } | 2021 | } |
| 1981 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ | 2022 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ |
| 1982 | for (i=0; i<psl->sl_count; i++) { | 2023 | for (i=0; i<psl->sl_count; i++) { |
| @@ -2072,11 +2113,13 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | |||
| 2072 | if (psl) { | 2113 | if (psl) { |
| 2073 | (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, | 2114 | (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, |
| 2074 | psl->sl_count, psl->sl_addr, 0); | 2115 | psl->sl_count, psl->sl_addr, 0); |
| 2075 | sock_kfree_s(sk, psl, IP_SFLSIZE(psl->sl_max)); | 2116 | /* decrease mem now to avoid the memleak warning */ |
| 2117 | atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); | ||
| 2118 | call_rcu(&psl->rcu, ip_sf_socklist_reclaim); | ||
| 2076 | } else | 2119 | } else |
| 2077 | (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, | 2120 | (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, |
| 2078 | 0, NULL, 0); | 2121 | 0, NULL, 0); |
| 2079 | pmc->sflist = newpsl; | 2122 | rcu_assign_pointer(pmc->sflist, newpsl); |
| 2080 | pmc->sfmode = msf->imsf_fmode; | 2123 | pmc->sfmode = msf->imsf_fmode; |
| 2081 | err = 0; | 2124 | err = 0; |
| 2082 | done: | 2125 | done: |
| @@ -2209,30 +2252,40 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) | |||
| 2209 | struct ip_mc_socklist *pmc; | 2252 | struct ip_mc_socklist *pmc; |
| 2210 | struct ip_sf_socklist *psl; | 2253 | struct ip_sf_socklist *psl; |
| 2211 | int i; | 2254 | int i; |
| 2255 | int ret; | ||
| 2212 | 2256 | ||
| 2257 | ret = 1; | ||
| 2213 | if (!ipv4_is_multicast(loc_addr)) | 2258 | if (!ipv4_is_multicast(loc_addr)) |
| 2214 | return 1; | 2259 | goto out; |
| 2215 | 2260 | ||
| 2216 | for (pmc=inet->mc_list; pmc; pmc=pmc->next) { | 2261 | rcu_read_lock(); |
| 2262 | for (pmc=rcu_dereference(inet->mc_list); pmc; pmc=rcu_dereference(pmc->next)) { | ||
| 2217 | if (pmc->multi.imr_multiaddr.s_addr == loc_addr && | 2263 | if (pmc->multi.imr_multiaddr.s_addr == loc_addr && |
| 2218 | pmc->multi.imr_ifindex == dif) | 2264 | pmc->multi.imr_ifindex == dif) |
| 2219 | break; | 2265 | break; |
| 2220 | } | 2266 | } |
| 2267 | ret = inet->mc_all; | ||
| 2221 | if (!pmc) | 2268 | if (!pmc) |
| 2222 | return inet->mc_all; | 2269 | goto unlock; |
| 2223 | psl = pmc->sflist; | 2270 | psl = pmc->sflist; |
| 2271 | ret = (pmc->sfmode == MCAST_EXCLUDE); | ||
| 2224 | if (!psl) | 2272 | if (!psl) |
| 2225 | return pmc->sfmode == MCAST_EXCLUDE; | 2273 | goto unlock; |
| 2226 | 2274 | ||
| 2227 | for (i=0; i<psl->sl_count; i++) { | 2275 | for (i=0; i<psl->sl_count; i++) { |
| 2228 | if (psl->sl_addr[i] == rmt_addr) | 2276 | if (psl->sl_addr[i] == rmt_addr) |
| 2229 | break; | 2277 | break; |
| 2230 | } | 2278 | } |
| 2279 | ret = 0; | ||
| 2231 | if (pmc->sfmode == MCAST_INCLUDE && i >= psl->sl_count) | 2280 | if (pmc->sfmode == MCAST_INCLUDE && i >= psl->sl_count) |
| 2232 | return 0; | 2281 | goto unlock; |
| 2233 | if (pmc->sfmode == MCAST_EXCLUDE && i < psl->sl_count) | 2282 | if (pmc->sfmode == MCAST_EXCLUDE && i < psl->sl_count) |
| 2234 | return 0; | 2283 | goto unlock; |
| 2235 | return 1; | 2284 | ret = 1; |
| 2285 | unlock: | ||
| 2286 | rcu_read_unlock(); | ||
| 2287 | out: | ||
| 2288 | return ret; | ||
| 2236 | } | 2289 | } |
| 2237 | 2290 | ||
| 2238 | /* | 2291 | /* |
| @@ -2251,7 +2304,7 @@ void ip_mc_drop_socket(struct sock *sk) | |||
| 2251 | rtnl_lock(); | 2304 | rtnl_lock(); |
| 2252 | while ((iml = inet->mc_list) != NULL) { | 2305 | while ((iml = inet->mc_list) != NULL) { |
| 2253 | struct in_device *in_dev; | 2306 | struct in_device *in_dev; |
| 2254 | inet->mc_list = iml->next; | 2307 | rcu_assign_pointer(inet->mc_list, iml->next); |
| 2255 | 2308 | ||
| 2256 | in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); | 2309 | in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); |
| 2257 | (void) ip_mc_leave_src(sk, iml, in_dev); | 2310 | (void) ip_mc_leave_src(sk, iml, in_dev); |
| @@ -2259,7 +2312,9 @@ void ip_mc_drop_socket(struct sock *sk) | |||
| 2259 | ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); | 2312 | ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); |
| 2260 | in_dev_put(in_dev); | 2313 | in_dev_put(in_dev); |
| 2261 | } | 2314 | } |
| 2262 | sock_kfree_s(sk, iml, sizeof(*iml)); | 2315 | /* decrease mem now to avoid the memleak warning */ |
| 2316 | atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); | ||
| 2317 | call_rcu(&iml->rcu, ip_mc_socklist_reclaim); | ||
| 2263 | } | 2318 | } |
| 2264 | rtnl_unlock(); | 2319 | rtnl_unlock(); |
| 2265 | } | 2320 | } |
| @@ -2603,7 +2658,7 @@ static const struct file_operations igmp_mcf_seq_fops = { | |||
| 2603 | .release = seq_release_net, | 2658 | .release = seq_release_net, |
| 2604 | }; | 2659 | }; |
| 2605 | 2660 | ||
| 2606 | static int igmp_net_init(struct net *net) | 2661 | static int __net_init igmp_net_init(struct net *net) |
| 2607 | { | 2662 | { |
| 2608 | struct proc_dir_entry *pde; | 2663 | struct proc_dir_entry *pde; |
| 2609 | 2664 | ||
| @@ -2621,7 +2676,7 @@ out_igmp: | |||
| 2621 | return -ENOMEM; | 2676 | return -ENOMEM; |
| 2622 | } | 2677 | } |
| 2623 | 2678 | ||
| 2624 | static void igmp_net_exit(struct net *net) | 2679 | static void __net_exit igmp_net_exit(struct net *net) |
| 2625 | { | 2680 | { |
| 2626 | proc_net_remove(net, "mcfilter"); | 2681 | proc_net_remove(net, "mcfilter"); |
| 2627 | proc_net_remove(net, "igmp"); | 2682 | proc_net_remove(net, "igmp"); |
| @@ -2637,8 +2692,3 @@ int __init igmp_mc_proc_init(void) | |||
| 2637 | return register_pernet_subsys(&igmp_net_ops); | 2692 | return register_pernet_subsys(&igmp_net_ops); |
| 2638 | } | 2693 | } |
| 2639 | #endif | 2694 | #endif |
| 2640 | |||
| 2641 | EXPORT_SYMBOL(ip_mc_dec_group); | ||
| 2642 | EXPORT_SYMBOL(ip_mc_inc_group); | ||
| 2643 | EXPORT_SYMBOL(ip_mc_join_group); | ||
| 2644 | EXPORT_SYMBOL(ip_mc_rejoin_group); | ||
