Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 46a4dee0 authored by Madhu Challa's avatar Madhu Challa Committed by David S. Miller
Browse files

igmp v6: add __ipv6_sock_mc_join and __ipv6_sock_mc_drop



Based on the igmp v4 changes from Eric Dumazet.
959d10f6("igmp: add __ip_mc_{join|leave}_group()")

These changes are needed to perform igmp v6 join/leave while
RTNL is held.

Make ipv6_sock_mc_join and ipv6_sock_mc_drop wrappers around
__ipv6_sock_mc_join and  __ipv6_sock_mc_drop to avoid
proliferation of work queues.

Signed-off-by: default avatarMadhu Challa <challa@noironetworks.com>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 723b8e46
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -940,4 +940,12 @@ int ipv6_sysctl_register(void);
void ipv6_sysctl_unregister(void);
#endif

int ipv6_sock_mc_join(struct sock *sk, int ifindex,
		      const struct in6_addr *addr);
int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
			const struct in6_addr *addr);
int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
		      const struct in6_addr *addr);
int __ipv6_sock_mc_drop(struct sock *sk, int ifindex,
			const struct in6_addr *addr);
#endif /* _NET_IPV6_H */
+31 −9
Original line number Diff line number Diff line
@@ -132,7 +132,7 @@ static int unsolicited_report_interval(struct inet6_dev *idev)
	return iv > 0 ? iv : 1;
}

int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
int __ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
{
	struct net_device *dev = NULL;
	struct ipv6_mc_socklist *mc_lst;
@@ -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;

@@ -161,7 +163,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
	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);
@@ -173,7 +174,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
		dev = __dev_get_by_index(net, ifindex);

	if (dev == NULL) {
		rtnl_unlock();
		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,25 +197,37 @@ 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);

	return 0;
}
EXPORT_SYMBOL(__ipv6_sock_mc_join);

int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
{
	int ret;

	rtnl_lock();
	ret = __ipv6_sock_mc_join(sk, ifindex, addr);
	rtnl_unlock();

	return 0;
	return ret;
}
EXPORT_SYMBOL(ipv6_sock_mc_join);

/*
 *	socket leave on multicast group
 */
int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
int __ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
{
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct ipv6_mc_socklist *mc_lst;
	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) {
@@ -235,17 +246,28 @@ 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);

int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
{
	int ret;

	rtnl_lock();
	ret = __ipv6_sock_mc_drop(sk, ifindex, addr);
	rtnl_unlock();

	return ret;
}
EXPORT_SYMBOL(ipv6_sock_mc_drop);

/* called with rcu_read_lock() */
static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,