xref: /linux/net/mptcp/token.c (revision c558246e)
179c0949eSPeter Krystad // SPDX-License-Identifier: GPL-2.0
279c0949eSPeter Krystad /* Multipath TCP token management
379c0949eSPeter Krystad  * Copyright (c) 2017 - 2019, Intel Corporation.
479c0949eSPeter Krystad  *
579c0949eSPeter Krystad  * Note: This code is based on mptcp_ctrl.c from multipath-tcp.org,
679c0949eSPeter Krystad  *       authored by:
779c0949eSPeter Krystad  *
879c0949eSPeter Krystad  *       Sébastien Barré <sebastien.barre@uclouvain.be>
979c0949eSPeter Krystad  *       Christoph Paasch <christoph.paasch@uclouvain.be>
1079c0949eSPeter Krystad  *       Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
1179c0949eSPeter Krystad  *       Gregory Detal <gregory.detal@uclouvain.be>
1279c0949eSPeter Krystad  *       Fabien Duchêne <fabien.duchene@uclouvain.be>
1379c0949eSPeter Krystad  *       Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
1479c0949eSPeter Krystad  *       Lavkesh Lahngir <lavkesh51@gmail.com>
1579c0949eSPeter Krystad  *       Andreas Ripke <ripke@neclab.eu>
1679c0949eSPeter Krystad  *       Vlad Dogaru <vlad.dogaru@intel.com>
1779c0949eSPeter Krystad  *       Octavian Purdila <octavian.purdila@intel.com>
1879c0949eSPeter Krystad  *       John Ronan <jronan@tssg.org>
1979c0949eSPeter Krystad  *       Catalin Nicutar <catalin.nicutar@gmail.com>
2079c0949eSPeter Krystad  *       Brandon Heller <brandonh@stanford.edu>
2179c0949eSPeter Krystad  */
2279c0949eSPeter Krystad 
2379c0949eSPeter Krystad #define pr_fmt(fmt) "MPTCP: " fmt
2479c0949eSPeter Krystad 
2579c0949eSPeter Krystad #include <linux/kernel.h>
2679c0949eSPeter Krystad #include <linux/module.h>
272c5ebd00SPaolo Abeni #include <linux/memblock.h>
2879c0949eSPeter Krystad #include <linux/ip.h>
2979c0949eSPeter Krystad #include <linux/tcp.h>
3079c0949eSPeter Krystad #include <net/sock.h>
3179c0949eSPeter Krystad #include <net/inet_common.h>
3279c0949eSPeter Krystad #include <net/protocol.h>
3379c0949eSPeter Krystad #include <net/mptcp.h>
3479c0949eSPeter Krystad #include "protocol.h"
3579c0949eSPeter Krystad 
362c5ebd00SPaolo Abeni #define TOKEN_MAX_CHAIN_LEN	4
372c5ebd00SPaolo Abeni 
382c5ebd00SPaolo Abeni struct token_bucket {
392c5ebd00SPaolo Abeni 	spinlock_t		lock;
402c5ebd00SPaolo Abeni 	int			chain_len;
412c5ebd00SPaolo Abeni 	struct hlist_nulls_head	req_chain;
422c5ebd00SPaolo Abeni 	struct hlist_nulls_head	msk_chain;
432c5ebd00SPaolo Abeni };
442c5ebd00SPaolo Abeni 
452c5ebd00SPaolo Abeni static struct token_bucket *token_hash __read_mostly;
462c5ebd00SPaolo Abeni static unsigned int token_mask __read_mostly;
472c5ebd00SPaolo Abeni 
token_bucket(u32 token)482c5ebd00SPaolo Abeni static struct token_bucket *token_bucket(u32 token)
492c5ebd00SPaolo Abeni {
502c5ebd00SPaolo Abeni 	return &token_hash[token & token_mask];
512c5ebd00SPaolo Abeni }
522c5ebd00SPaolo Abeni 
532c5ebd00SPaolo Abeni /* called with bucket lock held */
542c5ebd00SPaolo Abeni static struct mptcp_subflow_request_sock *
__token_lookup_req(struct token_bucket * t,u32 token)552c5ebd00SPaolo Abeni __token_lookup_req(struct token_bucket *t, u32 token)
562c5ebd00SPaolo Abeni {
572c5ebd00SPaolo Abeni 	struct mptcp_subflow_request_sock *req;
582c5ebd00SPaolo Abeni 	struct hlist_nulls_node *pos;
592c5ebd00SPaolo Abeni 
602c5ebd00SPaolo Abeni 	hlist_nulls_for_each_entry_rcu(req, pos, &t->req_chain, token_node)
612c5ebd00SPaolo Abeni 		if (req->token == token)
622c5ebd00SPaolo Abeni 			return req;
632c5ebd00SPaolo Abeni 	return NULL;
642c5ebd00SPaolo Abeni }
652c5ebd00SPaolo Abeni 
662c5ebd00SPaolo Abeni /* called with bucket lock held */
672c5ebd00SPaolo Abeni static struct mptcp_sock *
__token_lookup_msk(struct token_bucket * t,u32 token)682c5ebd00SPaolo Abeni __token_lookup_msk(struct token_bucket *t, u32 token)
692c5ebd00SPaolo Abeni {
702c5ebd00SPaolo Abeni 	struct hlist_nulls_node *pos;
712c5ebd00SPaolo Abeni 	struct sock *sk;
722c5ebd00SPaolo Abeni 
732c5ebd00SPaolo Abeni 	sk_nulls_for_each_rcu(sk, pos, &t->msk_chain)
742c5ebd00SPaolo Abeni 		if (mptcp_sk(sk)->token == token)
752c5ebd00SPaolo Abeni 			return mptcp_sk(sk);
762c5ebd00SPaolo Abeni 	return NULL;
772c5ebd00SPaolo Abeni }
782c5ebd00SPaolo Abeni 
__token_bucket_busy(struct token_bucket * t,u32 token)792c5ebd00SPaolo Abeni static bool __token_bucket_busy(struct token_bucket *t, u32 token)
802c5ebd00SPaolo Abeni {
812c5ebd00SPaolo Abeni 	return !token || t->chain_len >= TOKEN_MAX_CHAIN_LEN ||
822c5ebd00SPaolo Abeni 	       __token_lookup_req(t, token) || __token_lookup_msk(t, token);
832c5ebd00SPaolo Abeni }
8479c0949eSPeter Krystad 
mptcp_crypto_key_gen_sha(u64 * key,u32 * token,u64 * idsn)85c1d069e3SFlorian Westphal static void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
86c1d069e3SFlorian Westphal {
87c1d069e3SFlorian Westphal 	/* we might consider a faster version that computes the key as a
88c1d069e3SFlorian Westphal 	 * hash of some information available in the MPTCP socket. Use
89c1d069e3SFlorian Westphal 	 * random data at the moment, as it's probably the safest option
90c1d069e3SFlorian Westphal 	 * in case multiple sockets are opened in different namespaces at
91c1d069e3SFlorian Westphal 	 * the same time.
92c1d069e3SFlorian Westphal 	 */
93c1d069e3SFlorian Westphal 	get_random_bytes(key, sizeof(u64));
94c1d069e3SFlorian Westphal 	mptcp_crypto_key_sha(*key, token, idsn);
95c1d069e3SFlorian Westphal }
96c1d069e3SFlorian Westphal 
9779c0949eSPeter Krystad /**
9879c0949eSPeter Krystad  * mptcp_token_new_request - create new key/idsn/token for subflow_request
99564cf2f3SMatthieu Baerts  * @req: the request socket
10079c0949eSPeter Krystad  *
10179c0949eSPeter Krystad  * This function is called when a new mptcp connection is coming in.
10279c0949eSPeter Krystad  *
10379c0949eSPeter Krystad  * It creates a unique token to identify the new mptcp connection,
10479c0949eSPeter Krystad  * a secret local key and the initial data sequence number (idsn).
10579c0949eSPeter Krystad  *
10679c0949eSPeter Krystad  * Returns 0 on success.
10779c0949eSPeter Krystad  */
mptcp_token_new_request(struct request_sock * req)10879c0949eSPeter Krystad int mptcp_token_new_request(struct request_sock *req)
10979c0949eSPeter Krystad {
11079c0949eSPeter Krystad 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
1112c5ebd00SPaolo Abeni 	struct token_bucket *bucket;
11279c0949eSPeter Krystad 	u32 token;
11379c0949eSPeter Krystad 
114535fb815SFlorian Westphal 	mptcp_crypto_key_sha(subflow_req->local_key,
11579c0949eSPeter Krystad 			     &subflow_req->token,
11679c0949eSPeter Krystad 			     &subflow_req->idsn);
11779c0949eSPeter Krystad 	pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
11879c0949eSPeter Krystad 		 req, subflow_req->local_key, subflow_req->token,
11979c0949eSPeter Krystad 		 subflow_req->idsn);
12079c0949eSPeter Krystad 
12179c0949eSPeter Krystad 	token = subflow_req->token;
1222c5ebd00SPaolo Abeni 	bucket = token_bucket(token);
1232c5ebd00SPaolo Abeni 	spin_lock_bh(&bucket->lock);
1242c5ebd00SPaolo Abeni 	if (__token_bucket_busy(bucket, token)) {
1252c5ebd00SPaolo Abeni 		spin_unlock_bh(&bucket->lock);
1262c5ebd00SPaolo Abeni 		return -EBUSY;
12779c0949eSPeter Krystad 	}
12879c0949eSPeter Krystad 
1292c5ebd00SPaolo Abeni 	hlist_nulls_add_head_rcu(&subflow_req->token_node, &bucket->req_chain);
1302c5ebd00SPaolo Abeni 	bucket->chain_len++;
1312c5ebd00SPaolo Abeni 	spin_unlock_bh(&bucket->lock);
1322c5ebd00SPaolo Abeni 	return 0;
13379c0949eSPeter Krystad }
13479c0949eSPeter Krystad 
13579c0949eSPeter Krystad /**
13679c0949eSPeter Krystad  * mptcp_token_new_connect - create new key/idsn/token for subflow
137294de909SMenglong Dong  * @ssk: the socket that will initiate a connection
13879c0949eSPeter Krystad  *
13979c0949eSPeter Krystad  * This function is called when a new outgoing mptcp connection is
14079c0949eSPeter Krystad  * initiated.
14179c0949eSPeter Krystad  *
14279c0949eSPeter Krystad  * It creates a unique token to identify the new mptcp connection,
14379c0949eSPeter Krystad  * a secret local key and the initial data sequence number (idsn).
14479c0949eSPeter Krystad  *
14579c0949eSPeter Krystad  * On success, the mptcp connection can be found again using
14679c0949eSPeter Krystad  * the computed token at a later time, this is needed to process
14779c0949eSPeter Krystad  * join requests.
14879c0949eSPeter Krystad  *
14979c0949eSPeter Krystad  * returns 0 on success.
15079c0949eSPeter Krystad  */
mptcp_token_new_connect(struct sock * ssk)151294de909SMenglong Dong int mptcp_token_new_connect(struct sock *ssk)
15279c0949eSPeter Krystad {
153294de909SMenglong Dong 	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
1542c5ebd00SPaolo Abeni 	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
155c68a0cd1SJianguo Wu 	int retries = MPTCP_TOKEN_MAX_RETRIES;
156*c558246eSMenglong Dong 	struct sock *sk = subflow->conn;
1572c5ebd00SPaolo Abeni 	struct token_bucket *bucket;
15879c0949eSPeter Krystad 
1592c5ebd00SPaolo Abeni again:
1602c5ebd00SPaolo Abeni 	mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token,
1612c5ebd00SPaolo Abeni 				 &subflow->idsn);
16279c0949eSPeter Krystad 
1632c5ebd00SPaolo Abeni 	bucket = token_bucket(subflow->token);
1642c5ebd00SPaolo Abeni 	spin_lock_bh(&bucket->lock);
1652c5ebd00SPaolo Abeni 	if (__token_bucket_busy(bucket, subflow->token)) {
1662c5ebd00SPaolo Abeni 		spin_unlock_bh(&bucket->lock);
1672c5ebd00SPaolo Abeni 		if (!--retries)
1682c5ebd00SPaolo Abeni 			return -EBUSY;
1692c5ebd00SPaolo Abeni 		goto again;
1702c5ebd00SPaolo Abeni 	}
1712c5ebd00SPaolo Abeni 
1722f1af441SJianguo Wu 	pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n",
173294de909SMenglong Dong 		 ssk, subflow->local_key, subflow->token, subflow->idsn);
1742f1af441SJianguo Wu 
1752c5ebd00SPaolo Abeni 	WRITE_ONCE(msk->token, subflow->token);
1762c5ebd00SPaolo Abeni 	__sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
1772c5ebd00SPaolo Abeni 	bucket->chain_len++;
1782c5ebd00SPaolo Abeni 	spin_unlock_bh(&bucket->lock);
179*c558246eSMenglong Dong 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
1802c5ebd00SPaolo Abeni 	return 0;
18179c0949eSPeter Krystad }
18279c0949eSPeter Krystad 
18379c0949eSPeter Krystad /**
1842c5ebd00SPaolo Abeni  * mptcp_token_accept - replace a req sk with full sock in token hash
1852c5ebd00SPaolo Abeni  * @req: the request socket to be removed
1862c5ebd00SPaolo Abeni  * @msk: the just cloned socket linked to the new connection
18779c0949eSPeter Krystad  *
18879c0949eSPeter Krystad  * Called when a SYN packet creates a new logical connection, i.e.
18979c0949eSPeter Krystad  * is not a join request.
19079c0949eSPeter Krystad  */
mptcp_token_accept(struct mptcp_subflow_request_sock * req,struct mptcp_sock * msk)1912c5ebd00SPaolo Abeni void mptcp_token_accept(struct mptcp_subflow_request_sock *req,
1922c5ebd00SPaolo Abeni 			struct mptcp_sock *msk)
19379c0949eSPeter Krystad {
1942c5ebd00SPaolo Abeni 	struct mptcp_subflow_request_sock *pos;
195*c558246eSMenglong Dong 	struct sock *sk = (struct sock *)msk;
1962c5ebd00SPaolo Abeni 	struct token_bucket *bucket;
19779c0949eSPeter Krystad 
198*c558246eSMenglong Dong 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
1992c5ebd00SPaolo Abeni 	bucket = token_bucket(req->token);
2002c5ebd00SPaolo Abeni 	spin_lock_bh(&bucket->lock);
20179c0949eSPeter Krystad 
2022c5ebd00SPaolo Abeni 	/* pedantic lookup check for the moved token */
2032c5ebd00SPaolo Abeni 	pos = __token_lookup_req(bucket, req->token);
2042c5ebd00SPaolo Abeni 	if (!WARN_ON_ONCE(pos != req))
2052c5ebd00SPaolo Abeni 		hlist_nulls_del_init_rcu(&req->token_node);
2062c5ebd00SPaolo Abeni 	__sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
2072c5ebd00SPaolo Abeni 	spin_unlock_bh(&bucket->lock);
20879c0949eSPeter Krystad }
20979c0949eSPeter Krystad 
mptcp_token_exists(u32 token)210c83a47e5SFlorian Westphal bool mptcp_token_exists(u32 token)
211c83a47e5SFlorian Westphal {
212c83a47e5SFlorian Westphal 	struct hlist_nulls_node *pos;
213c83a47e5SFlorian Westphal 	struct token_bucket *bucket;
214c83a47e5SFlorian Westphal 	struct mptcp_sock *msk;
215c83a47e5SFlorian Westphal 	struct sock *sk;
216c83a47e5SFlorian Westphal 
217c83a47e5SFlorian Westphal 	rcu_read_lock();
218c83a47e5SFlorian Westphal 	bucket = token_bucket(token);
219c83a47e5SFlorian Westphal 
220c83a47e5SFlorian Westphal again:
221c83a47e5SFlorian Westphal 	sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
222c83a47e5SFlorian Westphal 		msk = mptcp_sk(sk);
223c83a47e5SFlorian Westphal 		if (READ_ONCE(msk->token) == token)
224c83a47e5SFlorian Westphal 			goto found;
225c83a47e5SFlorian Westphal 	}
226c83a47e5SFlorian Westphal 	if (get_nulls_value(pos) != (token & token_mask))
227c83a47e5SFlorian Westphal 		goto again;
228c83a47e5SFlorian Westphal 
229c83a47e5SFlorian Westphal 	rcu_read_unlock();
230c83a47e5SFlorian Westphal 	return false;
231c83a47e5SFlorian Westphal found:
232c83a47e5SFlorian Westphal 	rcu_read_unlock();
233c83a47e5SFlorian Westphal 	return true;
234c83a47e5SFlorian Westphal }
235c83a47e5SFlorian Westphal 
23679c0949eSPeter Krystad /**
237f296234cSPeter Krystad  * mptcp_token_get_sock - retrieve mptcp connection sock using its token
238ea1300b9SFlorian Westphal  * @net: restrict to this namespace
239f296234cSPeter Krystad  * @token: token of the mptcp connection to retrieve
240f296234cSPeter Krystad  *
241f296234cSPeter Krystad  * This function returns the mptcp connection structure with the given token.
242f296234cSPeter Krystad  * A reference count on the mptcp socket returned is taken.
243f296234cSPeter Krystad  *
244f296234cSPeter Krystad  * returns NULL if no connection with the given token value exists.
245f296234cSPeter Krystad  */
mptcp_token_get_sock(struct net * net,u32 token)246ea1300b9SFlorian Westphal struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token)
247f296234cSPeter Krystad {
2482c5ebd00SPaolo Abeni 	struct hlist_nulls_node *pos;
2492c5ebd00SPaolo Abeni 	struct token_bucket *bucket;
2502c5ebd00SPaolo Abeni 	struct mptcp_sock *msk;
2512c5ebd00SPaolo Abeni 	struct sock *sk;
252f296234cSPeter Krystad 
2532c5ebd00SPaolo Abeni 	rcu_read_lock();
2542c5ebd00SPaolo Abeni 	bucket = token_bucket(token);
2552c5ebd00SPaolo Abeni 
2562c5ebd00SPaolo Abeni again:
2572c5ebd00SPaolo Abeni 	sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
2582c5ebd00SPaolo Abeni 		msk = mptcp_sk(sk);
259ea1300b9SFlorian Westphal 		if (READ_ONCE(msk->token) != token ||
260ea1300b9SFlorian Westphal 		    !net_eq(sock_net(sk), net))
2612c5ebd00SPaolo Abeni 			continue;
262ea1300b9SFlorian Westphal 
2632c5ebd00SPaolo Abeni 		if (!refcount_inc_not_zero(&sk->sk_refcnt))
2642c5ebd00SPaolo Abeni 			goto not_found;
265ea1300b9SFlorian Westphal 
266ea1300b9SFlorian Westphal 		if (READ_ONCE(msk->token) != token ||
267ea1300b9SFlorian Westphal 		    !net_eq(sock_net(sk), net)) {
2682c5ebd00SPaolo Abeni 			sock_put(sk);
2692c5ebd00SPaolo Abeni 			goto again;
270f296234cSPeter Krystad 		}
2712c5ebd00SPaolo Abeni 		goto found;
2722c5ebd00SPaolo Abeni 	}
2732c5ebd00SPaolo Abeni 	if (get_nulls_value(pos) != (token & token_mask))
2742c5ebd00SPaolo Abeni 		goto again;
275f296234cSPeter Krystad 
2762c5ebd00SPaolo Abeni not_found:
2772c5ebd00SPaolo Abeni 	msk = NULL;
2782c5ebd00SPaolo Abeni 
2792c5ebd00SPaolo Abeni found:
2802c5ebd00SPaolo Abeni 	rcu_read_unlock();
2812c5ebd00SPaolo Abeni 	return msk;
282f296234cSPeter Krystad }
28396d890daSPaolo Abeni EXPORT_SYMBOL_GPL(mptcp_token_get_sock);
28496d890daSPaolo Abeni 
28596d890daSPaolo Abeni /**
28696d890daSPaolo Abeni  * mptcp_token_iter_next - iterate over the token container from given pos
28796d890daSPaolo Abeni  * @net: namespace to be iterated
28896d890daSPaolo Abeni  * @s_slot: start slot number
28996d890daSPaolo Abeni  * @s_num: start number inside the given lock
29096d890daSPaolo Abeni  *
29196d890daSPaolo Abeni  * This function returns the first mptcp connection structure found inside the
29296d890daSPaolo Abeni  * token container starting from the specified position, or NULL.
29396d890daSPaolo Abeni  *
2944373bf4bSMat Martineau  * On successful iteration, the iterator is moved to the next position and
2954373bf4bSMat Martineau  * a reference to the returned socket is acquired.
29696d890daSPaolo Abeni  */
mptcp_token_iter_next(const struct net * net,long * s_slot,long * s_num)29796d890daSPaolo Abeni struct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
29896d890daSPaolo Abeni 					 long *s_num)
29996d890daSPaolo Abeni {
30096d890daSPaolo Abeni 	struct mptcp_sock *ret = NULL;
30196d890daSPaolo Abeni 	struct hlist_nulls_node *pos;
302e16b874eSDavide Caratti 	int slot, num = 0;
30396d890daSPaolo Abeni 
30496d890daSPaolo Abeni 	for (slot = *s_slot; slot <= token_mask; *s_num = 0, slot++) {
30596d890daSPaolo Abeni 		struct token_bucket *bucket = &token_hash[slot];
30696d890daSPaolo Abeni 		struct sock *sk;
30796d890daSPaolo Abeni 
30896d890daSPaolo Abeni 		num = 0;
30996d890daSPaolo Abeni 
31096d890daSPaolo Abeni 		if (hlist_nulls_empty(&bucket->msk_chain))
31196d890daSPaolo Abeni 			continue;
31296d890daSPaolo Abeni 
31396d890daSPaolo Abeni 		rcu_read_lock();
31496d890daSPaolo Abeni 		sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
31596d890daSPaolo Abeni 			++num;
31696d890daSPaolo Abeni 			if (!net_eq(sock_net(sk), net))
31796d890daSPaolo Abeni 				continue;
31896d890daSPaolo Abeni 
31996d890daSPaolo Abeni 			if (num <= *s_num)
32096d890daSPaolo Abeni 				continue;
32196d890daSPaolo Abeni 
32296d890daSPaolo Abeni 			if (!refcount_inc_not_zero(&sk->sk_refcnt))
32396d890daSPaolo Abeni 				continue;
32496d890daSPaolo Abeni 
32596d890daSPaolo Abeni 			if (!net_eq(sock_net(sk), net)) {
32696d890daSPaolo Abeni 				sock_put(sk);
32796d890daSPaolo Abeni 				continue;
32896d890daSPaolo Abeni 			}
32996d890daSPaolo Abeni 
33096d890daSPaolo Abeni 			ret = mptcp_sk(sk);
33196d890daSPaolo Abeni 			rcu_read_unlock();
33296d890daSPaolo Abeni 			goto out;
33396d890daSPaolo Abeni 		}
33496d890daSPaolo Abeni 		rcu_read_unlock();
33596d890daSPaolo Abeni 	}
33696d890daSPaolo Abeni 
33796d890daSPaolo Abeni out:
33896d890daSPaolo Abeni 	*s_slot = slot;
33996d890daSPaolo Abeni 	*s_num = num;
34096d890daSPaolo Abeni 	return ret;
34196d890daSPaolo Abeni }
34296d890daSPaolo Abeni EXPORT_SYMBOL_GPL(mptcp_token_iter_next);
343f296234cSPeter Krystad 
344f296234cSPeter Krystad /**
34579c0949eSPeter Krystad  * mptcp_token_destroy_request - remove mptcp connection/token
3462c5ebd00SPaolo Abeni  * @req: mptcp request socket dropping the token
34779c0949eSPeter Krystad  *
3482c5ebd00SPaolo Abeni  * Remove the token associated to @req.
34979c0949eSPeter Krystad  */
mptcp_token_destroy_request(struct request_sock * req)3502c5ebd00SPaolo Abeni void mptcp_token_destroy_request(struct request_sock *req)
35179c0949eSPeter Krystad {
3522c5ebd00SPaolo Abeni 	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
3532c5ebd00SPaolo Abeni 	struct mptcp_subflow_request_sock *pos;
3542c5ebd00SPaolo Abeni 	struct token_bucket *bucket;
3552c5ebd00SPaolo Abeni 
3562c5ebd00SPaolo Abeni 	if (hlist_nulls_unhashed(&subflow_req->token_node))
3572c5ebd00SPaolo Abeni 		return;
3582c5ebd00SPaolo Abeni 
3592c5ebd00SPaolo Abeni 	bucket = token_bucket(subflow_req->token);
3602c5ebd00SPaolo Abeni 	spin_lock_bh(&bucket->lock);
3612c5ebd00SPaolo Abeni 	pos = __token_lookup_req(bucket, subflow_req->token);
3622c5ebd00SPaolo Abeni 	if (!WARN_ON_ONCE(pos != subflow_req)) {
3632c5ebd00SPaolo Abeni 		hlist_nulls_del_init_rcu(&pos->token_node);
3642c5ebd00SPaolo Abeni 		bucket->chain_len--;
3652c5ebd00SPaolo Abeni 	}
3662c5ebd00SPaolo Abeni 	spin_unlock_bh(&bucket->lock);
36779c0949eSPeter Krystad }
36879c0949eSPeter Krystad 
36979c0949eSPeter Krystad /**
37079c0949eSPeter Krystad  * mptcp_token_destroy - remove mptcp connection/token
3712c5ebd00SPaolo Abeni  * @msk: mptcp connection dropping the token
37279c0949eSPeter Krystad  *
3732c5ebd00SPaolo Abeni  * Remove the token associated to @msk
37479c0949eSPeter Krystad  */
mptcp_token_destroy(struct mptcp_sock * msk)3752c5ebd00SPaolo Abeni void mptcp_token_destroy(struct mptcp_sock *msk)
37679c0949eSPeter Krystad {
377*c558246eSMenglong Dong 	struct sock *sk = (struct sock *)msk;
3782c5ebd00SPaolo Abeni 	struct token_bucket *bucket;
3792c5ebd00SPaolo Abeni 	struct mptcp_sock *pos;
3802c5ebd00SPaolo Abeni 
3812c5ebd00SPaolo Abeni 	if (sk_unhashed((struct sock *)msk))
3822c5ebd00SPaolo Abeni 		return;
3832c5ebd00SPaolo Abeni 
384*c558246eSMenglong Dong 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
3852c5ebd00SPaolo Abeni 	bucket = token_bucket(msk->token);
3862c5ebd00SPaolo Abeni 	spin_lock_bh(&bucket->lock);
3872c5ebd00SPaolo Abeni 	pos = __token_lookup_msk(bucket, msk->token);
3882c5ebd00SPaolo Abeni 	if (!WARN_ON_ONCE(pos != msk)) {
3892c5ebd00SPaolo Abeni 		__sk_nulls_del_node_init_rcu((struct sock *)pos);
3902c5ebd00SPaolo Abeni 		bucket->chain_len--;
3912c5ebd00SPaolo Abeni 	}
3922c5ebd00SPaolo Abeni 	spin_unlock_bh(&bucket->lock);
393b29fcfb5SPaolo Abeni 	WRITE_ONCE(msk->token, 0);
3942c5ebd00SPaolo Abeni }
3952c5ebd00SPaolo Abeni 
mptcp_token_init(void)3962c5ebd00SPaolo Abeni void __init mptcp_token_init(void)
3972c5ebd00SPaolo Abeni {
3982c5ebd00SPaolo Abeni 	int i;
3992c5ebd00SPaolo Abeni 
4002c5ebd00SPaolo Abeni 	token_hash = alloc_large_system_hash("MPTCP token",
4012c5ebd00SPaolo Abeni 					     sizeof(struct token_bucket),
4022c5ebd00SPaolo Abeni 					     0,
4032c5ebd00SPaolo Abeni 					     20,/* one slot per 1MB of memory */
4046ab301c9SPaolo Abeni 					     HASH_ZERO,
4052c5ebd00SPaolo Abeni 					     NULL,
4062c5ebd00SPaolo Abeni 					     &token_mask,
4072c5ebd00SPaolo Abeni 					     0,
4082c5ebd00SPaolo Abeni 					     64 * 1024);
4092c5ebd00SPaolo Abeni 	for (i = 0; i < token_mask + 1; ++i) {
4102c5ebd00SPaolo Abeni 		INIT_HLIST_NULLS_HEAD(&token_hash[i].req_chain, i);
4112c5ebd00SPaolo Abeni 		INIT_HLIST_NULLS_HEAD(&token_hash[i].msk_chain, i);
4122c5ebd00SPaolo Abeni 		spin_lock_init(&token_hash[i].lock);
4132c5ebd00SPaolo Abeni 	}
41479c0949eSPeter Krystad }
415a8ee9c9bSPaolo Abeni 
4163fcc8a25SNico Pache #if IS_MODULE(CONFIG_MPTCP_KUNIT_TEST)
417a8ee9c9bSPaolo Abeni EXPORT_SYMBOL_GPL(mptcp_token_new_request);
418a8ee9c9bSPaolo Abeni EXPORT_SYMBOL_GPL(mptcp_token_new_connect);
419a8ee9c9bSPaolo Abeni EXPORT_SYMBOL_GPL(mptcp_token_accept);
420a8ee9c9bSPaolo Abeni EXPORT_SYMBOL_GPL(mptcp_token_destroy_request);
421a8ee9c9bSPaolo Abeni EXPORT_SYMBOL_GPL(mptcp_token_destroy);
422a8ee9c9bSPaolo Abeni #endif
423