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