18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Multipath TCP token management 38c2ecf20Sopenharmony_ci * Copyright (c) 2017 - 2019, Intel Corporation. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Note: This code is based on mptcp_ctrl.c from multipath-tcp.org, 68c2ecf20Sopenharmony_ci * authored by: 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Sébastien Barré <sebastien.barre@uclouvain.be> 98c2ecf20Sopenharmony_ci * Christoph Paasch <christoph.paasch@uclouvain.be> 108c2ecf20Sopenharmony_ci * Jaakko Korkeaniemi <jaakko.korkeaniemi@aalto.fi> 118c2ecf20Sopenharmony_ci * Gregory Detal <gregory.detal@uclouvain.be> 128c2ecf20Sopenharmony_ci * Fabien Duchêne <fabien.duchene@uclouvain.be> 138c2ecf20Sopenharmony_ci * Andreas Seelinger <Andreas.Seelinger@rwth-aachen.de> 148c2ecf20Sopenharmony_ci * Lavkesh Lahngir <lavkesh51@gmail.com> 158c2ecf20Sopenharmony_ci * Andreas Ripke <ripke@neclab.eu> 168c2ecf20Sopenharmony_ci * Vlad Dogaru <vlad.dogaru@intel.com> 178c2ecf20Sopenharmony_ci * Octavian Purdila <octavian.purdila@intel.com> 188c2ecf20Sopenharmony_ci * John Ronan <jronan@tssg.org> 198c2ecf20Sopenharmony_ci * Catalin Nicutar <catalin.nicutar@gmail.com> 208c2ecf20Sopenharmony_ci * Brandon Heller <brandonh@stanford.edu> 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "MPTCP: " fmt 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/module.h> 278c2ecf20Sopenharmony_ci#include <linux/memblock.h> 288c2ecf20Sopenharmony_ci#include <linux/ip.h> 298c2ecf20Sopenharmony_ci#include <linux/tcp.h> 308c2ecf20Sopenharmony_ci#include <net/sock.h> 318c2ecf20Sopenharmony_ci#include <net/inet_common.h> 328c2ecf20Sopenharmony_ci#include <net/protocol.h> 338c2ecf20Sopenharmony_ci#include <net/mptcp.h> 348c2ecf20Sopenharmony_ci#include "protocol.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define TOKEN_MAX_RETRIES 4 378c2ecf20Sopenharmony_ci#define TOKEN_MAX_CHAIN_LEN 4 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct token_bucket { 408c2ecf20Sopenharmony_ci spinlock_t lock; 418c2ecf20Sopenharmony_ci int chain_len; 428c2ecf20Sopenharmony_ci struct hlist_nulls_head req_chain; 438c2ecf20Sopenharmony_ci struct hlist_nulls_head msk_chain; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic struct token_bucket *token_hash __read_mostly; 478c2ecf20Sopenharmony_cistatic unsigned int token_mask __read_mostly; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic struct token_bucket *token_bucket(u32 token) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci return &token_hash[token & token_mask]; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* called with bucket lock held */ 558c2ecf20Sopenharmony_cistatic struct mptcp_subflow_request_sock * 568c2ecf20Sopenharmony_ci__token_lookup_req(struct token_bucket *t, u32 token) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct mptcp_subflow_request_sock *req; 598c2ecf20Sopenharmony_ci struct hlist_nulls_node *pos; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci hlist_nulls_for_each_entry_rcu(req, pos, &t->req_chain, token_node) 628c2ecf20Sopenharmony_ci if (req->token == token) 638c2ecf20Sopenharmony_ci return req; 648c2ecf20Sopenharmony_ci return NULL; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* called with bucket lock held */ 688c2ecf20Sopenharmony_cistatic struct mptcp_sock * 698c2ecf20Sopenharmony_ci__token_lookup_msk(struct token_bucket *t, u32 token) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct hlist_nulls_node *pos; 728c2ecf20Sopenharmony_ci struct sock *sk; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci sk_nulls_for_each_rcu(sk, pos, &t->msk_chain) 758c2ecf20Sopenharmony_ci if (mptcp_sk(sk)->token == token) 768c2ecf20Sopenharmony_ci return mptcp_sk(sk); 778c2ecf20Sopenharmony_ci return NULL; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic bool __token_bucket_busy(struct token_bucket *t, u32 token) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci return !token || t->chain_len >= TOKEN_MAX_CHAIN_LEN || 838c2ecf20Sopenharmony_ci __token_lookup_req(t, token) || __token_lookup_msk(t, token); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic void mptcp_crypto_key_gen_sha(u64 *key, u32 *token, u64 *idsn) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci /* we might consider a faster version that computes the key as a 898c2ecf20Sopenharmony_ci * hash of some information available in the MPTCP socket. Use 908c2ecf20Sopenharmony_ci * random data at the moment, as it's probably the safest option 918c2ecf20Sopenharmony_ci * in case multiple sockets are opened in different namespaces at 928c2ecf20Sopenharmony_ci * the same time. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_ci get_random_bytes(key, sizeof(u64)); 958c2ecf20Sopenharmony_ci mptcp_crypto_key_sha(*key, token, idsn); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * mptcp_token_new_request - create new key/idsn/token for subflow_request 1008c2ecf20Sopenharmony_ci * @req: the request socket 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * This function is called when a new mptcp connection is coming in. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * It creates a unique token to identify the new mptcp connection, 1058c2ecf20Sopenharmony_ci * a secret local key and the initial data sequence number (idsn). 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * Returns 0 on success. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ciint mptcp_token_new_request(struct request_sock *req) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req); 1128c2ecf20Sopenharmony_ci struct token_bucket *bucket; 1138c2ecf20Sopenharmony_ci u32 token; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci mptcp_crypto_key_sha(subflow_req->local_key, 1168c2ecf20Sopenharmony_ci &subflow_req->token, 1178c2ecf20Sopenharmony_ci &subflow_req->idsn); 1188c2ecf20Sopenharmony_ci pr_debug("req=%p local_key=%llu, token=%u, idsn=%llu\n", 1198c2ecf20Sopenharmony_ci req, subflow_req->local_key, subflow_req->token, 1208c2ecf20Sopenharmony_ci subflow_req->idsn); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci token = subflow_req->token; 1238c2ecf20Sopenharmony_ci bucket = token_bucket(token); 1248c2ecf20Sopenharmony_ci spin_lock_bh(&bucket->lock); 1258c2ecf20Sopenharmony_ci if (__token_bucket_busy(bucket, token)) { 1268c2ecf20Sopenharmony_ci spin_unlock_bh(&bucket->lock); 1278c2ecf20Sopenharmony_ci return -EBUSY; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci hlist_nulls_add_head_rcu(&subflow_req->token_node, &bucket->req_chain); 1318c2ecf20Sopenharmony_ci bucket->chain_len++; 1328c2ecf20Sopenharmony_ci spin_unlock_bh(&bucket->lock); 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/** 1378c2ecf20Sopenharmony_ci * mptcp_token_new_connect - create new key/idsn/token for subflow 1388c2ecf20Sopenharmony_ci * @sk: the socket that will initiate a connection 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * This function is called when a new outgoing mptcp connection is 1418c2ecf20Sopenharmony_ci * initiated. 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci * It creates a unique token to identify the new mptcp connection, 1448c2ecf20Sopenharmony_ci * a secret local key and the initial data sequence number (idsn). 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * On success, the mptcp connection can be found again using 1478c2ecf20Sopenharmony_ci * the computed token at a later time, this is needed to process 1488c2ecf20Sopenharmony_ci * join requests. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * returns 0 on success. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ciint mptcp_token_new_connect(struct sock *sk) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 1558c2ecf20Sopenharmony_ci struct mptcp_sock *msk = mptcp_sk(subflow->conn); 1568c2ecf20Sopenharmony_ci int retries = TOKEN_MAX_RETRIES; 1578c2ecf20Sopenharmony_ci struct token_bucket *bucket; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ciagain: 1608c2ecf20Sopenharmony_ci mptcp_crypto_key_gen_sha(&subflow->local_key, &subflow->token, 1618c2ecf20Sopenharmony_ci &subflow->idsn); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci bucket = token_bucket(subflow->token); 1648c2ecf20Sopenharmony_ci spin_lock_bh(&bucket->lock); 1658c2ecf20Sopenharmony_ci if (__token_bucket_busy(bucket, subflow->token)) { 1668c2ecf20Sopenharmony_ci spin_unlock_bh(&bucket->lock); 1678c2ecf20Sopenharmony_ci if (!--retries) 1688c2ecf20Sopenharmony_ci return -EBUSY; 1698c2ecf20Sopenharmony_ci goto again; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci pr_debug("ssk=%p, local_key=%llu, token=%u, idsn=%llu\n", 1738c2ecf20Sopenharmony_ci sk, subflow->local_key, subflow->token, subflow->idsn); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci WRITE_ONCE(msk->token, subflow->token); 1768c2ecf20Sopenharmony_ci __sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain); 1778c2ecf20Sopenharmony_ci bucket->chain_len++; 1788c2ecf20Sopenharmony_ci spin_unlock_bh(&bucket->lock); 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/** 1838c2ecf20Sopenharmony_ci * mptcp_token_accept - replace a req sk with full sock in token hash 1848c2ecf20Sopenharmony_ci * @req: the request socket to be removed 1858c2ecf20Sopenharmony_ci * @msk: the just cloned socket linked to the new connection 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * Called when a SYN packet creates a new logical connection, i.e. 1888c2ecf20Sopenharmony_ci * is not a join request. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_civoid mptcp_token_accept(struct mptcp_subflow_request_sock *req, 1918c2ecf20Sopenharmony_ci struct mptcp_sock *msk) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct mptcp_subflow_request_sock *pos; 1948c2ecf20Sopenharmony_ci struct token_bucket *bucket; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci bucket = token_bucket(req->token); 1978c2ecf20Sopenharmony_ci spin_lock_bh(&bucket->lock); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* pedantic lookup check for the moved token */ 2008c2ecf20Sopenharmony_ci pos = __token_lookup_req(bucket, req->token); 2018c2ecf20Sopenharmony_ci if (!WARN_ON_ONCE(pos != req)) 2028c2ecf20Sopenharmony_ci hlist_nulls_del_init_rcu(&req->token_node); 2038c2ecf20Sopenharmony_ci __sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain); 2048c2ecf20Sopenharmony_ci spin_unlock_bh(&bucket->lock); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cibool mptcp_token_exists(u32 token) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct hlist_nulls_node *pos; 2108c2ecf20Sopenharmony_ci struct token_bucket *bucket; 2118c2ecf20Sopenharmony_ci struct mptcp_sock *msk; 2128c2ecf20Sopenharmony_ci struct sock *sk; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci rcu_read_lock(); 2158c2ecf20Sopenharmony_ci bucket = token_bucket(token); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ciagain: 2188c2ecf20Sopenharmony_ci sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) { 2198c2ecf20Sopenharmony_ci msk = mptcp_sk(sk); 2208c2ecf20Sopenharmony_ci if (READ_ONCE(msk->token) == token) 2218c2ecf20Sopenharmony_ci goto found; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci if (get_nulls_value(pos) != (token & token_mask)) 2248c2ecf20Sopenharmony_ci goto again; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci rcu_read_unlock(); 2278c2ecf20Sopenharmony_ci return false; 2288c2ecf20Sopenharmony_cifound: 2298c2ecf20Sopenharmony_ci rcu_read_unlock(); 2308c2ecf20Sopenharmony_ci return true; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/** 2348c2ecf20Sopenharmony_ci * mptcp_token_get_sock - retrieve mptcp connection sock using its token 2358c2ecf20Sopenharmony_ci * @net: restrict to this namespace 2368c2ecf20Sopenharmony_ci * @token: token of the mptcp connection to retrieve 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * This function returns the mptcp connection structure with the given token. 2398c2ecf20Sopenharmony_ci * A reference count on the mptcp socket returned is taken. 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * returns NULL if no connection with the given token value exists. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistruct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct hlist_nulls_node *pos; 2468c2ecf20Sopenharmony_ci struct token_bucket *bucket; 2478c2ecf20Sopenharmony_ci struct mptcp_sock *msk; 2488c2ecf20Sopenharmony_ci struct sock *sk; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci rcu_read_lock(); 2518c2ecf20Sopenharmony_ci bucket = token_bucket(token); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ciagain: 2548c2ecf20Sopenharmony_ci sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) { 2558c2ecf20Sopenharmony_ci msk = mptcp_sk(sk); 2568c2ecf20Sopenharmony_ci if (READ_ONCE(msk->token) != token || 2578c2ecf20Sopenharmony_ci !net_eq(sock_net(sk), net)) 2588c2ecf20Sopenharmony_ci continue; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (!refcount_inc_not_zero(&sk->sk_refcnt)) 2618c2ecf20Sopenharmony_ci goto not_found; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (READ_ONCE(msk->token) != token || 2648c2ecf20Sopenharmony_ci !net_eq(sock_net(sk), net)) { 2658c2ecf20Sopenharmony_ci sock_put(sk); 2668c2ecf20Sopenharmony_ci goto again; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci goto found; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci if (get_nulls_value(pos) != (token & token_mask)) 2718c2ecf20Sopenharmony_ci goto again; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cinot_found: 2748c2ecf20Sopenharmony_ci msk = NULL; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cifound: 2778c2ecf20Sopenharmony_ci rcu_read_unlock(); 2788c2ecf20Sopenharmony_ci return msk; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_get_sock); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/** 2838c2ecf20Sopenharmony_ci * mptcp_token_iter_next - iterate over the token container from given pos 2848c2ecf20Sopenharmony_ci * @net: namespace to be iterated 2858c2ecf20Sopenharmony_ci * @s_slot: start slot number 2868c2ecf20Sopenharmony_ci * @s_num: start number inside the given lock 2878c2ecf20Sopenharmony_ci * 2888c2ecf20Sopenharmony_ci * This function returns the first mptcp connection structure found inside the 2898c2ecf20Sopenharmony_ci * token container starting from the specified position, or NULL. 2908c2ecf20Sopenharmony_ci * 2918c2ecf20Sopenharmony_ci * On successful iteration, the iterator is move to the next position and the 2928c2ecf20Sopenharmony_ci * the acquires a reference to the returned socket. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_cistruct mptcp_sock *mptcp_token_iter_next(const struct net *net, long *s_slot, 2958c2ecf20Sopenharmony_ci long *s_num) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct mptcp_sock *ret = NULL; 2988c2ecf20Sopenharmony_ci struct hlist_nulls_node *pos; 2998c2ecf20Sopenharmony_ci int slot, num = 0; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci for (slot = *s_slot; slot <= token_mask; *s_num = 0, slot++) { 3028c2ecf20Sopenharmony_ci struct token_bucket *bucket = &token_hash[slot]; 3038c2ecf20Sopenharmony_ci struct sock *sk; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci num = 0; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (hlist_nulls_empty(&bucket->msk_chain)) 3088c2ecf20Sopenharmony_ci continue; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci rcu_read_lock(); 3118c2ecf20Sopenharmony_ci sk_nulls_for_each_rcu(sk, pos, &bucket->msk_chain) { 3128c2ecf20Sopenharmony_ci ++num; 3138c2ecf20Sopenharmony_ci if (!net_eq(sock_net(sk), net)) 3148c2ecf20Sopenharmony_ci continue; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (num <= *s_num) 3178c2ecf20Sopenharmony_ci continue; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!refcount_inc_not_zero(&sk->sk_refcnt)) 3208c2ecf20Sopenharmony_ci continue; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (!net_eq(sock_net(sk), net)) { 3238c2ecf20Sopenharmony_ci sock_put(sk); 3248c2ecf20Sopenharmony_ci continue; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci ret = mptcp_sk(sk); 3288c2ecf20Sopenharmony_ci rcu_read_unlock(); 3298c2ecf20Sopenharmony_ci goto out; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci rcu_read_unlock(); 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ciout: 3358c2ecf20Sopenharmony_ci *s_slot = slot; 3368c2ecf20Sopenharmony_ci *s_num = num; 3378c2ecf20Sopenharmony_ci return ret; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_iter_next); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci/** 3428c2ecf20Sopenharmony_ci * mptcp_token_destroy_request - remove mptcp connection/token 3438c2ecf20Sopenharmony_ci * @req: mptcp request socket dropping the token 3448c2ecf20Sopenharmony_ci * 3458c2ecf20Sopenharmony_ci * Remove the token associated to @req. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_civoid mptcp_token_destroy_request(struct request_sock *req) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req); 3508c2ecf20Sopenharmony_ci struct mptcp_subflow_request_sock *pos; 3518c2ecf20Sopenharmony_ci struct token_bucket *bucket; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (hlist_nulls_unhashed(&subflow_req->token_node)) 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci bucket = token_bucket(subflow_req->token); 3578c2ecf20Sopenharmony_ci spin_lock_bh(&bucket->lock); 3588c2ecf20Sopenharmony_ci pos = __token_lookup_req(bucket, subflow_req->token); 3598c2ecf20Sopenharmony_ci if (!WARN_ON_ONCE(pos != subflow_req)) { 3608c2ecf20Sopenharmony_ci hlist_nulls_del_init_rcu(&pos->token_node); 3618c2ecf20Sopenharmony_ci bucket->chain_len--; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci spin_unlock_bh(&bucket->lock); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/** 3678c2ecf20Sopenharmony_ci * mptcp_token_destroy - remove mptcp connection/token 3688c2ecf20Sopenharmony_ci * @msk: mptcp connection dropping the token 3698c2ecf20Sopenharmony_ci * 3708c2ecf20Sopenharmony_ci * Remove the token associated to @msk 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_civoid mptcp_token_destroy(struct mptcp_sock *msk) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct token_bucket *bucket; 3758c2ecf20Sopenharmony_ci struct mptcp_sock *pos; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (sk_unhashed((struct sock *)msk)) 3788c2ecf20Sopenharmony_ci return; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci bucket = token_bucket(msk->token); 3818c2ecf20Sopenharmony_ci spin_lock_bh(&bucket->lock); 3828c2ecf20Sopenharmony_ci pos = __token_lookup_msk(bucket, msk->token); 3838c2ecf20Sopenharmony_ci if (!WARN_ON_ONCE(pos != msk)) { 3848c2ecf20Sopenharmony_ci __sk_nulls_del_node_init_rcu((struct sock *)pos); 3858c2ecf20Sopenharmony_ci bucket->chain_len--; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci spin_unlock_bh(&bucket->lock); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_civoid __init mptcp_token_init(void) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci int i; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci token_hash = alloc_large_system_hash("MPTCP token", 3958c2ecf20Sopenharmony_ci sizeof(struct token_bucket), 3968c2ecf20Sopenharmony_ci 0, 3978c2ecf20Sopenharmony_ci 20,/* one slot per 1MB of memory */ 3988c2ecf20Sopenharmony_ci HASH_ZERO, 3998c2ecf20Sopenharmony_ci NULL, 4008c2ecf20Sopenharmony_ci &token_mask, 4018c2ecf20Sopenharmony_ci 0, 4028c2ecf20Sopenharmony_ci 64 * 1024); 4038c2ecf20Sopenharmony_ci for (i = 0; i < token_mask + 1; ++i) { 4048c2ecf20Sopenharmony_ci INIT_HLIST_NULLS_HEAD(&token_hash[i].req_chain, i); 4058c2ecf20Sopenharmony_ci INIT_HLIST_NULLS_HEAD(&token_hash[i].msk_chain, i); 4068c2ecf20Sopenharmony_ci spin_lock_init(&token_hash[i].lock); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci#if IS_MODULE(CONFIG_MPTCP_KUNIT_TESTS) 4118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_new_request); 4128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_new_connect); 4138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_accept); 4148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_destroy_request); 4158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_token_destroy); 4168c2ecf20Sopenharmony_ci#endif 417