162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Multipath TCP token management
362306a36Sopenharmony_ci * Copyright (c) 2017 - 2019, Intel Corporation.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Note: This code is based on mptcp_ctrl.c from multipath-tcp.org,
662306a36Sopenharmony_ci *       authored by:
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *       Sébastien Barré <sebastien.barre@uclouvain.be>
962306a36Sopenharmony_ci *       Christoph Paasch <christoph.paasch@uclouvain.be>
1062306a36Sopenharmony_ci *       Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi>
1162306a36Sopenharmony_ci *       Gregory Detal <gregory.detal@uclouvain.be>
1262306a36Sopenharmony_ci *       Fabien Duchêne <fabien.duchene@uclouvain.be>
1362306a36Sopenharmony_ci *       Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de>
1462306a36Sopenharmony_ci *       Lavkesh Lahngir <lavkesh51@gmail.com>
1562306a36Sopenharmony_ci *       Andreas Ripke <ripke@neclab.eu>
1662306a36Sopenharmony_ci *       Vlad Dogaru <vlad.dogaru@intel.com>
1762306a36Sopenharmony_ci *       Octavian Purdila <octavian.purdila@intel.com>
1862306a36Sopenharmony_ci *       John Ronan <jronan@tssg.org>
1962306a36Sopenharmony_ci *       Catalin Nicutar <catalin.nicutar@gmail.com>
2062306a36Sopenharmony_ci *       Brandon Heller <brandonh@stanford.edu>
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define pr_fmt(fmt) "MPTCP: " fmt
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/kernel.h>
2662306a36Sopenharmony_ci#include <linux/module.h>
2762306a36Sopenharmony_ci#include <linux/memblock.h>
2862306a36Sopenharmony_ci#include <linux/ip.h>
2962306a36Sopenharmony_ci#include <linux/tcp.h>
3062306a36Sopenharmony_ci#include <net/sock.h>
3162306a36Sopenharmony_ci#include <net/inet_common.h>
3262306a36Sopenharmony_ci#include <net/protocol.h>
3362306a36Sopenharmony_ci#include <net/mptcp.h>
3462306a36Sopenharmony_ci#include "protocol.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define TOKEN_MAX_CHAIN_LEN	4
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistruct token_bucket {
3962306a36Sopenharmony_ci	spinlock_t		lock;
4062306a36Sopenharmony_ci	int			chain_len;
4162306a36Sopenharmony_ci	struct hlist_nulls_head	req_chain;
4262306a36Sopenharmony_ci	struct hlist_nulls_head	msk_chain;
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic struct token_bucket *token_hash __read_mostly;
4662306a36Sopenharmony_cistatic unsigned int token_mask __read_mostly;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic struct token_bucket *token_bucket(u32 token)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	return &token_hash[token & token_mask];
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* called with bucket lock held */
5462306a36Sopenharmony_cistatic struct mptcp_subflow_request_sock *
5562306a36Sopenharmony_ci__token_lookup_req(struct token_bucket *t, u32 token)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct mptcp_subflow_request_sock *req;
5862306a36Sopenharmony_ci	struct hlist_nulls_node *pos;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	hlist_nulls_for_each_entry_rcu(req, pos, &t->req_chain, token_node)
6162306a36Sopenharmony_ci		if (req->token == token)
6262306a36Sopenharmony_ci			return req;
6362306a36Sopenharmony_ci	return NULL;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* called with bucket lock held */
6762306a36Sopenharmony_cistatic struct mptcp_sock *
6862306a36Sopenharmony_ci__token_lookup_msk(struct token_bucket *t, u32 token)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct hlist_nulls_node *pos;
7162306a36Sopenharmony_ci	struct sock *sk;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	sk_nulls_for_each_rcu(sk, pos, &t->msk_chain)
7462306a36Sopenharmony_ci		if (mptcp_sk(sk)->token == token)
7562306a36Sopenharmony_ci			return mptcp_sk(sk);
7662306a36Sopenharmony_ci	return NULL;
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic bool __token_bucket_busy(struct token_bucket *t, u32 token)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	return !token || t->chain_len >= TOKEN_MAX_CHAIN_LEN ||
8262306a36Sopenharmony_ci	       __token_lookup_req(t, token) || __token_lookup_msk(t, token);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	/* we might consider a faster version that computes the key as a
8862306a36Sopenharmony_ci	 * hash of some information available in the MPTCP socket. Use
8962306a36Sopenharmony_ci	 * random data at the moment, as it's probably the safest option
9062306a36Sopenharmony_ci	 * in case multiple sockets are opened in different namespaces at
9162306a36Sopenharmony_ci	 * the same time.
9262306a36Sopenharmony_ci	 */
9362306a36Sopenharmony_ci	get_random_bytes(key, sizeof(u64));
9462306a36Sopenharmony_ci	mptcp_crypto_key_sha(*key, token, idsn);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/**
9862306a36Sopenharmony_ci * mptcp_token_new_request - create new key/idsn/token for subflow_request
9962306a36Sopenharmony_ci * @req: the request socket
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci * This function is called when a new mptcp connection is coming in.
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * It creates a unique token to identify the new mptcp connection,
10462306a36Sopenharmony_ci * a secret local key and the initial data sequence number (idsn).
10562306a36Sopenharmony_ci *
10662306a36Sopenharmony_ci * Returns 0 on success.
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_ciint mptcp_token_new_request(struct request_sock *req)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
11162306a36Sopenharmony_ci	struct token_bucket *bucket;
11262306a36Sopenharmony_ci	u32 token;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	mptcp_crypto_key_sha(subflow_req->local_key,
11562306a36Sopenharmony_ci			     &subflow_req->token,
11662306a36Sopenharmony_ci			     &subflow_req->idsn);
11762306a36Sopenharmony_ci	pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n",
11862306a36Sopenharmony_ci		 req, subflow_req->local_key, subflow_req->token,
11962306a36Sopenharmony_ci		 subflow_req->idsn);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	token = subflow_req->token;
12262306a36Sopenharmony_ci	bucket = token_bucket(token);
12362306a36Sopenharmony_ci	spin_lock_bh(&bucket->lock);
12462306a36Sopenharmony_ci	if (__token_bucket_busy(bucket, token)) {
12562306a36Sopenharmony_ci		spin_unlock_bh(&bucket->lock);
12662306a36Sopenharmony_ci		return -EBUSY;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	hlist_nulls_add_head_rcu(&subflow_req->token_node, &bucket->req_chain);
13062306a36Sopenharmony_ci	bucket->chain_len++;
13162306a36Sopenharmony_ci	spin_unlock_bh(&bucket->lock);
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/**
13662306a36Sopenharmony_ci * mptcp_token_new_connect - create new key/idsn/token for subflow
13762306a36Sopenharmony_ci * @ssk: the socket that will initiate a connection
13862306a36Sopenharmony_ci *
13962306a36Sopenharmony_ci * This function is called when a new outgoing mptcp connection is
14062306a36Sopenharmony_ci * initiated.
14162306a36Sopenharmony_ci *
14262306a36Sopenharmony_ci * It creates a unique token to identify the new mptcp connection,
14362306a36Sopenharmony_ci * a secret local key and the initial data sequence number (idsn).
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci * On success, the mptcp connection can be found again using
14662306a36Sopenharmony_ci * the computed token at a later time, this is needed to process
14762306a36Sopenharmony_ci * join requests.
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * returns 0 on success.
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_ciint mptcp_token_new_connect(struct sock *ssk)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
15462306a36Sopenharmony_ci	struct mptcp_sock *msk = mptcp_sk(subflow->conn);
15562306a36Sopenharmony_ci	int retries = MPTCP_TOKEN_MAX_RETRIES;
15662306a36Sopenharmony_ci	struct sock *sk = subflow->conn;
15762306a36Sopenharmony_ci	struct token_bucket *bucket;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ciagain:
16062306a36Sopenharmony_ci	mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token,
16162306a36Sopenharmony_ci				 &subflow->idsn);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	bucket = token_bucket(subflow->token);
16462306a36Sopenharmony_ci	spin_lock_bh(&bucket->lock);
16562306a36Sopenharmony_ci	if (__token_bucket_busy(bucket, subflow->token)) {
16662306a36Sopenharmony_ci		spin_unlock_bh(&bucket->lock);
16762306a36Sopenharmony_ci		if (!--retries)
16862306a36Sopenharmony_ci			return -EBUSY;
16962306a36Sopenharmony_ci		goto again;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n",
17362306a36Sopenharmony_ci		 ssk, subflow->local_key, subflow->token, subflow->idsn);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	WRITE_ONCE(msk->token, subflow->token);
17662306a36Sopenharmony_ci	__sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
17762306a36Sopenharmony_ci	bucket->chain_len++;
17862306a36Sopenharmony_ci	spin_unlock_bh(&bucket->lock);
17962306a36Sopenharmony_ci	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/**
18462306a36Sopenharmony_ci * mptcp_token_accept - replace a req sk with full sock in token hash
18562306a36Sopenharmony_ci * @req: the request socket to be removed
18662306a36Sopenharmony_ci * @msk: the just cloned socket linked to the new connection
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci * Called when a SYN packet creates a new logical connection, i.e.
18962306a36Sopenharmony_ci * is not a join request.
19062306a36Sopenharmony_ci */
19162306a36Sopenharmony_civoid mptcp_token_accept(struct mptcp_subflow_request_sock *req,
19262306a36Sopenharmony_ci			struct mptcp_sock *msk)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct mptcp_subflow_request_sock *pos;
19562306a36Sopenharmony_ci	struct sock *sk = (struct sock *)msk;
19662306a36Sopenharmony_ci	struct token_bucket *bucket;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
19962306a36Sopenharmony_ci	bucket = token_bucket(req->token);
20062306a36Sopenharmony_ci	spin_lock_bh(&bucket->lock);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/* pedantic lookup check for the moved token */
20362306a36Sopenharmony_ci	pos = __token_lookup_req(bucket, req->token);
20462306a36Sopenharmony_ci	if (!WARN_ON_ONCE(pos != req))
20562306a36Sopenharmony_ci		hlist_nulls_del_init_rcu(&req->token_node);
20662306a36Sopenharmony_ci	__sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
20762306a36Sopenharmony_ci	spin_unlock_bh(&bucket->lock);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cibool mptcp_token_exists(u32 token)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct hlist_nulls_node *pos;
21362306a36Sopenharmony_ci	struct token_bucket *bucket;
21462306a36Sopenharmony_ci	struct mptcp_sock *msk;
21562306a36Sopenharmony_ci	struct sock *sk;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	rcu_read_lock();
21862306a36Sopenharmony_ci	bucket = token_bucket(token);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ciagain:
22162306a36Sopenharmony_ci	sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
22262306a36Sopenharmony_ci		msk = mptcp_sk(sk);
22362306a36Sopenharmony_ci		if (READ_ONCE(msk->token) == token)
22462306a36Sopenharmony_ci			goto found;
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci	if (get_nulls_value(pos) != (token & token_mask))
22762306a36Sopenharmony_ci		goto again;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	rcu_read_unlock();
23062306a36Sopenharmony_ci	return false;
23162306a36Sopenharmony_cifound:
23262306a36Sopenharmony_ci	rcu_read_unlock();
23362306a36Sopenharmony_ci	return true;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/**
23762306a36Sopenharmony_ci * mptcp_token_get_sock - retrieve mptcp connection sock using its token
23862306a36Sopenharmony_ci * @net: restrict to this namespace
23962306a36Sopenharmony_ci * @token: token of the mptcp connection to retrieve
24062306a36Sopenharmony_ci *
24162306a36Sopenharmony_ci * This function returns the mptcp connection structure with the given token.
24262306a36Sopenharmony_ci * A reference count on the mptcp socket returned is taken.
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci * returns NULL if no connection with the given token value exists.
24562306a36Sopenharmony_ci */
24662306a36Sopenharmony_cistruct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct hlist_nulls_node *pos;
24962306a36Sopenharmony_ci	struct token_bucket *bucket;
25062306a36Sopenharmony_ci	struct mptcp_sock *msk;
25162306a36Sopenharmony_ci	struct sock *sk;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	rcu_read_lock();
25462306a36Sopenharmony_ci	bucket = token_bucket(token);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ciagain:
25762306a36Sopenharmony_ci	sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
25862306a36Sopenharmony_ci		msk = mptcp_sk(sk);
25962306a36Sopenharmony_ci		if (READ_ONCE(msk->token) != token ||
26062306a36Sopenharmony_ci		    !net_eq(sock_net(sk), net))
26162306a36Sopenharmony_ci			continue;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		if (!refcount_inc_not_zero(&sk->sk_refcnt))
26462306a36Sopenharmony_ci			goto not_found;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		if (READ_ONCE(msk->token) != token ||
26762306a36Sopenharmony_ci		    !net_eq(sock_net(sk), net)) {
26862306a36Sopenharmony_ci			sock_put(sk);
26962306a36Sopenharmony_ci			goto again;
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci		goto found;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	if (get_nulls_value(pos) != (token & token_mask))
27462306a36Sopenharmony_ci		goto again;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cinot_found:
27762306a36Sopenharmony_ci	msk = NULL;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cifound:
28062306a36Sopenharmony_ci	rcu_read_unlock();
28162306a36Sopenharmony_ci	return msk;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_get_sock);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/**
28662306a36Sopenharmony_ci * mptcp_token_iter_next - iterate over the token container from given pos
28762306a36Sopenharmony_ci * @net: namespace to be iterated
28862306a36Sopenharmony_ci * @s_slot: start slot number
28962306a36Sopenharmony_ci * @s_num: start number inside the given lock
29062306a36Sopenharmony_ci *
29162306a36Sopenharmony_ci * This function returns the first mptcp connection structure found inside the
29262306a36Sopenharmony_ci * token container starting from the specified position, or NULL.
29362306a36Sopenharmony_ci *
29462306a36Sopenharmony_ci * On successful iteration, the iterator is moved to the next position and
29562306a36Sopenharmony_ci * a reference to the returned socket is acquired.
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistruct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot,
29862306a36Sopenharmony_ci					 long *s_num)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct mptcp_sock *ret = NULL;
30162306a36Sopenharmony_ci	struct hlist_nulls_node *pos;
30262306a36Sopenharmony_ci	int slot, num = 0;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	for (slot = *s_slot; slot <= token_mask; *s_num = 0, slot++) {
30562306a36Sopenharmony_ci		struct token_bucket *bucket = &token_hash[slot];
30662306a36Sopenharmony_ci		struct sock *sk;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		num = 0;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		if (hlist_nulls_empty(&bucket->msk_chain))
31162306a36Sopenharmony_ci			continue;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		rcu_read_lock();
31462306a36Sopenharmony_ci		sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) {
31562306a36Sopenharmony_ci			++num;
31662306a36Sopenharmony_ci			if (!net_eq(sock_net(sk), net))
31762306a36Sopenharmony_ci				continue;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci			if (num <= *s_num)
32062306a36Sopenharmony_ci				continue;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci			if (!refcount_inc_not_zero(&sk->sk_refcnt))
32362306a36Sopenharmony_ci				continue;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci			if (!net_eq(sock_net(sk), net)) {
32662306a36Sopenharmony_ci				sock_put(sk);
32762306a36Sopenharmony_ci				continue;
32862306a36Sopenharmony_ci			}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci			ret = mptcp_sk(sk);
33162306a36Sopenharmony_ci			rcu_read_unlock();
33262306a36Sopenharmony_ci			goto out;
33362306a36Sopenharmony_ci		}
33462306a36Sopenharmony_ci		rcu_read_unlock();
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ciout:
33862306a36Sopenharmony_ci	*s_slot = slot;
33962306a36Sopenharmony_ci	*s_num = num;
34062306a36Sopenharmony_ci	return ret;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_iter_next);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci/**
34562306a36Sopenharmony_ci * mptcp_token_destroy_request - remove mptcp connection/token
34662306a36Sopenharmony_ci * @req: mptcp request socket dropping the token
34762306a36Sopenharmony_ci *
34862306a36Sopenharmony_ci * Remove the token associated to @req.
34962306a36Sopenharmony_ci */
35062306a36Sopenharmony_civoid mptcp_token_destroy_request(struct request_sock *req)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
35362306a36Sopenharmony_ci	struct mptcp_subflow_request_sock *pos;
35462306a36Sopenharmony_ci	struct token_bucket *bucket;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (hlist_nulls_unhashed(&subflow_req->token_node))
35762306a36Sopenharmony_ci		return;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	bucket = token_bucket(subflow_req->token);
36062306a36Sopenharmony_ci	spin_lock_bh(&bucket->lock);
36162306a36Sopenharmony_ci	pos = __token_lookup_req(bucket, subflow_req->token);
36262306a36Sopenharmony_ci	if (!WARN_ON_ONCE(pos != subflow_req)) {
36362306a36Sopenharmony_ci		hlist_nulls_del_init_rcu(&pos->token_node);
36462306a36Sopenharmony_ci		bucket->chain_len--;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci	spin_unlock_bh(&bucket->lock);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci/**
37062306a36Sopenharmony_ci * mptcp_token_destroy - remove mptcp connection/token
37162306a36Sopenharmony_ci * @msk: mptcp connection dropping the token
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * Remove the token associated to @msk
37462306a36Sopenharmony_ci */
37562306a36Sopenharmony_civoid mptcp_token_destroy(struct mptcp_sock *msk)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	struct sock *sk = (struct sock *)msk;
37862306a36Sopenharmony_ci	struct token_bucket *bucket;
37962306a36Sopenharmony_ci	struct mptcp_sock *pos;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	if (sk_unhashed((struct sock *)msk))
38262306a36Sopenharmony_ci		return;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
38562306a36Sopenharmony_ci	bucket = token_bucket(msk->token);
38662306a36Sopenharmony_ci	spin_lock_bh(&bucket->lock);
38762306a36Sopenharmony_ci	pos = __token_lookup_msk(bucket, msk->token);
38862306a36Sopenharmony_ci	if (!WARN_ON_ONCE(pos != msk)) {
38962306a36Sopenharmony_ci		__sk_nulls_del_node_init_rcu((struct sock *)pos);
39062306a36Sopenharmony_ci		bucket->chain_len--;
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci	spin_unlock_bh(&bucket->lock);
39362306a36Sopenharmony_ci	WRITE_ONCE(msk->token, 0);
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_civoid __init mptcp_token_init(void)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	int i;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	token_hash = alloc_large_system_hash("MPTCP token",
40162306a36Sopenharmony_ci					     sizeof(struct token_bucket),
40262306a36Sopenharmony_ci					     0,
40362306a36Sopenharmony_ci					     20,/* one slot per 1MB of memory */
40462306a36Sopenharmony_ci					     HASH_ZERO,
40562306a36Sopenharmony_ci					     NULL,
40662306a36Sopenharmony_ci					     &token_mask,
40762306a36Sopenharmony_ci					     0,
40862306a36Sopenharmony_ci					     64 * 1024);
40962306a36Sopenharmony_ci	for (i = 0; i < token_mask + 1; ++i) {
41062306a36Sopenharmony_ci		INIT_HLIST_NULLS_HEAD(&token_hash[i].req_chain, i);
41162306a36Sopenharmony_ci		INIT_HLIST_NULLS_HEAD(&token_hash[i].msk_chain, i);
41262306a36Sopenharmony_ci		spin_lock_init(&token_hash[i].lock);
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci#if IS_MODULE(CONFIG_MPTCP_KUNIT_TEST)
41762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_new_request);
41862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_new_connect);
41962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_accept);
42062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_destroy_request);
42162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_destroy);
42262306a36Sopenharmony_ci#endif
423