18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* RxRPC recvmsg() 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/net.h> 118c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 128c2ecf20Sopenharmony_ci#include <linux/export.h> 138c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <net/sock.h> 168c2ecf20Sopenharmony_ci#include <net/af_rxrpc.h> 178c2ecf20Sopenharmony_ci#include "ar-internal.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Post a call for attention by the socket or kernel service. Further 218c2ecf20Sopenharmony_ci * notifications are suppressed by putting recvmsg_link on a dummy queue. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_civoid rxrpc_notify_socket(struct rxrpc_call *call) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct rxrpc_sock *rx; 268c2ecf20Sopenharmony_ci struct sock *sk; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci _enter("%d", call->debug_id); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (!list_empty(&call->recvmsg_link)) 318c2ecf20Sopenharmony_ci return; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci rcu_read_lock(); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci rx = rcu_dereference(call->socket); 368c2ecf20Sopenharmony_ci sk = &rx->sk; 378c2ecf20Sopenharmony_ci if (rx && sk->sk_state < RXRPC_CLOSE) { 388c2ecf20Sopenharmony_ci if (call->notify_rx) { 398c2ecf20Sopenharmony_ci spin_lock_bh(&call->notify_lock); 408c2ecf20Sopenharmony_ci call->notify_rx(sk, call, call->user_call_ID); 418c2ecf20Sopenharmony_ci spin_unlock_bh(&call->notify_lock); 428c2ecf20Sopenharmony_ci } else { 438c2ecf20Sopenharmony_ci write_lock_bh(&rx->recvmsg_lock); 448c2ecf20Sopenharmony_ci if (list_empty(&call->recvmsg_link)) { 458c2ecf20Sopenharmony_ci rxrpc_get_call(call, rxrpc_call_got); 468c2ecf20Sopenharmony_ci list_add_tail(&call->recvmsg_link, &rx->recvmsg_q); 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci write_unlock_bh(&rx->recvmsg_lock); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) { 518c2ecf20Sopenharmony_ci _debug("call %ps", sk->sk_data_ready); 528c2ecf20Sopenharmony_ci sk->sk_data_ready(sk); 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci rcu_read_unlock(); 588c2ecf20Sopenharmony_ci _leave(""); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * Transition a call to the complete state. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cibool __rxrpc_set_call_completion(struct rxrpc_call *call, 658c2ecf20Sopenharmony_ci enum rxrpc_call_completion compl, 668c2ecf20Sopenharmony_ci u32 abort_code, 678c2ecf20Sopenharmony_ci int error) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci if (call->state < RXRPC_CALL_COMPLETE) { 708c2ecf20Sopenharmony_ci call->abort_code = abort_code; 718c2ecf20Sopenharmony_ci call->error = error; 728c2ecf20Sopenharmony_ci call->completion = compl, 738c2ecf20Sopenharmony_ci call->state = RXRPC_CALL_COMPLETE; 748c2ecf20Sopenharmony_ci trace_rxrpc_call_complete(call); 758c2ecf20Sopenharmony_ci wake_up(&call->waitq); 768c2ecf20Sopenharmony_ci rxrpc_notify_socket(call); 778c2ecf20Sopenharmony_ci return true; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci return false; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cibool rxrpc_set_call_completion(struct rxrpc_call *call, 838c2ecf20Sopenharmony_ci enum rxrpc_call_completion compl, 848c2ecf20Sopenharmony_ci u32 abort_code, 858c2ecf20Sopenharmony_ci int error) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci bool ret = false; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (call->state < RXRPC_CALL_COMPLETE) { 908c2ecf20Sopenharmony_ci write_lock_bh(&call->state_lock); 918c2ecf20Sopenharmony_ci ret = __rxrpc_set_call_completion(call, compl, abort_code, error); 928c2ecf20Sopenharmony_ci write_unlock_bh(&call->state_lock); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci return ret; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* 988c2ecf20Sopenharmony_ci * Record that a call successfully completed. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_cibool __rxrpc_call_completed(struct rxrpc_call *call) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci return __rxrpc_set_call_completion(call, RXRPC_CALL_SUCCEEDED, 0, 0); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cibool rxrpc_call_completed(struct rxrpc_call *call) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci bool ret = false; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (call->state < RXRPC_CALL_COMPLETE) { 1108c2ecf20Sopenharmony_ci write_lock_bh(&call->state_lock); 1118c2ecf20Sopenharmony_ci ret = __rxrpc_call_completed(call); 1128c2ecf20Sopenharmony_ci write_unlock_bh(&call->state_lock); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci return ret; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* 1188c2ecf20Sopenharmony_ci * Record that a call is locally aborted. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_cibool __rxrpc_abort_call(const char *why, struct rxrpc_call *call, 1218c2ecf20Sopenharmony_ci rxrpc_seq_t seq, u32 abort_code, int error) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci trace_rxrpc_abort(call->debug_id, why, call->cid, call->call_id, seq, 1248c2ecf20Sopenharmony_ci abort_code, error); 1258c2ecf20Sopenharmony_ci return __rxrpc_set_call_completion(call, RXRPC_CALL_LOCALLY_ABORTED, 1268c2ecf20Sopenharmony_ci abort_code, error); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cibool rxrpc_abort_call(const char *why, struct rxrpc_call *call, 1308c2ecf20Sopenharmony_ci rxrpc_seq_t seq, u32 abort_code, int error) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci bool ret; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci write_lock_bh(&call->state_lock); 1358c2ecf20Sopenharmony_ci ret = __rxrpc_abort_call(why, call, seq, abort_code, error); 1368c2ecf20Sopenharmony_ci write_unlock_bh(&call->state_lock); 1378c2ecf20Sopenharmony_ci return ret; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* 1418c2ecf20Sopenharmony_ci * Pass a call terminating message to userspace. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci u32 tmp = 0; 1468c2ecf20Sopenharmony_ci int ret; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci switch (call->completion) { 1498c2ecf20Sopenharmony_ci case RXRPC_CALL_SUCCEEDED: 1508c2ecf20Sopenharmony_ci ret = 0; 1518c2ecf20Sopenharmony_ci if (rxrpc_is_service_call(call)) 1528c2ecf20Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ACK, 0, &tmp); 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci case RXRPC_CALL_REMOTELY_ABORTED: 1558c2ecf20Sopenharmony_ci tmp = call->abort_code; 1568c2ecf20Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ABORT, 4, &tmp); 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci case RXRPC_CALL_LOCALLY_ABORTED: 1598c2ecf20Sopenharmony_ci tmp = call->abort_code; 1608c2ecf20Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ABORT, 4, &tmp); 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci case RXRPC_CALL_NETWORK_ERROR: 1638c2ecf20Sopenharmony_ci tmp = -call->error; 1648c2ecf20Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_NET_ERROR, 4, &tmp); 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci case RXRPC_CALL_LOCAL_ERROR: 1678c2ecf20Sopenharmony_ci tmp = -call->error; 1688c2ecf20Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_LOCAL_ERROR, 4, &tmp); 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci default: 1718c2ecf20Sopenharmony_ci pr_err("Invalid terminal call state %u\n", call->state); 1728c2ecf20Sopenharmony_ci BUG(); 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_terminal, call->rx_hard_ack, 1778c2ecf20Sopenharmony_ci call->rx_pkt_offset, call->rx_pkt_len, ret); 1788c2ecf20Sopenharmony_ci return ret; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * End the packet reception phase. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistatic void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci _enter("%d,%s", call->debug_id, rxrpc_call_states[call->state]); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci trace_rxrpc_receive(call, rxrpc_receive_end, 0, call->rx_top); 1898c2ecf20Sopenharmony_ci ASSERTCMP(call->rx_hard_ack, ==, call->rx_top); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY) { 1928c2ecf20Sopenharmony_ci rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, serial, false, true, 1938c2ecf20Sopenharmony_ci rxrpc_propose_ack_terminal_ack); 1948c2ecf20Sopenharmony_ci //rxrpc_send_ack_packet(call, false, NULL); 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci write_lock_bh(&call->state_lock); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci switch (call->state) { 2008c2ecf20Sopenharmony_ci case RXRPC_CALL_CLIENT_RECV_REPLY: 2018c2ecf20Sopenharmony_ci __rxrpc_call_completed(call); 2028c2ecf20Sopenharmony_ci write_unlock_bh(&call->state_lock); 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_RECV_REQUEST: 2068c2ecf20Sopenharmony_ci call->tx_phase = true; 2078c2ecf20Sopenharmony_ci call->state = RXRPC_CALL_SERVER_ACK_REQUEST; 2088c2ecf20Sopenharmony_ci call->expect_req_by = jiffies + MAX_JIFFY_OFFSET; 2098c2ecf20Sopenharmony_ci write_unlock_bh(&call->state_lock); 2108c2ecf20Sopenharmony_ci rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial, false, true, 2118c2ecf20Sopenharmony_ci rxrpc_propose_ack_processing_op); 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci default: 2148c2ecf20Sopenharmony_ci write_unlock_bh(&call->state_lock); 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* 2208c2ecf20Sopenharmony_ci * Discard a packet we've used up and advance the Rx window by one. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_cistatic void rxrpc_rotate_rx_window(struct rxrpc_call *call) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct rxrpc_skb_priv *sp; 2258c2ecf20Sopenharmony_ci struct sk_buff *skb; 2268c2ecf20Sopenharmony_ci rxrpc_serial_t serial; 2278c2ecf20Sopenharmony_ci rxrpc_seq_t hard_ack, top; 2288c2ecf20Sopenharmony_ci bool last = false; 2298c2ecf20Sopenharmony_ci u8 subpacket; 2308c2ecf20Sopenharmony_ci int ix; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci _enter("%d", call->debug_id); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci hard_ack = call->rx_hard_ack; 2358c2ecf20Sopenharmony_ci top = smp_load_acquire(&call->rx_top); 2368c2ecf20Sopenharmony_ci ASSERT(before(hard_ack, top)); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci hard_ack++; 2398c2ecf20Sopenharmony_ci ix = hard_ack & RXRPC_RXTX_BUFF_MASK; 2408c2ecf20Sopenharmony_ci skb = call->rxtx_buffer[ix]; 2418c2ecf20Sopenharmony_ci rxrpc_see_skb(skb, rxrpc_skb_rotated); 2428c2ecf20Sopenharmony_ci sp = rxrpc_skb(skb); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci subpacket = call->rxtx_annotations[ix] & RXRPC_RX_ANNO_SUBPACKET; 2458c2ecf20Sopenharmony_ci serial = sp->hdr.serial + subpacket; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (subpacket == sp->nr_subpackets - 1 && 2488c2ecf20Sopenharmony_ci sp->rx_flags & RXRPC_SKB_INCL_LAST) 2498c2ecf20Sopenharmony_ci last = true; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci call->rxtx_buffer[ix] = NULL; 2528c2ecf20Sopenharmony_ci call->rxtx_annotations[ix] = 0; 2538c2ecf20Sopenharmony_ci /* Barrier against rxrpc_input_data(). */ 2548c2ecf20Sopenharmony_ci smp_store_release(&call->rx_hard_ack, hard_ack); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci rxrpc_free_skb(skb, rxrpc_skb_freed); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci trace_rxrpc_receive(call, rxrpc_receive_rotate, serial, hard_ack); 2598c2ecf20Sopenharmony_ci if (last) { 2608c2ecf20Sopenharmony_ci rxrpc_end_rx_phase(call, serial); 2618c2ecf20Sopenharmony_ci } else { 2628c2ecf20Sopenharmony_ci /* Check to see if there's an ACK that needs sending. */ 2638c2ecf20Sopenharmony_ci if (atomic_inc_return(&call->ackr_nr_consumed) > 2) 2648c2ecf20Sopenharmony_ci rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, serial, 2658c2ecf20Sopenharmony_ci true, false, 2668c2ecf20Sopenharmony_ci rxrpc_propose_ack_rotate_rx); 2678c2ecf20Sopenharmony_ci if (call->ackr_reason && call->ackr_reason != RXRPC_ACK_DELAY) 2688c2ecf20Sopenharmony_ci rxrpc_send_ack_packet(call, false, NULL); 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* 2738c2ecf20Sopenharmony_ci * Decrypt and verify a (sub)packet. The packet's length may be changed due to 2748c2ecf20Sopenharmony_ci * padding, but if this is the case, the packet length will be resident in the 2758c2ecf20Sopenharmony_ci * socket buffer. Note that we can't modify the master skb info as the skb may 2768c2ecf20Sopenharmony_ci * be the home to multiple subpackets. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_cistatic int rxrpc_verify_packet(struct rxrpc_call *call, struct sk_buff *skb, 2798c2ecf20Sopenharmony_ci u8 annotation, 2808c2ecf20Sopenharmony_ci unsigned int offset, unsigned int len) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 2838c2ecf20Sopenharmony_ci rxrpc_seq_t seq = sp->hdr.seq; 2848c2ecf20Sopenharmony_ci u16 cksum = sp->hdr.cksum; 2858c2ecf20Sopenharmony_ci u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci _enter(""); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* For all but the head jumbo subpacket, the security checksum is in a 2908c2ecf20Sopenharmony_ci * jumbo header immediately prior to the data. 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_ci if (subpacket > 0) { 2938c2ecf20Sopenharmony_ci __be16 tmp; 2948c2ecf20Sopenharmony_ci if (skb_copy_bits(skb, offset - 2, &tmp, 2) < 0) 2958c2ecf20Sopenharmony_ci BUG(); 2968c2ecf20Sopenharmony_ci cksum = ntohs(tmp); 2978c2ecf20Sopenharmony_ci seq += subpacket; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return call->security->verify_packet(call, skb, offset, len, 3018c2ecf20Sopenharmony_ci seq, cksum); 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/* 3058c2ecf20Sopenharmony_ci * Locate the data within a packet. This is complicated by: 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * (1) An skb may contain a jumbo packet - so we have to find the appropriate 3088c2ecf20Sopenharmony_ci * subpacket. 3098c2ecf20Sopenharmony_ci * 3108c2ecf20Sopenharmony_ci * (2) The (sub)packets may be encrypted and, if so, the encrypted portion 3118c2ecf20Sopenharmony_ci * contains an extra header which includes the true length of the data, 3128c2ecf20Sopenharmony_ci * excluding any encrypted padding. 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_cistatic int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb, 3158c2ecf20Sopenharmony_ci u8 *_annotation, 3168c2ecf20Sopenharmony_ci unsigned int *_offset, unsigned int *_len, 3178c2ecf20Sopenharmony_ci bool *_last) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 3208c2ecf20Sopenharmony_ci unsigned int offset = sizeof(struct rxrpc_wire_header); 3218c2ecf20Sopenharmony_ci unsigned int len; 3228c2ecf20Sopenharmony_ci bool last = false; 3238c2ecf20Sopenharmony_ci int ret; 3248c2ecf20Sopenharmony_ci u8 annotation = *_annotation; 3258c2ecf20Sopenharmony_ci u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Locate the subpacket */ 3288c2ecf20Sopenharmony_ci offset += subpacket * RXRPC_JUMBO_SUBPKTLEN; 3298c2ecf20Sopenharmony_ci len = skb->len - offset; 3308c2ecf20Sopenharmony_ci if (subpacket < sp->nr_subpackets - 1) 3318c2ecf20Sopenharmony_ci len = RXRPC_JUMBO_DATALEN; 3328c2ecf20Sopenharmony_ci else if (sp->rx_flags & RXRPC_SKB_INCL_LAST) 3338c2ecf20Sopenharmony_ci last = true; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (!(annotation & RXRPC_RX_ANNO_VERIFIED)) { 3368c2ecf20Sopenharmony_ci ret = rxrpc_verify_packet(call, skb, annotation, offset, len); 3378c2ecf20Sopenharmony_ci if (ret < 0) 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci *_annotation |= RXRPC_RX_ANNO_VERIFIED; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci *_offset = offset; 3438c2ecf20Sopenharmony_ci *_len = len; 3448c2ecf20Sopenharmony_ci *_last = last; 3458c2ecf20Sopenharmony_ci call->security->locate_data(call, skb, _offset, _len); 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* 3508c2ecf20Sopenharmony_ci * Deliver messages to a call. This keeps processing packets until the buffer 3518c2ecf20Sopenharmony_ci * is filled and we find either more DATA (returns 0) or the end of the DATA 3528c2ecf20Sopenharmony_ci * (returns 1). If more packets are required, it returns -EAGAIN. 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_cistatic int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, 3558c2ecf20Sopenharmony_ci struct msghdr *msg, struct iov_iter *iter, 3568c2ecf20Sopenharmony_ci size_t len, int flags, size_t *_offset) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct rxrpc_skb_priv *sp; 3598c2ecf20Sopenharmony_ci struct sk_buff *skb; 3608c2ecf20Sopenharmony_ci rxrpc_serial_t serial; 3618c2ecf20Sopenharmony_ci rxrpc_seq_t hard_ack, top, seq; 3628c2ecf20Sopenharmony_ci size_t remain; 3638c2ecf20Sopenharmony_ci bool rx_pkt_last; 3648c2ecf20Sopenharmony_ci unsigned int rx_pkt_offset, rx_pkt_len; 3658c2ecf20Sopenharmony_ci int ix, copy, ret = -EAGAIN, ret2; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (test_and_clear_bit(RXRPC_CALL_RX_UNDERRUN, &call->flags) && 3688c2ecf20Sopenharmony_ci call->ackr_reason) 3698c2ecf20Sopenharmony_ci rxrpc_send_ack_packet(call, false, NULL); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci rx_pkt_offset = call->rx_pkt_offset; 3728c2ecf20Sopenharmony_ci rx_pkt_len = call->rx_pkt_len; 3738c2ecf20Sopenharmony_ci rx_pkt_last = call->rx_pkt_last; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (call->state >= RXRPC_CALL_SERVER_ACK_REQUEST) { 3768c2ecf20Sopenharmony_ci seq = call->rx_hard_ack; 3778c2ecf20Sopenharmony_ci ret = 1; 3788c2ecf20Sopenharmony_ci goto done; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Barriers against rxrpc_input_data(). */ 3828c2ecf20Sopenharmony_ci hard_ack = call->rx_hard_ack; 3838c2ecf20Sopenharmony_ci seq = hard_ack + 1; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci while (top = smp_load_acquire(&call->rx_top), 3868c2ecf20Sopenharmony_ci before_eq(seq, top) 3878c2ecf20Sopenharmony_ci ) { 3888c2ecf20Sopenharmony_ci ix = seq & RXRPC_RXTX_BUFF_MASK; 3898c2ecf20Sopenharmony_ci skb = call->rxtx_buffer[ix]; 3908c2ecf20Sopenharmony_ci if (!skb) { 3918c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_hole, seq, 3928c2ecf20Sopenharmony_ci rx_pkt_offset, rx_pkt_len, 0); 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci smp_rmb(); 3968c2ecf20Sopenharmony_ci rxrpc_see_skb(skb, rxrpc_skb_seen); 3978c2ecf20Sopenharmony_ci sp = rxrpc_skb(skb); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (!(flags & MSG_PEEK)) { 4008c2ecf20Sopenharmony_ci serial = sp->hdr.serial; 4018c2ecf20Sopenharmony_ci serial += call->rxtx_annotations[ix] & RXRPC_RX_ANNO_SUBPACKET; 4028c2ecf20Sopenharmony_ci trace_rxrpc_receive(call, rxrpc_receive_front, 4038c2ecf20Sopenharmony_ci serial, seq); 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (msg) 4078c2ecf20Sopenharmony_ci sock_recv_timestamp(msg, sock->sk, skb); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (rx_pkt_offset == 0) { 4108c2ecf20Sopenharmony_ci ret2 = rxrpc_locate_data(call, skb, 4118c2ecf20Sopenharmony_ci &call->rxtx_annotations[ix], 4128c2ecf20Sopenharmony_ci &rx_pkt_offset, &rx_pkt_len, 4138c2ecf20Sopenharmony_ci &rx_pkt_last); 4148c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_next, seq, 4158c2ecf20Sopenharmony_ci rx_pkt_offset, rx_pkt_len, ret2); 4168c2ecf20Sopenharmony_ci if (ret2 < 0) { 4178c2ecf20Sopenharmony_ci ret = ret2; 4188c2ecf20Sopenharmony_ci goto out; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci } else { 4218c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_cont, seq, 4228c2ecf20Sopenharmony_ci rx_pkt_offset, rx_pkt_len, 0); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* We have to handle short, empty and used-up DATA packets. */ 4268c2ecf20Sopenharmony_ci remain = len - *_offset; 4278c2ecf20Sopenharmony_ci copy = rx_pkt_len; 4288c2ecf20Sopenharmony_ci if (copy > remain) 4298c2ecf20Sopenharmony_ci copy = remain; 4308c2ecf20Sopenharmony_ci if (copy > 0) { 4318c2ecf20Sopenharmony_ci ret2 = skb_copy_datagram_iter(skb, rx_pkt_offset, iter, 4328c2ecf20Sopenharmony_ci copy); 4338c2ecf20Sopenharmony_ci if (ret2 < 0) { 4348c2ecf20Sopenharmony_ci ret = ret2; 4358c2ecf20Sopenharmony_ci goto out; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* handle piecemeal consumption of data packets */ 4398c2ecf20Sopenharmony_ci rx_pkt_offset += copy; 4408c2ecf20Sopenharmony_ci rx_pkt_len -= copy; 4418c2ecf20Sopenharmony_ci *_offset += copy; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (rx_pkt_len > 0) { 4458c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_full, seq, 4468c2ecf20Sopenharmony_ci rx_pkt_offset, rx_pkt_len, 0); 4478c2ecf20Sopenharmony_ci ASSERTCMP(*_offset, ==, len); 4488c2ecf20Sopenharmony_ci ret = 0; 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* The whole packet has been transferred. */ 4538c2ecf20Sopenharmony_ci if (!(flags & MSG_PEEK)) 4548c2ecf20Sopenharmony_ci rxrpc_rotate_rx_window(call); 4558c2ecf20Sopenharmony_ci rx_pkt_offset = 0; 4568c2ecf20Sopenharmony_ci rx_pkt_len = 0; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (rx_pkt_last) { 4598c2ecf20Sopenharmony_ci ASSERTCMP(seq, ==, READ_ONCE(call->rx_top)); 4608c2ecf20Sopenharmony_ci ret = 1; 4618c2ecf20Sopenharmony_ci goto out; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci seq++; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ciout: 4688c2ecf20Sopenharmony_ci if (!(flags & MSG_PEEK)) { 4698c2ecf20Sopenharmony_ci call->rx_pkt_offset = rx_pkt_offset; 4708c2ecf20Sopenharmony_ci call->rx_pkt_len = rx_pkt_len; 4718c2ecf20Sopenharmony_ci call->rx_pkt_last = rx_pkt_last; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_cidone: 4748c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_data_return, seq, 4758c2ecf20Sopenharmony_ci rx_pkt_offset, rx_pkt_len, ret); 4768c2ecf20Sopenharmony_ci if (ret == -EAGAIN) 4778c2ecf20Sopenharmony_ci set_bit(RXRPC_CALL_RX_UNDERRUN, &call->flags); 4788c2ecf20Sopenharmony_ci return ret; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/* 4828c2ecf20Sopenharmony_ci * Receive a message from an RxRPC socket 4838c2ecf20Sopenharmony_ci * - we need to be careful about two or more threads calling recvmsg 4848c2ecf20Sopenharmony_ci * simultaneously 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_ciint rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 4878c2ecf20Sopenharmony_ci int flags) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct rxrpc_call *call; 4908c2ecf20Sopenharmony_ci struct rxrpc_sock *rx = rxrpc_sk(sock->sk); 4918c2ecf20Sopenharmony_ci struct list_head *l; 4928c2ecf20Sopenharmony_ci size_t copied = 0; 4938c2ecf20Sopenharmony_ci long timeo; 4948c2ecf20Sopenharmony_ci int ret; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(NULL, rxrpc_recvmsg_enter, 0, 0, 0, 0); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (flags & (MSG_OOB | MSG_TRUNC)) 5018c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci timeo = sock_rcvtimeo(&rx->sk, flags & MSG_DONTWAIT); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_citry_again: 5068c2ecf20Sopenharmony_ci lock_sock(&rx->sk); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* Return immediately if a client socket has no outstanding calls */ 5098c2ecf20Sopenharmony_ci if (RB_EMPTY_ROOT(&rx->calls) && 5108c2ecf20Sopenharmony_ci list_empty(&rx->recvmsg_q) && 5118c2ecf20Sopenharmony_ci rx->sk.sk_state != RXRPC_SERVER_LISTENING) { 5128c2ecf20Sopenharmony_ci release_sock(&rx->sk); 5138c2ecf20Sopenharmony_ci return -EAGAIN; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (list_empty(&rx->recvmsg_q)) { 5178c2ecf20Sopenharmony_ci ret = -EWOULDBLOCK; 5188c2ecf20Sopenharmony_ci if (timeo == 0) { 5198c2ecf20Sopenharmony_ci call = NULL; 5208c2ecf20Sopenharmony_ci goto error_no_call; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci release_sock(&rx->sk); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* Wait for something to happen */ 5268c2ecf20Sopenharmony_ci prepare_to_wait_exclusive(sk_sleep(&rx->sk), &wait, 5278c2ecf20Sopenharmony_ci TASK_INTERRUPTIBLE); 5288c2ecf20Sopenharmony_ci ret = sock_error(&rx->sk); 5298c2ecf20Sopenharmony_ci if (ret) 5308c2ecf20Sopenharmony_ci goto wait_error; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (list_empty(&rx->recvmsg_q)) { 5338c2ecf20Sopenharmony_ci if (signal_pending(current)) 5348c2ecf20Sopenharmony_ci goto wait_interrupted; 5358c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(NULL, rxrpc_recvmsg_wait, 5368c2ecf20Sopenharmony_ci 0, 0, 0, 0); 5378c2ecf20Sopenharmony_ci timeo = schedule_timeout(timeo); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci finish_wait(sk_sleep(&rx->sk), &wait); 5408c2ecf20Sopenharmony_ci goto try_again; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Find the next call and dequeue it if we're not just peeking. If we 5448c2ecf20Sopenharmony_ci * do dequeue it, that comes with a ref that we will need to release. 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_ci write_lock_bh(&rx->recvmsg_lock); 5478c2ecf20Sopenharmony_ci l = rx->recvmsg_q.next; 5488c2ecf20Sopenharmony_ci call = list_entry(l, struct rxrpc_call, recvmsg_link); 5498c2ecf20Sopenharmony_ci if (!(flags & MSG_PEEK)) 5508c2ecf20Sopenharmony_ci list_del_init(&call->recvmsg_link); 5518c2ecf20Sopenharmony_ci else 5528c2ecf20Sopenharmony_ci rxrpc_get_call(call, rxrpc_call_got); 5538c2ecf20Sopenharmony_ci write_unlock_bh(&rx->recvmsg_lock); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_dequeue, 0, 0, 0, 0); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* We're going to drop the socket lock, so we need to lock the call 5588c2ecf20Sopenharmony_ci * against interference by sendmsg. 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci if (!mutex_trylock(&call->user_mutex)) { 5618c2ecf20Sopenharmony_ci ret = -EWOULDBLOCK; 5628c2ecf20Sopenharmony_ci if (flags & MSG_DONTWAIT) 5638c2ecf20Sopenharmony_ci goto error_requeue_call; 5648c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 5658c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&call->user_mutex) < 0) 5668c2ecf20Sopenharmony_ci goto error_requeue_call; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci release_sock(&rx->sk); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) 5728c2ecf20Sopenharmony_ci BUG(); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (test_bit(RXRPC_CALL_HAS_USERID, &call->flags)) { 5758c2ecf20Sopenharmony_ci if (flags & MSG_CMSG_COMPAT) { 5768c2ecf20Sopenharmony_ci unsigned int id32 = call->user_call_ID; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, 5798c2ecf20Sopenharmony_ci sizeof(unsigned int), &id32); 5808c2ecf20Sopenharmony_ci } else { 5818c2ecf20Sopenharmony_ci unsigned long idl = call->user_call_ID; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, 5848c2ecf20Sopenharmony_ci sizeof(unsigned long), &idl); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci if (ret < 0) 5878c2ecf20Sopenharmony_ci goto error_unlock_call; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (msg->msg_name && call->peer) { 5918c2ecf20Sopenharmony_ci struct sockaddr_rxrpc *srx = msg->msg_name; 5928c2ecf20Sopenharmony_ci size_t len = sizeof(call->peer->srx); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci memcpy(msg->msg_name, &call->peer->srx, len); 5958c2ecf20Sopenharmony_ci srx->srx_service = call->service_id; 5968c2ecf20Sopenharmony_ci msg->msg_namelen = len; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci switch (READ_ONCE(call->state)) { 6008c2ecf20Sopenharmony_ci case RXRPC_CALL_CLIENT_RECV_REPLY: 6018c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_RECV_REQUEST: 6028c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_ACK_REQUEST: 6038c2ecf20Sopenharmony_ci ret = rxrpc_recvmsg_data(sock, call, msg, &msg->msg_iter, len, 6048c2ecf20Sopenharmony_ci flags, &copied); 6058c2ecf20Sopenharmony_ci if (ret == -EAGAIN) 6068c2ecf20Sopenharmony_ci ret = 0; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (after(call->rx_top, call->rx_hard_ack) && 6098c2ecf20Sopenharmony_ci call->rxtx_buffer[(call->rx_hard_ack + 1) & RXRPC_RXTX_BUFF_MASK]) 6108c2ecf20Sopenharmony_ci rxrpc_notify_socket(call); 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci default: 6138c2ecf20Sopenharmony_ci ret = 0; 6148c2ecf20Sopenharmony_ci break; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (ret < 0) 6188c2ecf20Sopenharmony_ci goto error_unlock_call; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (call->state == RXRPC_CALL_COMPLETE) { 6218c2ecf20Sopenharmony_ci ret = rxrpc_recvmsg_term(call, msg); 6228c2ecf20Sopenharmony_ci if (ret < 0) 6238c2ecf20Sopenharmony_ci goto error_unlock_call; 6248c2ecf20Sopenharmony_ci if (!(flags & MSG_PEEK)) 6258c2ecf20Sopenharmony_ci rxrpc_release_call(rx, call); 6268c2ecf20Sopenharmony_ci msg->msg_flags |= MSG_EOR; 6278c2ecf20Sopenharmony_ci ret = 1; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (ret == 0) 6318c2ecf20Sopenharmony_ci msg->msg_flags |= MSG_MORE; 6328c2ecf20Sopenharmony_ci else 6338c2ecf20Sopenharmony_ci msg->msg_flags &= ~MSG_MORE; 6348c2ecf20Sopenharmony_ci ret = copied; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cierror_unlock_call: 6378c2ecf20Sopenharmony_ci mutex_unlock(&call->user_mutex); 6388c2ecf20Sopenharmony_ci rxrpc_put_call(call, rxrpc_call_put); 6398c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_return, 0, 0, 0, ret); 6408c2ecf20Sopenharmony_ci return ret; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cierror_requeue_call: 6438c2ecf20Sopenharmony_ci if (!(flags & MSG_PEEK)) { 6448c2ecf20Sopenharmony_ci write_lock_bh(&rx->recvmsg_lock); 6458c2ecf20Sopenharmony_ci list_add(&call->recvmsg_link, &rx->recvmsg_q); 6468c2ecf20Sopenharmony_ci write_unlock_bh(&rx->recvmsg_lock); 6478c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_requeue, 0, 0, 0, 0); 6488c2ecf20Sopenharmony_ci } else { 6498c2ecf20Sopenharmony_ci rxrpc_put_call(call, rxrpc_call_put); 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_cierror_no_call: 6528c2ecf20Sopenharmony_ci release_sock(&rx->sk); 6538c2ecf20Sopenharmony_cierror_trace: 6548c2ecf20Sopenharmony_ci trace_rxrpc_recvmsg(call, rxrpc_recvmsg_return, 0, 0, 0, ret); 6558c2ecf20Sopenharmony_ci return ret; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ciwait_interrupted: 6588c2ecf20Sopenharmony_ci ret = sock_intr_errno(timeo); 6598c2ecf20Sopenharmony_ciwait_error: 6608c2ecf20Sopenharmony_ci finish_wait(sk_sleep(&rx->sk), &wait); 6618c2ecf20Sopenharmony_ci call = NULL; 6628c2ecf20Sopenharmony_ci goto error_trace; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci/** 6668c2ecf20Sopenharmony_ci * rxrpc_kernel_recv_data - Allow a kernel service to receive data/info 6678c2ecf20Sopenharmony_ci * @sock: The socket that the call exists on 6688c2ecf20Sopenharmony_ci * @call: The call to send data through 6698c2ecf20Sopenharmony_ci * @iter: The buffer to receive into 6708c2ecf20Sopenharmony_ci * @want_more: True if more data is expected to be read 6718c2ecf20Sopenharmony_ci * @_abort: Where the abort code is stored if -ECONNABORTED is returned 6728c2ecf20Sopenharmony_ci * @_service: Where to store the actual service ID (may be upgraded) 6738c2ecf20Sopenharmony_ci * 6748c2ecf20Sopenharmony_ci * Allow a kernel service to receive data and pick up information about the 6758c2ecf20Sopenharmony_ci * state of a call. Returns 0 if got what was asked for and there's more 6768c2ecf20Sopenharmony_ci * available, 1 if we got what was asked for and we're at the end of the data 6778c2ecf20Sopenharmony_ci * and -EAGAIN if we need more data. 6788c2ecf20Sopenharmony_ci * 6798c2ecf20Sopenharmony_ci * Note that we may return -EAGAIN to drain empty packets at the end of the 6808c2ecf20Sopenharmony_ci * data, even if we've already copied over the requested data. 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * *_abort should also be initialised to 0. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ciint rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, 6858c2ecf20Sopenharmony_ci struct iov_iter *iter, 6868c2ecf20Sopenharmony_ci bool want_more, u32 *_abort, u16 *_service) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci size_t offset = 0; 6898c2ecf20Sopenharmony_ci int ret; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci _enter("{%d,%s},%zu,%d", 6928c2ecf20Sopenharmony_ci call->debug_id, rxrpc_call_states[call->state], 6938c2ecf20Sopenharmony_ci iov_iter_count(iter), want_more); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci ASSERTCMP(call->state, !=, RXRPC_CALL_SERVER_SECURING); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci mutex_lock(&call->user_mutex); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci switch (READ_ONCE(call->state)) { 7008c2ecf20Sopenharmony_ci case RXRPC_CALL_CLIENT_RECV_REPLY: 7018c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_RECV_REQUEST: 7028c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_ACK_REQUEST: 7038c2ecf20Sopenharmony_ci ret = rxrpc_recvmsg_data(sock, call, NULL, iter, 7048c2ecf20Sopenharmony_ci iov_iter_count(iter), 0, 7058c2ecf20Sopenharmony_ci &offset); 7068c2ecf20Sopenharmony_ci if (ret < 0) 7078c2ecf20Sopenharmony_ci goto out; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* We can only reach here with a partially full buffer if we 7108c2ecf20Sopenharmony_ci * have reached the end of the data. We must otherwise have a 7118c2ecf20Sopenharmony_ci * full buffer or have been given -EAGAIN. 7128c2ecf20Sopenharmony_ci */ 7138c2ecf20Sopenharmony_ci if (ret == 1) { 7148c2ecf20Sopenharmony_ci if (iov_iter_count(iter) > 0) 7158c2ecf20Sopenharmony_ci goto short_data; 7168c2ecf20Sopenharmony_ci if (!want_more) 7178c2ecf20Sopenharmony_ci goto read_phase_complete; 7188c2ecf20Sopenharmony_ci ret = 0; 7198c2ecf20Sopenharmony_ci goto out; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (!want_more) 7238c2ecf20Sopenharmony_ci goto excess_data; 7248c2ecf20Sopenharmony_ci goto out; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci case RXRPC_CALL_COMPLETE: 7278c2ecf20Sopenharmony_ci goto call_complete; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci default: 7308c2ecf20Sopenharmony_ci ret = -EINPROGRESS; 7318c2ecf20Sopenharmony_ci goto out; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ciread_phase_complete: 7358c2ecf20Sopenharmony_ci ret = 1; 7368c2ecf20Sopenharmony_ciout: 7378c2ecf20Sopenharmony_ci switch (call->ackr_reason) { 7388c2ecf20Sopenharmony_ci case RXRPC_ACK_IDLE: 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci case RXRPC_ACK_DELAY: 7418c2ecf20Sopenharmony_ci if (ret != -EAGAIN) 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci fallthrough; 7448c2ecf20Sopenharmony_ci default: 7458c2ecf20Sopenharmony_ci rxrpc_send_ack_packet(call, false, NULL); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (_service) 7498c2ecf20Sopenharmony_ci *_service = call->service_id; 7508c2ecf20Sopenharmony_ci mutex_unlock(&call->user_mutex); 7518c2ecf20Sopenharmony_ci _leave(" = %d [%zu,%d]", ret, iov_iter_count(iter), *_abort); 7528c2ecf20Sopenharmony_ci return ret; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cishort_data: 7558c2ecf20Sopenharmony_ci trace_rxrpc_rx_eproto(call, 0, tracepoint_string("short_data")); 7568c2ecf20Sopenharmony_ci ret = -EBADMSG; 7578c2ecf20Sopenharmony_ci goto out; 7588c2ecf20Sopenharmony_ciexcess_data: 7598c2ecf20Sopenharmony_ci trace_rxrpc_rx_eproto(call, 0, tracepoint_string("excess_data")); 7608c2ecf20Sopenharmony_ci ret = -EMSGSIZE; 7618c2ecf20Sopenharmony_ci goto out; 7628c2ecf20Sopenharmony_cicall_complete: 7638c2ecf20Sopenharmony_ci *_abort = call->abort_code; 7648c2ecf20Sopenharmony_ci ret = call->error; 7658c2ecf20Sopenharmony_ci if (call->completion == RXRPC_CALL_SUCCEEDED) { 7668c2ecf20Sopenharmony_ci ret = 1; 7678c2ecf20Sopenharmony_ci if (iov_iter_count(iter) > 0) 7688c2ecf20Sopenharmony_ci ret = -ECONNRESET; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci goto out; 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_recv_data); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci/** 7758c2ecf20Sopenharmony_ci * rxrpc_kernel_get_reply_time - Get timestamp on first reply packet 7768c2ecf20Sopenharmony_ci * @sock: The socket that the call exists on 7778c2ecf20Sopenharmony_ci * @call: The call to query 7788c2ecf20Sopenharmony_ci * @_ts: Where to put the timestamp 7798c2ecf20Sopenharmony_ci * 7808c2ecf20Sopenharmony_ci * Retrieve the timestamp from the first DATA packet of the reply if it is 7818c2ecf20Sopenharmony_ci * in the ring. Returns true if successful, false if not. 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_cibool rxrpc_kernel_get_reply_time(struct socket *sock, struct rxrpc_call *call, 7848c2ecf20Sopenharmony_ci ktime_t *_ts) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct sk_buff *skb; 7878c2ecf20Sopenharmony_ci rxrpc_seq_t hard_ack, top, seq; 7888c2ecf20Sopenharmony_ci bool success = false; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci mutex_lock(&call->user_mutex); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (READ_ONCE(call->state) != RXRPC_CALL_CLIENT_RECV_REPLY) 7938c2ecf20Sopenharmony_ci goto out; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci hard_ack = call->rx_hard_ack; 7968c2ecf20Sopenharmony_ci if (hard_ack != 0) 7978c2ecf20Sopenharmony_ci goto out; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci seq = hard_ack + 1; 8008c2ecf20Sopenharmony_ci top = smp_load_acquire(&call->rx_top); 8018c2ecf20Sopenharmony_ci if (after(seq, top)) 8028c2ecf20Sopenharmony_ci goto out; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci skb = call->rxtx_buffer[seq & RXRPC_RXTX_BUFF_MASK]; 8058c2ecf20Sopenharmony_ci if (!skb) 8068c2ecf20Sopenharmony_ci goto out; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci *_ts = skb_get_ktime(skb); 8098c2ecf20Sopenharmony_ci success = true; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ciout: 8128c2ecf20Sopenharmony_ci mutex_unlock(&call->user_mutex); 8138c2ecf20Sopenharmony_ci return success; 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_get_reply_time); 816