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.c87
1 files changed, 29 insertions, 58 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index e0e77e297de3..672e476c8c8a 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -149,17 +149,11 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc);
149static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, 149static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
150 int sfcount, __be32 *psfsrc, int delta); 150 int sfcount, __be32 *psfsrc, int delta);
151 151
152
153static void ip_mc_list_reclaim(struct rcu_head *head)
154{
155 kfree(container_of(head, struct ip_mc_list, rcu));
156}
157
158static void ip_ma_put(struct ip_mc_list *im) 152static void ip_ma_put(struct ip_mc_list *im)
159{ 153{
160 if (atomic_dec_and_test(&im->refcnt)) { 154 if (atomic_dec_and_test(&im->refcnt)) {
161 in_dev_put(im->interface); 155 in_dev_put(im->interface);
162 call_rcu(&im->rcu, ip_mc_list_reclaim); 156 kfree_rcu(im, rcu);
163 } 157 }
164} 158}
165 159
@@ -309,6 +303,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
309 struct iphdr *pip; 303 struct iphdr *pip;
310 struct igmpv3_report *pig; 304 struct igmpv3_report *pig;
311 struct net *net = dev_net(dev); 305 struct net *net = dev_net(dev);
306 struct flowi4 fl4;
312 307
313 while (1) { 308 while (1) {
314 skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev), 309 skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev),
@@ -321,18 +316,11 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
321 } 316 }
322 igmp_skb_size(skb) = size; 317 igmp_skb_size(skb) = size;
323 318
324 { 319 rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0,
325 struct flowi fl = { .oif = dev->ifindex, 320 0, 0,
326 .fl4_dst = IGMPV3_ALL_MCR, 321 IPPROTO_IGMP, 0, dev->ifindex);
327 .proto = IPPROTO_IGMP }; 322 if (IS_ERR(rt)) {
328 if (ip_route_output_key(net, &rt, &fl)) {
329 kfree_skb(skb);
330 return NULL;
331 }
332 }
333 if (rt->rt_src == 0) {
334 kfree_skb(skb); 323 kfree_skb(skb);
335 ip_rt_put(rt);
336 return NULL; 324 return NULL;
337 } 325 }
338 326
@@ -350,8 +338,8 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
350 pip->tos = 0xc0; 338 pip->tos = 0xc0;
351 pip->frag_off = htons(IP_DF); 339 pip->frag_off = htons(IP_DF);
352 pip->ttl = 1; 340 pip->ttl = 1;
353 pip->daddr = rt->rt_dst; 341 pip->daddr = fl4.daddr;
354 pip->saddr = rt->rt_src; 342 pip->saddr = fl4.saddr;
355 pip->protocol = IPPROTO_IGMP; 343 pip->protocol = IPPROTO_IGMP;
356 pip->tot_len = 0; /* filled in later */ 344 pip->tot_len = 0; /* filled in later */
357 ip_select_ident(pip, &rt->dst, NULL); 345 ip_select_ident(pip, &rt->dst, NULL);
@@ -657,6 +645,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
657 struct net_device *dev = in_dev->dev; 645 struct net_device *dev = in_dev->dev;
658 struct net *net = dev_net(dev); 646 struct net *net = dev_net(dev);
659 __be32 group = pmc ? pmc->multiaddr : 0; 647 __be32 group = pmc ? pmc->multiaddr : 0;
648 struct flowi4 fl4;
660 __be32 dst; 649 __be32 dst;
661 650
662 if (type == IGMPV3_HOST_MEMBERSHIP_REPORT) 651 if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
@@ -666,17 +655,11 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
666 else 655 else
667 dst = group; 656 dst = group;
668 657
669 { 658 rt = ip_route_output_ports(net, &fl4, NULL, dst, 0,
670 struct flowi fl = { .oif = dev->ifindex, 659 0, 0,
671 .fl4_dst = dst, 660 IPPROTO_IGMP, 0, dev->ifindex);
672 .proto = IPPROTO_IGMP }; 661 if (IS_ERR(rt))
673 if (ip_route_output_key(net, &rt, &fl))
674 return -1;
675 }
676 if (rt->rt_src == 0) {
677 ip_rt_put(rt);
678 return -1; 662 return -1;
679 }
680 663
681 skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC); 664 skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
682 if (skb == NULL) { 665 if (skb == NULL) {
@@ -698,7 +681,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
698 iph->frag_off = htons(IP_DF); 681 iph->frag_off = htons(IP_DF);
699 iph->ttl = 1; 682 iph->ttl = 1;
700 iph->daddr = dst; 683 iph->daddr = dst;
701 iph->saddr = rt->rt_src; 684 iph->saddr = fl4.saddr;
702 iph->protocol = IPPROTO_IGMP; 685 iph->protocol = IPPROTO_IGMP;
703 ip_select_ident(iph, &rt->dst, NULL); 686 ip_select_ident(iph, &rt->dst, NULL);
704 ((u8*)&iph[1])[0] = IPOPT_RA; 687 ((u8*)&iph[1])[0] = IPOPT_RA;
@@ -1439,8 +1422,6 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
1439/* RTNL is locked */ 1422/* RTNL is locked */
1440static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) 1423static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
1441{ 1424{
1442 struct flowi fl = { .fl4_dst = imr->imr_multiaddr.s_addr };
1443 struct rtable *rt;
1444 struct net_device *dev = NULL; 1425 struct net_device *dev = NULL;
1445 struct in_device *idev = NULL; 1426 struct in_device *idev = NULL;
1446 1427
@@ -1454,9 +1435,14 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
1454 return NULL; 1435 return NULL;
1455 } 1436 }
1456 1437
1457 if (!dev && !ip_route_output_key(net, &rt, &fl)) { 1438 if (!dev) {
1458 dev = rt->dst.dev; 1439 struct rtable *rt = ip_route_output(net,
1459 ip_rt_put(rt); 1440 imr->imr_multiaddr.s_addr,
1441 0, 0, 0);
1442 if (!IS_ERR(rt)) {
1443 dev = rt->dst.dev;
1444 ip_rt_put(rt);
1445 }
1460 } 1446 }
1461 if (dev) { 1447 if (dev) {
1462 imr->imr_ifindex = dev->ifindex; 1448 imr->imr_ifindex = dev->ifindex;
@@ -1836,12 +1822,6 @@ done:
1836} 1822}
1837EXPORT_SYMBOL(ip_mc_join_group); 1823EXPORT_SYMBOL(ip_mc_join_group);
1838 1824
1839static void ip_sf_socklist_reclaim(struct rcu_head *rp)
1840{
1841 kfree(container_of(rp, struct ip_sf_socklist, rcu));
1842 /* sk_omem_alloc should have been decreased by the caller*/
1843}
1844
1845static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, 1825static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
1846 struct in_device *in_dev) 1826 struct in_device *in_dev)
1847{ 1827{
@@ -1858,18 +1838,10 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
1858 rcu_assign_pointer(iml->sflist, NULL); 1838 rcu_assign_pointer(iml->sflist, NULL);
1859 /* decrease mem now to avoid the memleak warning */ 1839 /* decrease mem now to avoid the memleak warning */
1860 atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc); 1840 atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc);
1861 call_rcu(&psf->rcu, ip_sf_socklist_reclaim); 1841 kfree_rcu(psf, rcu);
1862 return err; 1842 return err;
1863} 1843}
1864 1844
1865
1866static void ip_mc_socklist_reclaim(struct rcu_head *rp)
1867{
1868 kfree(container_of(rp, struct ip_mc_socklist, rcu));
1869 /* sk_omem_alloc should have been decreased by the caller*/
1870}
1871
1872
1873/* 1845/*
1874 * Ask a socket to leave a group. 1846 * Ask a socket to leave a group.
1875 */ 1847 */
@@ -1909,7 +1881,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
1909 rtnl_unlock(); 1881 rtnl_unlock();
1910 /* decrease mem now to avoid the memleak warning */ 1882 /* decrease mem now to avoid the memleak warning */
1911 atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); 1883 atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
1912 call_rcu(&iml->rcu, ip_mc_socklist_reclaim); 1884 kfree_rcu(iml, rcu);
1913 return 0; 1885 return 0;
1914 } 1886 }
1915 if (!in_dev) 1887 if (!in_dev)
@@ -2026,7 +1998,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
2026 newpsl->sl_addr[i] = psl->sl_addr[i]; 1998 newpsl->sl_addr[i] = psl->sl_addr[i];
2027 /* decrease mem now to avoid the memleak warning */ 1999 /* decrease mem now to avoid the memleak warning */
2028 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); 2000 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
2029 call_rcu(&psl->rcu, ip_sf_socklist_reclaim); 2001 kfree_rcu(psl, rcu);
2030 } 2002 }
2031 rcu_assign_pointer(pmc->sflist, newpsl); 2003 rcu_assign_pointer(pmc->sflist, newpsl);
2032 psl = newpsl; 2004 psl = newpsl;
@@ -2127,7 +2099,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
2127 psl->sl_count, psl->sl_addr, 0); 2099 psl->sl_count, psl->sl_addr, 0);
2128 /* decrease mem now to avoid the memleak warning */ 2100 /* decrease mem now to avoid the memleak warning */
2129 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); 2101 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
2130 call_rcu(&psl->rcu, ip_sf_socklist_reclaim); 2102 kfree_rcu(psl, rcu);
2131 } else 2103 } else
2132 (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, 2104 (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
2133 0, NULL, 0); 2105 0, NULL, 0);
@@ -2324,18 +2296,18 @@ void ip_mc_drop_socket(struct sock *sk)
2324 ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); 2296 ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
2325 /* decrease mem now to avoid the memleak warning */ 2297 /* decrease mem now to avoid the memleak warning */
2326 atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); 2298 atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
2327 call_rcu(&iml->rcu, ip_mc_socklist_reclaim); 2299 kfree_rcu(iml, rcu);
2328 } 2300 }
2329 rtnl_unlock(); 2301 rtnl_unlock();
2330} 2302}
2331 2303
2332int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 proto) 2304/* called with rcu_read_lock() */
2305int ip_check_mc_rcu(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 proto)
2333{ 2306{
2334 struct ip_mc_list *im; 2307 struct ip_mc_list *im;
2335 struct ip_sf_list *psf; 2308 struct ip_sf_list *psf;
2336 int rv = 0; 2309 int rv = 0;
2337 2310
2338 rcu_read_lock();
2339 for_each_pmc_rcu(in_dev, im) { 2311 for_each_pmc_rcu(in_dev, im) {
2340 if (im->multiaddr == mc_addr) 2312 if (im->multiaddr == mc_addr)
2341 break; 2313 break;
@@ -2357,7 +2329,6 @@ int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 p
2357 } else 2329 } else
2358 rv = 1; /* unspecified source; tentatively allow */ 2330 rv = 1; /* unspecified source; tentatively allow */
2359 } 2331 }
2360 rcu_read_unlock();
2361 return rv; 2332 return rv;
2362} 2333}
2363 2334