162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* RxRPC recvmsg() implementation 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2007 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/net.h> 1162306a36Sopenharmony_ci#include <linux/skbuff.h> 1262306a36Sopenharmony_ci#include <linux/export.h> 1362306a36Sopenharmony_ci#include <linux/sched/signal.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <net/sock.h> 1662306a36Sopenharmony_ci#include <net/af_rxrpc.h> 1762306a36Sopenharmony_ci#include "ar-internal.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Post a call for attention by the socket or kernel service. Further 2162306a36Sopenharmony_ci * notifications are suppressed by putting recvmsg_link on a dummy queue. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_civoid rxrpc_notify_socket(struct rxrpc_call *call) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct rxrpc_sock *rx; 2662306a36Sopenharmony_ci struct sock *sk; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci _enter("%d", call->debug_id); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci if (!list_empty(&call->recvmsg_link)) 3162306a36Sopenharmony_ci return; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci rcu_read_lock(); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci rx = rcu_dereference(call->socket); 3662306a36Sopenharmony_ci sk = &rx->sk; 3762306a36Sopenharmony_ci if (rx && sk->sk_state < RXRPC_CLOSE) { 3862306a36Sopenharmony_ci if (call->notify_rx) { 3962306a36Sopenharmony_ci spin_lock(&call->notify_lock); 4062306a36Sopenharmony_ci call->notify_rx(sk, call, call->user_call_ID); 4162306a36Sopenharmony_ci spin_unlock(&call->notify_lock); 4262306a36Sopenharmony_ci } else { 4362306a36Sopenharmony_ci spin_lock(&rx->recvmsg_lock); 4462306a36Sopenharmony_ci if (list_empty(&call->recvmsg_link)) { 4562306a36Sopenharmony_ci rxrpc_get_call(call, rxrpc_call_get_notify_socket); 4662306a36Sopenharmony_ci list_add_tail(&call->recvmsg_link, &rx->recvmsg_q); 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci spin_unlock(&rx->recvmsg_lock); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) { 5162306a36Sopenharmony_ci _debug("call %ps", sk->sk_data_ready); 5262306a36Sopenharmony_ci sk->sk_data_ready(sk); 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci rcu_read_unlock(); 5862306a36Sopenharmony_ci _leave(""); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Pass a call terminating message to userspace. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistatic int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci u32 tmp = 0; 6762306a36Sopenharmony_ci int ret; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci switch (call->completion) { 7062306a36Sopenharmony_ci case RXRPC_CALL_SUCCEEDED: 7162306a36Sopenharmony_ci ret = 0; 7262306a36Sopenharmony_ci if (rxrpc_is_service_call(call)) 7362306a36Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ACK, 0, &tmp); 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci case RXRPC_CALL_REMOTELY_ABORTED: 7662306a36Sopenharmony_ci tmp = call->abort_code; 7762306a36Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ABORT, 4, &tmp); 7862306a36Sopenharmony_ci break; 7962306a36Sopenharmony_ci case RXRPC_CALL_LOCALLY_ABORTED: 8062306a36Sopenharmony_ci tmp = call->abort_code; 8162306a36Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ABORT, 4, &tmp); 8262306a36Sopenharmony_ci break; 8362306a36Sopenharmony_ci case RXRPC_CALL_NETWORK_ERROR: 8462306a36Sopenharmony_ci tmp = -call->error; 8562306a36Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_NET_ERROR, 4, &tmp); 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci case RXRPC_CALL_LOCAL_ERROR: 8862306a36Sopenharmony_ci tmp = -call->error; 8962306a36Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_LOCAL_ERROR, 4, &tmp); 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci default: 9262306a36Sopenharmony_ci pr_err("Invalid terminal call state %u\n", call->completion); 9362306a36Sopenharmony_ci BUG(); 9462306a36Sopenharmony_ci break; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci trace_rxrpc_recvdata(call, rxrpc_recvmsg_terminal, 9862306a36Sopenharmony_ci call->ackr_window - 1, 9962306a36Sopenharmony_ci call->rx_pkt_offset, call->rx_pkt_len, ret); 10062306a36Sopenharmony_ci return ret; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * Discard a packet we've used up and advance the Rx window by one. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cistatic void rxrpc_rotate_rx_window(struct rxrpc_call *call) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct rxrpc_skb_priv *sp; 10962306a36Sopenharmony_ci struct sk_buff *skb; 11062306a36Sopenharmony_ci rxrpc_serial_t serial; 11162306a36Sopenharmony_ci rxrpc_seq_t old_consumed = call->rx_consumed, tseq; 11262306a36Sopenharmony_ci bool last; 11362306a36Sopenharmony_ci int acked; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci _enter("%d", call->debug_id); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci skb = skb_dequeue(&call->recvmsg_queue); 11862306a36Sopenharmony_ci rxrpc_see_skb(skb, rxrpc_skb_see_rotate); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci sp = rxrpc_skb(skb); 12162306a36Sopenharmony_ci tseq = sp->hdr.seq; 12262306a36Sopenharmony_ci serial = sp->hdr.serial; 12362306a36Sopenharmony_ci last = sp->hdr.flags & RXRPC_LAST_PACKET; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* Barrier against rxrpc_input_data(). */ 12662306a36Sopenharmony_ci if (after(tseq, call->rx_consumed)) 12762306a36Sopenharmony_ci smp_store_release(&call->rx_consumed, tseq); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci rxrpc_free_skb(skb, rxrpc_skb_put_rotate); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci trace_rxrpc_receive(call, last ? rxrpc_receive_rotate_last : rxrpc_receive_rotate, 13262306a36Sopenharmony_ci serial, call->rx_consumed); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (last) 13562306a36Sopenharmony_ci set_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Check to see if there's an ACK that needs sending. */ 13862306a36Sopenharmony_ci acked = atomic_add_return(call->rx_consumed - old_consumed, 13962306a36Sopenharmony_ci &call->ackr_nr_consumed); 14062306a36Sopenharmony_ci if (acked > 8 && 14162306a36Sopenharmony_ci !test_and_set_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags)) 14262306a36Sopenharmony_ci rxrpc_poke_call(call, rxrpc_call_poke_idle); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * Decrypt and verify a DATA packet. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic int rxrpc_verify_data(struct rxrpc_call *call, struct sk_buff *skb) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (sp->flags & RXRPC_RX_VERIFIED) 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci return call->security->verify_packet(call, skb); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* 15862306a36Sopenharmony_ci * Deliver messages to a call. This keeps processing packets until the buffer 15962306a36Sopenharmony_ci * is filled and we find either more DATA (returns 0) or the end of the DATA 16062306a36Sopenharmony_ci * (returns 1). If more packets are required, it returns -EAGAIN and if the 16162306a36Sopenharmony_ci * call has failed it returns -EIO. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cistatic int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, 16462306a36Sopenharmony_ci struct msghdr *msg, struct iov_iter *iter, 16562306a36Sopenharmony_ci size_t len, int flags, size_t *_offset) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct rxrpc_skb_priv *sp; 16862306a36Sopenharmony_ci struct sk_buff *skb; 16962306a36Sopenharmony_ci rxrpc_seq_t seq = 0; 17062306a36Sopenharmony_ci size_t remain; 17162306a36Sopenharmony_ci unsigned int rx_pkt_offset, rx_pkt_len; 17262306a36Sopenharmony_ci int copy, ret = -EAGAIN, ret2; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci rx_pkt_offset = call->rx_pkt_offset; 17562306a36Sopenharmony_ci rx_pkt_len = call->rx_pkt_len; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (rxrpc_call_has_failed(call)) { 17862306a36Sopenharmony_ci seq = call->ackr_window - 1; 17962306a36Sopenharmony_ci ret = -EIO; 18062306a36Sopenharmony_ci goto done; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (test_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags)) { 18462306a36Sopenharmony_ci seq = call->ackr_window - 1; 18562306a36Sopenharmony_ci ret = 1; 18662306a36Sopenharmony_ci goto done; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* No one else can be removing stuff from the queue, so we shouldn't 19062306a36Sopenharmony_ci * need the Rx lock to walk it. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci skb = skb_peek(&call->recvmsg_queue); 19362306a36Sopenharmony_ci while (skb) { 19462306a36Sopenharmony_ci rxrpc_see_skb(skb, rxrpc_skb_see_recvmsg); 19562306a36Sopenharmony_ci sp = rxrpc_skb(skb); 19662306a36Sopenharmony_ci seq = sp->hdr.seq; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) 19962306a36Sopenharmony_ci trace_rxrpc_receive(call, rxrpc_receive_front, 20062306a36Sopenharmony_ci sp->hdr.serial, seq); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (msg) 20362306a36Sopenharmony_ci sock_recv_timestamp(msg, sock->sk, skb); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (rx_pkt_offset == 0) { 20662306a36Sopenharmony_ci ret2 = rxrpc_verify_data(call, skb); 20762306a36Sopenharmony_ci trace_rxrpc_recvdata(call, rxrpc_recvmsg_next, seq, 20862306a36Sopenharmony_ci sp->offset, sp->len, ret2); 20962306a36Sopenharmony_ci if (ret2 < 0) { 21062306a36Sopenharmony_ci kdebug("verify = %d", ret2); 21162306a36Sopenharmony_ci ret = ret2; 21262306a36Sopenharmony_ci goto out; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci rx_pkt_offset = sp->offset; 21562306a36Sopenharmony_ci rx_pkt_len = sp->len; 21662306a36Sopenharmony_ci } else { 21762306a36Sopenharmony_ci trace_rxrpc_recvdata(call, rxrpc_recvmsg_cont, seq, 21862306a36Sopenharmony_ci rx_pkt_offset, rx_pkt_len, 0); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* We have to handle short, empty and used-up DATA packets. */ 22262306a36Sopenharmony_ci remain = len - *_offset; 22362306a36Sopenharmony_ci copy = rx_pkt_len; 22462306a36Sopenharmony_ci if (copy > remain) 22562306a36Sopenharmony_ci copy = remain; 22662306a36Sopenharmony_ci if (copy > 0) { 22762306a36Sopenharmony_ci ret2 = skb_copy_datagram_iter(skb, rx_pkt_offset, iter, 22862306a36Sopenharmony_ci copy); 22962306a36Sopenharmony_ci if (ret2 < 0) { 23062306a36Sopenharmony_ci ret = ret2; 23162306a36Sopenharmony_ci goto out; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* handle piecemeal consumption of data packets */ 23562306a36Sopenharmony_ci rx_pkt_offset += copy; 23662306a36Sopenharmony_ci rx_pkt_len -= copy; 23762306a36Sopenharmony_ci *_offset += copy; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (rx_pkt_len > 0) { 24162306a36Sopenharmony_ci trace_rxrpc_recvdata(call, rxrpc_recvmsg_full, seq, 24262306a36Sopenharmony_ci rx_pkt_offset, rx_pkt_len, 0); 24362306a36Sopenharmony_ci ASSERTCMP(*_offset, ==, len); 24462306a36Sopenharmony_ci ret = 0; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* The whole packet has been transferred. */ 24962306a36Sopenharmony_ci if (sp->hdr.flags & RXRPC_LAST_PACKET) 25062306a36Sopenharmony_ci ret = 1; 25162306a36Sopenharmony_ci rx_pkt_offset = 0; 25262306a36Sopenharmony_ci rx_pkt_len = 0; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci skb = skb_peek_next(skb, &call->recvmsg_queue); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) 25762306a36Sopenharmony_ci rxrpc_rotate_rx_window(call); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ciout: 26162306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) { 26262306a36Sopenharmony_ci call->rx_pkt_offset = rx_pkt_offset; 26362306a36Sopenharmony_ci call->rx_pkt_len = rx_pkt_len; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_cidone: 26662306a36Sopenharmony_ci trace_rxrpc_recvdata(call, rxrpc_recvmsg_data_return, seq, 26762306a36Sopenharmony_ci rx_pkt_offset, rx_pkt_len, ret); 26862306a36Sopenharmony_ci if (ret == -EAGAIN) 26962306a36Sopenharmony_ci set_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags); 27062306a36Sopenharmony_ci return ret; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* 27462306a36Sopenharmony_ci * Receive a message from an RxRPC socket 27562306a36Sopenharmony_ci * - we need to be careful about two or more threads calling recvmsg 27662306a36Sopenharmony_ci * simultaneously 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_ciint rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 27962306a36Sopenharmony_ci int flags) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct rxrpc_call *call; 28262306a36Sopenharmony_ci struct rxrpc_sock *rx = rxrpc_sk(sock->sk); 28362306a36Sopenharmony_ci struct list_head *l; 28462306a36Sopenharmony_ci unsigned int call_debug_id = 0; 28562306a36Sopenharmony_ci size_t copied = 0; 28662306a36Sopenharmony_ci long timeo; 28762306a36Sopenharmony_ci int ret; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci DEFINE_WAIT(wait); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci trace_rxrpc_recvmsg(0, rxrpc_recvmsg_enter, 0); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (flags & (MSG_OOB | MSG_TRUNC)) 29462306a36Sopenharmony_ci return -EOPNOTSUPP; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci timeo = sock_rcvtimeo(&rx->sk, flags & MSG_DONTWAIT); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_citry_again: 29962306a36Sopenharmony_ci lock_sock(&rx->sk); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Return immediately if a client socket has no outstanding calls */ 30262306a36Sopenharmony_ci if (RB_EMPTY_ROOT(&rx->calls) && 30362306a36Sopenharmony_ci list_empty(&rx->recvmsg_q) && 30462306a36Sopenharmony_ci rx->sk.sk_state != RXRPC_SERVER_LISTENING) { 30562306a36Sopenharmony_ci release_sock(&rx->sk); 30662306a36Sopenharmony_ci return -EAGAIN; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (list_empty(&rx->recvmsg_q)) { 31062306a36Sopenharmony_ci ret = -EWOULDBLOCK; 31162306a36Sopenharmony_ci if (timeo == 0) { 31262306a36Sopenharmony_ci call = NULL; 31362306a36Sopenharmony_ci goto error_no_call; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci release_sock(&rx->sk); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* Wait for something to happen */ 31962306a36Sopenharmony_ci prepare_to_wait_exclusive(sk_sleep(&rx->sk), &wait, 32062306a36Sopenharmony_ci TASK_INTERRUPTIBLE); 32162306a36Sopenharmony_ci ret = sock_error(&rx->sk); 32262306a36Sopenharmony_ci if (ret) 32362306a36Sopenharmony_ci goto wait_error; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (list_empty(&rx->recvmsg_q)) { 32662306a36Sopenharmony_ci if (signal_pending(current)) 32762306a36Sopenharmony_ci goto wait_interrupted; 32862306a36Sopenharmony_ci trace_rxrpc_recvmsg(0, rxrpc_recvmsg_wait, 0); 32962306a36Sopenharmony_ci timeo = schedule_timeout(timeo); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci finish_wait(sk_sleep(&rx->sk), &wait); 33262306a36Sopenharmony_ci goto try_again; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Find the next call and dequeue it if we're not just peeking. If we 33662306a36Sopenharmony_ci * do dequeue it, that comes with a ref that we will need to release. 33762306a36Sopenharmony_ci * We also want to weed out calls that got requeued whilst we were 33862306a36Sopenharmony_ci * shovelling data out. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci spin_lock(&rx->recvmsg_lock); 34162306a36Sopenharmony_ci l = rx->recvmsg_q.next; 34262306a36Sopenharmony_ci call = list_entry(l, struct rxrpc_call, recvmsg_link); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (!rxrpc_call_is_complete(call) && 34562306a36Sopenharmony_ci skb_queue_empty(&call->recvmsg_queue)) { 34662306a36Sopenharmony_ci list_del_init(&call->recvmsg_link); 34762306a36Sopenharmony_ci spin_unlock(&rx->recvmsg_lock); 34862306a36Sopenharmony_ci release_sock(&rx->sk); 34962306a36Sopenharmony_ci trace_rxrpc_recvmsg(call->debug_id, rxrpc_recvmsg_unqueue, 0); 35062306a36Sopenharmony_ci rxrpc_put_call(call, rxrpc_call_put_recvmsg); 35162306a36Sopenharmony_ci goto try_again; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) 35562306a36Sopenharmony_ci list_del_init(&call->recvmsg_link); 35662306a36Sopenharmony_ci else 35762306a36Sopenharmony_ci rxrpc_get_call(call, rxrpc_call_get_recvmsg); 35862306a36Sopenharmony_ci spin_unlock(&rx->recvmsg_lock); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci call_debug_id = call->debug_id; 36162306a36Sopenharmony_ci trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_dequeue, 0); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* We're going to drop the socket lock, so we need to lock the call 36462306a36Sopenharmony_ci * against interference by sendmsg. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci if (!mutex_trylock(&call->user_mutex)) { 36762306a36Sopenharmony_ci ret = -EWOULDBLOCK; 36862306a36Sopenharmony_ci if (flags & MSG_DONTWAIT) 36962306a36Sopenharmony_ci goto error_requeue_call; 37062306a36Sopenharmony_ci ret = -ERESTARTSYS; 37162306a36Sopenharmony_ci if (mutex_lock_interruptible(&call->user_mutex) < 0) 37262306a36Sopenharmony_ci goto error_requeue_call; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci release_sock(&rx->sk); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) 37862306a36Sopenharmony_ci BUG(); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (test_bit(RXRPC_CALL_HAS_USERID, &call->flags)) { 38162306a36Sopenharmony_ci if (flags & MSG_CMSG_COMPAT) { 38262306a36Sopenharmony_ci unsigned int id32 = call->user_call_ID; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, 38562306a36Sopenharmony_ci sizeof(unsigned int), &id32); 38662306a36Sopenharmony_ci } else { 38762306a36Sopenharmony_ci unsigned long idl = call->user_call_ID; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, 39062306a36Sopenharmony_ci sizeof(unsigned long), &idl); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci if (ret < 0) 39362306a36Sopenharmony_ci goto error_unlock_call; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (msg->msg_name && call->peer) { 39762306a36Sopenharmony_ci size_t len = sizeof(call->dest_srx); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci memcpy(msg->msg_name, &call->dest_srx, len); 40062306a36Sopenharmony_ci msg->msg_namelen = len; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci ret = rxrpc_recvmsg_data(sock, call, msg, &msg->msg_iter, len, 40462306a36Sopenharmony_ci flags, &copied); 40562306a36Sopenharmony_ci if (ret == -EAGAIN) 40662306a36Sopenharmony_ci ret = 0; 40762306a36Sopenharmony_ci if (ret == -EIO) 40862306a36Sopenharmony_ci goto call_failed; 40962306a36Sopenharmony_ci if (ret < 0) 41062306a36Sopenharmony_ci goto error_unlock_call; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (rxrpc_call_is_complete(call) && 41362306a36Sopenharmony_ci skb_queue_empty(&call->recvmsg_queue)) 41462306a36Sopenharmony_ci goto call_complete; 41562306a36Sopenharmony_ci if (rxrpc_call_has_failed(call)) 41662306a36Sopenharmony_ci goto call_failed; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!skb_queue_empty(&call->recvmsg_queue)) 41962306a36Sopenharmony_ci rxrpc_notify_socket(call); 42062306a36Sopenharmony_ci goto not_yet_complete; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cicall_failed: 42362306a36Sopenharmony_ci rxrpc_purge_queue(&call->recvmsg_queue); 42462306a36Sopenharmony_cicall_complete: 42562306a36Sopenharmony_ci ret = rxrpc_recvmsg_term(call, msg); 42662306a36Sopenharmony_ci if (ret < 0) 42762306a36Sopenharmony_ci goto error_unlock_call; 42862306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) 42962306a36Sopenharmony_ci rxrpc_release_call(rx, call); 43062306a36Sopenharmony_ci msg->msg_flags |= MSG_EOR; 43162306a36Sopenharmony_ci ret = 1; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cinot_yet_complete: 43462306a36Sopenharmony_ci if (ret == 0) 43562306a36Sopenharmony_ci msg->msg_flags |= MSG_MORE; 43662306a36Sopenharmony_ci else 43762306a36Sopenharmony_ci msg->msg_flags &= ~MSG_MORE; 43862306a36Sopenharmony_ci ret = copied; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cierror_unlock_call: 44162306a36Sopenharmony_ci mutex_unlock(&call->user_mutex); 44262306a36Sopenharmony_ci rxrpc_put_call(call, rxrpc_call_put_recvmsg); 44362306a36Sopenharmony_ci trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_return, ret); 44462306a36Sopenharmony_ci return ret; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cierror_requeue_call: 44762306a36Sopenharmony_ci if (!(flags & MSG_PEEK)) { 44862306a36Sopenharmony_ci spin_lock(&rx->recvmsg_lock); 44962306a36Sopenharmony_ci list_add(&call->recvmsg_link, &rx->recvmsg_q); 45062306a36Sopenharmony_ci spin_unlock(&rx->recvmsg_lock); 45162306a36Sopenharmony_ci trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_requeue, 0); 45262306a36Sopenharmony_ci } else { 45362306a36Sopenharmony_ci rxrpc_put_call(call, rxrpc_call_put_recvmsg); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_cierror_no_call: 45662306a36Sopenharmony_ci release_sock(&rx->sk); 45762306a36Sopenharmony_cierror_trace: 45862306a36Sopenharmony_ci trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_return, ret); 45962306a36Sopenharmony_ci return ret; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ciwait_interrupted: 46262306a36Sopenharmony_ci ret = sock_intr_errno(timeo); 46362306a36Sopenharmony_ciwait_error: 46462306a36Sopenharmony_ci finish_wait(sk_sleep(&rx->sk), &wait); 46562306a36Sopenharmony_ci call = NULL; 46662306a36Sopenharmony_ci goto error_trace; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/** 47062306a36Sopenharmony_ci * rxrpc_kernel_recv_data - Allow a kernel service to receive data/info 47162306a36Sopenharmony_ci * @sock: The socket that the call exists on 47262306a36Sopenharmony_ci * @call: The call to send data through 47362306a36Sopenharmony_ci * @iter: The buffer to receive into 47462306a36Sopenharmony_ci * @_len: The amount of data we want to receive (decreased on return) 47562306a36Sopenharmony_ci * @want_more: True if more data is expected to be read 47662306a36Sopenharmony_ci * @_abort: Where the abort code is stored if -ECONNABORTED is returned 47762306a36Sopenharmony_ci * @_service: Where to store the actual service ID (may be upgraded) 47862306a36Sopenharmony_ci * 47962306a36Sopenharmony_ci * Allow a kernel service to receive data and pick up information about the 48062306a36Sopenharmony_ci * state of a call. Returns 0 if got what was asked for and there's more 48162306a36Sopenharmony_ci * available, 1 if we got what was asked for and we're at the end of the data 48262306a36Sopenharmony_ci * and -EAGAIN if we need more data. 48362306a36Sopenharmony_ci * 48462306a36Sopenharmony_ci * Note that we may return -EAGAIN to drain empty packets at the end of the 48562306a36Sopenharmony_ci * data, even if we've already copied over the requested data. 48662306a36Sopenharmony_ci * 48762306a36Sopenharmony_ci * *_abort should also be initialised to 0. 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_ciint rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, 49062306a36Sopenharmony_ci struct iov_iter *iter, size_t *_len, 49162306a36Sopenharmony_ci bool want_more, u32 *_abort, u16 *_service) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci size_t offset = 0; 49462306a36Sopenharmony_ci int ret; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci _enter("{%d},%zu,%d", call->debug_id, *_len, want_more); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci mutex_lock(&call->user_mutex); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci ret = rxrpc_recvmsg_data(sock, call, NULL, iter, *_len, 0, &offset); 50162306a36Sopenharmony_ci *_len -= offset; 50262306a36Sopenharmony_ci if (ret == -EIO) 50362306a36Sopenharmony_ci goto call_failed; 50462306a36Sopenharmony_ci if (ret < 0) 50562306a36Sopenharmony_ci goto out; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* We can only reach here with a partially full buffer if we have 50862306a36Sopenharmony_ci * reached the end of the data. We must otherwise have a full buffer 50962306a36Sopenharmony_ci * or have been given -EAGAIN. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci if (ret == 1) { 51262306a36Sopenharmony_ci if (iov_iter_count(iter) > 0) 51362306a36Sopenharmony_ci goto short_data; 51462306a36Sopenharmony_ci if (!want_more) 51562306a36Sopenharmony_ci goto read_phase_complete; 51662306a36Sopenharmony_ci ret = 0; 51762306a36Sopenharmony_ci goto out; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (!want_more) 52162306a36Sopenharmony_ci goto excess_data; 52262306a36Sopenharmony_ci goto out; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ciread_phase_complete: 52562306a36Sopenharmony_ci ret = 1; 52662306a36Sopenharmony_ciout: 52762306a36Sopenharmony_ci if (_service) 52862306a36Sopenharmony_ci *_service = call->dest_srx.srx_service; 52962306a36Sopenharmony_ci mutex_unlock(&call->user_mutex); 53062306a36Sopenharmony_ci _leave(" = %d [%zu,%d]", ret, iov_iter_count(iter), *_abort); 53162306a36Sopenharmony_ci return ret; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cishort_data: 53462306a36Sopenharmony_ci trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_short_data, 53562306a36Sopenharmony_ci call->cid, call->call_id, call->rx_consumed, 53662306a36Sopenharmony_ci 0, -EBADMSG); 53762306a36Sopenharmony_ci ret = -EBADMSG; 53862306a36Sopenharmony_ci goto out; 53962306a36Sopenharmony_ciexcess_data: 54062306a36Sopenharmony_ci trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_excess_data, 54162306a36Sopenharmony_ci call->cid, call->call_id, call->rx_consumed, 54262306a36Sopenharmony_ci 0, -EMSGSIZE); 54362306a36Sopenharmony_ci ret = -EMSGSIZE; 54462306a36Sopenharmony_ci goto out; 54562306a36Sopenharmony_cicall_failed: 54662306a36Sopenharmony_ci *_abort = call->abort_code; 54762306a36Sopenharmony_ci ret = call->error; 54862306a36Sopenharmony_ci if (call->completion == RXRPC_CALL_SUCCEEDED) { 54962306a36Sopenharmony_ci ret = 1; 55062306a36Sopenharmony_ci if (iov_iter_count(iter) > 0) 55162306a36Sopenharmony_ci ret = -ECONNRESET; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci goto out; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_recv_data); 556