mptcp: setsockopt: handle SO_KEEPALIVE and SO_PRIORITY

start with something simple: both take an integer value, both
need to be mirrored to all subflows.

Acked-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Florian Westphal 2021-04-15 16:44:55 -07:00 committed by David S. Miller
parent df00b087da
commit 1b3e7ede13

View File

@ -45,6 +45,90 @@ static u32 sockopt_seq_reset(const struct sock *sk)
return (u32)sk->sk_state << 24u;
}
static void sockopt_seq_inc(struct mptcp_sock *msk)
{
u32 seq = (msk->setsockopt_seq + 1) & 0x00ffffff;
msk->setsockopt_seq = sockopt_seq_reset((struct sock *)msk) + seq;
}
static int mptcp_get_int_option(struct mptcp_sock *msk, sockptr_t optval,
unsigned int optlen, int *val)
{
if (optlen < sizeof(int))
return -EINVAL;
if (copy_from_sockptr(val, optval, sizeof(*val)))
return -EFAULT;
return 0;
}
static void mptcp_sol_socket_sync_intval(struct mptcp_sock *msk, int optname, int val)
{
struct mptcp_subflow_context *subflow;
struct sock *sk = (struct sock *)msk;
lock_sock(sk);
sockopt_seq_inc(msk);
mptcp_for_each_subflow(msk, subflow) {
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
bool slow = lock_sock_fast(ssk);
switch (optname) {
case SO_KEEPALIVE:
if (ssk->sk_prot->keepalive)
ssk->sk_prot->keepalive(ssk, !!val);
sock_valbool_flag(ssk, SOCK_KEEPOPEN, !!val);
break;
case SO_PRIORITY:
ssk->sk_priority = val;
break;
}
subflow->setsockopt_seq = msk->setsockopt_seq;
unlock_sock_fast(ssk, slow);
}
release_sock(sk);
}
static int mptcp_sol_socket_intval(struct mptcp_sock *msk, int optname, int val)
{
sockptr_t optval = KERNEL_SOCKPTR(&val);
struct sock *sk = (struct sock *)msk;
int ret;
ret = sock_setsockopt(sk->sk_socket, SOL_SOCKET, optname,
optval, sizeof(val));
if (ret)
return ret;
mptcp_sol_socket_sync_intval(msk, optname, val);
return 0;
}
static int mptcp_setsockopt_sol_socket_int(struct mptcp_sock *msk, int optname,
sockptr_t optval, unsigned int optlen)
{
int val, ret;
ret = mptcp_get_int_option(msk, optval, optlen, &val);
if (ret)
return ret;
switch (optname) {
case SO_KEEPALIVE:
mptcp_sol_socket_sync_intval(msk, optname, val);
return 0;
case SO_PRIORITY:
return mptcp_sol_socket_intval(msk, optname, val);
}
return -ENOPROTOOPT;
}
static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,
sockptr_t optval, unsigned int optlen)
{
@ -71,6 +155,9 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,
}
release_sock(sk);
return ret;
case SO_KEEPALIVE:
case SO_PRIORITY:
return mptcp_setsockopt_sol_socket_int(msk, optname, optval, optlen);
}
return sock_setsockopt(sk->sk_socket, SOL_SOCKET, optname, optval, optlen);
@ -371,8 +458,27 @@ int mptcp_getsockopt(struct sock *sk, int level, int optname,
return -EOPNOTSUPP;
}
static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
{
struct sock *sk = (struct sock *)msk;
if (ssk->sk_prot->keepalive) {
if (sock_flag(sk, SOCK_KEEPOPEN))
ssk->sk_prot->keepalive(ssk, 1);
else
ssk->sk_prot->keepalive(ssk, 0);
}
ssk->sk_priority = sk->sk_priority;
}
static void __mptcp_sockopt_sync(struct mptcp_sock *msk, struct sock *ssk)
{
bool slow = lock_sock_fast(ssk);
sync_socket_options(msk, ssk);
unlock_sock_fast(ssk, slow);
}
void mptcp_sockopt_sync(struct mptcp_sock *msk, struct sock *ssk)