summaryrefslogtreecommitdiffstats
path: root/net/ipv6/mcast.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2015-04-20 11:32:26 +1000
committerDave Airlie <airlied@redhat.com>2015-04-20 13:05:20 +1000
commit2c33ce009ca2389dbf0535d0672214d09738e35e (patch)
tree6186a6458c3c160385d794a23eaf07c786a9e61b /net/ipv6/mcast.c
parentcec32a47010647e8b0603726ebb75b990a4057a4 (diff)
parent09d51602cf84a1264946711dd4ea0dddbac599a1 (diff)
downloadlinux-stable-2c33ce009ca2389dbf0535d0672214d09738e35e.tar.gz
linux-stable-2c33ce009ca2389dbf0535d0672214d09738e35e.tar.bz2
linux-stable-2c33ce009ca2389dbf0535d0672214d09738e35e.zip
Merge Linus master into drm-next
The merge is clean, but the arm build fails afterwards, due to API changes in the regulator tree. I've included the patch into the merge to fix the build. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r--net/ipv6/mcast.c75
1 files changed, 43 insertions, 32 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 5ce107c8aab3..083b2927fc67 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -140,6 +140,8 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
struct net *net = sock_net(sk);
int err;
+ ASSERT_RTNL();
+
if (!ipv6_addr_is_multicast(addr))
return -EINVAL;
@@ -155,13 +157,12 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL);
- if (mc_lst == NULL)
+ if (!mc_lst)
return -ENOMEM;
mc_lst->next = NULL;
mc_lst->addr = *addr;
- rtnl_lock();
if (ifindex == 0) {
struct rt6_info *rt;
rt = rt6_lookup(net, addr, NULL, 0, 0);
@@ -172,8 +173,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
} else
dev = __dev_get_by_index(net, ifindex);
- if (dev == NULL) {
- rtnl_unlock();
+ if (!dev) {
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
return -ENODEV;
}
@@ -190,7 +190,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
err = ipv6_dev_mc_inc(dev, addr);
if (err) {
- rtnl_unlock();
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
return err;
}
@@ -198,10 +197,9 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
mc_lst->next = np->ipv6_mc_list;
rcu_assign_pointer(np->ipv6_mc_list, mc_lst);
- rtnl_unlock();
-
return 0;
}
+EXPORT_SYMBOL(ipv6_sock_mc_join);
/*
* socket leave on multicast group
@@ -213,10 +211,11 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
struct ipv6_mc_socklist __rcu **lnk;
struct net *net = sock_net(sk);
+ ASSERT_RTNL();
+
if (!ipv6_addr_is_multicast(addr))
return -EINVAL;
- rtnl_lock();
for (lnk = &np->ipv6_mc_list;
(mc_lst = rtnl_dereference(*lnk)) != NULL;
lnk = &mc_lst->next) {
@@ -227,7 +226,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
*lnk = mc_lst->next;
dev = __dev_get_by_index(net, mc_lst->ifindex);
- if (dev != NULL) {
+ if (dev) {
struct inet6_dev *idev = __in6_dev_get(dev);
(void) ip6_mc_leave_src(sk, mc_lst, idev);
@@ -235,17 +234,16 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
} else
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
- rtnl_unlock();
atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
kfree_rcu(mc_lst, rcu);
return 0;
}
}
- rtnl_unlock();
return -EADDRNOTAVAIL;
}
+EXPORT_SYMBOL(ipv6_sock_mc_drop);
/* called with rcu_read_lock() */
static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
@@ -438,7 +436,7 @@ done:
read_unlock_bh(&idev->lock);
rcu_read_unlock();
if (leavegroup)
- return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group);
+ err = ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group);
return err;
}
@@ -825,7 +823,7 @@ static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev,
struct ifmcaddr6 *mc;
mc = kzalloc(sizeof(*mc), GFP_ATOMIC);
- if (mc == NULL)
+ if (!mc)
return NULL;
setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
@@ -862,7 +860,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
/* we need to take a reference on idev */
idev = in6_dev_get(dev);
- if (idev == NULL)
+ if (!idev)
return -EINVAL;
write_lock_bh(&idev->lock);
@@ -1330,7 +1328,7 @@ int igmp6_event_query(struct sk_buff *skb)
return -EINVAL;
idev = __in6_dev_get(skb->dev);
- if (idev == NULL)
+ if (!idev)
return 0;
mld = (struct mld_msg *)icmp6_hdr(skb);
@@ -1445,7 +1443,7 @@ int igmp6_event_report(struct sk_buff *skb)
return -EINVAL;
idev = __in6_dev_get(skb->dev);
- if (idev == NULL)
+ if (!idev)
return -ENODEV;
/*
@@ -1646,8 +1644,9 @@ static void mld_sendpack(struct sk_buff *skb)
payload_len = skb->len;
- err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
- dst_output);
+ err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
+ net->ipv6.igmp_sk, skb, NULL, skb->dev,
+ dst_output_sk);
out:
if (!err) {
ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT);
@@ -1964,7 +1963,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
skb = sock_alloc_send_skb(sk, hlen + tlen + full_len, 1, &err);
- if (skb == NULL) {
+ if (!skb) {
rcu_read_lock();
IP6_INC_STATS(net, __in6_dev_get(dev),
IPSTATS_MIB_OUTDISCARDS);
@@ -2009,8 +2008,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
}
skb_dst_set(skb, dst);
- err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
- dst_output);
+ err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb,
+ NULL, skb->dev, dst_output_sk);
out:
if (!err) {
ICMP6MSGOUT_INC_STATS(net, idev, type);
@@ -2613,7 +2612,7 @@ static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr
im = im->next;
while (!im) {
- if (likely(state->idev != NULL))
+ if (likely(state->idev))
read_unlock_bh(&state->idev->lock);
state->dev = next_net_device_rcu(state->dev);
@@ -2659,7 +2658,7 @@ static void igmp6_mc_seq_stop(struct seq_file *seq, void *v)
{
struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
- if (likely(state->idev != NULL)) {
+ if (likely(state->idev)) {
read_unlock_bh(&state->idev->lock);
state->idev = NULL;
}
@@ -2728,10 +2727,10 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
continue;
read_lock_bh(&idev->lock);
im = idev->mc_list;
- if (likely(im != NULL)) {
+ if (likely(im)) {
spin_lock_bh(&im->mca_lock);
psf = im->mca_sources;
- if (likely(psf != NULL)) {
+ if (likely(psf)) {
state->im = im;
state->idev = idev;
break;
@@ -2752,7 +2751,7 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s
spin_unlock_bh(&state->im->mca_lock);
state->im = state->im->next;
while (!state->im) {
- if (likely(state->idev != NULL))
+ if (likely(state->idev))
read_unlock_bh(&state->idev->lock);
state->dev = next_net_device_rcu(state->dev);
@@ -2806,11 +2805,11 @@ static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v)
__releases(RCU)
{
struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
- if (likely(state->im != NULL)) {
+ if (likely(state->im)) {
spin_unlock_bh(&state->im->mca_lock);
state->im = NULL;
}
- if (likely(state->idev != NULL)) {
+ if (likely(state->idev)) {
read_unlock_bh(&state->idev->lock);
state->idev = NULL;
}
@@ -2907,20 +2906,32 @@ static int __net_init igmp6_net_init(struct net *net)
inet6_sk(net->ipv6.igmp_sk)->hop_limit = 1;
+ err = inet_ctl_sock_create(&net->ipv6.mc_autojoin_sk, PF_INET6,
+ SOCK_RAW, IPPROTO_ICMPV6, net);
+ if (err < 0) {
+ pr_err("Failed to initialize the IGMP6 autojoin socket (err %d)\n",
+ err);
+ goto out_sock_create;
+ }
+
err = igmp6_proc_init(net);
if (err)
- goto out_sock_create;
-out:
- return err;
+ goto out_sock_create_autojoin;
+
+ return 0;
+out_sock_create_autojoin:
+ inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk);
out_sock_create:
inet_ctl_sock_destroy(net->ipv6.igmp_sk);
- goto out;
+out:
+ return err;
}
static void __net_exit igmp6_net_exit(struct net *net)
{
inet_ctl_sock_destroy(net->ipv6.igmp_sk);
+ inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk);
igmp6_proc_exit(net);
}