// SPDX-License-Identifier: GPL-2.0-or-later /* Out of band message handling (e.g. challenge-response) * * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
struct rxrpc_oob_params {
u64 oob_id; /* ID number of message if reply */
s32 abort_code; enum rxrpc_oob_command command; bool have_oob_id:1;
};
/* * Post an out-of-band message for attention by the socket or kernel service * associated with a reference call.
*/ void rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb)
{ struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_sock *rx; struct sock *sk;
rcu_read_lock();
rx = rcu_dereference(call->socket); if (rx) {
sk = &rx->sk;
spin_lock_irq(&rx->recvmsg_lock);
trace_rxrpc_notify_socket(call->debug_id, sp->hdr.serial); if (rx->app_ops)
rx->app_ops->notify_oob(sk, skb);
}
spin_unlock_irq(&rx->recvmsg_lock); if (!rx->app_ops && !sock_flag(sk, SOCK_DEAD))
sk->sk_data_ready(sk);
}
rcu_read_unlock();
}
/* * Locate the OOB message to respond to by its ID.
*/ staticstruct sk_buff *rxrpc_find_pending_oob(struct rxrpc_sock *rx, u64 oob_id)
{ struct rb_node *p; struct sk_buff *skb;
p = rx->pending_oobq.rb_node; while (p) {
skb = rb_entry(p, struct sk_buff, rbnode);
if (oob_id < skb->skb_mstamp_ns)
p = p->rb_left; elseif (oob_id > skb->skb_mstamp_ns)
p = p->rb_right; else return skb;
}
return NULL;
}
/* * Add an OOB message into the pending-response set. We always assign the next * value from a 64-bit counter to the oob_id, so just assume we're always going * to be on the right-hand edge of the tree and that the counter won't wrap. * The tree is also given a ref to the message.
*/ void rxrpc_add_pending_oob(struct rxrpc_sock *rx, struct sk_buff *skb)
{ struct rb_node **pp = &rx->pending_oobq.rb_node, *p = NULL;
/* * Extract control messages from the sendmsg() control buffer.
*/ staticint rxrpc_sendmsg_oob_cmsg(struct msghdr *msg, struct rxrpc_oob_params *p)
{ struct cmsghdr *cmsg; int len;
if (msg->msg_controllen == 0) return -EINVAL;
for_each_cmsghdr(cmsg, msg) { if (!CMSG_OK(msg, cmsg)) return -EINVAL;
/* * Send an out-of-band message or respond to a received out-of-band message. * - caller gives us the socket lock * - the socket may be either a client socket or a server socket
*/ int rxrpc_sendmsg_oob(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
{ struct rxrpc_oob_params p = {}; int ret;
_enter("");
ret = rxrpc_sendmsg_oob_cmsg(msg, &p); if (ret < 0) goto error_release_sock;
if (p.have_oob_id) return rxrpc_respond_to_oob(rx, &p, msg);
release_sock(&rx->sk);
switch (p.command) { default:
ret = -EINVAL; break;
}
/** * rxrpc_kernel_query_oob - Query the parameters of an out-of-band message * @oob: The message to query * @_peer: Where to return the peer record * @_peer_appdata: The application data attached to a peer record * * Extract useful parameters from an out-of-band message. The source peer * parameters are returned through the argument list and the message type is * returned. * * Return: * * %RXRPC_OOB_CHALLENGE - Challenge wanting a response.
*/ enum rxrpc_oob_type rxrpc_kernel_query_oob(struct sk_buff *oob, struct rxrpc_peer **_peer, unsignedlong *_peer_appdata)
{ struct rxrpc_skb_priv *sp = rxrpc_skb(oob); enum rxrpc_oob_type type = oob->mark;
/** * rxrpc_kernel_dequeue_oob - Dequeue and return the front OOB message * @sock: The socket to query * @_type: Where to return the message type * * Dequeue the front OOB message, if there is one, and return it and * its type. * * Return: The sk_buff representing the OOB message or %NULL if the queue was * empty.
*/ struct sk_buff *rxrpc_kernel_dequeue_oob(struct socket *sock, enum rxrpc_oob_type *_type)
{ struct rxrpc_sock *rx = rxrpc_sk(sock->sk); struct sk_buff *oob;
/** * rxrpc_kernel_free_oob - Free an out-of-band message * @oob: The OOB message to free * * Free an OOB message along with any resources it holds.
*/ void rxrpc_kernel_free_oob(struct sk_buff *oob)
{ struct rxrpc_skb_priv *sp = rxrpc_skb(oob);
switch (oob->mark) { case RXRPC_OOB_CHALLENGE:
rxrpc_put_connection(sp->chall.conn, rxrpc_conn_put_oob); break;
}
/** * rxrpc_kernel_query_challenge - Query the parameters of a challenge * @challenge: The challenge to query * @_peer: Where to return the peer record * @_peer_appdata: The application data attached to a peer record * @_service_id: Where to return the connection service ID * @_security_index: Where to return the connection security index * * Extract useful parameters from a CHALLENGE message.
*/ void rxrpc_kernel_query_challenge(struct sk_buff *challenge, struct rxrpc_peer **_peer, unsignedlong *_peer_appdata,
u16 *_service_id, u8 *_security_index)
{ struct rxrpc_skb_priv *sp = rxrpc_skb(challenge);
/** * rxrpc_kernel_reject_challenge - Allow a kernel service to reject a challenge * @challenge: The challenge to be rejected * @abort_code: The abort code to stick into the ABORT packet * @error: Local error value * @why: Indication as to why. * * Allow a kernel service to reject a challenge by aborting the connection if * it's still in an abortable state. The error is returned so this function * can be used with a return statement. * * Return: The %error parameter.
*/ int rxrpc_kernel_reject_challenge(struct sk_buff *challenge, u32 abort_code, int error, enum rxrpc_abort_reason why)
{ struct rxrpc_skb_priv *sp = rxrpc_skb(challenge);
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.