Skip to content

Commit

Permalink
mptcp: setsockopt: handle SO_KEEPALIVE and SO_PRIORITY
Browse files Browse the repository at this point in the history
start with something simple: both take an integer value, both
need to be mirrored to all subflows.

Acked-by: Paolo Abeni <[email protected]>
Signed-off-by: Florian Westphal <[email protected]>
Signed-off-by: Mat Martineau <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Florian Westphal authored and davem330 committed Apr 16, 2021
1 parent df00b08 commit 1b3e7ed
Showing 1 changed file with 106 additions and 0 deletions.
106 changes: 106 additions & 0 deletions net/mptcp/sockopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 1b3e7ed

Please sign in to comment.