mptcp: move sockopt function into a new file
The MPTCP sockopt implementation is going to be much more big and complex soon. Let's move it to a different source file. No functional change intended. Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bd005f5386
commit
0abdde82b1
|
@ -2,7 +2,7 @@
|
|||
obj-$(CONFIG_MPTCP) += mptcp.o
|
||||
|
||||
mptcp-y := protocol.o subflow.o options.o token.o crypto.o ctrl.o pm.o diag.o \
|
||||
mib.o pm_netlink.o
|
||||
mib.o pm_netlink.o sockopt.o
|
||||
|
||||
obj-$(CONFIG_SYN_COOKIES) += syncookies.o
|
||||
obj-$(CONFIG_INET_MPTCP_DIAG) += mptcp_diag.o
|
||||
|
|
|
@ -90,16 +90,6 @@ static bool mptcp_is_tcpsk(struct sock *sk)
|
|||
return false;
|
||||
}
|
||||
|
||||
static struct sock *__mptcp_tcp_fallback(struct mptcp_sock *msk)
|
||||
{
|
||||
sock_owned_by_me((const struct sock *)msk);
|
||||
|
||||
if (likely(!__mptcp_check_fallback(msk)))
|
||||
return NULL;
|
||||
|
||||
return msk->first;
|
||||
}
|
||||
|
||||
static int __mptcp_socket_create(struct mptcp_sock *msk)
|
||||
{
|
||||
struct mptcp_subflow_context *subflow;
|
||||
|
@ -2811,116 +2801,6 @@ static void mptcp_destroy(struct sock *sk)
|
|||
sk_sockets_allocated_dec(sk);
|
||||
}
|
||||
|
||||
static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,
|
||||
sockptr_t optval, unsigned int optlen)
|
||||
{
|
||||
struct sock *sk = (struct sock *)msk;
|
||||
struct socket *ssock;
|
||||
int ret;
|
||||
|
||||
switch (optname) {
|
||||
case SO_REUSEPORT:
|
||||
case SO_REUSEADDR:
|
||||
lock_sock(sk);
|
||||
ssock = __mptcp_nmpc_socket(msk);
|
||||
if (!ssock) {
|
||||
release_sock(sk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = sock_setsockopt(ssock, SOL_SOCKET, optname, optval, optlen);
|
||||
if (ret == 0) {
|
||||
if (optname == SO_REUSEPORT)
|
||||
sk->sk_reuseport = ssock->sk->sk_reuseport;
|
||||
else if (optname == SO_REUSEADDR)
|
||||
sk->sk_reuse = ssock->sk->sk_reuse;
|
||||
}
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return sock_setsockopt(sk->sk_socket, SOL_SOCKET, optname, optval, optlen);
|
||||
}
|
||||
|
||||
static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
|
||||
sockptr_t optval, unsigned int optlen)
|
||||
{
|
||||
struct sock *sk = (struct sock *)msk;
|
||||
int ret = -EOPNOTSUPP;
|
||||
struct socket *ssock;
|
||||
|
||||
switch (optname) {
|
||||
case IPV6_V6ONLY:
|
||||
lock_sock(sk);
|
||||
ssock = __mptcp_nmpc_socket(msk);
|
||||
if (!ssock) {
|
||||
release_sock(sk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tcp_setsockopt(ssock->sk, SOL_IPV6, optname, optval, optlen);
|
||||
if (ret == 0)
|
||||
sk->sk_ipv6only = ssock->sk->sk_ipv6only;
|
||||
|
||||
release_sock(sk);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mptcp_setsockopt(struct sock *sk, int level, int optname,
|
||||
sockptr_t optval, unsigned int optlen)
|
||||
{
|
||||
struct mptcp_sock *msk = mptcp_sk(sk);
|
||||
struct sock *ssk;
|
||||
|
||||
pr_debug("msk=%p", msk);
|
||||
|
||||
if (level == SOL_SOCKET)
|
||||
return mptcp_setsockopt_sol_socket(msk, optname, optval, optlen);
|
||||
|
||||
/* @@ the meaning of setsockopt() when the socket is connected and
|
||||
* there are multiple subflows is not yet defined. It is up to the
|
||||
* MPTCP-level socket to configure the subflows until the subflow
|
||||
* is in TCP fallback, when TCP socket options are passed through
|
||||
* to the one remaining subflow.
|
||||
*/
|
||||
lock_sock(sk);
|
||||
ssk = __mptcp_tcp_fallback(msk);
|
||||
release_sock(sk);
|
||||
if (ssk)
|
||||
return tcp_setsockopt(ssk, level, optname, optval, optlen);
|
||||
|
||||
if (level == SOL_IPV6)
|
||||
return mptcp_setsockopt_v6(msk, optname, optval, optlen);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int mptcp_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *option)
|
||||
{
|
||||
struct mptcp_sock *msk = mptcp_sk(sk);
|
||||
struct sock *ssk;
|
||||
|
||||
pr_debug("msk=%p", msk);
|
||||
|
||||
/* @@ the meaning of setsockopt() when the socket is connected and
|
||||
* there are multiple subflows is not yet defined. It is up to the
|
||||
* MPTCP-level socket to configure the subflows until the subflow
|
||||
* is in TCP fallback, when socket options are passed through
|
||||
* to the one remaining subflow.
|
||||
*/
|
||||
lock_sock(sk);
|
||||
ssk = __mptcp_tcp_fallback(msk);
|
||||
release_sock(sk);
|
||||
if (ssk)
|
||||
return tcp_getsockopt(ssk, level, optname, optval, option);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
void __mptcp_data_acked(struct sock *sk)
|
||||
{
|
||||
if (!sock_owned_by_user(sk))
|
||||
|
|
|
@ -571,6 +571,11 @@ void mptcp_rcv_space_init(struct mptcp_sock *msk, const struct sock *ssk);
|
|||
void mptcp_data_ready(struct sock *sk, struct sock *ssk);
|
||||
bool mptcp_finish_join(struct sock *sk);
|
||||
bool mptcp_schedule_work(struct sock *sk);
|
||||
int mptcp_setsockopt(struct sock *sk, int level, int optname,
|
||||
sockptr_t optval, unsigned int optlen);
|
||||
int mptcp_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *option);
|
||||
|
||||
void __mptcp_check_push(struct sock *sk, struct sock *ssk);
|
||||
void __mptcp_data_acked(struct sock *sk);
|
||||
void __mptcp_error_report(struct sock *sk);
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Multipath TCP
|
||||
*
|
||||
* Copyright (c) 2021, Red Hat.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "MPTCP: " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/mptcp.h>
|
||||
#include "protocol.h"
|
||||
|
||||
static struct sock *__mptcp_tcp_fallback(struct mptcp_sock *msk)
|
||||
{
|
||||
sock_owned_by_me((const struct sock *)msk);
|
||||
|
||||
if (likely(!__mptcp_check_fallback(msk)))
|
||||
return NULL;
|
||||
|
||||
return msk->first;
|
||||
}
|
||||
|
||||
static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,
|
||||
sockptr_t optval, unsigned int optlen)
|
||||
{
|
||||
struct sock *sk = (struct sock *)msk;
|
||||
struct socket *ssock;
|
||||
int ret;
|
||||
|
||||
switch (optname) {
|
||||
case SO_REUSEPORT:
|
||||
case SO_REUSEADDR:
|
||||
lock_sock(sk);
|
||||
ssock = __mptcp_nmpc_socket(msk);
|
||||
if (!ssock) {
|
||||
release_sock(sk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = sock_setsockopt(ssock, SOL_SOCKET, optname, optval, optlen);
|
||||
if (ret == 0) {
|
||||
if (optname == SO_REUSEPORT)
|
||||
sk->sk_reuseport = ssock->sk->sk_reuseport;
|
||||
else if (optname == SO_REUSEADDR)
|
||||
sk->sk_reuse = ssock->sk->sk_reuse;
|
||||
}
|
||||
release_sock(sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return sock_setsockopt(sk->sk_socket, SOL_SOCKET, optname, optval, optlen);
|
||||
}
|
||||
|
||||
static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
|
||||
sockptr_t optval, unsigned int optlen)
|
||||
{
|
||||
struct sock *sk = (struct sock *)msk;
|
||||
int ret = -EOPNOTSUPP;
|
||||
struct socket *ssock;
|
||||
|
||||
switch (optname) {
|
||||
case IPV6_V6ONLY:
|
||||
lock_sock(sk);
|
||||
ssock = __mptcp_nmpc_socket(msk);
|
||||
if (!ssock) {
|
||||
release_sock(sk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tcp_setsockopt(ssock->sk, SOL_IPV6, optname, optval, optlen);
|
||||
if (ret == 0)
|
||||
sk->sk_ipv6only = ssock->sk->sk_ipv6only;
|
||||
|
||||
release_sock(sk);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mptcp_setsockopt(struct sock *sk, int level, int optname,
|
||||
sockptr_t optval, unsigned int optlen)
|
||||
{
|
||||
struct mptcp_sock *msk = mptcp_sk(sk);
|
||||
struct sock *ssk;
|
||||
|
||||
pr_debug("msk=%p", msk);
|
||||
|
||||
if (level == SOL_SOCKET)
|
||||
return mptcp_setsockopt_sol_socket(msk, optname, optval, optlen);
|
||||
|
||||
/* @@ the meaning of setsockopt() when the socket is connected and
|
||||
* there are multiple subflows is not yet defined. It is up to the
|
||||
* MPTCP-level socket to configure the subflows until the subflow
|
||||
* is in TCP fallback, when TCP socket options are passed through
|
||||
* to the one remaining subflow.
|
||||
*/
|
||||
lock_sock(sk);
|
||||
ssk = __mptcp_tcp_fallback(msk);
|
||||
release_sock(sk);
|
||||
if (ssk)
|
||||
return tcp_setsockopt(ssk, level, optname, optval, optlen);
|
||||
|
||||
if (level == SOL_IPV6)
|
||||
return mptcp_setsockopt_v6(msk, optname, optval, optlen);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int mptcp_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *option)
|
||||
{
|
||||
struct mptcp_sock *msk = mptcp_sk(sk);
|
||||
struct sock *ssk;
|
||||
|
||||
pr_debug("msk=%p", msk);
|
||||
|
||||
/* @@ the meaning of setsockopt() when the socket is connected and
|
||||
* there are multiple subflows is not yet defined. It is up to the
|
||||
* MPTCP-level socket to configure the subflows until the subflow
|
||||
* is in TCP fallback, when socket options are passed through
|
||||
* to the one remaining subflow.
|
||||
*/
|
||||
lock_sock(sk);
|
||||
ssk = __mptcp_tcp_fallback(msk);
|
||||
release_sock(sk);
|
||||
if (ssk)
|
||||
return tcp_getsockopt(ssk, level, optname, optval, option);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
Loading…
Reference in New Issue