// SPDX-License-Identifier: GPL-2.0-or-later /* AF_RXRPC implementation * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
staticstruct proto rxrpc_proto; staticconststruct proto_ops rxrpc_rpc_ops;
/* current debugging ID */
atomic_t rxrpc_debug_id;
EXPORT_SYMBOL(rxrpc_debug_id);
/* count of skbs currently in use */
atomic_t rxrpc_n_rx_skbs;
struct workqueue_struct *rxrpc_workqueue;
staticvoid rxrpc_sock_destructor(struct sock *);
/* * see if an RxRPC socket is currently writable
*/ staticinlineint rxrpc_writable(struct sock *sk)
{ return refcount_read(&sk->sk_wmem_alloc) < (size_t) sk->sk_sndbuf;
}
/* * wait for write bufferage to become available
*/ staticvoid rxrpc_write_space(struct sock *sk)
{
_enter("%p", sk);
rcu_read_lock(); if (rxrpc_writable(sk)) { struct socket_wq *wq = rcu_dereference(sk->sk_wq);
if (skwq_has_sleeper(wq))
wake_up_interruptible(&wq->wait);
sk_wake_async_rcu(sk, SOCK_WAKE_SPACE, POLL_OUT);
}
rcu_read_unlock();
}
/* * validate an RxRPC address
*/ staticint rxrpc_validate_address(struct rxrpc_sock *rx, struct sockaddr_rxrpc *srx, int len)
{ unsignedint tail;
if (len < sizeof(struct sockaddr_rxrpc)) return -EINVAL;
if (srx->srx_family != AF_RXRPC) return -EAFNOSUPPORT;
if (srx->transport_type != SOCK_DGRAM) return -ESOCKTNOSUPPORT;
len -= offsetof(struct sockaddr_rxrpc, transport); if (srx->transport_len < sizeof(sa_family_t) ||
srx->transport_len > len) return -EINVAL;
switch (srx->transport.family) { case AF_INET: if (rx->family != AF_INET &&
rx->family != AF_INET6) return -EAFNOSUPPORT; if (srx->transport_len < sizeof(struct sockaddr_in)) return -EINVAL;
tail = offsetof(struct sockaddr_rxrpc, transport.sin.__pad); break;
#ifdef CONFIG_AF_RXRPC_IPV6 case AF_INET6: if (rx->family != AF_INET6) return -EAFNOSUPPORT; if (srx->transport_len < sizeof(struct sockaddr_in6)) return -EINVAL;
tail = offsetof(struct sockaddr_rxrpc, transport) + sizeof(struct sockaddr_in6); break; #endif
default: return -EAFNOSUPPORT;
}
if (tail < len)
memset((void *)srx + tail, 0, len - tail);
_debug("INET: %pISp", &srx->transport); return 0;
}
/* * bind a local address to an RxRPC socket
*/ staticint rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
{ struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)saddr; struct rxrpc_local *local; struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
u16 service_id; int ret;
_enter("%p,%p,%d", rx, saddr, len);
ret = rxrpc_validate_address(rx, srx, len); if (ret < 0) goto error;
service_id = srx->srx_service;
lock_sock(&rx->sk);
switch (rx->sk.sk_state) { case RXRPC_UNBOUND:
rx->srx = *srx;
local = rxrpc_lookup_local(sock_net(&rx->sk), &rx->srx); if (IS_ERR(local)) {
ret = PTR_ERR(local); goto error_unlock;
}
if (service_id) {
write_lock(&local->services_lock); if (local->service) goto service_in_use;
rx->local = local;
local->service = rx;
write_unlock(&local->services_lock);
/* * set the number of pending calls permitted on a listening socket
*/ staticint rxrpc_listen(struct socket *sock, int backlog)
{ struct sock *sk = sock->sk; struct rxrpc_sock *rx = rxrpc_sk(sk); unsignedint max, old; int ret;
_enter("%p,%d", rx, backlog);
lock_sock(&rx->sk);
switch (rx->sk.sk_state) { case RXRPC_UNBOUND:
ret = -EADDRNOTAVAIL; break; case RXRPC_SERVER_BOUND: case RXRPC_SERVER_BOUND2:
ASSERT(rx->local != NULL);
max = READ_ONCE(rxrpc_max_backlog);
ret = -EINVAL; if (backlog == INT_MAX)
backlog = max; elseif (backlog < 0 || backlog > max) break;
old = sk->sk_max_ack_backlog;
sk->sk_max_ack_backlog = backlog;
ret = rxrpc_service_prealloc(rx, GFP_KERNEL); if (ret == 0)
rx->sk.sk_state = RXRPC_SERVER_LISTENING; else
sk->sk_max_ack_backlog = old; break; case RXRPC_SERVER_LISTENING: if (backlog == 0) {
rx->sk.sk_state = RXRPC_SERVER_LISTEN_DISABLED;
sk->sk_max_ack_backlog = 0;
rxrpc_discard_prealloc(rx);
ret = 0; break;
}
fallthrough; default:
ret = -EBUSY; break;
}
/** * rxrpc_kernel_lookup_peer - Obtain remote transport endpoint for an address * @sock: The socket through which it will be accessed * @srx: The network address * @gfp: Allocation flags * * Lookup or create a remote transport endpoint record for the specified * address. * * Return: The peer record found with a reference, %NULL if no record is found * or a negative error code if the address is invalid or unsupported.
*/ struct rxrpc_peer *rxrpc_kernel_lookup_peer(struct socket *sock, struct sockaddr_rxrpc *srx, gfp_t gfp)
{ struct rxrpc_sock *rx = rxrpc_sk(sock->sk); int ret;
ret = rxrpc_validate_address(rx, srx, sizeof(*srx)); if (ret < 0) return ERR_PTR(ret);
/** * rxrpc_kernel_get_peer - Get a reference on a peer * @peer: The peer to get a reference on (may be NULL). * * Get a reference for a remote peer record (if not NULL). * * Return: The @peer argument.
*/ struct rxrpc_peer *rxrpc_kernel_get_peer(struct rxrpc_peer *peer)
{ return peer ? rxrpc_get_peer(peer, rxrpc_peer_get_application) : NULL;
}
EXPORT_SYMBOL(rxrpc_kernel_get_peer);
/** * rxrpc_kernel_put_peer - Allow a kernel app to drop a peer reference * @peer: The peer to drop a ref on * * Drop a reference on a peer record.
*/ void rxrpc_kernel_put_peer(struct rxrpc_peer *peer)
{
rxrpc_put_peer(peer, rxrpc_peer_put_application);
}
EXPORT_SYMBOL(rxrpc_kernel_put_peer);
/** * rxrpc_kernel_begin_call - Allow a kernel service to begin a call * @sock: The socket on which to make the call * @peer: The peer to contact * @key: The security context to use (defaults to socket setting) * @user_call_ID: The ID to use * @tx_total_len: Total length of data to transmit during the call (or -1) * @hard_timeout: The maximum lifespan of the call in sec * @gfp: The allocation constraints * @notify_rx: Where to send notifications instead of socket queue * @service_id: The ID of the service to contact * @upgrade: Request service upgrade for call * @interruptibility: The call is interruptible, or can be canceled. * @debug_id: The debug ID for tracing to be assigned to the call * * Allow a kernel service to begin a call on the nominated socket. This just * sets up all the internal tracking structures and allocates connection and * call IDs as appropriate. * * The default socket destination address and security may be overridden by * supplying @srx and @key. * * Return: The new call or an error code.
*/ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, struct rxrpc_peer *peer, struct key *key, unsignedlong user_call_ID,
s64 tx_total_len,
u32 hard_timeout,
gfp_t gfp,
rxrpc_notify_rx_t notify_rx,
u16 service_id, bool upgrade, enum rxrpc_interruptibility interruptibility, unsignedint debug_id)
{ struct rxrpc_conn_parameters cp; struct rxrpc_call_params p; struct rxrpc_call *call; struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
/* * Dummy function used to stop the notifier talking to recvmsg().
*/ staticvoid rxrpc_dummy_notify_rx(struct sock *sk, struct rxrpc_call *rxcall, unsignedlong call_user_ID)
{
}
/** * rxrpc_kernel_shutdown_call - Allow a kernel service to shut down a call it was using * @sock: The socket the call is on * @call: The call to end * * Allow a kernel service to shut down a call it was using. The call must be * complete before this is called (the call should be aborted if necessary).
*/ void rxrpc_kernel_shutdown_call(struct socket *sock, struct rxrpc_call *call)
{
_enter("%d{%d}", call->debug_id, refcount_read(&call->ref));
mutex_lock(&call->user_mutex); if (!test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
rxrpc_release_call(rxrpc_sk(sock->sk), call);
/* Make sure we're not going to call back into a kernel service */ if (call->notify_rx) {
spin_lock_irq(&call->notify_lock);
call->notify_rx = rxrpc_dummy_notify_rx;
spin_unlock_irq(&call->notify_lock);
}
}
mutex_unlock(&call->user_mutex);
}
EXPORT_SYMBOL(rxrpc_kernel_shutdown_call);
/** * rxrpc_kernel_put_call - Release a reference to a call * @sock: The socket the call is on * @call: The call to put * * Drop the application's ref on an rxrpc call.
*/ void rxrpc_kernel_put_call(struct socket *sock, struct rxrpc_call *call)
{
rxrpc_put_call(call, rxrpc_call_put_kernel);
}
EXPORT_SYMBOL(rxrpc_kernel_put_call);
/** * rxrpc_kernel_check_life - Check to see whether a call is still alive * @sock: The socket the call is on * @call: The call to check * * Allow a kernel service to find out whether a call is still alive - whether * it has completed successfully and all received data has been consumed. * * Return: %true if the call is still ongoing and %false if it has completed.
*/ bool rxrpc_kernel_check_life(conststruct socket *sock, conststruct rxrpc_call *call)
{ if (!rxrpc_call_is_complete(call)) returntrue; if (call->completion != RXRPC_CALL_SUCCEEDED) returnfalse; return !skb_queue_empty(&call->recvmsg_queue);
}
EXPORT_SYMBOL(rxrpc_kernel_check_life);
/** * rxrpc_kernel_set_notifications - Set table of callback operations * @sock: The socket to install table upon * @app_ops: Callback operation table to set * * Allow a kernel service to set a table of event notifications on a socket.
*/ void rxrpc_kernel_set_notifications(struct socket *sock, conststruct rxrpc_kernel_ops *app_ops)
{ struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
/* * connect an RxRPC socket * - this just targets it at a specific destination; no actual connection * negotiation takes place
*/ staticint rxrpc_connect(struct socket *sock, struct sockaddr *addr, int addr_len, int flags)
{ struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)addr; struct rxrpc_sock *rx = rxrpc_sk(sock->sk); int ret;
_enter("%p,%p,%d,%d", rx, addr, addr_len, flags);
ret = rxrpc_validate_address(rx, srx, addr_len); if (ret < 0) {
_leave(" = %d [bad addr]", ret); return ret;
}
lock_sock(&rx->sk);
ret = -EISCONN; if (test_bit(RXRPC_SOCK_CONNECTED, &rx->flags)) goto error;
switch (rx->sk.sk_state) { case RXRPC_UNBOUND:
rx->sk.sk_state = RXRPC_CLIENT_UNBOUND; break; case RXRPC_CLIENT_UNBOUND: case RXRPC_CLIENT_BOUND: break; default:
ret = -EBUSY; goto error;
}
rx->connect_srx = *srx;
set_bit(RXRPC_SOCK_CONNECTED, &rx->flags);
ret = 0;
error:
release_sock(&rx->sk); return ret;
}
/* * send a message through an RxRPC socket * - in a client this does a number of things: * - finds/sets up a connection for the security specified (if any) * - initiates a call (ID in control data) * - ends the request phase of a call (if MSG_MORE is not set) * - sends a call data packet * - may send an abort (abort code in control data)
*/ staticint rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
{ struct rxrpc_local *local; struct rxrpc_sock *rx = rxrpc_sk(sock->sk); int ret;
_enter(",{%d},,%zu", rx->sk.sk_state, len);
if (m->msg_flags & MSG_OOB) return -EOPNOTSUPP;
if (m->msg_name) {
ret = rxrpc_validate_address(rx, m->msg_name, m->msg_namelen); if (ret < 0) {
_leave(" = %d [bad addr]", ret); return ret;
}
}
lock_sock(&rx->sk);
switch (rx->sk.sk_state) { case RXRPC_UNBOUND: case RXRPC_CLIENT_UNBOUND:
rx->srx.srx_family = AF_RXRPC;
rx->srx.srx_service = 0;
rx->srx.transport_type = SOCK_DGRAM;
rx->srx.transport.family = rx->family; switch (rx->family) { case AF_INET:
rx->srx.transport_len = sizeof(struct sockaddr_in); break; #ifdef CONFIG_AF_RXRPC_IPV6 case AF_INET6:
rx->srx.transport_len = sizeof(struct sockaddr_in6); break; #endif default:
ret = -EAFNOSUPPORT; goto error_unlock;
}
local = rxrpc_lookup_local(sock_net(sock->sk), &rx->srx); if (IS_ERR(local)) {
ret = PTR_ERR(local); goto error_unlock;
}
case RXRPC_CLIENT_BOUND: if (!m->msg_name &&
test_bit(RXRPC_SOCK_CONNECTED, &rx->flags)) {
m->msg_name = &rx->connect_srx;
m->msg_namelen = sizeof(rx->connect_srx);
}
fallthrough; case RXRPC_SERVER_BOUND: case RXRPC_SERVER_LISTENING: if (m->msg_flags & MSG_OOB)
ret = rxrpc_sendmsg_oob(rx, m, len); else
ret = rxrpc_do_sendmsg(rx, m, len); /* The socket has been unlocked */ goto out; default:
ret = -EINVAL; goto error_unlock;
}
int rxrpc_sock_set_min_security_level(struct sock *sk, unsignedint val)
{ if (sk->sk_state != RXRPC_UNBOUND) return -EISCONN; if (val > RXRPC_SECURITY_MAX) return -EINVAL;
lock_sock(sk);
rxrpc_sk(sk)->min_sec_level = val;
release_sock(sk); return 0;
}
EXPORT_SYMBOL(rxrpc_sock_set_min_security_level);
/* * set RxRPC socket options
*/ staticint rxrpc_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsignedint optlen)
{ struct rxrpc_sock *rx = rxrpc_sk(sock->sk); unsignedint min_sec_level, val;
u16 service_upgrade[2]; int ret;
_enter(",%d,%d,,%d", level, optname, optlen);
lock_sock(&rx->sk);
ret = -EOPNOTSUPP;
if (level == SOL_RXRPC) { switch (optname) { case RXRPC_EXCLUSIVE_CONNECTION:
ret = -EINVAL; if (optlen != 0) goto error;
ret = -EISCONN; if (rx->sk.sk_state != RXRPC_UNBOUND) goto error;
rx->exclusive = true; goto success;
case RXRPC_SECURITY_KEY:
ret = -EINVAL; if (rx->key) goto error;
ret = -EISCONN; if (rx->sk.sk_state != RXRPC_UNBOUND) goto error;
ret = rxrpc_request_key(rx, optval, optlen); goto error;
case RXRPC_SECURITY_KEYRING:
ret = -EINVAL; if (rx->key) goto error;
ret = -EISCONN; if (rx->sk.sk_state != RXRPC_UNBOUND) goto error;
ret = rxrpc_server_keyring(rx, optval, optlen); goto error;
case RXRPC_MIN_SECURITY_LEVEL:
ret = -EINVAL; if (optlen != sizeof(unsignedint)) goto error;
ret = -EISCONN; if (rx->sk.sk_state != RXRPC_UNBOUND) goto error;
ret = copy_safe_from_sockptr(&min_sec_level, sizeof(min_sec_level),
optval, optlen); if (ret) goto error;
ret = -EINVAL; if (min_sec_level > RXRPC_SECURITY_MAX) goto error;
rx->min_sec_level = min_sec_level; goto success;
case RXRPC_UPGRADEABLE_SERVICE:
ret = -EINVAL; if (optlen != sizeof(service_upgrade) ||
rx->service_upgrade.from != 0) goto error;
ret = -EISCONN; if (rx->sk.sk_state != RXRPC_SERVER_BOUND2) goto error;
ret = -EFAULT; if (copy_from_sockptr(service_upgrade, optval, sizeof(service_upgrade)) != 0) goto error;
ret = -EINVAL; if ((service_upgrade[0] != rx->srx.srx_service ||
service_upgrade[1] != rx->second_service) &&
(service_upgrade[0] != rx->second_service ||
service_upgrade[1] != rx->srx.srx_service)) goto error;
rx->service_upgrade.from = service_upgrade[0];
rx->service_upgrade.to = service_upgrade[1]; goto success;
case RXRPC_MANAGE_RESPONSE:
ret = -EINVAL; if (optlen != sizeof(unsignedint)) goto error;
ret = -EISCONN; if (rx->sk.sk_state != RXRPC_UNBOUND) goto error;
ret = copy_safe_from_sockptr(&val, sizeof(val),
optval, optlen); if (ret) goto error;
ret = -EINVAL; if (val > 1) goto error; if (val)
set_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags); else
clear_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags); goto success;
default: break;
}
}
success:
ret = 0;
error:
release_sock(&rx->sk); return ret;
}
/* * Get socket options.
*/ staticint rxrpc_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *_optlen)
{ int optlen;
if (level != SOL_RXRPC) return -EOPNOTSUPP;
if (get_user(optlen, _optlen)) return -EFAULT;
switch (optname) { case RXRPC_SUPPORTED_CMSG: if (optlen < sizeof(int)) return -ETOOSMALL; if (put_user(RXRPC__SUPPORTED - 1, (int __user *)optval) ||
put_user(sizeof(int), _optlen)) return -EFAULT; return 0;
/* the socket is readable if there are any messages waiting on the Rx
* queue */ if (!list_empty(&rx->recvmsg_q))
mask |= EPOLLIN | EPOLLRDNORM;
/* the socket is writable if there is space to add new data to the * socket; there is no guarantee that any particular call in progress
* on the socket may have space in the Tx ACK window */ if (rxrpc_writable(sk))
mask |= EPOLLOUT | EPOLLWRNORM;
return mask;
}
/* * create an RxRPC socket
*/ staticint rxrpc_create(struct net *net, struct socket *sock, int protocol, int kern)
{ struct rxrpc_net *rxnet; struct rxrpc_sock *rx; struct sock *sk;
_enter("%p,%d", sock, protocol);
/* we support transport protocol UDP/UDP6 only */ if (protocol != PF_INET &&
IS_ENABLED(CONFIG_AF_RXRPC_IPV6) && protocol != PF_INET6) return -EPROTONOSUPPORT;
if (sock->type != SOCK_DGRAM) return -ESOCKTNOSUPPORT;
/* * Kill all the calls on a socket and shut it down.
*/ staticint rxrpc_shutdown(struct socket *sock, int flags)
{ struct sock *sk = sock->sk; struct rxrpc_sock *rx = rxrpc_sk(sk); int ret = 0;
_enter("%p,%d", sk, flags);
if (flags != SHUT_RDWR) return -EOPNOTSUPP; if (sk->sk_state == RXRPC_CLOSE) return -ESHUTDOWN;
lock_sock(sk);
if (sk->sk_state < RXRPC_CLOSE) {
spin_lock_irq(&rx->recvmsg_lock);
sk->sk_state = RXRPC_CLOSE;
sk->sk_shutdown = SHUTDOWN_MASK;
spin_unlock_irq(&rx->recvmsg_lock);
} else {
ret = -ESHUTDOWN;
}
/* declare the socket closed for business */
sock_orphan(sk);
sk->sk_shutdown = SHUTDOWN_MASK;
/* We want to kill off all connections from a service socket * as fast as possible because we can't share these; client * sockets, on the other hand, can share an endpoint.
*/ switch (sk->sk_state) { case RXRPC_SERVER_BOUND: case RXRPC_SERVER_BOUND2: case RXRPC_SERVER_LISTENING: case RXRPC_SERVER_LISTEN_DISABLED:
rx->local->service_closed = true; break;
}
/* try to flush out this socket */
rxrpc_discard_prealloc(rx);
rxrpc_release_calls_on_socket(rx);
flush_workqueue(rxrpc_workqueue);
rxrpc_purge_oob_queue(sk);
rxrpc_purge_queue(&sk->sk_receive_queue);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.