--- /dev/null
+From stable+bounces-47627-greg=kroah.com@vger.kernel.org Wed May 29 12:00:37 2024
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+Date: Wed, 29 May 2024 12:00:24 +0200
+Subject: mptcp: avoid some duplicate code in socket option handling
+To: mptcp@lists.linux.dev, stable@vger.kernel.org, gregkh@linuxfoundation.org, sashal@kernel.org
+Cc: Paolo Abeni <pabeni@redhat.com>, Mat Martineau <martineau@kernel.org>, Matthieu Baerts <matttbe@kernel.org>, "David S . Miller" <davem@davemloft.net>
+Message-ID: <20240529100022.3373664-6-matttbe@kernel.org>
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+commit a74762675f700a5473ebe54a671a0788a5b23cc9 upstream.
+
+The mptcp_get_int_option() helper is needless open-coded in a
+couple of places, replace the duplicate code with the helper
+call.
+
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: bd11dc4fb969 ("mptcp: fix full TCP keep-alive support")
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/sockopt.c | 20 ++++++++------------
+ 1 file changed, 8 insertions(+), 12 deletions(-)
+
+--- a/net/mptcp/sockopt.c
++++ b/net/mptcp/sockopt.c
+@@ -621,13 +621,11 @@ static int mptcp_setsockopt_sol_tcp_cork
+ {
+ struct mptcp_subflow_context *subflow;
+ struct sock *sk = (struct sock *)msk;
+- int val;
++ int val, ret;
+
+- if (optlen < sizeof(int))
+- return -EINVAL;
+-
+- if (copy_from_sockptr(&val, optval, sizeof(val)))
+- return -EFAULT;
++ ret = mptcp_get_int_option(msk, optval, optlen, &val);
++ if (ret)
++ return ret;
+
+ lock_sock(sk);
+ sockopt_seq_inc(msk);
+@@ -651,13 +649,11 @@ static int mptcp_setsockopt_sol_tcp_node
+ {
+ struct mptcp_subflow_context *subflow;
+ struct sock *sk = (struct sock *)msk;
+- int val;
+-
+- if (optlen < sizeof(int))
+- return -EINVAL;
++ int val, ret;
+
+- if (copy_from_sockptr(&val, optval, sizeof(val)))
+- return -EFAULT;
++ ret = mptcp_get_int_option(msk, optval, optlen, &val);
++ if (ret)
++ return ret;
+
+ lock_sock(sk);
+ sockopt_seq_inc(msk);
--- /dev/null
+From stable+bounces-47628-greg=kroah.com@vger.kernel.org Wed May 29 12:00:39 2024
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+Date: Wed, 29 May 2024 12:00:25 +0200
+Subject: mptcp: cleanup SOL_TCP handling
+To: mptcp@lists.linux.dev, stable@vger.kernel.org, gregkh@linuxfoundation.org, sashal@kernel.org
+Cc: Paolo Abeni <pabeni@redhat.com>, Mat Martineau <martineau@kernel.org>, Matthieu Baerts <matttbe@kernel.org>, "David S . Miller" <davem@davemloft.net>
+Message-ID: <20240529100022.3373664-7-matttbe@kernel.org>
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+commit 7f71a337b5152ea0e7bef408d1af53778a919316 upstream.
+
+Most TCP-level socket options get an integer from user space, and
+set the corresponding field under the msk-level socket lock.
+
+Reduce the code duplication moving such operations in the common code.
+
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: bd11dc4fb969 ("mptcp: fix full TCP keep-alive support")
+[ Without TCP_NOTSENT_LOWAT support, as it is not in this version, see
+ commit 29b5e5ef8739 ("mptcp: implement TCP_NOTSENT_LOWAT support") ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/sockopt.c | 61 ++++++++++++++++++++++------------------------------
+ 1 file changed, 26 insertions(+), 35 deletions(-)
+
+--- a/net/mptcp/sockopt.c
++++ b/net/mptcp/sockopt.c
+@@ -616,18 +616,11 @@ static int mptcp_setsockopt_sol_tcp_cong
+ return ret;
+ }
+
+-static int mptcp_setsockopt_sol_tcp_cork(struct mptcp_sock *msk, sockptr_t optval,
+- unsigned int optlen)
++static int __mptcp_setsockopt_sol_tcp_cork(struct mptcp_sock *msk, int val)
+ {
+ struct mptcp_subflow_context *subflow;
+ struct sock *sk = (struct sock *)msk;
+- int val, ret;
+
+- ret = mptcp_get_int_option(msk, optval, optlen, &val);
+- if (ret)
+- return ret;
+-
+- lock_sock(sk);
+ sockopt_seq_inc(msk);
+ msk->cork = !!val;
+ mptcp_for_each_subflow(msk, subflow) {
+@@ -639,23 +632,15 @@ static int mptcp_setsockopt_sol_tcp_cork
+ }
+ if (!val)
+ mptcp_check_and_set_pending(sk);
+- release_sock(sk);
+
+ return 0;
+ }
+
+-static int mptcp_setsockopt_sol_tcp_nodelay(struct mptcp_sock *msk, sockptr_t optval,
+- unsigned int optlen)
++static int __mptcp_setsockopt_sol_tcp_nodelay(struct mptcp_sock *msk, int val)
+ {
+ struct mptcp_subflow_context *subflow;
+ struct sock *sk = (struct sock *)msk;
+- int val, ret;
+-
+- ret = mptcp_get_int_option(msk, optval, optlen, &val);
+- if (ret)
+- return ret;
+
+- lock_sock(sk);
+ sockopt_seq_inc(msk);
+ msk->nodelay = !!val;
+ mptcp_for_each_subflow(msk, subflow) {
+@@ -667,8 +652,6 @@ static int mptcp_setsockopt_sol_tcp_node
+ }
+ if (val)
+ mptcp_check_and_set_pending(sk);
+- release_sock(sk);
+-
+ return 0;
+ }
+
+@@ -793,25 +776,10 @@ static int mptcp_setsockopt_sol_tcp(stru
+ int ret, val;
+
+ switch (optname) {
+- case TCP_INQ:
+- ret = mptcp_get_int_option(msk, optval, optlen, &val);
+- if (ret)
+- return ret;
+- if (val < 0 || val > 1)
+- return -EINVAL;
+-
+- lock_sock(sk);
+- msk->recvmsg_inq = !!val;
+- release_sock(sk);
+- return 0;
+ case TCP_ULP:
+ return -EOPNOTSUPP;
+ case TCP_CONGESTION:
+ return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen);
+- case TCP_CORK:
+- return mptcp_setsockopt_sol_tcp_cork(msk, optval, optlen);
+- case TCP_NODELAY:
+- return mptcp_setsockopt_sol_tcp_nodelay(msk, optval, optlen);
+ case TCP_DEFER_ACCEPT:
+ return mptcp_setsockopt_sol_tcp_defer(msk, optval, optlen);
+ case TCP_FASTOPEN_CONNECT:
+@@ -819,7 +787,30 @@ static int mptcp_setsockopt_sol_tcp(stru
+ optval, optlen);
+ }
+
+- return -EOPNOTSUPP;
++ ret = mptcp_get_int_option(msk, optval, optlen, &val);
++ if (ret)
++ return ret;
++
++ lock_sock(sk);
++ switch (optname) {
++ case TCP_INQ:
++ if (val < 0 || val > 1)
++ ret = -EINVAL;
++ else
++ msk->recvmsg_inq = !!val;
++ break;
++ case TCP_CORK:
++ ret = __mptcp_setsockopt_sol_tcp_cork(msk, val);
++ break;
++ case TCP_NODELAY:
++ ret = __mptcp_setsockopt_sol_tcp_nodelay(msk, val);
++ break;
++ default:
++ ret = -ENOPROTOOPT;
++ }
++
++ release_sock(sk);
++ return ret;
+ }
+
+ int mptcp_setsockopt(struct sock *sk, int level, int optname,
--- /dev/null
+From stable+bounces-47629-greg=kroah.com@vger.kernel.org Wed May 29 12:00:40 2024
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+Date: Wed, 29 May 2024 12:00:26 +0200
+Subject: mptcp: fix full TCP keep-alive support
+To: mptcp@lists.linux.dev, stable@vger.kernel.org, gregkh@linuxfoundation.org, sashal@kernel.org
+Cc: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Paolo Abeni <pabeni@redhat.com>, Mat Martineau <martineau@kernel.org>, Jakub Kicinski <kuba@kernel.org>
+Message-ID: <20240529100022.3373664-8-matttbe@kernel.org>
+
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+
+commit bd11dc4fb969ec148e50cd87f88a78246dbc4d0b upstream.
+
+SO_KEEPALIVE support has been added a while ago, as part of a series
+"adding SOL_SOCKET" support. To have a full control of this keep-alive
+feature, it is important to also support TCP_KEEP* socket options at the
+SOL_TCP level.
+
+Supporting them on the setsockopt() part is easy, it is just a matter of
+remembering each value in the MPTCP sock structure, and calling
+tcp_sock_set_keep*() helpers on each subflow. If the value is not
+modified (0), calling these helpers will not do anything. For the
+getsockopt() part, the corresponding value from the MPTCP sock structure
+or the default one is simply returned. All of this is very similar to
+other TCP_* socket options supported by MPTCP.
+
+It looks important for kernels supporting SO_KEEPALIVE, to also support
+TCP_KEEP* options as well: some apps seem to (wrongly) consider that if
+the former is supported, the latter ones will be supported as well. But
+also, not having this simple and isolated change is preventing MPTCP
+support in some apps, and libraries like GoLang [1]. This is why this
+patch is seen as a fix.
+
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/383
+Fixes: 1b3e7ede1365 ("mptcp: setsockopt: handle SO_KEEPALIVE and SO_PRIORITY")
+Link: https://github.com/golang/go/issues/56539 [1]
+Acked-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Mat Martineau <martineau@kernel.org>
+Link: https://lore.kernel.org/r/20240514011335.176158-3-martineau@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Conflicts in the same context, because commit 29b5e5ef8739 ("mptcp:
+ implement TCP_NOTSENT_LOWAT support") (new feature) and commit
+ 013e3179dbd2 ("mptcp: fix rcv space initialization") (not backported
+ because of the various conflicts, and because the race fixed by this
+ commit "does not produce ill effects in practice") are not in this
+ version. Also, TCP_KEEPINTVL and TCP_KEEPCNT value had to be set
+ without lock, the same way it was done on TCP side prior commit
+ 6fd70a6b4e6f ("tcp: set TCP_KEEPINTVL locklessly") and commit
+ 84485080cbc1 ("tcp: set TCP_KEEPCNT locklessly"). ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/protocol.h | 3 +
+ net/mptcp/sockopt.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 82 insertions(+)
+
+--- a/net/mptcp/protocol.h
++++ b/net/mptcp/protocol.h
+@@ -288,6 +288,9 @@ struct mptcp_sock {
+ fastopening:1,
+ in_accept_queue:1,
+ free_first:1;
++ int keepalive_cnt;
++ int keepalive_idle;
++ int keepalive_intvl;
+ struct work_struct work;
+ struct sk_buff *ooo_last_skb;
+ struct rb_root out_of_order_queue;
+--- a/net/mptcp/sockopt.c
++++ b/net/mptcp/sockopt.c
+@@ -616,6 +616,52 @@ static int mptcp_setsockopt_sol_tcp_cong
+ return ret;
+ }
+
++static int __tcp_sock_set_keepintvl(struct sock *sk, int val)
++{
++ if (val < 1 || val > MAX_TCP_KEEPINTVL)
++ return -EINVAL;
++
++ WRITE_ONCE(tcp_sk(sk)->keepalive_intvl, val * HZ);
++
++ return 0;
++}
++
++static int __tcp_sock_set_keepcnt(struct sock *sk, int val)
++{
++ if (val < 1 || val > MAX_TCP_KEEPCNT)
++ return -EINVAL;
++
++ /* Paired with READ_ONCE() in keepalive_probes() */
++ WRITE_ONCE(tcp_sk(sk)->keepalive_probes, val);
++
++ return 0;
++}
++
++static int __mptcp_setsockopt_set_val(struct mptcp_sock *msk, int max,
++ int (*set_val)(struct sock *, int),
++ int *msk_val, int val)
++{
++ struct mptcp_subflow_context *subflow;
++ int err = 0;
++
++ mptcp_for_each_subflow(msk, subflow) {
++ struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
++ int ret;
++
++ lock_sock(ssk);
++ ret = set_val(ssk, val);
++ err = err ? : ret;
++ release_sock(ssk);
++ }
++
++ if (!err) {
++ *msk_val = val;
++ sockopt_seq_inc(msk);
++ }
++
++ return err;
++}
++
+ static int __mptcp_setsockopt_sol_tcp_cork(struct mptcp_sock *msk, int val)
+ {
+ struct mptcp_subflow_context *subflow;
+@@ -805,6 +851,22 @@ static int mptcp_setsockopt_sol_tcp(stru
+ case TCP_NODELAY:
+ ret = __mptcp_setsockopt_sol_tcp_nodelay(msk, val);
+ break;
++ case TCP_KEEPIDLE:
++ ret = __mptcp_setsockopt_set_val(msk, MAX_TCP_KEEPIDLE,
++ &tcp_sock_set_keepidle_locked,
++ &msk->keepalive_idle, val);
++ break;
++ case TCP_KEEPINTVL:
++ ret = __mptcp_setsockopt_set_val(msk, MAX_TCP_KEEPINTVL,
++ &__tcp_sock_set_keepintvl,
++ &msk->keepalive_intvl, val);
++ break;
++ case TCP_KEEPCNT:
++ ret = __mptcp_setsockopt_set_val(msk, MAX_TCP_KEEPCNT,
++ &__tcp_sock_set_keepcnt,
++ &msk->keepalive_cnt,
++ val);
++ break;
+ default:
+ ret = -ENOPROTOOPT;
+ }
+@@ -1163,6 +1225,8 @@ static int mptcp_put_int_option(struct m
+ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
+ char __user *optval, int __user *optlen)
+ {
++ struct sock *sk = (void *)msk;
++
+ switch (optname) {
+ case TCP_ULP:
+ case TCP_CONGESTION:
+@@ -1178,6 +1242,18 @@ static int mptcp_getsockopt_sol_tcp(stru
+ return mptcp_put_int_option(msk, optval, optlen, msk->cork);
+ case TCP_NODELAY:
+ return mptcp_put_int_option(msk, optval, optlen, msk->nodelay);
++ case TCP_KEEPIDLE:
++ return mptcp_put_int_option(msk, optval, optlen,
++ msk->keepalive_idle ? :
++ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_keepalive_time) / HZ);
++ case TCP_KEEPINTVL:
++ return mptcp_put_int_option(msk, optval, optlen,
++ msk->keepalive_intvl ? :
++ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_keepalive_intvl) / HZ);
++ case TCP_KEEPCNT:
++ return mptcp_put_int_option(msk, optval, optlen,
++ msk->keepalive_cnt ? :
++ READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_keepalive_probes));
+ }
+ return -EOPNOTSUPP;
+ }
+@@ -1282,6 +1358,9 @@ static void sync_socket_options(struct m
+ tcp_set_congestion_control(ssk, msk->ca_name, false, true);
+ __tcp_sock_set_cork(ssk, !!msk->cork);
+ __tcp_sock_set_nodelay(ssk, !!msk->nodelay);
++ tcp_sock_set_keepidle_locked(ssk, msk->keepalive_idle);
++ __tcp_sock_set_keepintvl(ssk, msk->keepalive_intvl);
++ __tcp_sock_set_keepcnt(ssk, msk->keepalive_cnt);
+
+ inet_sk(ssk)->transparent = inet_sk(sk)->transparent;
+ inet_sk(ssk)->freebind = inet_sk(sk)->freebind;