aboutsummaryrefslogtreecommitdiffstats
path: root/net/mptcp/token.c
blob: 84d887806090f6d7de4a0845e05b1809418fb788 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// SPDX-License-Identifier: GPL-2.0
/* Multipath TCP token management
 * Copyright (c) 2017 - 2019, Intel Corporation.
 *
 * Note: This code is based on mptcp_ctrl.c from multipath-tcp.org,
 *       authored by:
 *
 *       Sébastien Barré <sebastien.barre@uclouvain.be>
 *       Christoph Paasch <christoph.paasch@uclouvain.be>
 *       Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
 *       Gregory Detal <gregory.detal@uclouvain.be>
 *       Fabien Duchêne <fabien.duchene@uclouvain.be>
 *       Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
 *       Lavkesh Lahngir <lavkesh51@gmail.com>
 *       Andreas Ripke <ripke@neclab.eu>
 *       Vlad Dogaru <vlad.dogaru@intel.com>
 *       Octavian Purdila <octavian.purdila@intel.com>
 *       John Ronan <jronan@tssg.org>
 *       Catalin Nicutar <catalin.nicutar@gmail.com>
 *       Brandon Heller <brandonh@stanford.edu>
 */

#define pr_fmt(fmt) "MPTCP: " fmt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/radix-tree.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <net/sock.h>
#include <net/inet_common.h>
#include <net/protocol.h>
#include <net/mptcp.h>
#include "protocol.h"

static RADIX_TREE(token_tree, GFP_ATOMIC);
static RADIX_TREE(token_req_tree, GFP_ATOMIC);
static DEFINE_SPINLOCK(token_tree_lock);
static int token_used __read_mostly;

/**
 * mptcp_token_new_request - create new key/idsn/token for subflow_request
 * @req - the request socket
 *
 * This function is called when a new mptcp connection is coming in.
 *
 * It creates a unique token to identify the new mptcp connection,
 * a secret local key and the initial data sequence number (idsn).
 *
 * Returns 0 on success.
 */
int mptcp_token_new_request(struct request_sock *req)
{
	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
	int err;

	while (1) {
		u32 token;

		mptcp_crypto_key_gen_sha(&subflow_req->local_key,
					 &subflow_req->token,
					 &subflow_req->idsn);
		pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
			 req, subflow_req->local_key, subflow_req->token,
			 subflow_req->idsn);

		token = subflow_req->token;
		spin_lock_bh(&token_tree_lock);
		if (!radix_tree_lookup(&token_req_tree, token) &&
		    !radix_tree_lookup(&token_tree, token))
			break;
		spin_unlock_bh(&token_tree_lock);
	}

	err = radix_tree_insert(&token_req_tree,
				subflow_req->token, &token_used);
	spin_unlock_bh(&token_tree_lock);
	return err;
}

/**
 * mptcp_token_new_connect - create new key/idsn/token for subflow
 * @sk - the socket that will initiate a connection
 *
 * This function is called when a new outgoing mptcp connection is
 * initiated.
 *
 * It creates a unique token to identify the new mptcp connection,
 * a secret local key and the initial data sequence number (idsn).
 *
 * On success, the mptcp connection can be found again using
 * the computed token at a later time, this is needed to process
 * join requests.
 *
 * returns 0 on success.
 */
int mptcp_token_new_connect(struct sock *sk)
{
	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
	struct sock *mptcp_sock = subflow->conn;
	int err;

	while (1) {
		u32 token;

		mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token,
					 &subflow->idsn);

		pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n",
			 sk, subflow->local_key, subflow->token, subflow->idsn);

		token = subflow->token;
		spin_lock_bh(&token_tree_lock);
		if (!radix_tree_lookup(&token_req_tree, token) &&
		    !radix_tree_lookup(&token_tree, token))
			break;
		spin_unlock_bh(&token_tree_lock);
	}
	err = radix_tree_insert(&token_tree, subflow->token, mptcp_sock);
	spin_unlock_bh(&token_tree_lock);

	return err;
}

/**
 * mptcp_token_new_accept - insert token for later processing
 * @token: the token to insert to the tree
 *
 * Called when a SYN packet creates a new logical connection, i.e.
 * is not a join request.
 *
 * We don't have an mptcp socket yet at that point.
 * This is paired with mptcp_token_update_accept, called on accept().
 */
int mptcp_token_new_accept(u32 token)
{
	int err;

	spin_lock_bh(&token_tree_lock);
	err = radix_tree_insert(&token_tree, token, &token_used);
	spin_unlock_bh(&token_tree_lock);

	return err;
}

/**
 * mptcp_token_update_accept - update token to map to mptcp socket
 * @conn: the new struct mptcp_sock
 * @sk: the initial subflow for this mptcp socket
 *
 * Called when the first mptcp socket is created on accept to
 * refresh the dummy mapping (done to reserve the token) with
 * the mptcp_socket structure that wasn't allocated before.
 */
void mptcp_token_update_accept(struct sock *sk, struct sock *conn)
{
	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
	void __rcu **slot;

	spin_lock_bh(&token_tree_lock);
	slot = radix_tree_lookup_slot(&token_tree, subflow->token);
	WARN_ON_ONCE(!slot);
	if (slot) {
		WARN_ON_ONCE(rcu_access_pointer(*slot) != &token_used);
		radix_tree_replace_slot(&token_tree, slot, conn);
	}
	spin_unlock_bh(&token_tree_lock);
}

/**
 * mptcp_token_destroy_request - remove mptcp connection/token
 * @token - token of mptcp connection to remove
 *
 * Remove not-yet-fully-established incoming connection identified
 * by @token.
 */
void mptcp_token_destroy_request(u32 token)
{
	spin_lock_bh(&token_tree_lock);
	radix_tree_delete(&token_req_tree, token);
	spin_unlock_bh(&token_tree_lock);
}

/**
 * mptcp_token_destroy - remove mptcp connection/token
 * @token - token of mptcp connection to remove
 *
 * Remove the connection identified by @token.
 */
void mptcp_token_destroy(u32 token)
{
	spin_lock_bh(&token_tree_lock);
	radix_tree_delete(&token_tree, token);
	spin_unlock_bh(&token_tree_lock);
}