diff options
Diffstat (limited to 'net/ipv4/igmp.c')
| -rw-r--r-- | net/ipv4/igmp.c | 72 |
1 files changed, 38 insertions, 34 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 666cf364df86..a3a697f5ffba 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
| @@ -97,6 +97,7 @@ | |||
| 97 | #include <net/route.h> | 97 | #include <net/route.h> |
| 98 | #include <net/sock.h> | 98 | #include <net/sock.h> |
| 99 | #include <net/checksum.h> | 99 | #include <net/checksum.h> |
| 100 | #include <net/inet_common.h> | ||
| 100 | #include <linux/netfilter_ipv4.h> | 101 | #include <linux/netfilter_ipv4.h> |
| 101 | #ifdef CONFIG_IP_MROUTE | 102 | #ifdef CONFIG_IP_MROUTE |
| 102 | #include <linux/mroute.h> | 103 | #include <linux/mroute.h> |
| @@ -369,7 +370,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) | |||
| 369 | pip->saddr = fl4.saddr; | 370 | pip->saddr = fl4.saddr; |
| 370 | pip->protocol = IPPROTO_IGMP; | 371 | pip->protocol = IPPROTO_IGMP; |
| 371 | pip->tot_len = 0; /* filled in later */ | 372 | pip->tot_len = 0; /* filled in later */ |
| 372 | ip_select_ident(skb, NULL); | 373 | ip_select_ident(net, skb, NULL); |
| 373 | ((u8 *)&pip[1])[0] = IPOPT_RA; | 374 | ((u8 *)&pip[1])[0] = IPOPT_RA; |
| 374 | ((u8 *)&pip[1])[1] = 4; | 375 | ((u8 *)&pip[1])[1] = 4; |
| 375 | ((u8 *)&pip[1])[2] = 0; | 376 | ((u8 *)&pip[1])[2] = 0; |
| @@ -691,7 +692,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, | |||
| 691 | hlen = LL_RESERVED_SPACE(dev); | 692 | hlen = LL_RESERVED_SPACE(dev); |
| 692 | tlen = dev->needed_tailroom; | 693 | tlen = dev->needed_tailroom; |
| 693 | skb = alloc_skb(IGMP_SIZE + hlen + tlen, GFP_ATOMIC); | 694 | skb = alloc_skb(IGMP_SIZE + hlen + tlen, GFP_ATOMIC); |
| 694 | if (skb == NULL) { | 695 | if (!skb) { |
| 695 | ip_rt_put(rt); | 696 | ip_rt_put(rt); |
| 696 | return -1; | 697 | return -1; |
| 697 | } | 698 | } |
| @@ -713,7 +714,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, | |||
| 713 | iph->daddr = dst; | 714 | iph->daddr = dst; |
| 714 | iph->saddr = fl4.saddr; | 715 | iph->saddr = fl4.saddr; |
| 715 | iph->protocol = IPPROTO_IGMP; | 716 | iph->protocol = IPPROTO_IGMP; |
| 716 | ip_select_ident(skb, NULL); | 717 | ip_select_ident(net, skb, NULL); |
| 717 | ((u8 *)&iph[1])[0] = IPOPT_RA; | 718 | ((u8 *)&iph[1])[0] = IPOPT_RA; |
| 718 | ((u8 *)&iph[1])[1] = 4; | 719 | ((u8 *)&iph[1])[1] = 4; |
| 719 | ((u8 *)&iph[1])[2] = 0; | 720 | ((u8 *)&iph[1])[2] = 0; |
| @@ -980,7 +981,7 @@ int igmp_rcv(struct sk_buff *skb) | |||
| 980 | int len = skb->len; | 981 | int len = skb->len; |
| 981 | bool dropped = true; | 982 | bool dropped = true; |
| 982 | 983 | ||
| 983 | if (in_dev == NULL) | 984 | if (!in_dev) |
| 984 | goto drop; | 985 | goto drop; |
| 985 | 986 | ||
| 986 | if (!pskb_may_pull(skb, sizeof(struct igmphdr))) | 987 | if (!pskb_may_pull(skb, sizeof(struct igmphdr))) |
| @@ -1849,30 +1850,28 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc) | |||
| 1849 | pmc->sfcount[MCAST_EXCLUDE] = 1; | 1850 | pmc->sfcount[MCAST_EXCLUDE] = 1; |
| 1850 | } | 1851 | } |
| 1851 | 1852 | ||
| 1852 | 1853 | /* Join a multicast group | |
| 1853 | /* | ||
| 1854 | * Join a multicast group | ||
| 1855 | */ | 1854 | */ |
| 1856 | int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | 1855 | |
| 1856 | int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr) | ||
| 1857 | { | 1857 | { |
| 1858 | int err; | ||
| 1859 | __be32 addr = imr->imr_multiaddr.s_addr; | 1858 | __be32 addr = imr->imr_multiaddr.s_addr; |
| 1860 | struct ip_mc_socklist *iml = NULL, *i; | 1859 | struct ip_mc_socklist *iml, *i; |
| 1861 | struct in_device *in_dev; | 1860 | struct in_device *in_dev; |
| 1862 | struct inet_sock *inet = inet_sk(sk); | 1861 | struct inet_sock *inet = inet_sk(sk); |
| 1863 | struct net *net = sock_net(sk); | 1862 | struct net *net = sock_net(sk); |
| 1864 | int ifindex; | 1863 | int ifindex; |
| 1865 | int count = 0; | 1864 | int count = 0; |
| 1865 | int err; | ||
| 1866 | |||
| 1867 | ASSERT_RTNL(); | ||
| 1866 | 1868 | ||
| 1867 | if (!ipv4_is_multicast(addr)) | 1869 | if (!ipv4_is_multicast(addr)) |
| 1868 | return -EINVAL; | 1870 | return -EINVAL; |
| 1869 | 1871 | ||
| 1870 | rtnl_lock(); | ||
| 1871 | |||
| 1872 | in_dev = ip_mc_find_dev(net, imr); | 1872 | in_dev = ip_mc_find_dev(net, imr); |
| 1873 | 1873 | ||
| 1874 | if (!in_dev) { | 1874 | if (!in_dev) { |
| 1875 | iml = NULL; | ||
| 1876 | err = -ENODEV; | 1875 | err = -ENODEV; |
| 1877 | goto done; | 1876 | goto done; |
| 1878 | } | 1877 | } |
| @@ -1889,7 +1888,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | |||
| 1889 | if (count >= sysctl_igmp_max_memberships) | 1888 | if (count >= sysctl_igmp_max_memberships) |
| 1890 | goto done; | 1889 | goto done; |
| 1891 | iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); | 1890 | iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); |
| 1892 | if (iml == NULL) | 1891 | if (!iml) |
| 1893 | goto done; | 1892 | goto done; |
| 1894 | 1893 | ||
| 1895 | memcpy(&iml->multi, imr, sizeof(*imr)); | 1894 | memcpy(&iml->multi, imr, sizeof(*imr)); |
| @@ -1900,7 +1899,6 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | |||
| 1900 | ip_mc_inc_group(in_dev, addr); | 1899 | ip_mc_inc_group(in_dev, addr); |
| 1901 | err = 0; | 1900 | err = 0; |
| 1902 | done: | 1901 | done: |
| 1903 | rtnl_unlock(); | ||
| 1904 | return err; | 1902 | return err; |
| 1905 | } | 1903 | } |
| 1906 | EXPORT_SYMBOL(ip_mc_join_group); | 1904 | EXPORT_SYMBOL(ip_mc_join_group); |
| @@ -1911,7 +1909,7 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, | |||
| 1911 | struct ip_sf_socklist *psf = rtnl_dereference(iml->sflist); | 1909 | struct ip_sf_socklist *psf = rtnl_dereference(iml->sflist); |
| 1912 | int err; | 1910 | int err; |
| 1913 | 1911 | ||
| 1914 | if (psf == NULL) { | 1912 | if (!psf) { |
| 1915 | /* any-source empty exclude case */ | 1913 | /* any-source empty exclude case */ |
| 1916 | return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, | 1914 | return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, |
| 1917 | iml->sfmode, 0, NULL, 0); | 1915 | iml->sfmode, 0, NULL, 0); |
| @@ -1925,10 +1923,6 @@ static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, | |||
| 1925 | return err; | 1923 | return err; |
| 1926 | } | 1924 | } |
| 1927 | 1925 | ||
| 1928 | /* | ||
| 1929 | * Ask a socket to leave a group. | ||
| 1930 | */ | ||
| 1931 | |||
| 1932 | int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | 1926 | int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) |
| 1933 | { | 1927 | { |
| 1934 | struct inet_sock *inet = inet_sk(sk); | 1928 | struct inet_sock *inet = inet_sk(sk); |
| @@ -1940,7 +1934,8 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | |||
| 1940 | u32 ifindex; | 1934 | u32 ifindex; |
| 1941 | int ret = -EADDRNOTAVAIL; | 1935 | int ret = -EADDRNOTAVAIL; |
| 1942 | 1936 | ||
| 1943 | rtnl_lock(); | 1937 | ASSERT_RTNL(); |
| 1938 | |||
| 1944 | in_dev = ip_mc_find_dev(net, imr); | 1939 | in_dev = ip_mc_find_dev(net, imr); |
| 1945 | if (!in_dev) { | 1940 | if (!in_dev) { |
| 1946 | ret = -ENODEV; | 1941 | ret = -ENODEV; |
| @@ -1964,14 +1959,13 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) | |||
| 1964 | *imlp = iml->next_rcu; | 1959 | *imlp = iml->next_rcu; |
| 1965 | 1960 | ||
| 1966 | ip_mc_dec_group(in_dev, group); | 1961 | ip_mc_dec_group(in_dev, group); |
| 1967 | rtnl_unlock(); | 1962 | |
| 1968 | /* decrease mem now to avoid the memleak warning */ | 1963 | /* decrease mem now to avoid the memleak warning */ |
| 1969 | atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); | 1964 | atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); |
| 1970 | kfree_rcu(iml, rcu); | 1965 | kfree_rcu(iml, rcu); |
| 1971 | return 0; | 1966 | return 0; |
| 1972 | } | 1967 | } |
| 1973 | out: | 1968 | out: |
| 1974 | rtnl_unlock(); | ||
| 1975 | return ret; | 1969 | return ret; |
| 1976 | } | 1970 | } |
| 1977 | EXPORT_SYMBOL(ip_mc_leave_group); | 1971 | EXPORT_SYMBOL(ip_mc_leave_group); |
| @@ -1993,7 +1987,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
| 1993 | if (!ipv4_is_multicast(addr)) | 1987 | if (!ipv4_is_multicast(addr)) |
| 1994 | return -EINVAL; | 1988 | return -EINVAL; |
| 1995 | 1989 | ||
| 1996 | rtnl_lock(); | 1990 | ASSERT_RTNL(); |
| 1997 | 1991 | ||
| 1998 | imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr; | 1992 | imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr; |
| 1999 | imr.imr_address.s_addr = mreqs->imr_interface; | 1993 | imr.imr_address.s_addr = mreqs->imr_interface; |
| @@ -2107,9 +2101,8 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
| 2107 | ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1, | 2101 | ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1, |
| 2108 | &mreqs->imr_sourceaddr, 1); | 2102 | &mreqs->imr_sourceaddr, 1); |
| 2109 | done: | 2103 | done: |
| 2110 | rtnl_unlock(); | ||
| 2111 | if (leavegroup) | 2104 | if (leavegroup) |
| 2112 | return ip_mc_leave_group(sk, &imr); | 2105 | err = ip_mc_leave_group(sk, &imr); |
| 2113 | return err; | 2106 | return err; |
| 2114 | } | 2107 | } |
| 2115 | 2108 | ||
| @@ -2131,7 +2124,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | |||
| 2131 | msf->imsf_fmode != MCAST_EXCLUDE) | 2124 | msf->imsf_fmode != MCAST_EXCLUDE) |
| 2132 | return -EINVAL; | 2125 | return -EINVAL; |
| 2133 | 2126 | ||
| 2134 | rtnl_lock(); | 2127 | ASSERT_RTNL(); |
| 2135 | 2128 | ||
| 2136 | imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; | 2129 | imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; |
| 2137 | imr.imr_address.s_addr = msf->imsf_interface; | 2130 | imr.imr_address.s_addr = msf->imsf_interface; |
| @@ -2193,7 +2186,6 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | |||
| 2193 | pmc->sfmode = msf->imsf_fmode; | 2186 | pmc->sfmode = msf->imsf_fmode; |
| 2194 | err = 0; | 2187 | err = 0; |
| 2195 | done: | 2188 | done: |
| 2196 | rtnl_unlock(); | ||
| 2197 | if (leavegroup) | 2189 | if (leavegroup) |
| 2198 | err = ip_mc_leave_group(sk, &imr); | 2190 | err = ip_mc_leave_group(sk, &imr); |
| 2199 | return err; | 2191 | return err; |
| @@ -2368,7 +2360,7 @@ void ip_mc_drop_socket(struct sock *sk) | |||
| 2368 | struct ip_mc_socklist *iml; | 2360 | struct ip_mc_socklist *iml; |
| 2369 | struct net *net = sock_net(sk); | 2361 | struct net *net = sock_net(sk); |
| 2370 | 2362 | ||
| 2371 | if (inet->mc_list == NULL) | 2363 | if (!inet->mc_list) |
| 2372 | return; | 2364 | return; |
| 2373 | 2365 | ||
| 2374 | rtnl_lock(); | 2366 | rtnl_lock(); |
| @@ -2378,7 +2370,7 @@ void ip_mc_drop_socket(struct sock *sk) | |||
| 2378 | inet->mc_list = iml->next_rcu; | 2370 | inet->mc_list = iml->next_rcu; |
| 2379 | in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); | 2371 | in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); |
| 2380 | (void) ip_mc_leave_src(sk, iml, in_dev); | 2372 | (void) ip_mc_leave_src(sk, iml, in_dev); |
| 2381 | if (in_dev != NULL) | 2373 | if (in_dev) |
| 2382 | ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); | 2374 | ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); |
| 2383 | /* decrease mem now to avoid the memleak warning */ | 2375 | /* decrease mem now to avoid the memleak warning */ |
| 2384 | atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); | 2376 | atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); |
| @@ -2595,13 +2587,13 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) | |||
| 2595 | for_each_netdev_rcu(net, state->dev) { | 2587 | for_each_netdev_rcu(net, state->dev) { |
| 2596 | struct in_device *idev; | 2588 | struct in_device *idev; |
| 2597 | idev = __in_dev_get_rcu(state->dev); | 2589 | idev = __in_dev_get_rcu(state->dev); |
| 2598 | if (unlikely(idev == NULL)) | 2590 | if (unlikely(!idev)) |
| 2599 | continue; | 2591 | continue; |
| 2600 | im = rcu_dereference(idev->mc_list); | 2592 | im = rcu_dereference(idev->mc_list); |
| 2601 | if (likely(im != NULL)) { | 2593 | if (likely(im)) { |
| 2602 | spin_lock_bh(&im->lock); | 2594 | spin_lock_bh(&im->lock); |
| 2603 | psf = im->sources; | 2595 | psf = im->sources; |
| 2604 | if (likely(psf != NULL)) { | 2596 | if (likely(psf)) { |
| 2605 | state->im = im; | 2597 | state->im = im; |
| 2606 | state->idev = idev; | 2598 | state->idev = idev; |
| 2607 | break; | 2599 | break; |
| @@ -2671,7 +2663,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) | |||
| 2671 | __releases(rcu) | 2663 | __releases(rcu) |
| 2672 | { | 2664 | { |
| 2673 | struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); | 2665 | struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); |
| 2674 | if (likely(state->im != NULL)) { | 2666 | if (likely(state->im)) { |
| 2675 | spin_unlock_bh(&state->im->lock); | 2667 | spin_unlock_bh(&state->im->lock); |
| 2676 | state->im = NULL; | 2668 | state->im = NULL; |
| 2677 | } | 2669 | } |
| @@ -2724,6 +2716,7 @@ static const struct file_operations igmp_mcf_seq_fops = { | |||
| 2724 | static int __net_init igmp_net_init(struct net *net) | 2716 | static int __net_init igmp_net_init(struct net *net) |
| 2725 | { | 2717 | { |
| 2726 | struct proc_dir_entry *pde; | 2718 | struct proc_dir_entry *pde; |
| 2719 | int err; | ||
| 2727 | 2720 | ||
| 2728 | pde = proc_create("igmp", S_IRUGO, net->proc_net, &igmp_mc_seq_fops); | 2721 | pde = proc_create("igmp", S_IRUGO, net->proc_net, &igmp_mc_seq_fops); |
| 2729 | if (!pde) | 2722 | if (!pde) |
| @@ -2732,8 +2725,18 @@ static int __net_init igmp_net_init(struct net *net) | |||
| 2732 | &igmp_mcf_seq_fops); | 2725 | &igmp_mcf_seq_fops); |
| 2733 | if (!pde) | 2726 | if (!pde) |
| 2734 | goto out_mcfilter; | 2727 | goto out_mcfilter; |
| 2728 | err = inet_ctl_sock_create(&net->ipv4.mc_autojoin_sk, AF_INET, | ||
| 2729 | SOCK_DGRAM, 0, net); | ||
| 2730 | if (err < 0) { | ||
| 2731 | pr_err("Failed to initialize the IGMP autojoin socket (err %d)\n", | ||
| 2732 | err); | ||
| 2733 | goto out_sock; | ||
| 2734 | } | ||
| 2735 | |||
| 2735 | return 0; | 2736 | return 0; |
| 2736 | 2737 | ||
| 2738 | out_sock: | ||
| 2739 | remove_proc_entry("mcfilter", net->proc_net); | ||
| 2737 | out_mcfilter: | 2740 | out_mcfilter: |
| 2738 | remove_proc_entry("igmp", net->proc_net); | 2741 | remove_proc_entry("igmp", net->proc_net); |
| 2739 | out_igmp: | 2742 | out_igmp: |
| @@ -2744,6 +2747,7 @@ static void __net_exit igmp_net_exit(struct net *net) | |||
| 2744 | { | 2747 | { |
| 2745 | remove_proc_entry("mcfilter", net->proc_net); | 2748 | remove_proc_entry("mcfilter", net->proc_net); |
| 2746 | remove_proc_entry("igmp", net->proc_net); | 2749 | remove_proc_entry("igmp", net->proc_net); |
| 2750 | inet_ctl_sock_destroy(net->ipv4.mc_autojoin_sk); | ||
| 2747 | } | 2751 | } |
| 2748 | 2752 | ||
| 2749 | static struct pernet_operations igmp_net_ops = { | 2753 | static struct pernet_operations igmp_net_ops = { |
