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