linux/net/mptcp/subflow.c

120 lines
2.3 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0
/* Multipath TCP
*
* Copyright (c) 2017 - 2019, Intel Corporation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <net/sock.h>
#include <net/inet_common.h>
#include <net/inet_hashtables.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/mptcp.h>
#include "protocol.h"
int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
{
struct mptcp_subflow_context *subflow;
struct net *net = sock_net(sk);
struct socket *sf;
int err;
err = sock_create_kern(net, PF_INET, SOCK_STREAM, IPPROTO_TCP, &sf);
if (err)
return err;
lock_sock(sf->sk);
/* kernel sockets do not by default acquire net ref, but TCP timer
* needs it.
*/
sf->sk->sk_net_refcnt = 1;
get_net(net);
this_cpu_add(*net->core.sock_inuse, 1);
err = tcp_set_ulp(sf->sk, "mptcp");
release_sock(sf->sk);
if (err)
return err;
subflow = mptcp_subflow_ctx(sf->sk);
pr_debug("subflow=%p", subflow);
*new_sock = sf;
subflow->conn = sk;
return 0;
}
static struct mptcp_subflow_context *subflow_create_ctx(struct sock *sk,
gfp_t priority)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct mptcp_subflow_context *ctx;
ctx = kzalloc(sizeof(*ctx), priority);
if (!ctx)
return NULL;
rcu_assign_pointer(icsk->icsk_ulp_data, ctx);
pr_debug("subflow=%p", ctx);
ctx->tcp_sock = sk;
return ctx;
}
static int subflow_ulp_init(struct sock *sk)
{
struct mptcp_subflow_context *ctx;
struct tcp_sock *tp = tcp_sk(sk);
int err = 0;
/* disallow attaching ULP to a socket unless it has been
* created with sock_create_kern()
*/
if (!sk->sk_kern_sock) {
err = -EOPNOTSUPP;
goto out;
}
ctx = subflow_create_ctx(sk, GFP_KERNEL);
if (!ctx) {
err = -ENOMEM;
goto out;
}
pr_debug("subflow=%p, family=%d", ctx, sk->sk_family);
tp->is_mptcp = 1;
out:
return err;
}
static void subflow_ulp_release(struct sock *sk)
{
struct mptcp_subflow_context *ctx = mptcp_subflow_ctx(sk);
if (!ctx)
return;
kfree_rcu(ctx, rcu);
}
static struct tcp_ulp_ops subflow_ulp_ops __read_mostly = {
.name = "mptcp",
.owner = THIS_MODULE,
.init = subflow_ulp_init,
.release = subflow_ulp_release,
};
void mptcp_subflow_init(void)
{
if (tcp_register_ulp(&subflow_ulp_ops) != 0)
panic("MPTCP: failed to register subflows to ULP\n");
}