Commit | Line | Data |
---|---|---|
79c0949e PK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Multipath TCP token management | |
3 | * Copyright (c) 2017 - 2019, Intel Corporation. | |
4 | * | |
5 | * Note: This code is based on mptcp_ctrl.c from multipath-tcp.org, | |
6 | * authored by: | |
7 | * | |
8 | * Sébastien Barré <sebastien.barre@uclouvain.be> | |
9 | * Christoph Paasch <christoph.paasch@uclouvain.be> | |
10 | * Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi> | |
11 | * Gregory Detal <gregory.detal@uclouvain.be> | |
12 | * Fabien Duchêne <fabien.duchene@uclouvain.be> | |
13 | * Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de> | |
14 | * Lavkesh Lahngir <lavkesh51@gmail.com> | |
15 | * Andreas Ripke <ripke@neclab.eu> | |
16 | * Vlad Dogaru <vlad.dogaru@intel.com> | |
17 | * Octavian Purdila <octavian.purdila@intel.com> | |
18 | * John Ronan <jronan@tssg.org> | |
19 | * Catalin Nicutar <catalin.nicutar@gmail.com> | |
20 | * Brandon Heller <brandonh@stanford.edu> | |
21 | */ | |
22 | ||
23 | #define pr_fmt(fmt) "MPTCP: " fmt | |
24 | ||
25 | #include <linux/kernel.h> | |
26 | #include <linux/module.h> | |
27 | #include <linux/radix-tree.h> | |
28 | #include <linux/ip.h> | |
29 | #include <linux/tcp.h> | |
30 | #include <net/sock.h> | |
31 | #include <net/inet_common.h> | |
32 | #include <net/protocol.h> | |
33 | #include <net/mptcp.h> | |
34 | #include "protocol.h" | |
35 | ||
36 | static RADIX_TREE(token_tree, GFP_ATOMIC); | |
37 | static RADIX_TREE(token_req_tree, GFP_ATOMIC); | |
38 | static DEFINE_SPINLOCK(token_tree_lock); | |
39 | static int token_used __read_mostly; | |
40 | ||
41 | /** | |
42 | * mptcp_token_new_request - create new key/idsn/token for subflow_request | |
564cf2f3 | 43 | * @req: the request socket |
79c0949e PK |
44 | * |
45 | * This function is called when a new mptcp connection is coming in. | |
46 | * | |
47 | * It creates a unique token to identify the new mptcp connection, | |
48 | * a secret local key and the initial data sequence number (idsn). | |
49 | * | |
50 | * Returns 0 on success. | |
51 | */ | |
52 | int mptcp_token_new_request(struct request_sock *req) | |
53 | { | |
54 | struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req); | |
55 | int err; | |
56 | ||
57 | while (1) { | |
58 | u32 token; | |
59 | ||
60 | mptcp_crypto_key_gen_sha(&subflow_req->local_key, | |
61 | &subflow_req->token, | |
62 | &subflow_req->idsn); | |
63 | pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n", | |
64 | req, subflow_req->local_key, subflow_req->token, | |
65 | subflow_req->idsn); | |
66 | ||
67 | token = subflow_req->token; | |
68 | spin_lock_bh(&token_tree_lock); | |
69 | if (!radix_tree_lookup(&token_req_tree, token) && | |
70 | !radix_tree_lookup(&token_tree, token)) | |
71 | break; | |
72 | spin_unlock_bh(&token_tree_lock); | |
73 | } | |
74 | ||
75 | err = radix_tree_insert(&token_req_tree, | |
76 | subflow_req->token, &token_used); | |
77 | spin_unlock_bh(&token_tree_lock); | |
78 | return err; | |
79 | } | |
80 | ||
81 | /** | |
82 | * mptcp_token_new_connect - create new key/idsn/token for subflow | |
564cf2f3 | 83 | * @sk: the socket that will initiate a connection |
79c0949e PK |
84 | * |
85 | * This function is called when a new outgoing mptcp connection is | |
86 | * initiated. | |
87 | * | |
88 | * It creates a unique token to identify the new mptcp connection, | |
89 | * a secret local key and the initial data sequence number (idsn). | |
90 | * | |
91 | * On success, the mptcp connection can be found again using | |
92 | * the computed token at a later time, this is needed to process | |
93 | * join requests. | |
94 | * | |
95 | * returns 0 on success. | |
96 | */ | |
97 | int mptcp_token_new_connect(struct sock *sk) | |
98 | { | |
99 | struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); | |
100 | struct sock *mptcp_sock = subflow->conn; | |
101 | int err; | |
102 | ||
103 | while (1) { | |
104 | u32 token; | |
105 | ||
106 | mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token, | |
107 | &subflow->idsn); | |
108 | ||
109 | pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n", | |
110 | sk, subflow->local_key, subflow->token, subflow->idsn); | |
111 | ||
112 | token = subflow->token; | |
113 | spin_lock_bh(&token_tree_lock); | |
114 | if (!radix_tree_lookup(&token_req_tree, token) && | |
115 | !radix_tree_lookup(&token_tree, token)) | |
116 | break; | |
117 | spin_unlock_bh(&token_tree_lock); | |
118 | } | |
119 | err = radix_tree_insert(&token_tree, subflow->token, mptcp_sock); | |
120 | spin_unlock_bh(&token_tree_lock); | |
121 | ||
122 | return err; | |
123 | } | |
124 | ||
125 | /** | |
126 | * mptcp_token_new_accept - insert token for later processing | |
127 | * @token: the token to insert to the tree | |
564cf2f3 | 128 | * @conn: the just cloned socket linked to the new connection |
79c0949e PK |
129 | * |
130 | * Called when a SYN packet creates a new logical connection, i.e. | |
131 | * is not a join request. | |
79c0949e | 132 | */ |
58b09919 | 133 | int mptcp_token_new_accept(u32 token, struct sock *conn) |
79c0949e PK |
134 | { |
135 | int err; | |
136 | ||
137 | spin_lock_bh(&token_tree_lock); | |
58b09919 | 138 | err = radix_tree_insert(&token_tree, token, conn); |
79c0949e PK |
139 | spin_unlock_bh(&token_tree_lock); |
140 | ||
141 | return err; | |
142 | } | |
143 | ||
f296234c PK |
144 | /** |
145 | * mptcp_token_get_sock - retrieve mptcp connection sock using its token | |
146 | * @token: token of the mptcp connection to retrieve | |
147 | * | |
148 | * This function returns the mptcp connection structure with the given token. | |
149 | * A reference count on the mptcp socket returned is taken. | |
150 | * | |
151 | * returns NULL if no connection with the given token value exists. | |
152 | */ | |
153 | struct mptcp_sock *mptcp_token_get_sock(u32 token) | |
154 | { | |
155 | struct sock *conn; | |
156 | ||
157 | spin_lock_bh(&token_tree_lock); | |
158 | conn = radix_tree_lookup(&token_tree, token); | |
159 | if (conn) { | |
160 | /* token still reserved? */ | |
161 | if (conn == (struct sock *)&token_used) | |
162 | conn = NULL; | |
163 | else | |
164 | sock_hold(conn); | |
165 | } | |
166 | spin_unlock_bh(&token_tree_lock); | |
167 | ||
168 | return mptcp_sk(conn); | |
169 | } | |
170 | ||
79c0949e PK |
171 | /** |
172 | * mptcp_token_destroy_request - remove mptcp connection/token | |
564cf2f3 | 173 | * @token: token of mptcp connection to remove |
79c0949e PK |
174 | * |
175 | * Remove not-yet-fully-established incoming connection identified | |
176 | * by @token. | |
177 | */ | |
178 | void mptcp_token_destroy_request(u32 token) | |
179 | { | |
180 | spin_lock_bh(&token_tree_lock); | |
181 | radix_tree_delete(&token_req_tree, token); | |
182 | spin_unlock_bh(&token_tree_lock); | |
183 | } | |
184 | ||
185 | /** | |
186 | * mptcp_token_destroy - remove mptcp connection/token | |
564cf2f3 | 187 | * @token: token of mptcp connection to remove |
79c0949e PK |
188 | * |
189 | * Remove the connection identified by @token. | |
190 | */ | |
191 | void mptcp_token_destroy(u32 token) | |
192 | { | |
193 | spin_lock_bh(&token_tree_lock); | |
194 | radix_tree_delete(&token_tree, token); | |
195 | spin_unlock_bh(&token_tree_lock); | |
196 | } |