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
|
obj-$(CONFIG_MPTCP) += mptcp.o
|
||||||
|
|
||||||
mptcp-y := protocol.o subflow.o options.o token.o crypto.o ctrl.o pm.o diag.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_SYN_COOKIES) += syncookies.o
|
||||||
obj-$(CONFIG_INET_MPTCP_DIAG) += mptcp_diag.o
|
obj-$(CONFIG_INET_MPTCP_DIAG) += mptcp_diag.o
|
||||||
|
@ -90,16 +90,6 @@ static bool mptcp_is_tcpsk(struct sock *sk)
|
|||||||
return false;
|
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)
|
static int __mptcp_socket_create(struct mptcp_sock *msk)
|
||||||
{
|
{
|
||||||
struct mptcp_subflow_context *subflow;
|
struct mptcp_subflow_context *subflow;
|
||||||
@ -2811,116 +2801,6 @@ static void mptcp_destroy(struct sock *sk)
|
|||||||
sk_sockets_allocated_dec(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)
|
void __mptcp_data_acked(struct sock *sk)
|
||||||
{
|
{
|
||||||
if (!sock_owned_by_user(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);
|
void mptcp_data_ready(struct sock *sk, struct sock *ssk);
|
||||||
bool mptcp_finish_join(struct sock *sk);
|
bool mptcp_finish_join(struct sock *sk);
|
||||||
bool mptcp_schedule_work(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_check_push(struct sock *sk, struct sock *ssk);
|
||||||
void __mptcp_data_acked(struct sock *sk);
|
void __mptcp_data_acked(struct sock *sk);
|
||||||
void __mptcp_error_report(struct sock *sk);
|
void __mptcp_error_report(struct sock *sk);
|
||||||
|
136
net/mptcp/sockopt.c
Normal file
136
net/mptcp/sockopt.c
Normal file
@ -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…
x
Reference in New Issue
Block a user