Commit 02caad7c authored by Christoph Hellwig's avatar Christoph Hellwig Committed by David S. Miller
Browse files

net/ipv4: factor out mcast join/leave setsockopt helpers



Factor out one helper each for setting the native and compat
version of the MCAST_MSFILTER option.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d62c38f6
Loading
Loading
Loading
Loading
+56 −53
Original line number Diff line number Diff line
@@ -806,6 +806,60 @@ out_free_gsf:
}
#endif

static int ip_mcast_join_leave(struct sock *sk, int optname,
		void __user *optval, int optlen)
{
	struct ip_mreqn mreq = { };
	struct sockaddr_in *psin;
	struct group_req greq;

	if (optlen < sizeof(struct group_req))
		return -EINVAL;
	if (copy_from_user(&greq, optval, sizeof(greq)))
		return -EFAULT;

	psin = (struct sockaddr_in *)&greq.gr_group;
	if (psin->sin_family != AF_INET)
		return -EINVAL;
	mreq.imr_multiaddr = psin->sin_addr;
	mreq.imr_ifindex = greq.gr_interface;
	if (optname == MCAST_JOIN_GROUP)
		return ip_mc_join_group(sk, &mreq);
	return ip_mc_leave_group(sk, &mreq);
}

#ifdef CONFIG_COMPAT
static int compat_ip_mcast_join_leave(struct sock *sk, int optname,
		void __user *optval, int optlen)
{
	struct compat_group_req greq;
	struct ip_mreqn mreq = { };
	struct sockaddr_in *psin;
	int err;

	if (optlen < sizeof(struct compat_group_req))
		return -EINVAL;
	if (copy_from_user(&greq, optval, sizeof(greq)))
		return -EFAULT;

	psin = (struct sockaddr_in *)&greq.gr_group;
	if (psin->sin_family != AF_INET)
		return -EINVAL;
	mreq.imr_multiaddr = psin->sin_addr;
	mreq.imr_ifindex = greq.gr_interface;

	rtnl_lock();
	lock_sock(sk);
	if (optname == MCAST_JOIN_GROUP)
		err = ip_mc_join_group(sk, &mreq);
	else
		err = ip_mc_leave_group(sk, &mreq);
	release_sock(sk);
	rtnl_unlock();
	return err;
}
#endif

static int do_ip_setsockopt(struct sock *sk, int level,
			    int optname, char __user *optval, unsigned int optlen)
{
@@ -1211,29 +1265,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
	}
	case MCAST_JOIN_GROUP:
	case MCAST_LEAVE_GROUP:
	{
		struct group_req greq;
		struct sockaddr_in *psin;
		struct ip_mreqn mreq;

		if (optlen < sizeof(struct group_req))
			goto e_inval;
		err = -EFAULT;
		if (copy_from_user(&greq, optval, sizeof(greq)))
		err = ip_mcast_join_leave(sk, optname, optval, optlen);
		break;
		psin = (struct sockaddr_in *)&greq.gr_group;
		if (psin->sin_family != AF_INET)
			goto e_inval;
		memset(&mreq, 0, sizeof(mreq));
		mreq.imr_multiaddr = psin->sin_addr;
		mreq.imr_ifindex = greq.gr_interface;

		if (optname == MCAST_JOIN_GROUP)
			err = ip_mc_join_group(sk, &mreq);
		else
			err = ip_mc_leave_group(sk, &mreq);
		break;
	}
	case MCAST_JOIN_SOURCE_GROUP:
	case MCAST_LEAVE_SOURCE_GROUP:
	case MCAST_BLOCK_SOURCE:
@@ -1389,37 +1422,7 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname,
	switch (optname) {
	case MCAST_JOIN_GROUP:
	case MCAST_LEAVE_GROUP:
	{
		struct compat_group_req __user *gr32 = (void __user *)optval;
		struct group_req greq;
		struct sockaddr_in *psin = (struct sockaddr_in *)&greq.gr_group;
		struct ip_mreqn mreq;

		if (optlen < sizeof(struct compat_group_req))
			return -EINVAL;

		if (get_user(greq.gr_interface, &gr32->gr_interface) ||
		    copy_from_user(&greq.gr_group, &gr32->gr_group,
				sizeof(greq.gr_group)))
			return -EFAULT;

		if (psin->sin_family != AF_INET)
			return -EINVAL;

		memset(&mreq, 0, sizeof(mreq));
		mreq.imr_multiaddr = psin->sin_addr;
		mreq.imr_ifindex = greq.gr_interface;

		rtnl_lock();
		lock_sock(sk);
		if (optname == MCAST_JOIN_GROUP)
			err = ip_mc_join_group(sk, &mreq);
		else
			err = ip_mc_leave_group(sk, &mreq);
		release_sock(sk);
		rtnl_unlock();
		return err;
	}
		return compat_ip_mcast_join_leave(sk, optname, optval, optlen);
	case MCAST_JOIN_SOURCE_GROUP:
	case MCAST_LEAVE_SOURCE_GROUP:
	case MCAST_BLOCK_SOURCE: