162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* RxRPC remote transport endpoint record management 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/net.h> 1262306a36Sopenharmony_ci#include <linux/skbuff.h> 1362306a36Sopenharmony_ci#include <linux/udp.h> 1462306a36Sopenharmony_ci#include <linux/in.h> 1562306a36Sopenharmony_ci#include <linux/in6.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/hashtable.h> 1862306a36Sopenharmony_ci#include <net/sock.h> 1962306a36Sopenharmony_ci#include <net/af_rxrpc.h> 2062306a36Sopenharmony_ci#include <net/ip.h> 2162306a36Sopenharmony_ci#include <net/route.h> 2262306a36Sopenharmony_ci#include <net/ip6_route.h> 2362306a36Sopenharmony_ci#include "ar-internal.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Hash a peer key. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_cistatic unsigned long rxrpc_peer_hash_key(struct rxrpc_local *local, 2962306a36Sopenharmony_ci const struct sockaddr_rxrpc *srx) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci const u16 *p; 3262306a36Sopenharmony_ci unsigned int i, size; 3362306a36Sopenharmony_ci unsigned long hash_key; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci _enter(""); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci hash_key = (unsigned long)local / __alignof__(*local); 3862306a36Sopenharmony_ci hash_key += srx->transport_type; 3962306a36Sopenharmony_ci hash_key += srx->transport_len; 4062306a36Sopenharmony_ci hash_key += srx->transport.family; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci switch (srx->transport.family) { 4362306a36Sopenharmony_ci case AF_INET: 4462306a36Sopenharmony_ci hash_key += (u16 __force)srx->transport.sin.sin_port; 4562306a36Sopenharmony_ci size = sizeof(srx->transport.sin.sin_addr); 4662306a36Sopenharmony_ci p = (u16 *)&srx->transport.sin.sin_addr; 4762306a36Sopenharmony_ci break; 4862306a36Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_IPV6 4962306a36Sopenharmony_ci case AF_INET6: 5062306a36Sopenharmony_ci hash_key += (u16 __force)srx->transport.sin.sin_port; 5162306a36Sopenharmony_ci size = sizeof(srx->transport.sin6.sin6_addr); 5262306a36Sopenharmony_ci p = (u16 *)&srx->transport.sin6.sin6_addr; 5362306a36Sopenharmony_ci break; 5462306a36Sopenharmony_ci#endif 5562306a36Sopenharmony_ci default: 5662306a36Sopenharmony_ci WARN(1, "AF_RXRPC: Unsupported transport address family\n"); 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* Step through the peer address in 16-bit portions for speed */ 6162306a36Sopenharmony_ci for (i = 0; i < size; i += sizeof(*p), p++) 6262306a36Sopenharmony_ci hash_key += *p; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci _leave(" 0x%lx", hash_key); 6562306a36Sopenharmony_ci return hash_key; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* 6962306a36Sopenharmony_ci * Compare a peer to a key. Return -ve, 0 or +ve to indicate less than, same 7062306a36Sopenharmony_ci * or greater than. 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * Unfortunately, the primitives in linux/hashtable.h don't allow for sorted 7362306a36Sopenharmony_ci * buckets and mid-bucket insertion, so we don't make full use of this 7462306a36Sopenharmony_ci * information at this point. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_cistatic long rxrpc_peer_cmp_key(const struct rxrpc_peer *peer, 7762306a36Sopenharmony_ci struct rxrpc_local *local, 7862306a36Sopenharmony_ci const struct sockaddr_rxrpc *srx, 7962306a36Sopenharmony_ci unsigned long hash_key) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci long diff; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci diff = ((peer->hash_key - hash_key) ?: 8462306a36Sopenharmony_ci ((unsigned long)peer->local - (unsigned long)local) ?: 8562306a36Sopenharmony_ci (peer->srx.transport_type - srx->transport_type) ?: 8662306a36Sopenharmony_ci (peer->srx.transport_len - srx->transport_len) ?: 8762306a36Sopenharmony_ci (peer->srx.transport.family - srx->transport.family)); 8862306a36Sopenharmony_ci if (diff != 0) 8962306a36Sopenharmony_ci return diff; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci switch (srx->transport.family) { 9262306a36Sopenharmony_ci case AF_INET: 9362306a36Sopenharmony_ci return ((u16 __force)peer->srx.transport.sin.sin_port - 9462306a36Sopenharmony_ci (u16 __force)srx->transport.sin.sin_port) ?: 9562306a36Sopenharmony_ci memcmp(&peer->srx.transport.sin.sin_addr, 9662306a36Sopenharmony_ci &srx->transport.sin.sin_addr, 9762306a36Sopenharmony_ci sizeof(struct in_addr)); 9862306a36Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_IPV6 9962306a36Sopenharmony_ci case AF_INET6: 10062306a36Sopenharmony_ci return ((u16 __force)peer->srx.transport.sin6.sin6_port - 10162306a36Sopenharmony_ci (u16 __force)srx->transport.sin6.sin6_port) ?: 10262306a36Sopenharmony_ci memcmp(&peer->srx.transport.sin6.sin6_addr, 10362306a36Sopenharmony_ci &srx->transport.sin6.sin6_addr, 10462306a36Sopenharmony_ci sizeof(struct in6_addr)); 10562306a36Sopenharmony_ci#endif 10662306a36Sopenharmony_ci default: 10762306a36Sopenharmony_ci BUG(); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci * Look up a remote transport endpoint for the specified address using RCU. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_cistatic struct rxrpc_peer *__rxrpc_lookup_peer_rcu( 11562306a36Sopenharmony_ci struct rxrpc_local *local, 11662306a36Sopenharmony_ci const struct sockaddr_rxrpc *srx, 11762306a36Sopenharmony_ci unsigned long hash_key) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct rxrpc_peer *peer; 12062306a36Sopenharmony_ci struct rxrpc_net *rxnet = local->rxnet; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci hash_for_each_possible_rcu(rxnet->peer_hash, peer, hash_link, hash_key) { 12362306a36Sopenharmony_ci if (rxrpc_peer_cmp_key(peer, local, srx, hash_key) == 0 && 12462306a36Sopenharmony_ci refcount_read(&peer->ref) > 0) 12562306a36Sopenharmony_ci return peer; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return NULL; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* 13262306a36Sopenharmony_ci * Look up a remote transport endpoint for the specified address using RCU. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_cistruct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local, 13562306a36Sopenharmony_ci const struct sockaddr_rxrpc *srx) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct rxrpc_peer *peer; 13862306a36Sopenharmony_ci unsigned long hash_key = rxrpc_peer_hash_key(local, srx); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); 14162306a36Sopenharmony_ci if (peer) 14262306a36Sopenharmony_ci _leave(" = %p {u=%d}", peer, refcount_read(&peer->ref)); 14362306a36Sopenharmony_ci return peer; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * assess the MTU size for the network interface through which this peer is 14862306a36Sopenharmony_ci * reached 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_cistatic void rxrpc_assess_MTU_size(struct rxrpc_local *local, 15162306a36Sopenharmony_ci struct rxrpc_peer *peer) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct net *net = local->net; 15462306a36Sopenharmony_ci struct dst_entry *dst; 15562306a36Sopenharmony_ci struct rtable *rt; 15662306a36Sopenharmony_ci struct flowi fl; 15762306a36Sopenharmony_ci struct flowi4 *fl4 = &fl.u.ip4; 15862306a36Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_IPV6 15962306a36Sopenharmony_ci struct flowi6 *fl6 = &fl.u.ip6; 16062306a36Sopenharmony_ci#endif 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci peer->if_mtu = 1500; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci memset(&fl, 0, sizeof(fl)); 16562306a36Sopenharmony_ci switch (peer->srx.transport.family) { 16662306a36Sopenharmony_ci case AF_INET: 16762306a36Sopenharmony_ci rt = ip_route_output_ports( 16862306a36Sopenharmony_ci net, fl4, NULL, 16962306a36Sopenharmony_ci peer->srx.transport.sin.sin_addr.s_addr, 0, 17062306a36Sopenharmony_ci htons(7000), htons(7001), IPPROTO_UDP, 0, 0); 17162306a36Sopenharmony_ci if (IS_ERR(rt)) { 17262306a36Sopenharmony_ci _leave(" [route err %ld]", PTR_ERR(rt)); 17362306a36Sopenharmony_ci return; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci dst = &rt->dst; 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_IPV6 17962306a36Sopenharmony_ci case AF_INET6: 18062306a36Sopenharmony_ci fl6->flowi6_iif = LOOPBACK_IFINDEX; 18162306a36Sopenharmony_ci fl6->flowi6_scope = RT_SCOPE_UNIVERSE; 18262306a36Sopenharmony_ci fl6->flowi6_proto = IPPROTO_UDP; 18362306a36Sopenharmony_ci memcpy(&fl6->daddr, &peer->srx.transport.sin6.sin6_addr, 18462306a36Sopenharmony_ci sizeof(struct in6_addr)); 18562306a36Sopenharmony_ci fl6->fl6_dport = htons(7001); 18662306a36Sopenharmony_ci fl6->fl6_sport = htons(7000); 18762306a36Sopenharmony_ci dst = ip6_route_output(net, NULL, fl6); 18862306a36Sopenharmony_ci if (dst->error) { 18962306a36Sopenharmony_ci _leave(" [route err %d]", dst->error); 19062306a36Sopenharmony_ci return; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci break; 19362306a36Sopenharmony_ci#endif 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci default: 19662306a36Sopenharmony_ci BUG(); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci peer->if_mtu = dst_mtu(dst); 20062306a36Sopenharmony_ci dst_release(dst); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci _leave(" [if_mtu %u]", peer->if_mtu); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* 20662306a36Sopenharmony_ci * Allocate a peer. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistruct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp, 20962306a36Sopenharmony_ci enum rxrpc_peer_trace why) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct rxrpc_peer *peer; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci _enter(""); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci peer = kzalloc(sizeof(struct rxrpc_peer), gfp); 21662306a36Sopenharmony_ci if (peer) { 21762306a36Sopenharmony_ci refcount_set(&peer->ref, 1); 21862306a36Sopenharmony_ci peer->local = rxrpc_get_local(local, rxrpc_local_get_peer); 21962306a36Sopenharmony_ci INIT_HLIST_HEAD(&peer->error_targets); 22062306a36Sopenharmony_ci peer->service_conns = RB_ROOT; 22162306a36Sopenharmony_ci seqlock_init(&peer->service_conn_lock); 22262306a36Sopenharmony_ci spin_lock_init(&peer->lock); 22362306a36Sopenharmony_ci spin_lock_init(&peer->rtt_input_lock); 22462306a36Sopenharmony_ci peer->debug_id = atomic_inc_return(&rxrpc_debug_id); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci rxrpc_peer_init_rtt(peer); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci peer->cong_ssthresh = RXRPC_TX_MAX_WINDOW; 22962306a36Sopenharmony_ci trace_rxrpc_peer(peer->debug_id, 1, why); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci _leave(" = %p", peer); 23362306a36Sopenharmony_ci return peer; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/* 23762306a36Sopenharmony_ci * Initialise peer record. 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_cistatic void rxrpc_init_peer(struct rxrpc_local *local, struct rxrpc_peer *peer, 24062306a36Sopenharmony_ci unsigned long hash_key) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci peer->hash_key = hash_key; 24362306a36Sopenharmony_ci rxrpc_assess_MTU_size(local, peer); 24462306a36Sopenharmony_ci peer->mtu = peer->if_mtu; 24562306a36Sopenharmony_ci peer->rtt_last_req = ktime_get_real(); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci switch (peer->srx.transport.family) { 24862306a36Sopenharmony_ci case AF_INET: 24962306a36Sopenharmony_ci peer->hdrsize = sizeof(struct iphdr); 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_IPV6 25262306a36Sopenharmony_ci case AF_INET6: 25362306a36Sopenharmony_ci peer->hdrsize = sizeof(struct ipv6hdr); 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci#endif 25662306a36Sopenharmony_ci default: 25762306a36Sopenharmony_ci BUG(); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci switch (peer->srx.transport_type) { 26162306a36Sopenharmony_ci case SOCK_DGRAM: 26262306a36Sopenharmony_ci peer->hdrsize += sizeof(struct udphdr); 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci default: 26562306a36Sopenharmony_ci BUG(); 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci peer->hdrsize += sizeof(struct rxrpc_wire_header); 26962306a36Sopenharmony_ci peer->maxdata = peer->mtu - peer->hdrsize; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* 27362306a36Sopenharmony_ci * Set up a new peer. 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_cistatic struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_local *local, 27662306a36Sopenharmony_ci struct sockaddr_rxrpc *srx, 27762306a36Sopenharmony_ci unsigned long hash_key, 27862306a36Sopenharmony_ci gfp_t gfp) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct rxrpc_peer *peer; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci _enter(""); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci peer = rxrpc_alloc_peer(local, gfp, rxrpc_peer_new_client); 28562306a36Sopenharmony_ci if (peer) { 28662306a36Sopenharmony_ci memcpy(&peer->srx, srx, sizeof(*srx)); 28762306a36Sopenharmony_ci rxrpc_init_peer(local, peer, hash_key); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci _leave(" = %p", peer); 29162306a36Sopenharmony_ci return peer; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic void rxrpc_free_peer(struct rxrpc_peer *peer) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci trace_rxrpc_peer(peer->debug_id, 0, rxrpc_peer_free); 29762306a36Sopenharmony_ci rxrpc_put_local(peer->local, rxrpc_local_put_peer); 29862306a36Sopenharmony_ci kfree_rcu(peer, rcu); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* 30262306a36Sopenharmony_ci * Set up a new incoming peer. There shouldn't be any other matching peers 30362306a36Sopenharmony_ci * since we've already done a search in the list from the non-reentrant context 30462306a36Sopenharmony_ci * (the data_ready handler) that is the only place we can add new peers. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_civoid rxrpc_new_incoming_peer(struct rxrpc_local *local, struct rxrpc_peer *peer) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct rxrpc_net *rxnet = local->rxnet; 30962306a36Sopenharmony_ci unsigned long hash_key; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci hash_key = rxrpc_peer_hash_key(local, &peer->srx); 31262306a36Sopenharmony_ci rxrpc_init_peer(local, peer, hash_key); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci spin_lock(&rxnet->peer_hash_lock); 31562306a36Sopenharmony_ci hash_add_rcu(rxnet->peer_hash, &peer->hash_link, hash_key); 31662306a36Sopenharmony_ci list_add_tail(&peer->keepalive_link, &rxnet->peer_keepalive_new); 31762306a36Sopenharmony_ci spin_unlock(&rxnet->peer_hash_lock); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/* 32162306a36Sopenharmony_ci * obtain a remote transport endpoint for the specified address 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_cistruct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local, 32462306a36Sopenharmony_ci struct sockaddr_rxrpc *srx, gfp_t gfp) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct rxrpc_peer *peer, *candidate; 32762306a36Sopenharmony_ci struct rxrpc_net *rxnet = local->rxnet; 32862306a36Sopenharmony_ci unsigned long hash_key = rxrpc_peer_hash_key(local, srx); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci _enter("{%pISp}", &srx->transport); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* search the peer list first */ 33362306a36Sopenharmony_ci rcu_read_lock(); 33462306a36Sopenharmony_ci peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); 33562306a36Sopenharmony_ci if (peer && !rxrpc_get_peer_maybe(peer, rxrpc_peer_get_lookup_client)) 33662306a36Sopenharmony_ci peer = NULL; 33762306a36Sopenharmony_ci rcu_read_unlock(); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!peer) { 34062306a36Sopenharmony_ci /* The peer is not yet present in hash - create a candidate 34162306a36Sopenharmony_ci * for a new record and then redo the search. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ci candidate = rxrpc_create_peer(local, srx, hash_key, gfp); 34462306a36Sopenharmony_ci if (!candidate) { 34562306a36Sopenharmony_ci _leave(" = NULL [nomem]"); 34662306a36Sopenharmony_ci return NULL; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci spin_lock(&rxnet->peer_hash_lock); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* Need to check that we aren't racing with someone else */ 35262306a36Sopenharmony_ci peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); 35362306a36Sopenharmony_ci if (peer && !rxrpc_get_peer_maybe(peer, rxrpc_peer_get_lookup_client)) 35462306a36Sopenharmony_ci peer = NULL; 35562306a36Sopenharmony_ci if (!peer) { 35662306a36Sopenharmony_ci hash_add_rcu(rxnet->peer_hash, 35762306a36Sopenharmony_ci &candidate->hash_link, hash_key); 35862306a36Sopenharmony_ci list_add_tail(&candidate->keepalive_link, 35962306a36Sopenharmony_ci &rxnet->peer_keepalive_new); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci spin_unlock(&rxnet->peer_hash_lock); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (peer) 36562306a36Sopenharmony_ci rxrpc_free_peer(candidate); 36662306a36Sopenharmony_ci else 36762306a36Sopenharmony_ci peer = candidate; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci _leave(" = %p {u=%d}", peer, refcount_read(&peer->ref)); 37162306a36Sopenharmony_ci return peer; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci/* 37562306a36Sopenharmony_ci * Get a ref on a peer record. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_cistruct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *peer, enum rxrpc_peer_trace why) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci int r; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci __refcount_inc(&peer->ref, &r); 38262306a36Sopenharmony_ci trace_rxrpc_peer(peer->debug_id, r + 1, why); 38362306a36Sopenharmony_ci return peer; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/* 38762306a36Sopenharmony_ci * Get a ref on a peer record unless its usage has already reached 0. 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_cistruct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *peer, 39062306a36Sopenharmony_ci enum rxrpc_peer_trace why) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci int r; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (peer) { 39562306a36Sopenharmony_ci if (__refcount_inc_not_zero(&peer->ref, &r)) 39662306a36Sopenharmony_ci trace_rxrpc_peer(peer->debug_id, r + 1, why); 39762306a36Sopenharmony_ci else 39862306a36Sopenharmony_ci peer = NULL; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci return peer; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/* 40462306a36Sopenharmony_ci * Discard a peer record. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_cistatic void __rxrpc_put_peer(struct rxrpc_peer *peer) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct rxrpc_net *rxnet = peer->local->rxnet; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ASSERT(hlist_empty(&peer->error_targets)); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci spin_lock(&rxnet->peer_hash_lock); 41362306a36Sopenharmony_ci hash_del_rcu(&peer->hash_link); 41462306a36Sopenharmony_ci list_del_init(&peer->keepalive_link); 41562306a36Sopenharmony_ci spin_unlock(&rxnet->peer_hash_lock); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci rxrpc_free_peer(peer); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/* 42162306a36Sopenharmony_ci * Drop a ref on a peer record. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_civoid rxrpc_put_peer(struct rxrpc_peer *peer, enum rxrpc_peer_trace why) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci unsigned int debug_id; 42662306a36Sopenharmony_ci bool dead; 42762306a36Sopenharmony_ci int r; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (peer) { 43062306a36Sopenharmony_ci debug_id = peer->debug_id; 43162306a36Sopenharmony_ci dead = __refcount_dec_and_test(&peer->ref, &r); 43262306a36Sopenharmony_ci trace_rxrpc_peer(debug_id, r - 1, why); 43362306a36Sopenharmony_ci if (dead) 43462306a36Sopenharmony_ci __rxrpc_put_peer(peer); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/* 43962306a36Sopenharmony_ci * Make sure all peer records have been discarded. 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_civoid rxrpc_destroy_all_peers(struct rxrpc_net *rxnet) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct rxrpc_peer *peer; 44462306a36Sopenharmony_ci int i; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci for (i = 0; i < HASH_SIZE(rxnet->peer_hash); i++) { 44762306a36Sopenharmony_ci if (hlist_empty(&rxnet->peer_hash[i])) 44862306a36Sopenharmony_ci continue; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci hlist_for_each_entry(peer, &rxnet->peer_hash[i], hash_link) { 45162306a36Sopenharmony_ci pr_err("Leaked peer %u {%u} %pISp\n", 45262306a36Sopenharmony_ci peer->debug_id, 45362306a36Sopenharmony_ci refcount_read(&peer->ref), 45462306a36Sopenharmony_ci &peer->srx.transport); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/** 46062306a36Sopenharmony_ci * rxrpc_kernel_get_peer - Get the peer address of a call 46162306a36Sopenharmony_ci * @sock: The socket on which the call is in progress. 46262306a36Sopenharmony_ci * @call: The call to query 46362306a36Sopenharmony_ci * @_srx: Where to place the result 46462306a36Sopenharmony_ci * 46562306a36Sopenharmony_ci * Get the address of the remote peer in a call. 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_civoid rxrpc_kernel_get_peer(struct socket *sock, struct rxrpc_call *call, 46862306a36Sopenharmony_ci struct sockaddr_rxrpc *_srx) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci *_srx = call->peer->srx; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_get_peer); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/** 47562306a36Sopenharmony_ci * rxrpc_kernel_get_srtt - Get a call's peer smoothed RTT 47662306a36Sopenharmony_ci * @sock: The socket on which the call is in progress. 47762306a36Sopenharmony_ci * @call: The call to query 47862306a36Sopenharmony_ci * @_srtt: Where to store the SRTT value. 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * Get the call's peer smoothed RTT in uS. 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_cibool rxrpc_kernel_get_srtt(struct socket *sock, struct rxrpc_call *call, 48362306a36Sopenharmony_ci u32 *_srtt) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct rxrpc_peer *peer = call->peer; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (peer->rtt_count == 0) { 48862306a36Sopenharmony_ci *_srtt = 1000000; /* 1S */ 48962306a36Sopenharmony_ci return false; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci *_srtt = call->peer->srtt_us >> 3; 49362306a36Sopenharmony_ci return true; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_get_srtt); 496