18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* AF_RXRPC implementation
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/net.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
158c2ecf20Sopenharmony_ci#include <linux/random.h>
168c2ecf20Sopenharmony_ci#include <linux/poll.h>
178c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
188c2ecf20Sopenharmony_ci#include <linux/key-type.h>
198c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
208c2ecf20Sopenharmony_ci#include <net/sock.h>
218c2ecf20Sopenharmony_ci#include <net/af_rxrpc.h>
228c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS
238c2ecf20Sopenharmony_ci#include "ar-internal.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RxRPC network protocol");
268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Red Hat, Inc.");
278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
288c2ecf20Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_RXRPC);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciunsigned int rxrpc_debug; // = RXRPC_DEBUG_KPROTO;
318c2ecf20Sopenharmony_cimodule_param_named(debug, rxrpc_debug, uint, 0644);
328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "RxRPC debugging mask");
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic struct proto rxrpc_proto;
358c2ecf20Sopenharmony_cistatic const struct proto_ops rxrpc_rpc_ops;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/* current debugging ID */
388c2ecf20Sopenharmony_ciatomic_t rxrpc_debug_id;
398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_debug_id);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* count of skbs currently in use */
428c2ecf20Sopenharmony_ciatomic_t rxrpc_n_tx_skbs, rxrpc_n_rx_skbs;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistruct workqueue_struct *rxrpc_workqueue;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic void rxrpc_sock_destructor(struct sock *);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/*
498c2ecf20Sopenharmony_ci * see if an RxRPC socket is currently writable
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_cistatic inline int rxrpc_writable(struct sock *sk)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	return refcount_read(&sk->sk_wmem_alloc) < (size_t) sk->sk_sndbuf;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/*
578c2ecf20Sopenharmony_ci * wait for write bufferage to become available
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_cistatic void rxrpc_write_space(struct sock *sk)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	_enter("%p", sk);
628c2ecf20Sopenharmony_ci	rcu_read_lock();
638c2ecf20Sopenharmony_ci	if (rxrpc_writable(sk)) {
648c2ecf20Sopenharmony_ci		struct socket_wq *wq = rcu_dereference(sk->sk_wq);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci		if (skwq_has_sleeper(wq))
678c2ecf20Sopenharmony_ci			wake_up_interruptible(&wq->wait);
688c2ecf20Sopenharmony_ci		sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci	rcu_read_unlock();
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * validate an RxRPC address
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_cistatic int rxrpc_validate_address(struct rxrpc_sock *rx,
778c2ecf20Sopenharmony_ci				  struct sockaddr_rxrpc *srx,
788c2ecf20Sopenharmony_ci				  int len)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	unsigned int tail;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (len < sizeof(struct sockaddr_rxrpc))
838c2ecf20Sopenharmony_ci		return -EINVAL;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (srx->srx_family != AF_RXRPC)
868c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (srx->transport_type != SOCK_DGRAM)
898c2ecf20Sopenharmony_ci		return -ESOCKTNOSUPPORT;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	len -= offsetof(struct sockaddr_rxrpc, transport);
928c2ecf20Sopenharmony_ci	if (srx->transport_len < sizeof(sa_family_t) ||
938c2ecf20Sopenharmony_ci	    srx->transport_len > len)
948c2ecf20Sopenharmony_ci		return -EINVAL;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (srx->transport.family != rx->family &&
978c2ecf20Sopenharmony_ci	    srx->transport.family == AF_INET && rx->family != AF_INET6)
988c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	switch (srx->transport.family) {
1018c2ecf20Sopenharmony_ci	case AF_INET:
1028c2ecf20Sopenharmony_ci		if (srx->transport_len < sizeof(struct sockaddr_in))
1038c2ecf20Sopenharmony_ci			return -EINVAL;
1048c2ecf20Sopenharmony_ci		tail = offsetof(struct sockaddr_rxrpc, transport.sin.__pad);
1058c2ecf20Sopenharmony_ci		break;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_IPV6
1088c2ecf20Sopenharmony_ci	case AF_INET6:
1098c2ecf20Sopenharmony_ci		if (srx->transport_len < sizeof(struct sockaddr_in6))
1108c2ecf20Sopenharmony_ci			return -EINVAL;
1118c2ecf20Sopenharmony_ci		tail = offsetof(struct sockaddr_rxrpc, transport) +
1128c2ecf20Sopenharmony_ci			sizeof(struct sockaddr_in6);
1138c2ecf20Sopenharmony_ci		break;
1148c2ecf20Sopenharmony_ci#endif
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	default:
1178c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (tail < len)
1218c2ecf20Sopenharmony_ci		memset((void *)srx + tail, 0, len - tail);
1228c2ecf20Sopenharmony_ci	_debug("INET: %pISp", &srx->transport);
1238c2ecf20Sopenharmony_ci	return 0;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/*
1278c2ecf20Sopenharmony_ci * bind a local address to an RxRPC socket
1288c2ecf20Sopenharmony_ci */
1298c2ecf20Sopenharmony_cistatic int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)saddr;
1328c2ecf20Sopenharmony_ci	struct rxrpc_local *local;
1338c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
1348c2ecf20Sopenharmony_ci	u16 service_id;
1358c2ecf20Sopenharmony_ci	int ret;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	_enter("%p,%p,%d", rx, saddr, len);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	ret = rxrpc_validate_address(rx, srx, len);
1408c2ecf20Sopenharmony_ci	if (ret < 0)
1418c2ecf20Sopenharmony_ci		goto error;
1428c2ecf20Sopenharmony_ci	service_id = srx->srx_service;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	lock_sock(&rx->sk);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	switch (rx->sk.sk_state) {
1478c2ecf20Sopenharmony_ci	case RXRPC_UNBOUND:
1488c2ecf20Sopenharmony_ci		rx->srx = *srx;
1498c2ecf20Sopenharmony_ci		local = rxrpc_lookup_local(sock_net(&rx->sk), &rx->srx);
1508c2ecf20Sopenharmony_ci		if (IS_ERR(local)) {
1518c2ecf20Sopenharmony_ci			ret = PTR_ERR(local);
1528c2ecf20Sopenharmony_ci			goto error_unlock;
1538c2ecf20Sopenharmony_ci		}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci		if (service_id) {
1568c2ecf20Sopenharmony_ci			write_lock(&local->services_lock);
1578c2ecf20Sopenharmony_ci			if (rcu_access_pointer(local->service))
1588c2ecf20Sopenharmony_ci				goto service_in_use;
1598c2ecf20Sopenharmony_ci			rx->local = local;
1608c2ecf20Sopenharmony_ci			rcu_assign_pointer(local->service, rx);
1618c2ecf20Sopenharmony_ci			write_unlock(&local->services_lock);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci			rx->sk.sk_state = RXRPC_SERVER_BOUND;
1648c2ecf20Sopenharmony_ci		} else {
1658c2ecf20Sopenharmony_ci			rx->local = local;
1668c2ecf20Sopenharmony_ci			rx->sk.sk_state = RXRPC_CLIENT_BOUND;
1678c2ecf20Sopenharmony_ci		}
1688c2ecf20Sopenharmony_ci		break;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	case RXRPC_SERVER_BOUND:
1718c2ecf20Sopenharmony_ci		ret = -EINVAL;
1728c2ecf20Sopenharmony_ci		if (service_id == 0)
1738c2ecf20Sopenharmony_ci			goto error_unlock;
1748c2ecf20Sopenharmony_ci		ret = -EADDRINUSE;
1758c2ecf20Sopenharmony_ci		if (service_id == rx->srx.srx_service)
1768c2ecf20Sopenharmony_ci			goto error_unlock;
1778c2ecf20Sopenharmony_ci		ret = -EINVAL;
1788c2ecf20Sopenharmony_ci		srx->srx_service = rx->srx.srx_service;
1798c2ecf20Sopenharmony_ci		if (memcmp(srx, &rx->srx, sizeof(*srx)) != 0)
1808c2ecf20Sopenharmony_ci			goto error_unlock;
1818c2ecf20Sopenharmony_ci		rx->second_service = service_id;
1828c2ecf20Sopenharmony_ci		rx->sk.sk_state = RXRPC_SERVER_BOUND2;
1838c2ecf20Sopenharmony_ci		break;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	default:
1868c2ecf20Sopenharmony_ci		ret = -EINVAL;
1878c2ecf20Sopenharmony_ci		goto error_unlock;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	release_sock(&rx->sk);
1918c2ecf20Sopenharmony_ci	_leave(" = 0");
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ciservice_in_use:
1958c2ecf20Sopenharmony_ci	write_unlock(&local->services_lock);
1968c2ecf20Sopenharmony_ci	rxrpc_unuse_local(local);
1978c2ecf20Sopenharmony_ci	rxrpc_put_local(local);
1988c2ecf20Sopenharmony_ci	ret = -EADDRINUSE;
1998c2ecf20Sopenharmony_cierror_unlock:
2008c2ecf20Sopenharmony_ci	release_sock(&rx->sk);
2018c2ecf20Sopenharmony_cierror:
2028c2ecf20Sopenharmony_ci	_leave(" = %d", ret);
2038c2ecf20Sopenharmony_ci	return ret;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/*
2078c2ecf20Sopenharmony_ci * set the number of pending calls permitted on a listening socket
2088c2ecf20Sopenharmony_ci */
2098c2ecf20Sopenharmony_cistatic int rxrpc_listen(struct socket *sock, int backlog)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
2128c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sk);
2138c2ecf20Sopenharmony_ci	unsigned int max, old;
2148c2ecf20Sopenharmony_ci	int ret;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	_enter("%p,%d", rx, backlog);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	lock_sock(&rx->sk);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	switch (rx->sk.sk_state) {
2218c2ecf20Sopenharmony_ci	case RXRPC_UNBOUND:
2228c2ecf20Sopenharmony_ci		ret = -EADDRNOTAVAIL;
2238c2ecf20Sopenharmony_ci		break;
2248c2ecf20Sopenharmony_ci	case RXRPC_SERVER_BOUND:
2258c2ecf20Sopenharmony_ci	case RXRPC_SERVER_BOUND2:
2268c2ecf20Sopenharmony_ci		ASSERT(rx->local != NULL);
2278c2ecf20Sopenharmony_ci		max = READ_ONCE(rxrpc_max_backlog);
2288c2ecf20Sopenharmony_ci		ret = -EINVAL;
2298c2ecf20Sopenharmony_ci		if (backlog == INT_MAX)
2308c2ecf20Sopenharmony_ci			backlog = max;
2318c2ecf20Sopenharmony_ci		else if (backlog < 0 || backlog > max)
2328c2ecf20Sopenharmony_ci			break;
2338c2ecf20Sopenharmony_ci		old = sk->sk_max_ack_backlog;
2348c2ecf20Sopenharmony_ci		sk->sk_max_ack_backlog = backlog;
2358c2ecf20Sopenharmony_ci		ret = rxrpc_service_prealloc(rx, GFP_KERNEL);
2368c2ecf20Sopenharmony_ci		if (ret == 0)
2378c2ecf20Sopenharmony_ci			rx->sk.sk_state = RXRPC_SERVER_LISTENING;
2388c2ecf20Sopenharmony_ci		else
2398c2ecf20Sopenharmony_ci			sk->sk_max_ack_backlog = old;
2408c2ecf20Sopenharmony_ci		break;
2418c2ecf20Sopenharmony_ci	case RXRPC_SERVER_LISTENING:
2428c2ecf20Sopenharmony_ci		if (backlog == 0) {
2438c2ecf20Sopenharmony_ci			rx->sk.sk_state = RXRPC_SERVER_LISTEN_DISABLED;
2448c2ecf20Sopenharmony_ci			sk->sk_max_ack_backlog = 0;
2458c2ecf20Sopenharmony_ci			rxrpc_discard_prealloc(rx);
2468c2ecf20Sopenharmony_ci			ret = 0;
2478c2ecf20Sopenharmony_ci			break;
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci		fallthrough;
2508c2ecf20Sopenharmony_ci	default:
2518c2ecf20Sopenharmony_ci		ret = -EBUSY;
2528c2ecf20Sopenharmony_ci		break;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	release_sock(&rx->sk);
2568c2ecf20Sopenharmony_ci	_leave(" = %d", ret);
2578c2ecf20Sopenharmony_ci	return ret;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci/**
2618c2ecf20Sopenharmony_ci * rxrpc_kernel_begin_call - Allow a kernel service to begin a call
2628c2ecf20Sopenharmony_ci * @sock: The socket on which to make the call
2638c2ecf20Sopenharmony_ci * @srx: The address of the peer to contact
2648c2ecf20Sopenharmony_ci * @key: The security context to use (defaults to socket setting)
2658c2ecf20Sopenharmony_ci * @user_call_ID: The ID to use
2668c2ecf20Sopenharmony_ci * @tx_total_len: Total length of data to transmit during the call (or -1)
2678c2ecf20Sopenharmony_ci * @gfp: The allocation constraints
2688c2ecf20Sopenharmony_ci * @notify_rx: Where to send notifications instead of socket queue
2698c2ecf20Sopenharmony_ci * @upgrade: Request service upgrade for call
2708c2ecf20Sopenharmony_ci * @interruptibility: The call is interruptible, or can be canceled.
2718c2ecf20Sopenharmony_ci * @debug_id: The debug ID for tracing to be assigned to the call
2728c2ecf20Sopenharmony_ci *
2738c2ecf20Sopenharmony_ci * Allow a kernel service to begin a call on the nominated socket.  This just
2748c2ecf20Sopenharmony_ci * sets up all the internal tracking structures and allocates connection and
2758c2ecf20Sopenharmony_ci * call IDs as appropriate.  The call to be used is returned.
2768c2ecf20Sopenharmony_ci *
2778c2ecf20Sopenharmony_ci * The default socket destination address and security may be overridden by
2788c2ecf20Sopenharmony_ci * supplying @srx and @key.
2798c2ecf20Sopenharmony_ci */
2808c2ecf20Sopenharmony_cistruct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
2818c2ecf20Sopenharmony_ci					   struct sockaddr_rxrpc *srx,
2828c2ecf20Sopenharmony_ci					   struct key *key,
2838c2ecf20Sopenharmony_ci					   unsigned long user_call_ID,
2848c2ecf20Sopenharmony_ci					   s64 tx_total_len,
2858c2ecf20Sopenharmony_ci					   gfp_t gfp,
2868c2ecf20Sopenharmony_ci					   rxrpc_notify_rx_t notify_rx,
2878c2ecf20Sopenharmony_ci					   bool upgrade,
2888c2ecf20Sopenharmony_ci					   enum rxrpc_interruptibility interruptibility,
2898c2ecf20Sopenharmony_ci					   unsigned int debug_id)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct rxrpc_conn_parameters cp;
2928c2ecf20Sopenharmony_ci	struct rxrpc_call_params p;
2938c2ecf20Sopenharmony_ci	struct rxrpc_call *call;
2948c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
2958c2ecf20Sopenharmony_ci	int ret;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	_enter(",,%x,%lx", key_serial(key), user_call_ID);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	ret = rxrpc_validate_address(rx, srx, sizeof(*srx));
3008c2ecf20Sopenharmony_ci	if (ret < 0)
3018c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	lock_sock(&rx->sk);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (!key)
3068c2ecf20Sopenharmony_ci		key = rx->key;
3078c2ecf20Sopenharmony_ci	if (key && !key->payload.data[0])
3088c2ecf20Sopenharmony_ci		key = NULL; /* a no-security key */
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	memset(&p, 0, sizeof(p));
3118c2ecf20Sopenharmony_ci	p.user_call_ID		= user_call_ID;
3128c2ecf20Sopenharmony_ci	p.tx_total_len		= tx_total_len;
3138c2ecf20Sopenharmony_ci	p.interruptibility	= interruptibility;
3148c2ecf20Sopenharmony_ci	p.kernel		= true;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	memset(&cp, 0, sizeof(cp));
3178c2ecf20Sopenharmony_ci	cp.local		= rx->local;
3188c2ecf20Sopenharmony_ci	cp.key			= key;
3198c2ecf20Sopenharmony_ci	cp.security_level	= rx->min_sec_level;
3208c2ecf20Sopenharmony_ci	cp.exclusive		= false;
3218c2ecf20Sopenharmony_ci	cp.upgrade		= upgrade;
3228c2ecf20Sopenharmony_ci	cp.service_id		= srx->srx_service;
3238c2ecf20Sopenharmony_ci	call = rxrpc_new_client_call(rx, &cp, srx, &p, gfp, debug_id);
3248c2ecf20Sopenharmony_ci	/* The socket has been unlocked. */
3258c2ecf20Sopenharmony_ci	if (!IS_ERR(call)) {
3268c2ecf20Sopenharmony_ci		call->notify_rx = notify_rx;
3278c2ecf20Sopenharmony_ci		mutex_unlock(&call->user_mutex);
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	rxrpc_put_peer(cp.peer);
3318c2ecf20Sopenharmony_ci	_leave(" = %p", call);
3328c2ecf20Sopenharmony_ci	return call;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_begin_call);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci/*
3378c2ecf20Sopenharmony_ci * Dummy function used to stop the notifier talking to recvmsg().
3388c2ecf20Sopenharmony_ci */
3398c2ecf20Sopenharmony_cistatic void rxrpc_dummy_notify_rx(struct sock *sk, struct rxrpc_call *rxcall,
3408c2ecf20Sopenharmony_ci				  unsigned long call_user_ID)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci/**
3458c2ecf20Sopenharmony_ci * rxrpc_kernel_end_call - Allow a kernel service to end a call it was using
3468c2ecf20Sopenharmony_ci * @sock: The socket the call is on
3478c2ecf20Sopenharmony_ci * @call: The call to end
3488c2ecf20Sopenharmony_ci *
3498c2ecf20Sopenharmony_ci * Allow a kernel service to end a call it was using.  The call must be
3508c2ecf20Sopenharmony_ci * complete before this is called (the call should be aborted if necessary).
3518c2ecf20Sopenharmony_ci */
3528c2ecf20Sopenharmony_civoid rxrpc_kernel_end_call(struct socket *sock, struct rxrpc_call *call)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	_enter("%d{%d}", call->debug_id, refcount_read(&call->ref));
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	mutex_lock(&call->user_mutex);
3578c2ecf20Sopenharmony_ci	rxrpc_release_call(rxrpc_sk(sock->sk), call);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/* Make sure we're not going to call back into a kernel service */
3608c2ecf20Sopenharmony_ci	if (call->notify_rx) {
3618c2ecf20Sopenharmony_ci		spin_lock_bh(&call->notify_lock);
3628c2ecf20Sopenharmony_ci		call->notify_rx = rxrpc_dummy_notify_rx;
3638c2ecf20Sopenharmony_ci		spin_unlock_bh(&call->notify_lock);
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	mutex_unlock(&call->user_mutex);
3678c2ecf20Sopenharmony_ci	rxrpc_put_call(call, rxrpc_call_put_kernel);
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_end_call);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/**
3728c2ecf20Sopenharmony_ci * rxrpc_kernel_check_life - Check to see whether a call is still alive
3738c2ecf20Sopenharmony_ci * @sock: The socket the call is on
3748c2ecf20Sopenharmony_ci * @call: The call to check
3758c2ecf20Sopenharmony_ci *
3768c2ecf20Sopenharmony_ci * Allow a kernel service to find out whether a call is still alive -
3778c2ecf20Sopenharmony_ci * ie. whether it has completed.
3788c2ecf20Sopenharmony_ci */
3798c2ecf20Sopenharmony_cibool rxrpc_kernel_check_life(const struct socket *sock,
3808c2ecf20Sopenharmony_ci			     const struct rxrpc_call *call)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	return call->state != RXRPC_CALL_COMPLETE;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_check_life);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/**
3878c2ecf20Sopenharmony_ci * rxrpc_kernel_get_epoch - Retrieve the epoch value from a call.
3888c2ecf20Sopenharmony_ci * @sock: The socket the call is on
3898c2ecf20Sopenharmony_ci * @call: The call to query
3908c2ecf20Sopenharmony_ci *
3918c2ecf20Sopenharmony_ci * Allow a kernel service to retrieve the epoch value from a service call to
3928c2ecf20Sopenharmony_ci * see if the client at the other end rebooted.
3938c2ecf20Sopenharmony_ci */
3948c2ecf20Sopenharmony_ciu32 rxrpc_kernel_get_epoch(struct socket *sock, struct rxrpc_call *call)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	return call->conn->proto.epoch;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_get_epoch);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/**
4018c2ecf20Sopenharmony_ci * rxrpc_kernel_new_call_notification - Get notifications of new calls
4028c2ecf20Sopenharmony_ci * @sock: The socket to intercept received messages on
4038c2ecf20Sopenharmony_ci * @notify_new_call: Function to be called when new calls appear
4048c2ecf20Sopenharmony_ci * @discard_new_call: Function to discard preallocated calls
4058c2ecf20Sopenharmony_ci *
4068c2ecf20Sopenharmony_ci * Allow a kernel service to be given notifications about new calls.
4078c2ecf20Sopenharmony_ci */
4088c2ecf20Sopenharmony_civoid rxrpc_kernel_new_call_notification(
4098c2ecf20Sopenharmony_ci	struct socket *sock,
4108c2ecf20Sopenharmony_ci	rxrpc_notify_new_call_t notify_new_call,
4118c2ecf20Sopenharmony_ci	rxrpc_discard_new_call_t discard_new_call)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	rx->notify_new_call = notify_new_call;
4168c2ecf20Sopenharmony_ci	rx->discard_new_call = discard_new_call;
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_new_call_notification);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci/**
4218c2ecf20Sopenharmony_ci * rxrpc_kernel_set_max_life - Set maximum lifespan on a call
4228c2ecf20Sopenharmony_ci * @sock: The socket the call is on
4238c2ecf20Sopenharmony_ci * @call: The call to configure
4248c2ecf20Sopenharmony_ci * @hard_timeout: The maximum lifespan of the call in jiffies
4258c2ecf20Sopenharmony_ci *
4268c2ecf20Sopenharmony_ci * Set the maximum lifespan of a call.  The call will end with ETIME or
4278c2ecf20Sopenharmony_ci * ETIMEDOUT if it takes longer than this.
4288c2ecf20Sopenharmony_ci */
4298c2ecf20Sopenharmony_civoid rxrpc_kernel_set_max_life(struct socket *sock, struct rxrpc_call *call,
4308c2ecf20Sopenharmony_ci			       unsigned long hard_timeout)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	unsigned long now;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	mutex_lock(&call->user_mutex);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	now = jiffies;
4378c2ecf20Sopenharmony_ci	hard_timeout += now;
4388c2ecf20Sopenharmony_ci	WRITE_ONCE(call->expect_term_by, hard_timeout);
4398c2ecf20Sopenharmony_ci	rxrpc_reduce_call_timer(call, hard_timeout, now, rxrpc_timer_set_for_hard);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	mutex_unlock(&call->user_mutex);
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_set_max_life);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci/*
4468c2ecf20Sopenharmony_ci * connect an RxRPC socket
4478c2ecf20Sopenharmony_ci * - this just targets it at a specific destination; no actual connection
4488c2ecf20Sopenharmony_ci *   negotiation takes place
4498c2ecf20Sopenharmony_ci */
4508c2ecf20Sopenharmony_cistatic int rxrpc_connect(struct socket *sock, struct sockaddr *addr,
4518c2ecf20Sopenharmony_ci			 int addr_len, int flags)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)addr;
4548c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
4558c2ecf20Sopenharmony_ci	int ret;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	_enter("%p,%p,%d,%d", rx, addr, addr_len, flags);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	ret = rxrpc_validate_address(rx, srx, addr_len);
4608c2ecf20Sopenharmony_ci	if (ret < 0) {
4618c2ecf20Sopenharmony_ci		_leave(" = %d [bad addr]", ret);
4628c2ecf20Sopenharmony_ci		return ret;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	lock_sock(&rx->sk);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	ret = -EISCONN;
4688c2ecf20Sopenharmony_ci	if (test_bit(RXRPC_SOCK_CONNECTED, &rx->flags))
4698c2ecf20Sopenharmony_ci		goto error;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	switch (rx->sk.sk_state) {
4728c2ecf20Sopenharmony_ci	case RXRPC_UNBOUND:
4738c2ecf20Sopenharmony_ci		rx->sk.sk_state = RXRPC_CLIENT_UNBOUND;
4748c2ecf20Sopenharmony_ci	case RXRPC_CLIENT_UNBOUND:
4758c2ecf20Sopenharmony_ci	case RXRPC_CLIENT_BOUND:
4768c2ecf20Sopenharmony_ci		break;
4778c2ecf20Sopenharmony_ci	default:
4788c2ecf20Sopenharmony_ci		ret = -EBUSY;
4798c2ecf20Sopenharmony_ci		goto error;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	rx->connect_srx = *srx;
4838c2ecf20Sopenharmony_ci	set_bit(RXRPC_SOCK_CONNECTED, &rx->flags);
4848c2ecf20Sopenharmony_ci	ret = 0;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cierror:
4878c2ecf20Sopenharmony_ci	release_sock(&rx->sk);
4888c2ecf20Sopenharmony_ci	return ret;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci/*
4928c2ecf20Sopenharmony_ci * send a message through an RxRPC socket
4938c2ecf20Sopenharmony_ci * - in a client this does a number of things:
4948c2ecf20Sopenharmony_ci *   - finds/sets up a connection for the security specified (if any)
4958c2ecf20Sopenharmony_ci *   - initiates a call (ID in control data)
4968c2ecf20Sopenharmony_ci *   - ends the request phase of a call (if MSG_MORE is not set)
4978c2ecf20Sopenharmony_ci *   - sends a call data packet
4988c2ecf20Sopenharmony_ci *   - may send an abort (abort code in control data)
4998c2ecf20Sopenharmony_ci */
5008c2ecf20Sopenharmony_cistatic int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	struct rxrpc_local *local;
5038c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
5048c2ecf20Sopenharmony_ci	int ret;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	_enter(",{%d},,%zu", rx->sk.sk_state, len);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (m->msg_flags & MSG_OOB)
5098c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (m->msg_name) {
5128c2ecf20Sopenharmony_ci		ret = rxrpc_validate_address(rx, m->msg_name, m->msg_namelen);
5138c2ecf20Sopenharmony_ci		if (ret < 0) {
5148c2ecf20Sopenharmony_ci			_leave(" = %d [bad addr]", ret);
5158c2ecf20Sopenharmony_ci			return ret;
5168c2ecf20Sopenharmony_ci		}
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	lock_sock(&rx->sk);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	switch (rx->sk.sk_state) {
5228c2ecf20Sopenharmony_ci	case RXRPC_UNBOUND:
5238c2ecf20Sopenharmony_ci	case RXRPC_CLIENT_UNBOUND:
5248c2ecf20Sopenharmony_ci		rx->srx.srx_family = AF_RXRPC;
5258c2ecf20Sopenharmony_ci		rx->srx.srx_service = 0;
5268c2ecf20Sopenharmony_ci		rx->srx.transport_type = SOCK_DGRAM;
5278c2ecf20Sopenharmony_ci		rx->srx.transport.family = rx->family;
5288c2ecf20Sopenharmony_ci		switch (rx->family) {
5298c2ecf20Sopenharmony_ci		case AF_INET:
5308c2ecf20Sopenharmony_ci			rx->srx.transport_len = sizeof(struct sockaddr_in);
5318c2ecf20Sopenharmony_ci			break;
5328c2ecf20Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_IPV6
5338c2ecf20Sopenharmony_ci		case AF_INET6:
5348c2ecf20Sopenharmony_ci			rx->srx.transport_len = sizeof(struct sockaddr_in6);
5358c2ecf20Sopenharmony_ci			break;
5368c2ecf20Sopenharmony_ci#endif
5378c2ecf20Sopenharmony_ci		default:
5388c2ecf20Sopenharmony_ci			ret = -EAFNOSUPPORT;
5398c2ecf20Sopenharmony_ci			goto error_unlock;
5408c2ecf20Sopenharmony_ci		}
5418c2ecf20Sopenharmony_ci		local = rxrpc_lookup_local(sock_net(sock->sk), &rx->srx);
5428c2ecf20Sopenharmony_ci		if (IS_ERR(local)) {
5438c2ecf20Sopenharmony_ci			ret = PTR_ERR(local);
5448c2ecf20Sopenharmony_ci			goto error_unlock;
5458c2ecf20Sopenharmony_ci		}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci		rx->local = local;
5488c2ecf20Sopenharmony_ci		rx->sk.sk_state = RXRPC_CLIENT_BOUND;
5498c2ecf20Sopenharmony_ci		fallthrough;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	case RXRPC_CLIENT_BOUND:
5528c2ecf20Sopenharmony_ci		if (!m->msg_name &&
5538c2ecf20Sopenharmony_ci		    test_bit(RXRPC_SOCK_CONNECTED, &rx->flags)) {
5548c2ecf20Sopenharmony_ci			m->msg_name = &rx->connect_srx;
5558c2ecf20Sopenharmony_ci			m->msg_namelen = sizeof(rx->connect_srx);
5568c2ecf20Sopenharmony_ci		}
5578c2ecf20Sopenharmony_ci		fallthrough;
5588c2ecf20Sopenharmony_ci	case RXRPC_SERVER_BOUND:
5598c2ecf20Sopenharmony_ci	case RXRPC_SERVER_LISTENING:
5608c2ecf20Sopenharmony_ci		ret = rxrpc_do_sendmsg(rx, m, len);
5618c2ecf20Sopenharmony_ci		/* The socket has been unlocked */
5628c2ecf20Sopenharmony_ci		goto out;
5638c2ecf20Sopenharmony_ci	default:
5648c2ecf20Sopenharmony_ci		ret = -EINVAL;
5658c2ecf20Sopenharmony_ci		goto error_unlock;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cierror_unlock:
5698c2ecf20Sopenharmony_ci	release_sock(&rx->sk);
5708c2ecf20Sopenharmony_ciout:
5718c2ecf20Sopenharmony_ci	_leave(" = %d", ret);
5728c2ecf20Sopenharmony_ci	return ret;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ciint rxrpc_sock_set_min_security_level(struct sock *sk, unsigned int val)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	if (sk->sk_state != RXRPC_UNBOUND)
5788c2ecf20Sopenharmony_ci		return -EISCONN;
5798c2ecf20Sopenharmony_ci	if (val > RXRPC_SECURITY_MAX)
5808c2ecf20Sopenharmony_ci		return -EINVAL;
5818c2ecf20Sopenharmony_ci	lock_sock(sk);
5828c2ecf20Sopenharmony_ci	rxrpc_sk(sk)->min_sec_level = val;
5838c2ecf20Sopenharmony_ci	release_sock(sk);
5848c2ecf20Sopenharmony_ci	return 0;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_sock_set_min_security_level);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci/*
5898c2ecf20Sopenharmony_ci * set RxRPC socket options
5908c2ecf20Sopenharmony_ci */
5918c2ecf20Sopenharmony_cistatic int rxrpc_setsockopt(struct socket *sock, int level, int optname,
5928c2ecf20Sopenharmony_ci			    sockptr_t optval, unsigned int optlen)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
5958c2ecf20Sopenharmony_ci	unsigned int min_sec_level;
5968c2ecf20Sopenharmony_ci	u16 service_upgrade[2];
5978c2ecf20Sopenharmony_ci	int ret;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	_enter(",%d,%d,,%d", level, optname, optlen);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	lock_sock(&rx->sk);
6028c2ecf20Sopenharmony_ci	ret = -EOPNOTSUPP;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	if (level == SOL_RXRPC) {
6058c2ecf20Sopenharmony_ci		switch (optname) {
6068c2ecf20Sopenharmony_ci		case RXRPC_EXCLUSIVE_CONNECTION:
6078c2ecf20Sopenharmony_ci			ret = -EINVAL;
6088c2ecf20Sopenharmony_ci			if (optlen != 0)
6098c2ecf20Sopenharmony_ci				goto error;
6108c2ecf20Sopenharmony_ci			ret = -EISCONN;
6118c2ecf20Sopenharmony_ci			if (rx->sk.sk_state != RXRPC_UNBOUND)
6128c2ecf20Sopenharmony_ci				goto error;
6138c2ecf20Sopenharmony_ci			rx->exclusive = true;
6148c2ecf20Sopenharmony_ci			goto success;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci		case RXRPC_SECURITY_KEY:
6178c2ecf20Sopenharmony_ci			ret = -EINVAL;
6188c2ecf20Sopenharmony_ci			if (rx->key)
6198c2ecf20Sopenharmony_ci				goto error;
6208c2ecf20Sopenharmony_ci			ret = -EISCONN;
6218c2ecf20Sopenharmony_ci			if (rx->sk.sk_state != RXRPC_UNBOUND)
6228c2ecf20Sopenharmony_ci				goto error;
6238c2ecf20Sopenharmony_ci			ret = rxrpc_request_key(rx, optval, optlen);
6248c2ecf20Sopenharmony_ci			goto error;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		case RXRPC_SECURITY_KEYRING:
6278c2ecf20Sopenharmony_ci			ret = -EINVAL;
6288c2ecf20Sopenharmony_ci			if (rx->key)
6298c2ecf20Sopenharmony_ci				goto error;
6308c2ecf20Sopenharmony_ci			ret = -EISCONN;
6318c2ecf20Sopenharmony_ci			if (rx->sk.sk_state != RXRPC_UNBOUND)
6328c2ecf20Sopenharmony_ci				goto error;
6338c2ecf20Sopenharmony_ci			ret = rxrpc_server_keyring(rx, optval, optlen);
6348c2ecf20Sopenharmony_ci			goto error;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci		case RXRPC_MIN_SECURITY_LEVEL:
6378c2ecf20Sopenharmony_ci			ret = -EINVAL;
6388c2ecf20Sopenharmony_ci			if (optlen != sizeof(unsigned int))
6398c2ecf20Sopenharmony_ci				goto error;
6408c2ecf20Sopenharmony_ci			ret = -EISCONN;
6418c2ecf20Sopenharmony_ci			if (rx->sk.sk_state != RXRPC_UNBOUND)
6428c2ecf20Sopenharmony_ci				goto error;
6438c2ecf20Sopenharmony_ci			ret = copy_from_sockptr(&min_sec_level, optval,
6448c2ecf20Sopenharmony_ci				       sizeof(unsigned int));
6458c2ecf20Sopenharmony_ci			if (ret < 0)
6468c2ecf20Sopenharmony_ci				goto error;
6478c2ecf20Sopenharmony_ci			ret = -EINVAL;
6488c2ecf20Sopenharmony_ci			if (min_sec_level > RXRPC_SECURITY_MAX)
6498c2ecf20Sopenharmony_ci				goto error;
6508c2ecf20Sopenharmony_ci			rx->min_sec_level = min_sec_level;
6518c2ecf20Sopenharmony_ci			goto success;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci		case RXRPC_UPGRADEABLE_SERVICE:
6548c2ecf20Sopenharmony_ci			ret = -EINVAL;
6558c2ecf20Sopenharmony_ci			if (optlen != sizeof(service_upgrade) ||
6568c2ecf20Sopenharmony_ci			    rx->service_upgrade.from != 0)
6578c2ecf20Sopenharmony_ci				goto error;
6588c2ecf20Sopenharmony_ci			ret = -EISCONN;
6598c2ecf20Sopenharmony_ci			if (rx->sk.sk_state != RXRPC_SERVER_BOUND2)
6608c2ecf20Sopenharmony_ci				goto error;
6618c2ecf20Sopenharmony_ci			ret = -EFAULT;
6628c2ecf20Sopenharmony_ci			if (copy_from_sockptr(service_upgrade, optval,
6638c2ecf20Sopenharmony_ci					   sizeof(service_upgrade)) != 0)
6648c2ecf20Sopenharmony_ci				goto error;
6658c2ecf20Sopenharmony_ci			ret = -EINVAL;
6668c2ecf20Sopenharmony_ci			if ((service_upgrade[0] != rx->srx.srx_service ||
6678c2ecf20Sopenharmony_ci			     service_upgrade[1] != rx->second_service) &&
6688c2ecf20Sopenharmony_ci			    (service_upgrade[0] != rx->second_service ||
6698c2ecf20Sopenharmony_ci			     service_upgrade[1] != rx->srx.srx_service))
6708c2ecf20Sopenharmony_ci				goto error;
6718c2ecf20Sopenharmony_ci			rx->service_upgrade.from = service_upgrade[0];
6728c2ecf20Sopenharmony_ci			rx->service_upgrade.to = service_upgrade[1];
6738c2ecf20Sopenharmony_ci			goto success;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		default:
6768c2ecf20Sopenharmony_ci			break;
6778c2ecf20Sopenharmony_ci		}
6788c2ecf20Sopenharmony_ci	}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cisuccess:
6818c2ecf20Sopenharmony_ci	ret = 0;
6828c2ecf20Sopenharmony_cierror:
6838c2ecf20Sopenharmony_ci	release_sock(&rx->sk);
6848c2ecf20Sopenharmony_ci	return ret;
6858c2ecf20Sopenharmony_ci}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci/*
6888c2ecf20Sopenharmony_ci * Get socket options.
6898c2ecf20Sopenharmony_ci */
6908c2ecf20Sopenharmony_cistatic int rxrpc_getsockopt(struct socket *sock, int level, int optname,
6918c2ecf20Sopenharmony_ci			    char __user *optval, int __user *_optlen)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	int optlen;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (level != SOL_RXRPC)
6968c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	if (get_user(optlen, _optlen))
6998c2ecf20Sopenharmony_ci		return -EFAULT;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	switch (optname) {
7028c2ecf20Sopenharmony_ci	case RXRPC_SUPPORTED_CMSG:
7038c2ecf20Sopenharmony_ci		if (optlen < sizeof(int))
7048c2ecf20Sopenharmony_ci			return -ETOOSMALL;
7058c2ecf20Sopenharmony_ci		if (put_user(RXRPC__SUPPORTED - 1, (int __user *)optval) ||
7068c2ecf20Sopenharmony_ci		    put_user(sizeof(int), _optlen))
7078c2ecf20Sopenharmony_ci			return -EFAULT;
7088c2ecf20Sopenharmony_ci		return 0;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	default:
7118c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci/*
7168c2ecf20Sopenharmony_ci * permit an RxRPC socket to be polled
7178c2ecf20Sopenharmony_ci */
7188c2ecf20Sopenharmony_cistatic __poll_t rxrpc_poll(struct file *file, struct socket *sock,
7198c2ecf20Sopenharmony_ci			       poll_table *wait)
7208c2ecf20Sopenharmony_ci{
7218c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
7228c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sk);
7238c2ecf20Sopenharmony_ci	__poll_t mask;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	sock_poll_wait(file, sock, wait);
7268c2ecf20Sopenharmony_ci	mask = 0;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	/* the socket is readable if there are any messages waiting on the Rx
7298c2ecf20Sopenharmony_ci	 * queue */
7308c2ecf20Sopenharmony_ci	if (!list_empty(&rx->recvmsg_q))
7318c2ecf20Sopenharmony_ci		mask |= EPOLLIN | EPOLLRDNORM;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	/* the socket is writable if there is space to add new data to the
7348c2ecf20Sopenharmony_ci	 * socket; there is no guarantee that any particular call in progress
7358c2ecf20Sopenharmony_ci	 * on the socket may have space in the Tx ACK window */
7368c2ecf20Sopenharmony_ci	if (rxrpc_writable(sk))
7378c2ecf20Sopenharmony_ci		mask |= EPOLLOUT | EPOLLWRNORM;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	return mask;
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci/*
7438c2ecf20Sopenharmony_ci * create an RxRPC socket
7448c2ecf20Sopenharmony_ci */
7458c2ecf20Sopenharmony_cistatic int rxrpc_create(struct net *net, struct socket *sock, int protocol,
7468c2ecf20Sopenharmony_ci			int kern)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	struct rxrpc_net *rxnet;
7498c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx;
7508c2ecf20Sopenharmony_ci	struct sock *sk;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	_enter("%p,%d", sock, protocol);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	/* we support transport protocol UDP/UDP6 only */
7558c2ecf20Sopenharmony_ci	if (protocol != PF_INET &&
7568c2ecf20Sopenharmony_ci	    IS_ENABLED(CONFIG_AF_RXRPC_IPV6) && protocol != PF_INET6)
7578c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	if (sock->type != SOCK_DGRAM)
7608c2ecf20Sopenharmony_ci		return -ESOCKTNOSUPPORT;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	sock->ops = &rxrpc_rpc_ops;
7638c2ecf20Sopenharmony_ci	sock->state = SS_UNCONNECTED;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	sk = sk_alloc(net, PF_RXRPC, GFP_KERNEL, &rxrpc_proto, kern);
7668c2ecf20Sopenharmony_ci	if (!sk)
7678c2ecf20Sopenharmony_ci		return -ENOMEM;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	sock_init_data(sock, sk);
7708c2ecf20Sopenharmony_ci	sock_set_flag(sk, SOCK_RCU_FREE);
7718c2ecf20Sopenharmony_ci	sk->sk_state		= RXRPC_UNBOUND;
7728c2ecf20Sopenharmony_ci	sk->sk_write_space	= rxrpc_write_space;
7738c2ecf20Sopenharmony_ci	sk->sk_max_ack_backlog	= 0;
7748c2ecf20Sopenharmony_ci	sk->sk_destruct		= rxrpc_sock_destructor;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	rx = rxrpc_sk(sk);
7778c2ecf20Sopenharmony_ci	rx->family = protocol;
7788c2ecf20Sopenharmony_ci	rx->calls = RB_ROOT;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	spin_lock_init(&rx->incoming_lock);
7818c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rx->sock_calls);
7828c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rx->to_be_accepted);
7838c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&rx->recvmsg_q);
7848c2ecf20Sopenharmony_ci	rwlock_init(&rx->recvmsg_lock);
7858c2ecf20Sopenharmony_ci	rwlock_init(&rx->call_lock);
7868c2ecf20Sopenharmony_ci	memset(&rx->srx, 0, sizeof(rx->srx));
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	rxnet = rxrpc_net(sock_net(&rx->sk));
7898c2ecf20Sopenharmony_ci	timer_reduce(&rxnet->peer_keepalive_timer, jiffies + 1);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	_leave(" = 0 [%p]", rx);
7928c2ecf20Sopenharmony_ci	return 0;
7938c2ecf20Sopenharmony_ci}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci/*
7968c2ecf20Sopenharmony_ci * Kill all the calls on a socket and shut it down.
7978c2ecf20Sopenharmony_ci */
7988c2ecf20Sopenharmony_cistatic int rxrpc_shutdown(struct socket *sock, int flags)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
8018c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sk);
8028c2ecf20Sopenharmony_ci	int ret = 0;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	_enter("%p,%d", sk, flags);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	if (flags != SHUT_RDWR)
8078c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8088c2ecf20Sopenharmony_ci	if (sk->sk_state == RXRPC_CLOSE)
8098c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	lock_sock(sk);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	spin_lock_bh(&sk->sk_receive_queue.lock);
8148c2ecf20Sopenharmony_ci	if (sk->sk_state < RXRPC_CLOSE) {
8158c2ecf20Sopenharmony_ci		sk->sk_state = RXRPC_CLOSE;
8168c2ecf20Sopenharmony_ci		sk->sk_shutdown = SHUTDOWN_MASK;
8178c2ecf20Sopenharmony_ci	} else {
8188c2ecf20Sopenharmony_ci		ret = -ESHUTDOWN;
8198c2ecf20Sopenharmony_ci	}
8208c2ecf20Sopenharmony_ci	spin_unlock_bh(&sk->sk_receive_queue.lock);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	rxrpc_discard_prealloc(rx);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	release_sock(sk);
8258c2ecf20Sopenharmony_ci	return ret;
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci/*
8298c2ecf20Sopenharmony_ci * RxRPC socket destructor
8308c2ecf20Sopenharmony_ci */
8318c2ecf20Sopenharmony_cistatic void rxrpc_sock_destructor(struct sock *sk)
8328c2ecf20Sopenharmony_ci{
8338c2ecf20Sopenharmony_ci	_enter("%p", sk);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	rxrpc_purge_queue(&sk->sk_receive_queue);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	WARN_ON(refcount_read(&sk->sk_wmem_alloc));
8388c2ecf20Sopenharmony_ci	WARN_ON(!sk_unhashed(sk));
8398c2ecf20Sopenharmony_ci	WARN_ON(sk->sk_socket);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	if (!sock_flag(sk, SOCK_DEAD)) {
8428c2ecf20Sopenharmony_ci		printk("Attempt to release alive rxrpc socket: %p\n", sk);
8438c2ecf20Sopenharmony_ci		return;
8448c2ecf20Sopenharmony_ci	}
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci/*
8488c2ecf20Sopenharmony_ci * release an RxRPC socket
8498c2ecf20Sopenharmony_ci */
8508c2ecf20Sopenharmony_cistatic int rxrpc_release_sock(struct sock *sk)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci	struct rxrpc_sock *rx = rxrpc_sk(sk);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	_enter("%p{%d,%d}", sk, sk->sk_state, refcount_read(&sk->sk_refcnt));
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	/* declare the socket closed for business */
8578c2ecf20Sopenharmony_ci	sock_orphan(sk);
8588c2ecf20Sopenharmony_ci	sk->sk_shutdown = SHUTDOWN_MASK;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	/* We want to kill off all connections from a service socket
8618c2ecf20Sopenharmony_ci	 * as fast as possible because we can't share these; client
8628c2ecf20Sopenharmony_ci	 * sockets, on the other hand, can share an endpoint.
8638c2ecf20Sopenharmony_ci	 */
8648c2ecf20Sopenharmony_ci	switch (sk->sk_state) {
8658c2ecf20Sopenharmony_ci	case RXRPC_SERVER_BOUND:
8668c2ecf20Sopenharmony_ci	case RXRPC_SERVER_BOUND2:
8678c2ecf20Sopenharmony_ci	case RXRPC_SERVER_LISTENING:
8688c2ecf20Sopenharmony_ci	case RXRPC_SERVER_LISTEN_DISABLED:
8698c2ecf20Sopenharmony_ci		rx->local->service_closed = true;
8708c2ecf20Sopenharmony_ci		break;
8718c2ecf20Sopenharmony_ci	}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	spin_lock_bh(&sk->sk_receive_queue.lock);
8748c2ecf20Sopenharmony_ci	sk->sk_state = RXRPC_CLOSE;
8758c2ecf20Sopenharmony_ci	spin_unlock_bh(&sk->sk_receive_queue.lock);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	if (rx->local && rcu_access_pointer(rx->local->service) == rx) {
8788c2ecf20Sopenharmony_ci		write_lock(&rx->local->services_lock);
8798c2ecf20Sopenharmony_ci		rcu_assign_pointer(rx->local->service, NULL);
8808c2ecf20Sopenharmony_ci		write_unlock(&rx->local->services_lock);
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	/* try to flush out this socket */
8848c2ecf20Sopenharmony_ci	rxrpc_discard_prealloc(rx);
8858c2ecf20Sopenharmony_ci	rxrpc_release_calls_on_socket(rx);
8868c2ecf20Sopenharmony_ci	flush_workqueue(rxrpc_workqueue);
8878c2ecf20Sopenharmony_ci	rxrpc_purge_queue(&sk->sk_receive_queue);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	rxrpc_unuse_local(rx->local);
8908c2ecf20Sopenharmony_ci	rxrpc_put_local(rx->local);
8918c2ecf20Sopenharmony_ci	rx->local = NULL;
8928c2ecf20Sopenharmony_ci	key_put(rx->key);
8938c2ecf20Sopenharmony_ci	rx->key = NULL;
8948c2ecf20Sopenharmony_ci	key_put(rx->securities);
8958c2ecf20Sopenharmony_ci	rx->securities = NULL;
8968c2ecf20Sopenharmony_ci	sock_put(sk);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	_leave(" = 0");
8998c2ecf20Sopenharmony_ci	return 0;
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci/*
9038c2ecf20Sopenharmony_ci * release an RxRPC BSD socket on close() or equivalent
9048c2ecf20Sopenharmony_ci */
9058c2ecf20Sopenharmony_cistatic int rxrpc_release(struct socket *sock)
9068c2ecf20Sopenharmony_ci{
9078c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	_enter("%p{%p}", sock, sk);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	if (!sk)
9128c2ecf20Sopenharmony_ci		return 0;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	sock->sk = NULL;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	return rxrpc_release_sock(sk);
9178c2ecf20Sopenharmony_ci}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci/*
9208c2ecf20Sopenharmony_ci * RxRPC network protocol
9218c2ecf20Sopenharmony_ci */
9228c2ecf20Sopenharmony_cistatic const struct proto_ops rxrpc_rpc_ops = {
9238c2ecf20Sopenharmony_ci	.family		= PF_RXRPC,
9248c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
9258c2ecf20Sopenharmony_ci	.release	= rxrpc_release,
9268c2ecf20Sopenharmony_ci	.bind		= rxrpc_bind,
9278c2ecf20Sopenharmony_ci	.connect	= rxrpc_connect,
9288c2ecf20Sopenharmony_ci	.socketpair	= sock_no_socketpair,
9298c2ecf20Sopenharmony_ci	.accept		= sock_no_accept,
9308c2ecf20Sopenharmony_ci	.getname	= sock_no_getname,
9318c2ecf20Sopenharmony_ci	.poll		= rxrpc_poll,
9328c2ecf20Sopenharmony_ci	.ioctl		= sock_no_ioctl,
9338c2ecf20Sopenharmony_ci	.listen		= rxrpc_listen,
9348c2ecf20Sopenharmony_ci	.shutdown	= rxrpc_shutdown,
9358c2ecf20Sopenharmony_ci	.setsockopt	= rxrpc_setsockopt,
9368c2ecf20Sopenharmony_ci	.getsockopt	= rxrpc_getsockopt,
9378c2ecf20Sopenharmony_ci	.sendmsg	= rxrpc_sendmsg,
9388c2ecf20Sopenharmony_ci	.recvmsg	= rxrpc_recvmsg,
9398c2ecf20Sopenharmony_ci	.mmap		= sock_no_mmap,
9408c2ecf20Sopenharmony_ci	.sendpage	= sock_no_sendpage,
9418c2ecf20Sopenharmony_ci};
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_cistatic struct proto rxrpc_proto = {
9448c2ecf20Sopenharmony_ci	.name		= "RXRPC",
9458c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
9468c2ecf20Sopenharmony_ci	.obj_size	= sizeof(struct rxrpc_sock),
9478c2ecf20Sopenharmony_ci	.max_header	= sizeof(struct rxrpc_wire_header),
9488c2ecf20Sopenharmony_ci};
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_cistatic const struct net_proto_family rxrpc_family_ops = {
9518c2ecf20Sopenharmony_ci	.family	= PF_RXRPC,
9528c2ecf20Sopenharmony_ci	.create = rxrpc_create,
9538c2ecf20Sopenharmony_ci	.owner	= THIS_MODULE,
9548c2ecf20Sopenharmony_ci};
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci/*
9578c2ecf20Sopenharmony_ci * initialise and register the RxRPC protocol
9588c2ecf20Sopenharmony_ci */
9598c2ecf20Sopenharmony_cistatic int __init af_rxrpc_init(void)
9608c2ecf20Sopenharmony_ci{
9618c2ecf20Sopenharmony_ci	int ret = -1;
9628c2ecf20Sopenharmony_ci	unsigned int tmp;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof_field(struct sk_buff, cb));
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	get_random_bytes(&tmp, sizeof(tmp));
9678c2ecf20Sopenharmony_ci	tmp &= 0x3fffffff;
9688c2ecf20Sopenharmony_ci	if (tmp == 0)
9698c2ecf20Sopenharmony_ci		tmp = 1;
9708c2ecf20Sopenharmony_ci	idr_set_cursor(&rxrpc_client_conn_ids, tmp);
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	ret = -ENOMEM;
9738c2ecf20Sopenharmony_ci	rxrpc_call_jar = kmem_cache_create(
9748c2ecf20Sopenharmony_ci		"rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
9758c2ecf20Sopenharmony_ci		SLAB_HWCACHE_ALIGN, NULL);
9768c2ecf20Sopenharmony_ci	if (!rxrpc_call_jar) {
9778c2ecf20Sopenharmony_ci		pr_notice("Failed to allocate call jar\n");
9788c2ecf20Sopenharmony_ci		goto error_call_jar;
9798c2ecf20Sopenharmony_ci	}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	rxrpc_workqueue = alloc_workqueue("krxrpcd", 0, 1);
9828c2ecf20Sopenharmony_ci	if (!rxrpc_workqueue) {
9838c2ecf20Sopenharmony_ci		pr_notice("Failed to allocate work queue\n");
9848c2ecf20Sopenharmony_ci		goto error_work_queue;
9858c2ecf20Sopenharmony_ci	}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	ret = rxrpc_init_security();
9888c2ecf20Sopenharmony_ci	if (ret < 0) {
9898c2ecf20Sopenharmony_ci		pr_crit("Cannot initialise security\n");
9908c2ecf20Sopenharmony_ci		goto error_security;
9918c2ecf20Sopenharmony_ci	}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	ret = register_pernet_device(&rxrpc_net_ops);
9948c2ecf20Sopenharmony_ci	if (ret)
9958c2ecf20Sopenharmony_ci		goto error_pernet;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	ret = proto_register(&rxrpc_proto, 1);
9988c2ecf20Sopenharmony_ci	if (ret < 0) {
9998c2ecf20Sopenharmony_ci		pr_crit("Cannot register protocol\n");
10008c2ecf20Sopenharmony_ci		goto error_proto;
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	ret = sock_register(&rxrpc_family_ops);
10048c2ecf20Sopenharmony_ci	if (ret < 0) {
10058c2ecf20Sopenharmony_ci		pr_crit("Cannot register socket family\n");
10068c2ecf20Sopenharmony_ci		goto error_sock;
10078c2ecf20Sopenharmony_ci	}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	ret = register_key_type(&key_type_rxrpc);
10108c2ecf20Sopenharmony_ci	if (ret < 0) {
10118c2ecf20Sopenharmony_ci		pr_crit("Cannot register client key type\n");
10128c2ecf20Sopenharmony_ci		goto error_key_type;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	ret = register_key_type(&key_type_rxrpc_s);
10168c2ecf20Sopenharmony_ci	if (ret < 0) {
10178c2ecf20Sopenharmony_ci		pr_crit("Cannot register server key type\n");
10188c2ecf20Sopenharmony_ci		goto error_key_type_s;
10198c2ecf20Sopenharmony_ci	}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	ret = rxrpc_sysctl_init();
10228c2ecf20Sopenharmony_ci	if (ret < 0) {
10238c2ecf20Sopenharmony_ci		pr_crit("Cannot register sysctls\n");
10248c2ecf20Sopenharmony_ci		goto error_sysctls;
10258c2ecf20Sopenharmony_ci	}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	return 0;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_cierror_sysctls:
10308c2ecf20Sopenharmony_ci	unregister_key_type(&key_type_rxrpc_s);
10318c2ecf20Sopenharmony_cierror_key_type_s:
10328c2ecf20Sopenharmony_ci	unregister_key_type(&key_type_rxrpc);
10338c2ecf20Sopenharmony_cierror_key_type:
10348c2ecf20Sopenharmony_ci	sock_unregister(PF_RXRPC);
10358c2ecf20Sopenharmony_cierror_sock:
10368c2ecf20Sopenharmony_ci	proto_unregister(&rxrpc_proto);
10378c2ecf20Sopenharmony_cierror_proto:
10388c2ecf20Sopenharmony_ci	unregister_pernet_device(&rxrpc_net_ops);
10398c2ecf20Sopenharmony_cierror_pernet:
10408c2ecf20Sopenharmony_ci	rxrpc_exit_security();
10418c2ecf20Sopenharmony_cierror_security:
10428c2ecf20Sopenharmony_ci	destroy_workqueue(rxrpc_workqueue);
10438c2ecf20Sopenharmony_cierror_work_queue:
10448c2ecf20Sopenharmony_ci	kmem_cache_destroy(rxrpc_call_jar);
10458c2ecf20Sopenharmony_cierror_call_jar:
10468c2ecf20Sopenharmony_ci	return ret;
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci/*
10508c2ecf20Sopenharmony_ci * unregister the RxRPC protocol
10518c2ecf20Sopenharmony_ci */
10528c2ecf20Sopenharmony_cistatic void __exit af_rxrpc_exit(void)
10538c2ecf20Sopenharmony_ci{
10548c2ecf20Sopenharmony_ci	_enter("");
10558c2ecf20Sopenharmony_ci	rxrpc_sysctl_exit();
10568c2ecf20Sopenharmony_ci	unregister_key_type(&key_type_rxrpc_s);
10578c2ecf20Sopenharmony_ci	unregister_key_type(&key_type_rxrpc);
10588c2ecf20Sopenharmony_ci	sock_unregister(PF_RXRPC);
10598c2ecf20Sopenharmony_ci	proto_unregister(&rxrpc_proto);
10608c2ecf20Sopenharmony_ci	unregister_pernet_device(&rxrpc_net_ops);
10618c2ecf20Sopenharmony_ci	ASSERTCMP(atomic_read(&rxrpc_n_tx_skbs), ==, 0);
10628c2ecf20Sopenharmony_ci	ASSERTCMP(atomic_read(&rxrpc_n_rx_skbs), ==, 0);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	/* Make sure the local and peer records pinned by any dying connections
10658c2ecf20Sopenharmony_ci	 * are released.
10668c2ecf20Sopenharmony_ci	 */
10678c2ecf20Sopenharmony_ci	rcu_barrier();
10688c2ecf20Sopenharmony_ci	rxrpc_destroy_client_conn_ids();
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	destroy_workqueue(rxrpc_workqueue);
10718c2ecf20Sopenharmony_ci	rxrpc_exit_security();
10728c2ecf20Sopenharmony_ci	kmem_cache_destroy(rxrpc_call_jar);
10738c2ecf20Sopenharmony_ci	_leave("");
10748c2ecf20Sopenharmony_ci}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_cimodule_init(af_rxrpc_init);
10778c2ecf20Sopenharmony_cimodule_exit(af_rxrpc_exit);
1078