162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Local endpoint object management 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 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/slab.h> 1462306a36Sopenharmony_ci#include <linux/udp.h> 1562306a36Sopenharmony_ci#include <linux/ip.h> 1662306a36Sopenharmony_ci#include <linux/hashtable.h> 1762306a36Sopenharmony_ci#include <net/sock.h> 1862306a36Sopenharmony_ci#include <net/udp.h> 1962306a36Sopenharmony_ci#include <net/udp_tunnel.h> 2062306a36Sopenharmony_ci#include <net/af_rxrpc.h> 2162306a36Sopenharmony_ci#include "ar-internal.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void rxrpc_local_rcu(struct rcu_head *); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Handle an ICMP/ICMP6 error turning up at the tunnel. Push it through the 2762306a36Sopenharmony_ci * usual mechanism so that it gets parsed and presented through the UDP 2862306a36Sopenharmony_ci * socket's error_report(). 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_cistatic void rxrpc_encap_err_rcv(struct sock *sk, struct sk_buff *skb, int err, 3162306a36Sopenharmony_ci __be16 port, u32 info, u8 *payload) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci if (ip_hdr(skb)->version == IPVERSION) 3462306a36Sopenharmony_ci return ip_icmp_error(sk, skb, err, port, info, payload); 3562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_AF_RXRPC_IPV6)) 3662306a36Sopenharmony_ci return ipv6_icmp_error(sk, skb, err, port, info, payload); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * Set or clear the Don't Fragment flag on a socket. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_civoid rxrpc_local_dont_fragment(const struct rxrpc_local *local, bool set) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci if (set) 4562306a36Sopenharmony_ci ip_sock_set_mtu_discover(local->socket->sk, IP_PMTUDISC_DO); 4662306a36Sopenharmony_ci else 4762306a36Sopenharmony_ci ip_sock_set_mtu_discover(local->socket->sk, IP_PMTUDISC_DONT); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * Compare a local to an address. Return -ve, 0 or +ve to indicate less than, 5262306a36Sopenharmony_ci * same or greater than. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * We explicitly don't compare the RxRPC service ID as we want to reject 5562306a36Sopenharmony_ci * conflicting uses by differing services. Further, we don't want to share 5662306a36Sopenharmony_ci * addresses with different options (IPv6), so we don't compare those bits 5762306a36Sopenharmony_ci * either. 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_cistatic long rxrpc_local_cmp_key(const struct rxrpc_local *local, 6062306a36Sopenharmony_ci const struct sockaddr_rxrpc *srx) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci long diff; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci diff = ((local->srx.transport_type - srx->transport_type) ?: 6562306a36Sopenharmony_ci (local->srx.transport_len - srx->transport_len) ?: 6662306a36Sopenharmony_ci (local->srx.transport.family - srx->transport.family)); 6762306a36Sopenharmony_ci if (diff != 0) 6862306a36Sopenharmony_ci return diff; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci switch (srx->transport.family) { 7162306a36Sopenharmony_ci case AF_INET: 7262306a36Sopenharmony_ci /* If the choice of UDP port is left up to the transport, then 7362306a36Sopenharmony_ci * the endpoint record doesn't match. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci return ((u16 __force)local->srx.transport.sin.sin_port - 7662306a36Sopenharmony_ci (u16 __force)srx->transport.sin.sin_port) ?: 7762306a36Sopenharmony_ci memcmp(&local->srx.transport.sin.sin_addr, 7862306a36Sopenharmony_ci &srx->transport.sin.sin_addr, 7962306a36Sopenharmony_ci sizeof(struct in_addr)); 8062306a36Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_IPV6 8162306a36Sopenharmony_ci case AF_INET6: 8262306a36Sopenharmony_ci /* If the choice of UDP6 port is left up to the transport, then 8362306a36Sopenharmony_ci * the endpoint record doesn't match. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci return ((u16 __force)local->srx.transport.sin6.sin6_port - 8662306a36Sopenharmony_ci (u16 __force)srx->transport.sin6.sin6_port) ?: 8762306a36Sopenharmony_ci memcmp(&local->srx.transport.sin6.sin6_addr, 8862306a36Sopenharmony_ci &srx->transport.sin6.sin6_addr, 8962306a36Sopenharmony_ci sizeof(struct in6_addr)); 9062306a36Sopenharmony_ci#endif 9162306a36Sopenharmony_ci default: 9262306a36Sopenharmony_ci BUG(); 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void rxrpc_client_conn_reap_timeout(struct timer_list *timer) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct rxrpc_local *local = 9962306a36Sopenharmony_ci container_of(timer, struct rxrpc_local, client_conn_reap_timer); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (!local->kill_all_client_conns && 10262306a36Sopenharmony_ci test_and_set_bit(RXRPC_CLIENT_CONN_REAP_TIMER, &local->client_conn_flags)) 10362306a36Sopenharmony_ci rxrpc_wake_up_io_thread(local); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* 10762306a36Sopenharmony_ci * Allocate a new local endpoint. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistatic struct rxrpc_local *rxrpc_alloc_local(struct net *net, 11062306a36Sopenharmony_ci const struct sockaddr_rxrpc *srx) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct rxrpc_local *local; 11362306a36Sopenharmony_ci u32 tmp; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL); 11662306a36Sopenharmony_ci if (local) { 11762306a36Sopenharmony_ci refcount_set(&local->ref, 1); 11862306a36Sopenharmony_ci atomic_set(&local->active_users, 1); 11962306a36Sopenharmony_ci local->net = net; 12062306a36Sopenharmony_ci local->rxnet = rxrpc_net(net); 12162306a36Sopenharmony_ci INIT_HLIST_NODE(&local->link); 12262306a36Sopenharmony_ci init_completion(&local->io_thread_ready); 12362306a36Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 12462306a36Sopenharmony_ci skb_queue_head_init(&local->rx_delay_queue); 12562306a36Sopenharmony_ci#endif 12662306a36Sopenharmony_ci skb_queue_head_init(&local->rx_queue); 12762306a36Sopenharmony_ci INIT_LIST_HEAD(&local->conn_attend_q); 12862306a36Sopenharmony_ci INIT_LIST_HEAD(&local->call_attend_q); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci local->client_bundles = RB_ROOT; 13162306a36Sopenharmony_ci spin_lock_init(&local->client_bundles_lock); 13262306a36Sopenharmony_ci local->kill_all_client_conns = false; 13362306a36Sopenharmony_ci INIT_LIST_HEAD(&local->idle_client_conns); 13462306a36Sopenharmony_ci timer_setup(&local->client_conn_reap_timer, 13562306a36Sopenharmony_ci rxrpc_client_conn_reap_timeout, 0); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci spin_lock_init(&local->lock); 13862306a36Sopenharmony_ci rwlock_init(&local->services_lock); 13962306a36Sopenharmony_ci local->debug_id = atomic_inc_return(&rxrpc_debug_id); 14062306a36Sopenharmony_ci memcpy(&local->srx, srx, sizeof(*srx)); 14162306a36Sopenharmony_ci local->srx.srx_service = 0; 14262306a36Sopenharmony_ci idr_init(&local->conn_ids); 14362306a36Sopenharmony_ci get_random_bytes(&tmp, sizeof(tmp)); 14462306a36Sopenharmony_ci tmp &= 0x3fffffff; 14562306a36Sopenharmony_ci if (tmp == 0) 14662306a36Sopenharmony_ci tmp = 1; 14762306a36Sopenharmony_ci idr_set_cursor(&local->conn_ids, tmp); 14862306a36Sopenharmony_ci INIT_LIST_HEAD(&local->new_client_calls); 14962306a36Sopenharmony_ci spin_lock_init(&local->client_call_lock); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, 1); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci _leave(" = %p", local); 15562306a36Sopenharmony_ci return local; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* 15962306a36Sopenharmony_ci * create the local socket 16062306a36Sopenharmony_ci * - must be called with rxrpc_local_mutex locked 16162306a36Sopenharmony_ci */ 16262306a36Sopenharmony_cistatic int rxrpc_open_socket(struct rxrpc_local *local, struct net *net) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct udp_tunnel_sock_cfg tuncfg = {NULL}; 16562306a36Sopenharmony_ci struct sockaddr_rxrpc *srx = &local->srx; 16662306a36Sopenharmony_ci struct udp_port_cfg udp_conf = {0}; 16762306a36Sopenharmony_ci struct task_struct *io_thread; 16862306a36Sopenharmony_ci struct sock *usk; 16962306a36Sopenharmony_ci int ret; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci _enter("%p{%d,%d}", 17262306a36Sopenharmony_ci local, srx->transport_type, srx->transport.family); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci udp_conf.family = srx->transport.family; 17562306a36Sopenharmony_ci udp_conf.use_udp_checksums = true; 17662306a36Sopenharmony_ci if (udp_conf.family == AF_INET) { 17762306a36Sopenharmony_ci udp_conf.local_ip = srx->transport.sin.sin_addr; 17862306a36Sopenharmony_ci udp_conf.local_udp_port = srx->transport.sin.sin_port; 17962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AF_RXRPC_IPV6) 18062306a36Sopenharmony_ci } else { 18162306a36Sopenharmony_ci udp_conf.local_ip6 = srx->transport.sin6.sin6_addr; 18262306a36Sopenharmony_ci udp_conf.local_udp_port = srx->transport.sin6.sin6_port; 18362306a36Sopenharmony_ci udp_conf.use_udp6_tx_checksums = true; 18462306a36Sopenharmony_ci udp_conf.use_udp6_rx_checksums = true; 18562306a36Sopenharmony_ci#endif 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci ret = udp_sock_create(net, &udp_conf, &local->socket); 18862306a36Sopenharmony_ci if (ret < 0) { 18962306a36Sopenharmony_ci _leave(" = %d [socket]", ret); 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci tuncfg.encap_type = UDP_ENCAP_RXRPC; 19462306a36Sopenharmony_ci tuncfg.encap_rcv = rxrpc_encap_rcv; 19562306a36Sopenharmony_ci tuncfg.encap_err_rcv = rxrpc_encap_err_rcv; 19662306a36Sopenharmony_ci tuncfg.sk_user_data = local; 19762306a36Sopenharmony_ci setup_udp_tunnel_sock(net, local->socket, &tuncfg); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* set the socket up */ 20062306a36Sopenharmony_ci usk = local->socket->sk; 20162306a36Sopenharmony_ci usk->sk_error_report = rxrpc_error_report; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci switch (srx->transport.family) { 20462306a36Sopenharmony_ci case AF_INET6: 20562306a36Sopenharmony_ci /* we want to receive ICMPv6 errors */ 20662306a36Sopenharmony_ci ip6_sock_set_recverr(usk); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Fall through and set IPv4 options too otherwise we don't get 20962306a36Sopenharmony_ci * errors from IPv4 packets sent through the IPv6 socket. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci fallthrough; 21262306a36Sopenharmony_ci case AF_INET: 21362306a36Sopenharmony_ci /* we want to receive ICMP errors */ 21462306a36Sopenharmony_ci ip_sock_set_recverr(usk); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* we want to set the don't fragment bit */ 21762306a36Sopenharmony_ci rxrpc_local_dont_fragment(local, true); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* We want receive timestamps. */ 22062306a36Sopenharmony_ci sock_enable_timestamps(usk); 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci default: 22462306a36Sopenharmony_ci BUG(); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci io_thread = kthread_run(rxrpc_io_thread, local, 22862306a36Sopenharmony_ci "krxrpcio/%u", ntohs(udp_conf.local_udp_port)); 22962306a36Sopenharmony_ci if (IS_ERR(io_thread)) { 23062306a36Sopenharmony_ci ret = PTR_ERR(io_thread); 23162306a36Sopenharmony_ci goto error_sock; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci wait_for_completion(&local->io_thread_ready); 23562306a36Sopenharmony_ci local->io_thread = io_thread; 23662306a36Sopenharmony_ci _leave(" = 0"); 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cierror_sock: 24062306a36Sopenharmony_ci kernel_sock_shutdown(local->socket, SHUT_RDWR); 24162306a36Sopenharmony_ci local->socket->sk->sk_user_data = NULL; 24262306a36Sopenharmony_ci sock_release(local->socket); 24362306a36Sopenharmony_ci local->socket = NULL; 24462306a36Sopenharmony_ci return ret; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/* 24862306a36Sopenharmony_ci * Look up or create a new local endpoint using the specified local address. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_cistruct rxrpc_local *rxrpc_lookup_local(struct net *net, 25162306a36Sopenharmony_ci const struct sockaddr_rxrpc *srx) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct rxrpc_local *local; 25462306a36Sopenharmony_ci struct rxrpc_net *rxnet = rxrpc_net(net); 25562306a36Sopenharmony_ci struct hlist_node *cursor; 25662306a36Sopenharmony_ci long diff; 25762306a36Sopenharmony_ci int ret; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci _enter("{%d,%d,%pISp}", 26062306a36Sopenharmony_ci srx->transport_type, srx->transport.family, &srx->transport); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci mutex_lock(&rxnet->local_mutex); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci hlist_for_each(cursor, &rxnet->local_endpoints) { 26562306a36Sopenharmony_ci local = hlist_entry(cursor, struct rxrpc_local, link); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci diff = rxrpc_local_cmp_key(local, srx); 26862306a36Sopenharmony_ci if (diff != 0) 26962306a36Sopenharmony_ci continue; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Services aren't allowed to share transport sockets, so 27262306a36Sopenharmony_ci * reject that here. It is possible that the object is dying - 27362306a36Sopenharmony_ci * but it may also still have the local transport address that 27462306a36Sopenharmony_ci * we want bound. 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ci if (srx->srx_service) { 27762306a36Sopenharmony_ci local = NULL; 27862306a36Sopenharmony_ci goto addr_in_use; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Found a match. We want to replace a dying object. 28262306a36Sopenharmony_ci * Attempting to bind the transport socket may still fail if 28362306a36Sopenharmony_ci * we're attempting to use a local address that the dying 28462306a36Sopenharmony_ci * object is still using. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci if (!rxrpc_use_local(local, rxrpc_local_use_lookup)) 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci goto found; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci local = rxrpc_alloc_local(net, srx); 29362306a36Sopenharmony_ci if (!local) 29462306a36Sopenharmony_ci goto nomem; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci ret = rxrpc_open_socket(local, net); 29762306a36Sopenharmony_ci if (ret < 0) 29862306a36Sopenharmony_ci goto sock_error; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (cursor) { 30162306a36Sopenharmony_ci hlist_replace_rcu(cursor, &local->link); 30262306a36Sopenharmony_ci cursor->pprev = NULL; 30362306a36Sopenharmony_ci } else { 30462306a36Sopenharmony_ci hlist_add_head_rcu(&local->link, &rxnet->local_endpoints); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cifound: 30862306a36Sopenharmony_ci mutex_unlock(&rxnet->local_mutex); 30962306a36Sopenharmony_ci _leave(" = %p", local); 31062306a36Sopenharmony_ci return local; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cinomem: 31362306a36Sopenharmony_ci ret = -ENOMEM; 31462306a36Sopenharmony_cisock_error: 31562306a36Sopenharmony_ci mutex_unlock(&rxnet->local_mutex); 31662306a36Sopenharmony_ci if (local) 31762306a36Sopenharmony_ci call_rcu(&local->rcu, rxrpc_local_rcu); 31862306a36Sopenharmony_ci _leave(" = %d", ret); 31962306a36Sopenharmony_ci return ERR_PTR(ret); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ciaddr_in_use: 32262306a36Sopenharmony_ci mutex_unlock(&rxnet->local_mutex); 32362306a36Sopenharmony_ci _leave(" = -EADDRINUSE"); 32462306a36Sopenharmony_ci return ERR_PTR(-EADDRINUSE); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/* 32862306a36Sopenharmony_ci * Get a ref on a local endpoint. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_cistruct rxrpc_local *rxrpc_get_local(struct rxrpc_local *local, 33162306a36Sopenharmony_ci enum rxrpc_local_trace why) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci int r, u; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci u = atomic_read(&local->active_users); 33662306a36Sopenharmony_ci __refcount_inc(&local->ref, &r); 33762306a36Sopenharmony_ci trace_rxrpc_local(local->debug_id, why, r + 1, u); 33862306a36Sopenharmony_ci return local; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* 34262306a36Sopenharmony_ci * Get a ref on a local endpoint unless its usage has already reached 0. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_cistruct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local, 34562306a36Sopenharmony_ci enum rxrpc_local_trace why) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci int r, u; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (local && __refcount_inc_not_zero(&local->ref, &r)) { 35062306a36Sopenharmony_ci u = atomic_read(&local->active_users); 35162306a36Sopenharmony_ci trace_rxrpc_local(local->debug_id, why, r + 1, u); 35262306a36Sopenharmony_ci return local; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return NULL; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/* 35962306a36Sopenharmony_ci * Drop a ref on a local endpoint. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_civoid rxrpc_put_local(struct rxrpc_local *local, enum rxrpc_local_trace why) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci unsigned int debug_id; 36462306a36Sopenharmony_ci bool dead; 36562306a36Sopenharmony_ci int r, u; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (local) { 36862306a36Sopenharmony_ci debug_id = local->debug_id; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci u = atomic_read(&local->active_users); 37162306a36Sopenharmony_ci dead = __refcount_dec_and_test(&local->ref, &r); 37262306a36Sopenharmony_ci trace_rxrpc_local(debug_id, why, r, u); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (dead) 37562306a36Sopenharmony_ci call_rcu(&local->rcu, rxrpc_local_rcu); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* 38062306a36Sopenharmony_ci * Start using a local endpoint. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_cistruct rxrpc_local *rxrpc_use_local(struct rxrpc_local *local, 38362306a36Sopenharmony_ci enum rxrpc_local_trace why) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci local = rxrpc_get_local_maybe(local, rxrpc_local_get_for_use); 38662306a36Sopenharmony_ci if (!local) 38762306a36Sopenharmony_ci return NULL; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (!__rxrpc_use_local(local, why)) { 39062306a36Sopenharmony_ci rxrpc_put_local(local, rxrpc_local_put_for_use); 39162306a36Sopenharmony_ci return NULL; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return local; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci/* 39862306a36Sopenharmony_ci * Cease using a local endpoint. Once the number of active users reaches 0, we 39962306a36Sopenharmony_ci * start the closure of the transport in the I/O thread.. 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_civoid rxrpc_unuse_local(struct rxrpc_local *local, enum rxrpc_local_trace why) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci unsigned int debug_id; 40462306a36Sopenharmony_ci int r, u; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (local) { 40762306a36Sopenharmony_ci debug_id = local->debug_id; 40862306a36Sopenharmony_ci r = refcount_read(&local->ref); 40962306a36Sopenharmony_ci u = atomic_dec_return(&local->active_users); 41062306a36Sopenharmony_ci trace_rxrpc_local(debug_id, why, r, u); 41162306a36Sopenharmony_ci if (u == 0) 41262306a36Sopenharmony_ci kthread_stop(local->io_thread); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci/* 41762306a36Sopenharmony_ci * Destroy a local endpoint's socket and then hand the record to RCU to dispose 41862306a36Sopenharmony_ci * of. 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * Closing the socket cannot be done from bottom half context or RCU callback 42162306a36Sopenharmony_ci * context because it might sleep. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_civoid rxrpc_destroy_local(struct rxrpc_local *local) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct socket *socket = local->socket; 42662306a36Sopenharmony_ci struct rxrpc_net *rxnet = local->rxnet; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci _enter("%d", local->debug_id); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci local->dead = true; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci mutex_lock(&rxnet->local_mutex); 43362306a36Sopenharmony_ci hlist_del_init_rcu(&local->link); 43462306a36Sopenharmony_ci mutex_unlock(&rxnet->local_mutex); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci rxrpc_clean_up_local_conns(local); 43762306a36Sopenharmony_ci rxrpc_service_connection_reaper(&rxnet->service_conn_reaper); 43862306a36Sopenharmony_ci ASSERT(!local->service); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (socket) { 44162306a36Sopenharmony_ci local->socket = NULL; 44262306a36Sopenharmony_ci kernel_sock_shutdown(socket, SHUT_RDWR); 44362306a36Sopenharmony_ci socket->sk->sk_user_data = NULL; 44462306a36Sopenharmony_ci sock_release(socket); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* At this point, there should be no more packets coming in to the 44862306a36Sopenharmony_ci * local endpoint. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_INJECT_RX_DELAY 45162306a36Sopenharmony_ci rxrpc_purge_queue(&local->rx_delay_queue); 45262306a36Sopenharmony_ci#endif 45362306a36Sopenharmony_ci rxrpc_purge_queue(&local->rx_queue); 45462306a36Sopenharmony_ci rxrpc_purge_client_connections(local); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci/* 45862306a36Sopenharmony_ci * Destroy a local endpoint after the RCU grace period expires. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_cistatic void rxrpc_local_rcu(struct rcu_head *rcu) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct rxrpc_local *local = container_of(rcu, struct rxrpc_local, rcu); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci rxrpc_see_local(local, rxrpc_local_free); 46562306a36Sopenharmony_ci kfree(local); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/* 46962306a36Sopenharmony_ci * Verify the local endpoint list is empty by this point. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_civoid rxrpc_destroy_all_locals(struct rxrpc_net *rxnet) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct rxrpc_local *local; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci _enter(""); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci flush_workqueue(rxrpc_workqueue); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (!hlist_empty(&rxnet->local_endpoints)) { 48062306a36Sopenharmony_ci mutex_lock(&rxnet->local_mutex); 48162306a36Sopenharmony_ci hlist_for_each_entry(local, &rxnet->local_endpoints, link) { 48262306a36Sopenharmony_ci pr_err("AF_RXRPC: Leaked local %p {%d}\n", 48362306a36Sopenharmony_ci local, refcount_read(&local->ref)); 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci mutex_unlock(&rxnet->local_mutex); 48662306a36Sopenharmony_ci BUG(); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci} 489