diff options
author | Florian Westphal <fw@strlen.de> | 2021-04-16 01:44:57 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-04-17 00:23:10 +0200 |
commit | 268b1238746086f3608daa20b068182ddc2b0128 (patch) | |
tree | ed0fb686113901b556983110499e96ce4c563936 /net/mptcp/sockopt.c | |
parent | mptcp: setsockopt: handle receive/send buffer and device bind (diff) | |
download | linux-268b1238746086f3608daa20b068182ddc2b0128.tar.xz linux-268b1238746086f3608daa20b068182ddc2b0128.zip |
mptcp: setsockopt: support SO_LINGER
Similar to PRIORITY/KEEPALIVE: needs 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>
Diffstat (limited to 'net/mptcp/sockopt.c')
-rw-r--r-- | net/mptcp/sockopt.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index bfb9db04d26b..ee5d58747ce7 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -143,6 +143,47 @@ static int mptcp_setsockopt_sol_socket_int(struct mptcp_sock *msk, int optname, return -ENOPROTOOPT; } +static int mptcp_setsockopt_sol_socket_linger(struct mptcp_sock *msk, sockptr_t optval, + unsigned int optlen) +{ + struct mptcp_subflow_context *subflow; + struct sock *sk = (struct sock *)msk; + struct linger ling; + sockptr_t kopt; + int ret; + + if (optlen < sizeof(ling)) + return -EINVAL; + + if (copy_from_sockptr(&ling, optval, sizeof(ling))) + return -EFAULT; + + kopt = KERNEL_SOCKPTR(&ling); + ret = sock_setsockopt(sk->sk_socket, SOL_SOCKET, SO_LINGER, kopt, sizeof(ling)); + if (ret) + return ret; + + 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); + + if (!ling.l_onoff) { + sock_reset_flag(ssk, SOCK_LINGER); + } else { + ssk->sk_lingertime = sk->sk_lingertime; + sock_set_flag(ssk, SOCK_LINGER); + } + + subflow->setsockopt_seq = msk->setsockopt_seq; + unlock_sock_fast(ssk, slow); + } + + release_sock(sk); + return 0; +} + static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname, sockptr_t optval, unsigned int optlen) { @@ -182,6 +223,8 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname, case SO_RCVBUF: case SO_RCVBUFFORCE: return mptcp_setsockopt_sol_socket_int(msk, optname, optval, optlen); + case SO_LINGER: + return mptcp_setsockopt_sol_socket_linger(msk, optval, optlen); } return sock_setsockopt(sk->sk_socket, SOL_SOCKET, optname, optval, optlen); |