From: Peter Krystad <peter.krys...@linux.intel.com>

set/getsockopt behaviour with multiple subflows is undefined.
Therefore, for now, we return -EOPNOTSUPP unless we're in fallback mode.

Signed-off-by: Peter Krystad <peter.krys...@linux.intel.com>
Signed-off-by: Paolo Abeni <pab...@redhat.com>
---
 net/mptcp/protocol.c | 67 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index dba4d7a4a61a..41588758f74b 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -28,6 +28,17 @@ static struct socket *__mptcp_fallback_get_ref(const struct 
mptcp_sock *msk)
        return msk->subflow;
 }
 
+static struct socket *mptcp_fallback_get_ref(const struct mptcp_sock *msk)
+{
+       struct socket *ssock;
+
+       lock_sock((struct sock *)msk);
+       ssock = __mptcp_fallback_get_ref(msk);
+       release_sock((struct sock *)msk);
+
+       return ssock;
+}
+
 static struct sock *mptcp_subflow_get_ref(const struct mptcp_sock *msk)
 {
        struct mptcp_subflow_context *subflow;
@@ -224,6 +235,60 @@ static void mptcp_destroy(struct sock *sk)
 {
 }
 
+static int mptcp_setsockopt(struct sock *sk, int level, int optname,
+                           char __user *uoptval, unsigned int optlen)
+{
+       struct mptcp_sock *msk = mptcp_sk(sk);
+       char __kernel *optval;
+       struct socket *ssock;
+       int ret;
+
+       /* will be treated as __user in tcp_setsockopt */
+       optval = (char __kernel __force *)uoptval;
+
+       pr_debug("msk=%p", msk);
+       ssock = mptcp_fallback_get_ref(msk);
+       if (ssock) {
+               pr_debug("subflow=%p", ssock->sk);
+               ret = kernel_setsockopt(ssock, level, optname, optval, optlen);
+               sock_put(ssock->sk);
+               return ret;
+       }
+
+       /* @@ the meaning of setsockopt() when the socket is connected and
+        * there are multiple subflows is not defined.
+        */
+       return -EOPNOTSUPP;
+}
+
+static int mptcp_getsockopt(struct sock *sk, int level, int optname,
+                           char __user *uoptval, int __user *uoption)
+{
+       struct mptcp_sock *msk = mptcp_sk(sk);
+       char __kernel *optval;
+       int __kernel *option;
+       struct socket *ssock;
+       int ret;
+
+       /* will be treated as __user in tcp_getsockopt */
+       optval = (char __kernel __force *)uoptval;
+       option = (int __kernel __force *)uoption;
+
+       pr_debug("msk=%p", msk);
+       ssock = mptcp_fallback_get_ref(msk);
+       if (ssock) {
+               pr_debug("subflow=%p", ssock->sk);
+               ret = kernel_getsockopt(ssock, level, optname, optval, option);
+               sock_put(ssock->sk);
+               return ret;
+       }
+
+       /* @@ the meaning of getsockopt() when the socket is connected and
+        * there are multiple subflows is not defined.
+        */
+       return -EOPNOTSUPP;
+}
+
 static int mptcp_get_port(struct sock *sk, unsigned short snum)
 {
        struct mptcp_sock *msk = mptcp_sk(sk);
@@ -282,6 +347,8 @@ static struct proto mptcp_prot = {
        .init           = mptcp_init_sock,
        .close          = mptcp_close,
        .accept         = mptcp_accept,
+       .setsockopt     = mptcp_setsockopt,
+       .getsockopt     = mptcp_getsockopt,
        .shutdown       = tcp_shutdown,
        .destroy        = mptcp_destroy,
        .sendmsg        = mptcp_sendmsg,
-- 
2.23.0

Reply via email to