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

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
......@@ -806,6 +806,60 @@ static int compat_ip_set_mcast_msfilter(struct sock *sk, void __user *optval,
}
#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)))
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);
err = ip_mcast_join_leave(sk, optname, optval, optlen);
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:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment