aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/igmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/igmp.c')
-rw-r--r--net/ipv4/igmp.c140
1 files changed, 90 insertions, 50 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index d41e5de79a82..15d3eeda92f5 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>
@@ -946,7 +947,6 @@ int igmp_rcv(struct sk_buff *skb)
946 break; 947 break;
947 case IGMP_HOST_MEMBERSHIP_REPORT: 948 case IGMP_HOST_MEMBERSHIP_REPORT:
948 case IGMPV2_HOST_MEMBERSHIP_REPORT: 949 case IGMPV2_HOST_MEMBERSHIP_REPORT:
949 case IGMPV3_HOST_MEMBERSHIP_REPORT:
950 /* Is it our report looped back? */ 950 /* Is it our report looped back? */
951 if (skb_rtable(skb)->fl.iif == 0) 951 if (skb_rtable(skb)->fl.iif == 0)
952 break; 952 break;
@@ -960,6 +960,7 @@ int igmp_rcv(struct sk_buff *skb)
960 in_dev_put(in_dev); 960 in_dev_put(in_dev);
961 return pim_rcv_v1(skb); 961 return pim_rcv_v1(skb);
962#endif 962#endif
963 case IGMPV3_HOST_MEMBERSHIP_REPORT:
963 case IGMP_DVMRP: 964 case IGMP_DVMRP:
964 case IGMP_TRACE: 965 case IGMP_TRACE:
965 case IGMP_HOST_LEAVE_MESSAGE: 966 case IGMP_HOST_LEAVE_MESSAGE:
@@ -1799,7 +1800,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
1799 iml->next = inet->mc_list; 1800 iml->next = inet->mc_list;
1800 iml->sflist = NULL; 1801 iml->sflist = NULL;
1801 iml->sfmode = MCAST_EXCLUDE; 1802 iml->sfmode = MCAST_EXCLUDE;
1802 inet->mc_list = iml; 1803 rcu_assign_pointer(inet->mc_list, iml);
1803 ip_mc_inc_group(in_dev, addr); 1804 ip_mc_inc_group(in_dev, addr);
1804 err = 0; 1805 err = 0;
1805done: 1806done:
@@ -1807,24 +1808,46 @@ done:
1807 return err; 1808 return err;
1808} 1809}
1809 1810
1811static void ip_sf_socklist_reclaim(struct rcu_head *rp)
1812{
1813 struct ip_sf_socklist *psf;
1814
1815 psf = container_of(rp, struct ip_sf_socklist, rcu);
1816 /* sk_omem_alloc should have been decreased by the caller*/
1817 kfree(psf);
1818}
1819
1810static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, 1820static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
1811 struct in_device *in_dev) 1821 struct in_device *in_dev)
1812{ 1822{
1823 struct ip_sf_socklist *psf = iml->sflist;
1813 int err; 1824 int err;
1814 1825
1815 if (iml->sflist == NULL) { 1826 if (psf == NULL) {
1816 /* any-source empty exclude case */ 1827 /* any-source empty exclude case */
1817 return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, 1828 return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr,
1818 iml->sfmode, 0, NULL, 0); 1829 iml->sfmode, 0, NULL, 0);
1819 } 1830 }
1820 err = ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, 1831 err = ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr,
1821 iml->sfmode, iml->sflist->sl_count, 1832 iml->sfmode, psf->sl_count, psf->sl_addr, 0);
1822 iml->sflist->sl_addr, 0); 1833 rcu_assign_pointer(iml->sflist, NULL);
1823 sock_kfree_s(sk, iml->sflist, IP_SFLSIZE(iml->sflist->sl_max)); 1834 /* decrease mem now to avoid the memleak warning */
1824 iml->sflist = NULL; 1835 atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc);
1836 call_rcu(&psf->rcu, ip_sf_socklist_reclaim);
1825 return err; 1837 return err;
1826} 1838}
1827 1839
1840
1841static void ip_mc_socklist_reclaim(struct rcu_head *rp)
1842{
1843 struct ip_mc_socklist *iml;
1844
1845 iml = container_of(rp, struct ip_mc_socklist, rcu);
1846 /* sk_omem_alloc should have been decreased by the caller*/
1847 kfree(iml);
1848}
1849
1850
1828/* 1851/*
1829 * Ask a socket to leave a group. 1852 * Ask a socket to leave a group.
1830 */ 1853 */
@@ -1854,12 +1877,14 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
1854 1877
1855 (void) ip_mc_leave_src(sk, iml, in_dev); 1878 (void) ip_mc_leave_src(sk, iml, in_dev);
1856 1879
1857 *imlp = iml->next; 1880 rcu_assign_pointer(*imlp, iml->next);
1858 1881
1859 if (in_dev) 1882 if (in_dev)
1860 ip_mc_dec_group(in_dev, group); 1883 ip_mc_dec_group(in_dev, group);
1861 rtnl_unlock(); 1884 rtnl_unlock();
1862 sock_kfree_s(sk, iml, sizeof(*iml)); 1885 /* decrease mem now to avoid the memleak warning */
1886 atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
1887 call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
1863 return 0; 1888 return 0;
1864 } 1889 }
1865 if (!in_dev) 1890 if (!in_dev)
@@ -1899,8 +1924,9 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
1899 err = -EADDRNOTAVAIL; 1924 err = -EADDRNOTAVAIL;
1900 1925
1901 for (pmc=inet->mc_list; pmc; pmc=pmc->next) { 1926 for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
1902 if (pmc->multi.imr_multiaddr.s_addr == imr.imr_multiaddr.s_addr 1927 if ((pmc->multi.imr_multiaddr.s_addr ==
1903 && pmc->multi.imr_ifindex == imr.imr_ifindex) 1928 imr.imr_multiaddr.s_addr) &&
1929 (pmc->multi.imr_ifindex == imr.imr_ifindex))
1904 break; 1930 break;
1905 } 1931 }
1906 if (!pmc) { /* must have a prior join */ 1932 if (!pmc) { /* must have a prior join */
@@ -1973,9 +1999,12 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
1973 if (psl) { 1999 if (psl) {
1974 for (i=0; i<psl->sl_count; i++) 2000 for (i=0; i<psl->sl_count; i++)
1975 newpsl->sl_addr[i] = psl->sl_addr[i]; 2001 newpsl->sl_addr[i] = psl->sl_addr[i];
1976 sock_kfree_s(sk, psl, IP_SFLSIZE(psl->sl_max)); 2002 /* decrease mem now to avoid the memleak warning */
2003 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
2004 call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
1977 } 2005 }
1978 pmc->sflist = psl = newpsl; 2006 rcu_assign_pointer(pmc->sflist, newpsl);
2007 psl = newpsl;
1979 } 2008 }
1980 rv = 1; /* > 0 for insert logic below if sl_count is 0 */ 2009 rv = 1; /* > 0 for insert logic below if sl_count is 0 */
1981 for (i=0; i<psl->sl_count; i++) { 2010 for (i=0; i<psl->sl_count; i++) {
@@ -2071,11 +2100,13 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
2071 if (psl) { 2100 if (psl) {
2072 (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, 2101 (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
2073 psl->sl_count, psl->sl_addr, 0); 2102 psl->sl_count, psl->sl_addr, 0);
2074 sock_kfree_s(sk, psl, IP_SFLSIZE(psl->sl_max)); 2103 /* decrease mem now to avoid the memleak warning */
2104 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
2105 call_rcu(&psl->rcu, ip_sf_socklist_reclaim);
2075 } else 2106 } else
2076 (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, 2107 (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
2077 0, NULL, 0); 2108 0, NULL, 0);
2078 pmc->sflist = newpsl; 2109 rcu_assign_pointer(pmc->sflist, newpsl);
2079 pmc->sfmode = msf->imsf_fmode; 2110 pmc->sfmode = msf->imsf_fmode;
2080 err = 0; 2111 err = 0;
2081done: 2112done:
@@ -2208,30 +2239,40 @@ int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif)
2208 struct ip_mc_socklist *pmc; 2239 struct ip_mc_socklist *pmc;
2209 struct ip_sf_socklist *psl; 2240 struct ip_sf_socklist *psl;
2210 int i; 2241 int i;
2242 int ret;
2211 2243
2244 ret = 1;
2212 if (!ipv4_is_multicast(loc_addr)) 2245 if (!ipv4_is_multicast(loc_addr))
2213 return 1; 2246 goto out;
2214 2247
2215 for (pmc=inet->mc_list; pmc; pmc=pmc->next) { 2248 rcu_read_lock();
2249 for (pmc=rcu_dereference(inet->mc_list); pmc; pmc=rcu_dereference(pmc->next)) {
2216 if (pmc->multi.imr_multiaddr.s_addr == loc_addr && 2250 if (pmc->multi.imr_multiaddr.s_addr == loc_addr &&
2217 pmc->multi.imr_ifindex == dif) 2251 pmc->multi.imr_ifindex == dif)
2218 break; 2252 break;
2219 } 2253 }
2254 ret = inet->mc_all;
2220 if (!pmc) 2255 if (!pmc)
2221 return inet->mc_all; 2256 goto unlock;
2222 psl = pmc->sflist; 2257 psl = pmc->sflist;
2258 ret = (pmc->sfmode == MCAST_EXCLUDE);
2223 if (!psl) 2259 if (!psl)
2224 return pmc->sfmode == MCAST_EXCLUDE; 2260 goto unlock;
2225 2261
2226 for (i=0; i<psl->sl_count; i++) { 2262 for (i=0; i<psl->sl_count; i++) {
2227 if (psl->sl_addr[i] == rmt_addr) 2263 if (psl->sl_addr[i] == rmt_addr)
2228 break; 2264 break;
2229 } 2265 }
2266 ret = 0;
2230 if (pmc->sfmode == MCAST_INCLUDE && i >= psl->sl_count) 2267 if (pmc->sfmode == MCAST_INCLUDE && i >= psl->sl_count)
2231 return 0; 2268 goto unlock;
2232 if (pmc->sfmode == MCAST_EXCLUDE && i < psl->sl_count) 2269 if (pmc->sfmode == MCAST_EXCLUDE && i < psl->sl_count)
2233 return 0; 2270 goto unlock;
2234 return 1; 2271 ret = 1;
2272unlock:
2273 rcu_read_unlock();
2274out:
2275 return ret;
2235} 2276}
2236 2277
2237/* 2278/*
@@ -2250,7 +2291,7 @@ void ip_mc_drop_socket(struct sock *sk)
2250 rtnl_lock(); 2291 rtnl_lock();
2251 while ((iml = inet->mc_list) != NULL) { 2292 while ((iml = inet->mc_list) != NULL) {
2252 struct in_device *in_dev; 2293 struct in_device *in_dev;
2253 inet->mc_list = iml->next; 2294 rcu_assign_pointer(inet->mc_list, iml->next);
2254 2295
2255 in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); 2296 in_dev = inetdev_by_index(net, iml->multi.imr_ifindex);
2256 (void) ip_mc_leave_src(sk, iml, in_dev); 2297 (void) ip_mc_leave_src(sk, iml, in_dev);
@@ -2258,7 +2299,9 @@ void ip_mc_drop_socket(struct sock *sk)
2258 ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); 2299 ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
2259 in_dev_put(in_dev); 2300 in_dev_put(in_dev);
2260 } 2301 }
2261 sock_kfree_s(sk, iml, sizeof(*iml)); 2302 /* decrease mem now to avoid the memleak warning */
2303 atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
2304 call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
2262 } 2305 }
2263 rtnl_unlock(); 2306 rtnl_unlock();
2264} 2307}
@@ -2311,9 +2354,10 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
2311 struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); 2354 struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
2312 2355
2313 state->in_dev = NULL; 2356 state->in_dev = NULL;
2314 for_each_netdev(net, state->dev) { 2357 for_each_netdev_rcu(net, state->dev) {
2315 struct in_device *in_dev; 2358 struct in_device *in_dev;
2316 in_dev = in_dev_get(state->dev); 2359
2360 in_dev = __in_dev_get_rcu(state->dev);
2317 if (!in_dev) 2361 if (!in_dev)
2318 continue; 2362 continue;
2319 read_lock(&in_dev->mc_list_lock); 2363 read_lock(&in_dev->mc_list_lock);
@@ -2323,7 +2367,6 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
2323 break; 2367 break;
2324 } 2368 }
2325 read_unlock(&in_dev->mc_list_lock); 2369 read_unlock(&in_dev->mc_list_lock);
2326 in_dev_put(in_dev);
2327 } 2370 }
2328 return im; 2371 return im;
2329} 2372}
@@ -2333,16 +2376,15 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li
2333 struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); 2376 struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
2334 im = im->next; 2377 im = im->next;
2335 while (!im) { 2378 while (!im) {
2336 if (likely(state->in_dev != NULL)) { 2379 if (likely(state->in_dev != NULL))
2337 read_unlock(&state->in_dev->mc_list_lock); 2380 read_unlock(&state->in_dev->mc_list_lock);
2338 in_dev_put(state->in_dev); 2381
2339 } 2382 state->dev = next_net_device_rcu(state->dev);
2340 state->dev = next_net_device(state->dev);
2341 if (!state->dev) { 2383 if (!state->dev) {
2342 state->in_dev = NULL; 2384 state->in_dev = NULL;
2343 break; 2385 break;
2344 } 2386 }
2345 state->in_dev = in_dev_get(state->dev); 2387 state->in_dev = __in_dev_get_rcu(state->dev);
2346 if (!state->in_dev) 2388 if (!state->in_dev)
2347 continue; 2389 continue;
2348 read_lock(&state->in_dev->mc_list_lock); 2390 read_lock(&state->in_dev->mc_list_lock);
@@ -2361,9 +2403,9 @@ static struct ip_mc_list *igmp_mc_get_idx(struct seq_file *seq, loff_t pos)
2361} 2403}
2362 2404
2363static void *igmp_mc_seq_start(struct seq_file *seq, loff_t *pos) 2405static void *igmp_mc_seq_start(struct seq_file *seq, loff_t *pos)
2364 __acquires(dev_base_lock) 2406 __acquires(rcu)
2365{ 2407{
2366 read_lock(&dev_base_lock); 2408 rcu_read_lock();
2367 return *pos ? igmp_mc_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; 2409 return *pos ? igmp_mc_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
2368} 2410}
2369 2411
@@ -2379,16 +2421,15 @@ static void *igmp_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2379} 2421}
2380 2422
2381static void igmp_mc_seq_stop(struct seq_file *seq, void *v) 2423static void igmp_mc_seq_stop(struct seq_file *seq, void *v)
2382 __releases(dev_base_lock) 2424 __releases(rcu)
2383{ 2425{
2384 struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); 2426 struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
2385 if (likely(state->in_dev != NULL)) { 2427 if (likely(state->in_dev != NULL)) {
2386 read_unlock(&state->in_dev->mc_list_lock); 2428 read_unlock(&state->in_dev->mc_list_lock);
2387 in_dev_put(state->in_dev);
2388 state->in_dev = NULL; 2429 state->in_dev = NULL;
2389 } 2430 }
2390 state->dev = NULL; 2431 state->dev = NULL;
2391 read_unlock(&dev_base_lock); 2432 rcu_read_unlock();
2392} 2433}
2393 2434
2394static int igmp_mc_seq_show(struct seq_file *seq, void *v) 2435static int igmp_mc_seq_show(struct seq_file *seq, void *v)
@@ -2462,9 +2503,9 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
2462 2503
2463 state->idev = NULL; 2504 state->idev = NULL;
2464 state->im = NULL; 2505 state->im = NULL;
2465 for_each_netdev(net, state->dev) { 2506 for_each_netdev_rcu(net, state->dev) {
2466 struct in_device *idev; 2507 struct in_device *idev;
2467 idev = in_dev_get(state->dev); 2508 idev = __in_dev_get_rcu(state->dev);
2468 if (unlikely(idev == NULL)) 2509 if (unlikely(idev == NULL))
2469 continue; 2510 continue;
2470 read_lock(&idev->mc_list_lock); 2511 read_lock(&idev->mc_list_lock);
@@ -2480,7 +2521,6 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
2480 spin_unlock_bh(&im->lock); 2521 spin_unlock_bh(&im->lock);
2481 } 2522 }
2482 read_unlock(&idev->mc_list_lock); 2523 read_unlock(&idev->mc_list_lock);
2483 in_dev_put(idev);
2484 } 2524 }
2485 return psf; 2525 return psf;
2486} 2526}
@@ -2494,16 +2534,15 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l
2494 spin_unlock_bh(&state->im->lock); 2534 spin_unlock_bh(&state->im->lock);
2495 state->im = state->im->next; 2535 state->im = state->im->next;
2496 while (!state->im) { 2536 while (!state->im) {
2497 if (likely(state->idev != NULL)) { 2537 if (likely(state->idev != NULL))
2498 read_unlock(&state->idev->mc_list_lock); 2538 read_unlock(&state->idev->mc_list_lock);
2499 in_dev_put(state->idev); 2539
2500 } 2540 state->dev = next_net_device_rcu(state->dev);
2501 state->dev = next_net_device(state->dev);
2502 if (!state->dev) { 2541 if (!state->dev) {
2503 state->idev = NULL; 2542 state->idev = NULL;
2504 goto out; 2543 goto out;
2505 } 2544 }
2506 state->idev = in_dev_get(state->dev); 2545 state->idev = __in_dev_get_rcu(state->dev);
2507 if (!state->idev) 2546 if (!state->idev)
2508 continue; 2547 continue;
2509 read_lock(&state->idev->mc_list_lock); 2548 read_lock(&state->idev->mc_list_lock);
@@ -2528,8 +2567,9 @@ static struct ip_sf_list *igmp_mcf_get_idx(struct seq_file *seq, loff_t pos)
2528} 2567}
2529 2568
2530static void *igmp_mcf_seq_start(struct seq_file *seq, loff_t *pos) 2569static void *igmp_mcf_seq_start(struct seq_file *seq, loff_t *pos)
2570 __acquires(rcu)
2531{ 2571{
2532 read_lock(&dev_base_lock); 2572 rcu_read_lock();
2533 return *pos ? igmp_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; 2573 return *pos ? igmp_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
2534} 2574}
2535 2575
@@ -2545,6 +2585,7 @@ static void *igmp_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2545} 2585}
2546 2586
2547static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) 2587static void igmp_mcf_seq_stop(struct seq_file *seq, void *v)
2588 __releases(rcu)
2548{ 2589{
2549 struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); 2590 struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
2550 if (likely(state->im != NULL)) { 2591 if (likely(state->im != NULL)) {
@@ -2553,11 +2594,10 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v)
2553 } 2594 }
2554 if (likely(state->idev != NULL)) { 2595 if (likely(state->idev != NULL)) {
2555 read_unlock(&state->idev->mc_list_lock); 2596 read_unlock(&state->idev->mc_list_lock);
2556 in_dev_put(state->idev);
2557 state->idev = NULL; 2597 state->idev = NULL;
2558 } 2598 }
2559 state->dev = NULL; 2599 state->dev = NULL;
2560 read_unlock(&dev_base_lock); 2600 rcu_read_unlock();
2561} 2601}
2562 2602
2563static int igmp_mcf_seq_show(struct seq_file *seq, void *v) 2603static int igmp_mcf_seq_show(struct seq_file *seq, void *v)
@@ -2605,7 +2645,7 @@ static const struct file_operations igmp_mcf_seq_fops = {
2605 .release = seq_release_net, 2645 .release = seq_release_net,
2606}; 2646};
2607 2647
2608static int igmp_net_init(struct net *net) 2648static int __net_init igmp_net_init(struct net *net)
2609{ 2649{
2610 struct proc_dir_entry *pde; 2650 struct proc_dir_entry *pde;
2611 2651
@@ -2623,7 +2663,7 @@ out_igmp:
2623 return -ENOMEM; 2663 return -ENOMEM;
2624} 2664}
2625 2665
2626static void igmp_net_exit(struct net *net) 2666static void __net_exit igmp_net_exit(struct net *net)
2627{ 2667{
2628 proc_net_remove(net, "mcfilter"); 2668 proc_net_remove(net, "mcfilter");
2629 proc_net_remove(net, "igmp"); 2669 proc_net_remove(net, "igmp");