18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* AF_RXRPC sendmsg() implementation. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2007, 2016 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/gfp.h> 128c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 138c2ecf20Sopenharmony_ci#include <linux/export.h> 148c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <net/sock.h> 178c2ecf20Sopenharmony_ci#include <net/af_rxrpc.h> 188c2ecf20Sopenharmony_ci#include "ar-internal.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * Return true if there's sufficient Tx queue space. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cistatic bool rxrpc_check_tx_space(struct rxrpc_call *call, rxrpc_seq_t *_tx_win) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci unsigned int win_size = 268c2ecf20Sopenharmony_ci min_t(unsigned int, call->tx_winsize, 278c2ecf20Sopenharmony_ci call->cong_cwnd + call->cong_extra); 288c2ecf20Sopenharmony_ci rxrpc_seq_t tx_win = READ_ONCE(call->tx_hard_ack); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (_tx_win) 318c2ecf20Sopenharmony_ci *_tx_win = tx_win; 328c2ecf20Sopenharmony_ci return call->tx_top - tx_win < win_size; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Wait for space to appear in the Tx queue or a signal to occur. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cistatic int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx, 398c2ecf20Sopenharmony_ci struct rxrpc_call *call, 408c2ecf20Sopenharmony_ci long *timeo) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci for (;;) { 438c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 448c2ecf20Sopenharmony_ci if (rxrpc_check_tx_space(call, NULL)) 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (call->state >= RXRPC_CALL_COMPLETE) 488c2ecf20Sopenharmony_ci return call->error; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (signal_pending(current)) 518c2ecf20Sopenharmony_ci return sock_intr_errno(*timeo); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci trace_rxrpc_transmit(call, rxrpc_transmit_wait); 548c2ecf20Sopenharmony_ci *timeo = schedule_timeout(*timeo); 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * Wait for space to appear in the Tx queue uninterruptibly, but with 608c2ecf20Sopenharmony_ci * a timeout of 2*RTT if no progress was made and a signal occurred. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistatic int rxrpc_wait_for_tx_window_waitall(struct rxrpc_sock *rx, 638c2ecf20Sopenharmony_ci struct rxrpc_call *call) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci rxrpc_seq_t tx_start, tx_win; 668c2ecf20Sopenharmony_ci signed long rtt, timeout; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci rtt = READ_ONCE(call->peer->srtt_us) >> 3; 698c2ecf20Sopenharmony_ci rtt = usecs_to_jiffies(rtt) * 2; 708c2ecf20Sopenharmony_ci if (rtt < 2) 718c2ecf20Sopenharmony_ci rtt = 2; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci timeout = rtt; 748c2ecf20Sopenharmony_ci tx_start = READ_ONCE(call->tx_hard_ack); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci for (;;) { 778c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci tx_win = READ_ONCE(call->tx_hard_ack); 808c2ecf20Sopenharmony_ci if (rxrpc_check_tx_space(call, &tx_win)) 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (call->state >= RXRPC_CALL_COMPLETE) 848c2ecf20Sopenharmony_ci return call->error; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (timeout == 0 && 878c2ecf20Sopenharmony_ci tx_win == tx_start && signal_pending(current)) 888c2ecf20Sopenharmony_ci return -EINTR; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (tx_win != tx_start) { 918c2ecf20Sopenharmony_ci timeout = rtt; 928c2ecf20Sopenharmony_ci tx_start = tx_win; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci trace_rxrpc_transmit(call, rxrpc_transmit_wait); 968c2ecf20Sopenharmony_ci timeout = schedule_timeout(timeout); 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * Wait for space to appear in the Tx queue uninterruptibly. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_cistatic int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx, 1048c2ecf20Sopenharmony_ci struct rxrpc_call *call, 1058c2ecf20Sopenharmony_ci long *timeo) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci for (;;) { 1088c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 1098c2ecf20Sopenharmony_ci if (rxrpc_check_tx_space(call, NULL)) 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (call->state >= RXRPC_CALL_COMPLETE) 1138c2ecf20Sopenharmony_ci return call->error; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci trace_rxrpc_transmit(call, rxrpc_transmit_wait); 1168c2ecf20Sopenharmony_ci *timeo = schedule_timeout(*timeo); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* 1218c2ecf20Sopenharmony_ci * wait for space to appear in the transmit/ACK window 1228c2ecf20Sopenharmony_ci * - caller holds the socket locked 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cistatic int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx, 1258c2ecf20Sopenharmony_ci struct rxrpc_call *call, 1268c2ecf20Sopenharmony_ci long *timeo, 1278c2ecf20Sopenharmony_ci bool waitall) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(myself, current); 1308c2ecf20Sopenharmony_ci int ret; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci _enter(",{%u,%u,%u}", 1338c2ecf20Sopenharmony_ci call->tx_hard_ack, call->tx_top, call->tx_winsize); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci add_wait_queue(&call->waitq, &myself); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci switch (call->interruptibility) { 1388c2ecf20Sopenharmony_ci case RXRPC_INTERRUPTIBLE: 1398c2ecf20Sopenharmony_ci if (waitall) 1408c2ecf20Sopenharmony_ci ret = rxrpc_wait_for_tx_window_waitall(rx, call); 1418c2ecf20Sopenharmony_ci else 1428c2ecf20Sopenharmony_ci ret = rxrpc_wait_for_tx_window_intr(rx, call, timeo); 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci case RXRPC_PREINTERRUPTIBLE: 1458c2ecf20Sopenharmony_ci case RXRPC_UNINTERRUPTIBLE: 1468c2ecf20Sopenharmony_ci default: 1478c2ecf20Sopenharmony_ci ret = rxrpc_wait_for_tx_window_nonintr(rx, call, timeo); 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci remove_wait_queue(&call->waitq, &myself); 1528c2ecf20Sopenharmony_ci set_current_state(TASK_RUNNING); 1538c2ecf20Sopenharmony_ci _leave(" = %d", ret); 1548c2ecf20Sopenharmony_ci return ret; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* 1588c2ecf20Sopenharmony_ci * Schedule an instant Tx resend. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_cistatic inline void rxrpc_instant_resend(struct rxrpc_call *call, int ix) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci spin_lock_bh(&call->lock); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (call->state < RXRPC_CALL_COMPLETE) { 1658c2ecf20Sopenharmony_ci call->rxtx_annotations[ix] = 1668c2ecf20Sopenharmony_ci (call->rxtx_annotations[ix] & RXRPC_TX_ANNO_LAST) | 1678c2ecf20Sopenharmony_ci RXRPC_TX_ANNO_RETRANS; 1688c2ecf20Sopenharmony_ci if (!test_and_set_bit(RXRPC_CALL_EV_RESEND, &call->events)) 1698c2ecf20Sopenharmony_ci rxrpc_queue_call(call); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci spin_unlock_bh(&call->lock); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* 1768c2ecf20Sopenharmony_ci * Notify the owner of the call that the transmit phase is ended and the last 1778c2ecf20Sopenharmony_ci * packet has been queued. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistatic void rxrpc_notify_end_tx(struct rxrpc_sock *rx, struct rxrpc_call *call, 1808c2ecf20Sopenharmony_ci rxrpc_notify_end_tx_t notify_end_tx) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci if (notify_end_tx) 1838c2ecf20Sopenharmony_ci notify_end_tx(&rx->sk, call, call->user_call_ID); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* 1878c2ecf20Sopenharmony_ci * Queue a DATA packet for transmission, set the resend timeout and send 1888c2ecf20Sopenharmony_ci * the packet immediately. Returns the error from rxrpc_send_data_packet() 1898c2ecf20Sopenharmony_ci * in case the caller wants to do something with it. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic int rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call, 1928c2ecf20Sopenharmony_ci struct sk_buff *skb, bool last, 1938c2ecf20Sopenharmony_ci rxrpc_notify_end_tx_t notify_end_tx) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 1968c2ecf20Sopenharmony_ci unsigned long now; 1978c2ecf20Sopenharmony_ci rxrpc_seq_t seq = sp->hdr.seq; 1988c2ecf20Sopenharmony_ci int ret, ix; 1998c2ecf20Sopenharmony_ci u8 annotation = RXRPC_TX_ANNO_UNACK; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci _net("queue skb %p [%d]", skb, seq); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ASSERTCMP(seq, ==, call->tx_top + 1); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (last) 2068c2ecf20Sopenharmony_ci annotation |= RXRPC_TX_ANNO_LAST; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* We have to set the timestamp before queueing as the retransmit 2098c2ecf20Sopenharmony_ci * algorithm can see the packet as soon as we queue it. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci skb->tstamp = ktime_get_real(); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ix = seq & RXRPC_RXTX_BUFF_MASK; 2148c2ecf20Sopenharmony_ci rxrpc_get_skb(skb, rxrpc_skb_got); 2158c2ecf20Sopenharmony_ci call->rxtx_annotations[ix] = annotation; 2168c2ecf20Sopenharmony_ci smp_wmb(); 2178c2ecf20Sopenharmony_ci call->rxtx_buffer[ix] = skb; 2188c2ecf20Sopenharmony_ci call->tx_top = seq; 2198c2ecf20Sopenharmony_ci if (last) 2208c2ecf20Sopenharmony_ci trace_rxrpc_transmit(call, rxrpc_transmit_queue_last); 2218c2ecf20Sopenharmony_ci else 2228c2ecf20Sopenharmony_ci trace_rxrpc_transmit(call, rxrpc_transmit_queue); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (last || call->state == RXRPC_CALL_SERVER_ACK_REQUEST) { 2258c2ecf20Sopenharmony_ci _debug("________awaiting reply/ACK__________"); 2268c2ecf20Sopenharmony_ci write_lock_bh(&call->state_lock); 2278c2ecf20Sopenharmony_ci switch (call->state) { 2288c2ecf20Sopenharmony_ci case RXRPC_CALL_CLIENT_SEND_REQUEST: 2298c2ecf20Sopenharmony_ci call->state = RXRPC_CALL_CLIENT_AWAIT_REPLY; 2308c2ecf20Sopenharmony_ci rxrpc_notify_end_tx(rx, call, notify_end_tx); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_ACK_REQUEST: 2338c2ecf20Sopenharmony_ci call->state = RXRPC_CALL_SERVER_SEND_REPLY; 2348c2ecf20Sopenharmony_ci now = jiffies; 2358c2ecf20Sopenharmony_ci WRITE_ONCE(call->ack_at, now + MAX_JIFFY_OFFSET); 2368c2ecf20Sopenharmony_ci if (call->ackr_reason == RXRPC_ACK_DELAY) 2378c2ecf20Sopenharmony_ci call->ackr_reason = 0; 2388c2ecf20Sopenharmony_ci trace_rxrpc_timer(call, rxrpc_timer_init_for_send_reply, now); 2398c2ecf20Sopenharmony_ci if (!last) 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci fallthrough; 2428c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_SEND_REPLY: 2438c2ecf20Sopenharmony_ci call->state = RXRPC_CALL_SERVER_AWAIT_ACK; 2448c2ecf20Sopenharmony_ci rxrpc_notify_end_tx(rx, call, notify_end_tx); 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci default: 2478c2ecf20Sopenharmony_ci break; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci write_unlock_bh(&call->state_lock); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (seq == 1 && rxrpc_is_client_call(call)) 2538c2ecf20Sopenharmony_ci rxrpc_expose_client_call(call); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ret = rxrpc_send_data_packet(call, skb, false); 2568c2ecf20Sopenharmony_ci if (ret < 0) { 2578c2ecf20Sopenharmony_ci switch (ret) { 2588c2ecf20Sopenharmony_ci case -ENETUNREACH: 2598c2ecf20Sopenharmony_ci case -EHOSTUNREACH: 2608c2ecf20Sopenharmony_ci case -ECONNREFUSED: 2618c2ecf20Sopenharmony_ci rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, 2628c2ecf20Sopenharmony_ci 0, ret); 2638c2ecf20Sopenharmony_ci goto out; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci _debug("need instant resend %d", ret); 2668c2ecf20Sopenharmony_ci rxrpc_instant_resend(call, ix); 2678c2ecf20Sopenharmony_ci } else { 2688c2ecf20Sopenharmony_ci unsigned long now = jiffies; 2698c2ecf20Sopenharmony_ci unsigned long resend_at = now + call->peer->rto_j; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci WRITE_ONCE(call->resend_at, resend_at); 2728c2ecf20Sopenharmony_ci rxrpc_reduce_call_timer(call, resend_at, now, 2738c2ecf20Sopenharmony_ci rxrpc_timer_set_for_send); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ciout: 2778c2ecf20Sopenharmony_ci rxrpc_free_skb(skb, rxrpc_skb_freed); 2788c2ecf20Sopenharmony_ci _leave(" = %d", ret); 2798c2ecf20Sopenharmony_ci return ret; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci * send data through a socket 2848c2ecf20Sopenharmony_ci * - must be called in process context 2858c2ecf20Sopenharmony_ci * - The caller holds the call user access mutex, but not the socket lock. 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_cistatic int rxrpc_send_data(struct rxrpc_sock *rx, 2888c2ecf20Sopenharmony_ci struct rxrpc_call *call, 2898c2ecf20Sopenharmony_ci struct msghdr *msg, size_t len, 2908c2ecf20Sopenharmony_ci rxrpc_notify_end_tx_t notify_end_tx, 2918c2ecf20Sopenharmony_ci bool *_dropped_lock) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct rxrpc_skb_priv *sp; 2948c2ecf20Sopenharmony_ci struct sk_buff *skb; 2958c2ecf20Sopenharmony_ci struct sock *sk = &rx->sk; 2968c2ecf20Sopenharmony_ci enum rxrpc_call_state state; 2978c2ecf20Sopenharmony_ci long timeo; 2988c2ecf20Sopenharmony_ci bool more = msg->msg_flags & MSG_MORE; 2998c2ecf20Sopenharmony_ci int ret, copied = 0; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* this should be in poll */ 3048c2ecf20Sopenharmony_ci sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cireload: 3078c2ecf20Sopenharmony_ci ret = -EPIPE; 3088c2ecf20Sopenharmony_ci if (sk->sk_shutdown & SEND_SHUTDOWN) 3098c2ecf20Sopenharmony_ci goto maybe_error; 3108c2ecf20Sopenharmony_ci state = READ_ONCE(call->state); 3118c2ecf20Sopenharmony_ci ret = -ESHUTDOWN; 3128c2ecf20Sopenharmony_ci if (state >= RXRPC_CALL_COMPLETE) 3138c2ecf20Sopenharmony_ci goto maybe_error; 3148c2ecf20Sopenharmony_ci ret = -EPROTO; 3158c2ecf20Sopenharmony_ci if (state != RXRPC_CALL_CLIENT_SEND_REQUEST && 3168c2ecf20Sopenharmony_ci state != RXRPC_CALL_SERVER_ACK_REQUEST && 3178c2ecf20Sopenharmony_ci state != RXRPC_CALL_SERVER_SEND_REPLY) 3188c2ecf20Sopenharmony_ci goto maybe_error; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci ret = -EMSGSIZE; 3218c2ecf20Sopenharmony_ci if (call->tx_total_len != -1) { 3228c2ecf20Sopenharmony_ci if (len - copied > call->tx_total_len) 3238c2ecf20Sopenharmony_ci goto maybe_error; 3248c2ecf20Sopenharmony_ci if (!more && len - copied != call->tx_total_len) 3258c2ecf20Sopenharmony_ci goto maybe_error; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci skb = call->tx_pending; 3298c2ecf20Sopenharmony_ci call->tx_pending = NULL; 3308c2ecf20Sopenharmony_ci rxrpc_see_skb(skb, rxrpc_skb_seen); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci do { 3338c2ecf20Sopenharmony_ci /* Check to see if there's a ping ACK to reply to. */ 3348c2ecf20Sopenharmony_ci if (call->ackr_reason == RXRPC_ACK_PING_RESPONSE) 3358c2ecf20Sopenharmony_ci rxrpc_send_ack_packet(call, false, NULL); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (!skb) { 3388c2ecf20Sopenharmony_ci size_t size, chunk, max, space; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci _debug("alloc"); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (!rxrpc_check_tx_space(call, NULL)) 3438c2ecf20Sopenharmony_ci goto wait_for_space; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci max = RXRPC_JUMBO_DATALEN; 3468c2ecf20Sopenharmony_ci max -= call->conn->security_size; 3478c2ecf20Sopenharmony_ci max &= ~(call->conn->size_align - 1UL); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci chunk = max; 3508c2ecf20Sopenharmony_ci if (chunk > msg_data_left(msg) && !more) 3518c2ecf20Sopenharmony_ci chunk = msg_data_left(msg); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci space = chunk + call->conn->size_align; 3548c2ecf20Sopenharmony_ci space &= ~(call->conn->size_align - 1UL); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci size = space + call->conn->security_size; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci _debug("SIZE: %zu/%zu/%zu", chunk, space, size); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* create a buffer that we can retain until it's ACK'd */ 3618c2ecf20Sopenharmony_ci skb = sock_alloc_send_skb( 3628c2ecf20Sopenharmony_ci sk, size, msg->msg_flags & MSG_DONTWAIT, &ret); 3638c2ecf20Sopenharmony_ci if (!skb) 3648c2ecf20Sopenharmony_ci goto maybe_error; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci sp = rxrpc_skb(skb); 3678c2ecf20Sopenharmony_ci sp->rx_flags |= RXRPC_SKB_TX_BUFFER; 3688c2ecf20Sopenharmony_ci rxrpc_new_skb(skb, rxrpc_skb_new); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci _debug("ALLOC SEND %p", skb); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci ASSERTCMP(skb->mark, ==, 0); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci _debug("HS: %u", call->conn->security_size); 3758c2ecf20Sopenharmony_ci skb_reserve(skb, call->conn->security_size); 3768c2ecf20Sopenharmony_ci skb->len += call->conn->security_size; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci sp->remain = chunk; 3798c2ecf20Sopenharmony_ci if (sp->remain > skb_tailroom(skb)) 3808c2ecf20Sopenharmony_ci sp->remain = skb_tailroom(skb); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci _net("skb: hr %d, tr %d, hl %d, rm %d", 3838c2ecf20Sopenharmony_ci skb_headroom(skb), 3848c2ecf20Sopenharmony_ci skb_tailroom(skb), 3858c2ecf20Sopenharmony_ci skb_headlen(skb), 3868c2ecf20Sopenharmony_ci sp->remain); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci _debug("append"); 3928c2ecf20Sopenharmony_ci sp = rxrpc_skb(skb); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* append next segment of data to the current buffer */ 3958c2ecf20Sopenharmony_ci if (msg_data_left(msg) > 0) { 3968c2ecf20Sopenharmony_ci int copy = skb_tailroom(skb); 3978c2ecf20Sopenharmony_ci ASSERTCMP(copy, >, 0); 3988c2ecf20Sopenharmony_ci if (copy > msg_data_left(msg)) 3998c2ecf20Sopenharmony_ci copy = msg_data_left(msg); 4008c2ecf20Sopenharmony_ci if (copy > sp->remain) 4018c2ecf20Sopenharmony_ci copy = sp->remain; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci _debug("add"); 4048c2ecf20Sopenharmony_ci ret = skb_add_data(skb, &msg->msg_iter, copy); 4058c2ecf20Sopenharmony_ci _debug("added"); 4068c2ecf20Sopenharmony_ci if (ret < 0) 4078c2ecf20Sopenharmony_ci goto efault; 4088c2ecf20Sopenharmony_ci sp->remain -= copy; 4098c2ecf20Sopenharmony_ci skb->mark += copy; 4108c2ecf20Sopenharmony_ci copied += copy; 4118c2ecf20Sopenharmony_ci if (call->tx_total_len != -1) 4128c2ecf20Sopenharmony_ci call->tx_total_len -= copy; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* check for the far side aborting the call or a network error 4168c2ecf20Sopenharmony_ci * occurring */ 4178c2ecf20Sopenharmony_ci if (call->state == RXRPC_CALL_COMPLETE) 4188c2ecf20Sopenharmony_ci goto call_terminated; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* add the packet to the send queue if it's now full */ 4218c2ecf20Sopenharmony_ci if (sp->remain <= 0 || 4228c2ecf20Sopenharmony_ci (msg_data_left(msg) == 0 && !more)) { 4238c2ecf20Sopenharmony_ci struct rxrpc_connection *conn = call->conn; 4248c2ecf20Sopenharmony_ci uint32_t seq; 4258c2ecf20Sopenharmony_ci size_t pad; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* pad out if we're using security */ 4288c2ecf20Sopenharmony_ci if (conn->security_ix) { 4298c2ecf20Sopenharmony_ci pad = conn->security_size + skb->mark; 4308c2ecf20Sopenharmony_ci pad = conn->size_align - pad; 4318c2ecf20Sopenharmony_ci pad &= conn->size_align - 1; 4328c2ecf20Sopenharmony_ci _debug("pad %zu", pad); 4338c2ecf20Sopenharmony_ci if (pad) 4348c2ecf20Sopenharmony_ci skb_put_zero(skb, pad); 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci seq = call->tx_top + 1; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci sp->hdr.seq = seq; 4408c2ecf20Sopenharmony_ci sp->hdr._rsvd = 0; 4418c2ecf20Sopenharmony_ci sp->hdr.flags = conn->out_clientflag; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (msg_data_left(msg) == 0 && !more) 4448c2ecf20Sopenharmony_ci sp->hdr.flags |= RXRPC_LAST_PACKET; 4458c2ecf20Sopenharmony_ci else if (call->tx_top - call->tx_hard_ack < 4468c2ecf20Sopenharmony_ci call->tx_winsize) 4478c2ecf20Sopenharmony_ci sp->hdr.flags |= RXRPC_MORE_PACKETS; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci ret = call->security->secure_packet( 4508c2ecf20Sopenharmony_ci call, skb, skb->mark, skb->head); 4518c2ecf20Sopenharmony_ci if (ret < 0) 4528c2ecf20Sopenharmony_ci goto out; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci ret = rxrpc_queue_packet(rx, call, skb, 4558c2ecf20Sopenharmony_ci !msg_data_left(msg) && !more, 4568c2ecf20Sopenharmony_ci notify_end_tx); 4578c2ecf20Sopenharmony_ci /* Should check for failure here */ 4588c2ecf20Sopenharmony_ci skb = NULL; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci } while (msg_data_left(msg) > 0); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cisuccess: 4638c2ecf20Sopenharmony_ci ret = copied; 4648c2ecf20Sopenharmony_ci if (READ_ONCE(call->state) == RXRPC_CALL_COMPLETE) { 4658c2ecf20Sopenharmony_ci read_lock_bh(&call->state_lock); 4668c2ecf20Sopenharmony_ci if (call->error < 0) 4678c2ecf20Sopenharmony_ci ret = call->error; 4688c2ecf20Sopenharmony_ci read_unlock_bh(&call->state_lock); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ciout: 4718c2ecf20Sopenharmony_ci call->tx_pending = skb; 4728c2ecf20Sopenharmony_ci _leave(" = %d", ret); 4738c2ecf20Sopenharmony_ci return ret; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cicall_terminated: 4768c2ecf20Sopenharmony_ci rxrpc_free_skb(skb, rxrpc_skb_freed); 4778c2ecf20Sopenharmony_ci _leave(" = %d", call->error); 4788c2ecf20Sopenharmony_ci return call->error; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cimaybe_error: 4818c2ecf20Sopenharmony_ci if (copied) 4828c2ecf20Sopenharmony_ci goto success; 4838c2ecf20Sopenharmony_ci goto out; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ciefault: 4868c2ecf20Sopenharmony_ci ret = -EFAULT; 4878c2ecf20Sopenharmony_ci goto out; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ciwait_for_space: 4908c2ecf20Sopenharmony_ci ret = -EAGAIN; 4918c2ecf20Sopenharmony_ci if (msg->msg_flags & MSG_DONTWAIT) 4928c2ecf20Sopenharmony_ci goto maybe_error; 4938c2ecf20Sopenharmony_ci mutex_unlock(&call->user_mutex); 4948c2ecf20Sopenharmony_ci *_dropped_lock = true; 4958c2ecf20Sopenharmony_ci ret = rxrpc_wait_for_tx_window(rx, call, &timeo, 4968c2ecf20Sopenharmony_ci msg->msg_flags & MSG_WAITALL); 4978c2ecf20Sopenharmony_ci if (ret < 0) 4988c2ecf20Sopenharmony_ci goto maybe_error; 4998c2ecf20Sopenharmony_ci if (call->interruptibility == RXRPC_INTERRUPTIBLE) { 5008c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&call->user_mutex) < 0) { 5018c2ecf20Sopenharmony_ci ret = sock_intr_errno(timeo); 5028c2ecf20Sopenharmony_ci goto maybe_error; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci } else { 5058c2ecf20Sopenharmony_ci mutex_lock(&call->user_mutex); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci *_dropped_lock = false; 5088c2ecf20Sopenharmony_ci goto reload; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci/* 5128c2ecf20Sopenharmony_ci * extract control messages from the sendmsg() control buffer 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_cistatic int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct cmsghdr *cmsg; 5178c2ecf20Sopenharmony_ci bool got_user_ID = false; 5188c2ecf20Sopenharmony_ci int len; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (msg->msg_controllen == 0) 5218c2ecf20Sopenharmony_ci return -EINVAL; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci for_each_cmsghdr(cmsg, msg) { 5248c2ecf20Sopenharmony_ci if (!CMSG_OK(msg, cmsg)) 5258c2ecf20Sopenharmony_ci return -EINVAL; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci len = cmsg->cmsg_len - sizeof(struct cmsghdr); 5288c2ecf20Sopenharmony_ci _debug("CMSG %d, %d, %d", 5298c2ecf20Sopenharmony_ci cmsg->cmsg_level, cmsg->cmsg_type, len); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (cmsg->cmsg_level != SOL_RXRPC) 5328c2ecf20Sopenharmony_ci continue; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci switch (cmsg->cmsg_type) { 5358c2ecf20Sopenharmony_ci case RXRPC_USER_CALL_ID: 5368c2ecf20Sopenharmony_ci if (msg->msg_flags & MSG_CMSG_COMPAT) { 5378c2ecf20Sopenharmony_ci if (len != sizeof(u32)) 5388c2ecf20Sopenharmony_ci return -EINVAL; 5398c2ecf20Sopenharmony_ci p->call.user_call_ID = *(u32 *)CMSG_DATA(cmsg); 5408c2ecf20Sopenharmony_ci } else { 5418c2ecf20Sopenharmony_ci if (len != sizeof(unsigned long)) 5428c2ecf20Sopenharmony_ci return -EINVAL; 5438c2ecf20Sopenharmony_ci p->call.user_call_ID = *(unsigned long *) 5448c2ecf20Sopenharmony_ci CMSG_DATA(cmsg); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci got_user_ID = true; 5478c2ecf20Sopenharmony_ci break; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci case RXRPC_ABORT: 5508c2ecf20Sopenharmony_ci if (p->command != RXRPC_CMD_SEND_DATA) 5518c2ecf20Sopenharmony_ci return -EINVAL; 5528c2ecf20Sopenharmony_ci p->command = RXRPC_CMD_SEND_ABORT; 5538c2ecf20Sopenharmony_ci if (len != sizeof(p->abort_code)) 5548c2ecf20Sopenharmony_ci return -EINVAL; 5558c2ecf20Sopenharmony_ci p->abort_code = *(unsigned int *)CMSG_DATA(cmsg); 5568c2ecf20Sopenharmony_ci if (p->abort_code == 0) 5578c2ecf20Sopenharmony_ci return -EINVAL; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci case RXRPC_CHARGE_ACCEPT: 5618c2ecf20Sopenharmony_ci if (p->command != RXRPC_CMD_SEND_DATA) 5628c2ecf20Sopenharmony_ci return -EINVAL; 5638c2ecf20Sopenharmony_ci p->command = RXRPC_CMD_CHARGE_ACCEPT; 5648c2ecf20Sopenharmony_ci if (len != 0) 5658c2ecf20Sopenharmony_ci return -EINVAL; 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci case RXRPC_EXCLUSIVE_CALL: 5698c2ecf20Sopenharmony_ci p->exclusive = true; 5708c2ecf20Sopenharmony_ci if (len != 0) 5718c2ecf20Sopenharmony_ci return -EINVAL; 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci case RXRPC_UPGRADE_SERVICE: 5758c2ecf20Sopenharmony_ci p->upgrade = true; 5768c2ecf20Sopenharmony_ci if (len != 0) 5778c2ecf20Sopenharmony_ci return -EINVAL; 5788c2ecf20Sopenharmony_ci break; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci case RXRPC_TX_LENGTH: 5818c2ecf20Sopenharmony_ci if (p->call.tx_total_len != -1 || len != sizeof(__s64)) 5828c2ecf20Sopenharmony_ci return -EINVAL; 5838c2ecf20Sopenharmony_ci p->call.tx_total_len = *(__s64 *)CMSG_DATA(cmsg); 5848c2ecf20Sopenharmony_ci if (p->call.tx_total_len < 0) 5858c2ecf20Sopenharmony_ci return -EINVAL; 5868c2ecf20Sopenharmony_ci break; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci case RXRPC_SET_CALL_TIMEOUT: 5898c2ecf20Sopenharmony_ci if (len & 3 || len < 4 || len > 12) 5908c2ecf20Sopenharmony_ci return -EINVAL; 5918c2ecf20Sopenharmony_ci memcpy(&p->call.timeouts, CMSG_DATA(cmsg), len); 5928c2ecf20Sopenharmony_ci p->call.nr_timeouts = len / 4; 5938c2ecf20Sopenharmony_ci if (p->call.timeouts.hard > INT_MAX / HZ) 5948c2ecf20Sopenharmony_ci return -ERANGE; 5958c2ecf20Sopenharmony_ci if (p->call.nr_timeouts >= 2 && p->call.timeouts.idle > 60 * 60 * 1000) 5968c2ecf20Sopenharmony_ci return -ERANGE; 5978c2ecf20Sopenharmony_ci if (p->call.nr_timeouts >= 3 && p->call.timeouts.normal > 60 * 60 * 1000) 5988c2ecf20Sopenharmony_ci return -ERANGE; 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci default: 6028c2ecf20Sopenharmony_ci return -EINVAL; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (!got_user_ID) 6078c2ecf20Sopenharmony_ci return -EINVAL; 6088c2ecf20Sopenharmony_ci if (p->call.tx_total_len != -1 && p->command != RXRPC_CMD_SEND_DATA) 6098c2ecf20Sopenharmony_ci return -EINVAL; 6108c2ecf20Sopenharmony_ci _leave(" = 0"); 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci/* 6158c2ecf20Sopenharmony_ci * Create a new client call for sendmsg(). 6168c2ecf20Sopenharmony_ci * - Called with the socket lock held, which it must release. 6178c2ecf20Sopenharmony_ci * - If it returns a call, the call's lock will need releasing by the caller. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_cistatic struct rxrpc_call * 6208c2ecf20Sopenharmony_cirxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, 6218c2ecf20Sopenharmony_ci struct rxrpc_send_params *p) 6228c2ecf20Sopenharmony_ci __releases(&rx->sk.sk_lock.slock) 6238c2ecf20Sopenharmony_ci __acquires(&call->user_mutex) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct rxrpc_conn_parameters cp; 6268c2ecf20Sopenharmony_ci struct rxrpc_call *call; 6278c2ecf20Sopenharmony_ci struct key *key; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_rxrpc *, srx, msg->msg_name); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci _enter(""); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (!msg->msg_name) { 6348c2ecf20Sopenharmony_ci release_sock(&rx->sk); 6358c2ecf20Sopenharmony_ci return ERR_PTR(-EDESTADDRREQ); 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci key = rx->key; 6398c2ecf20Sopenharmony_ci if (key && !rx->key->payload.data[0]) 6408c2ecf20Sopenharmony_ci key = NULL; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci memset(&cp, 0, sizeof(cp)); 6438c2ecf20Sopenharmony_ci cp.local = rx->local; 6448c2ecf20Sopenharmony_ci cp.key = rx->key; 6458c2ecf20Sopenharmony_ci cp.security_level = rx->min_sec_level; 6468c2ecf20Sopenharmony_ci cp.exclusive = rx->exclusive | p->exclusive; 6478c2ecf20Sopenharmony_ci cp.upgrade = p->upgrade; 6488c2ecf20Sopenharmony_ci cp.service_id = srx->srx_service; 6498c2ecf20Sopenharmony_ci call = rxrpc_new_client_call(rx, &cp, srx, &p->call, GFP_KERNEL, 6508c2ecf20Sopenharmony_ci atomic_inc_return(&rxrpc_debug_id)); 6518c2ecf20Sopenharmony_ci /* The socket is now unlocked */ 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci rxrpc_put_peer(cp.peer); 6548c2ecf20Sopenharmony_ci _leave(" = %p\n", call); 6558c2ecf20Sopenharmony_ci return call; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci/* 6598c2ecf20Sopenharmony_ci * send a message forming part of a client call through an RxRPC socket 6608c2ecf20Sopenharmony_ci * - caller holds the socket locked 6618c2ecf20Sopenharmony_ci * - the socket may be either a client socket or a server socket 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_ciint rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) 6648c2ecf20Sopenharmony_ci __releases(&rx->sk.sk_lock.slock) 6658c2ecf20Sopenharmony_ci __releases(&call->user_mutex) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci enum rxrpc_call_state state; 6688c2ecf20Sopenharmony_ci struct rxrpc_call *call; 6698c2ecf20Sopenharmony_ci unsigned long now, j; 6708c2ecf20Sopenharmony_ci bool dropped_lock = false; 6718c2ecf20Sopenharmony_ci int ret; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci struct rxrpc_send_params p = { 6748c2ecf20Sopenharmony_ci .call.tx_total_len = -1, 6758c2ecf20Sopenharmony_ci .call.user_call_ID = 0, 6768c2ecf20Sopenharmony_ci .call.nr_timeouts = 0, 6778c2ecf20Sopenharmony_ci .call.interruptibility = RXRPC_INTERRUPTIBLE, 6788c2ecf20Sopenharmony_ci .abort_code = 0, 6798c2ecf20Sopenharmony_ci .command = RXRPC_CMD_SEND_DATA, 6808c2ecf20Sopenharmony_ci .exclusive = false, 6818c2ecf20Sopenharmony_ci .upgrade = false, 6828c2ecf20Sopenharmony_ci }; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci _enter(""); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci ret = rxrpc_sendmsg_cmsg(msg, &p); 6878c2ecf20Sopenharmony_ci if (ret < 0) 6888c2ecf20Sopenharmony_ci goto error_release_sock; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (p.command == RXRPC_CMD_CHARGE_ACCEPT) { 6918c2ecf20Sopenharmony_ci ret = -EINVAL; 6928c2ecf20Sopenharmony_ci if (rx->sk.sk_state != RXRPC_SERVER_LISTENING) 6938c2ecf20Sopenharmony_ci goto error_release_sock; 6948c2ecf20Sopenharmony_ci ret = rxrpc_user_charge_accept(rx, p.call.user_call_ID); 6958c2ecf20Sopenharmony_ci goto error_release_sock; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci call = rxrpc_find_call_by_user_ID(rx, p.call.user_call_ID); 6998c2ecf20Sopenharmony_ci if (!call) { 7008c2ecf20Sopenharmony_ci ret = -EBADSLT; 7018c2ecf20Sopenharmony_ci if (p.command != RXRPC_CMD_SEND_DATA) 7028c2ecf20Sopenharmony_ci goto error_release_sock; 7038c2ecf20Sopenharmony_ci call = rxrpc_new_client_call_for_sendmsg(rx, msg, &p); 7048c2ecf20Sopenharmony_ci /* The socket is now unlocked... */ 7058c2ecf20Sopenharmony_ci if (IS_ERR(call)) 7068c2ecf20Sopenharmony_ci return PTR_ERR(call); 7078c2ecf20Sopenharmony_ci /* ... and we have the call lock. */ 7088c2ecf20Sopenharmony_ci ret = 0; 7098c2ecf20Sopenharmony_ci if (READ_ONCE(call->state) == RXRPC_CALL_COMPLETE) 7108c2ecf20Sopenharmony_ci goto out_put_unlock; 7118c2ecf20Sopenharmony_ci } else { 7128c2ecf20Sopenharmony_ci switch (READ_ONCE(call->state)) { 7138c2ecf20Sopenharmony_ci case RXRPC_CALL_UNINITIALISED: 7148c2ecf20Sopenharmony_ci case RXRPC_CALL_CLIENT_AWAIT_CONN: 7158c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_PREALLOC: 7168c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_SECURING: 7178c2ecf20Sopenharmony_ci rxrpc_put_call(call, rxrpc_call_put); 7188c2ecf20Sopenharmony_ci ret = -EBUSY; 7198c2ecf20Sopenharmony_ci goto error_release_sock; 7208c2ecf20Sopenharmony_ci default: 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci ret = mutex_lock_interruptible(&call->user_mutex); 7258c2ecf20Sopenharmony_ci release_sock(&rx->sk); 7268c2ecf20Sopenharmony_ci if (ret < 0) { 7278c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 7288c2ecf20Sopenharmony_ci goto error_put; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (p.call.tx_total_len != -1) { 7328c2ecf20Sopenharmony_ci ret = -EINVAL; 7338c2ecf20Sopenharmony_ci if (call->tx_total_len != -1 || 7348c2ecf20Sopenharmony_ci call->tx_pending || 7358c2ecf20Sopenharmony_ci call->tx_top != 0) 7368c2ecf20Sopenharmony_ci goto out_put_unlock; 7378c2ecf20Sopenharmony_ci call->tx_total_len = p.call.tx_total_len; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci switch (p.call.nr_timeouts) { 7428c2ecf20Sopenharmony_ci case 3: 7438c2ecf20Sopenharmony_ci j = msecs_to_jiffies(p.call.timeouts.normal); 7448c2ecf20Sopenharmony_ci if (p.call.timeouts.normal > 0 && j == 0) 7458c2ecf20Sopenharmony_ci j = 1; 7468c2ecf20Sopenharmony_ci WRITE_ONCE(call->next_rx_timo, j); 7478c2ecf20Sopenharmony_ci fallthrough; 7488c2ecf20Sopenharmony_ci case 2: 7498c2ecf20Sopenharmony_ci j = msecs_to_jiffies(p.call.timeouts.idle); 7508c2ecf20Sopenharmony_ci if (p.call.timeouts.idle > 0 && j == 0) 7518c2ecf20Sopenharmony_ci j = 1; 7528c2ecf20Sopenharmony_ci WRITE_ONCE(call->next_req_timo, j); 7538c2ecf20Sopenharmony_ci fallthrough; 7548c2ecf20Sopenharmony_ci case 1: 7558c2ecf20Sopenharmony_ci if (p.call.timeouts.hard > 0) { 7568c2ecf20Sopenharmony_ci j = p.call.timeouts.hard * HZ; 7578c2ecf20Sopenharmony_ci now = jiffies; 7588c2ecf20Sopenharmony_ci j += now; 7598c2ecf20Sopenharmony_ci WRITE_ONCE(call->expect_term_by, j); 7608c2ecf20Sopenharmony_ci rxrpc_reduce_call_timer(call, j, now, 7618c2ecf20Sopenharmony_ci rxrpc_timer_set_for_hard); 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci state = READ_ONCE(call->state); 7678c2ecf20Sopenharmony_ci _debug("CALL %d USR %lx ST %d on CONN %p", 7688c2ecf20Sopenharmony_ci call->debug_id, call->user_call_ID, state, call->conn); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (state >= RXRPC_CALL_COMPLETE) { 7718c2ecf20Sopenharmony_ci /* it's too late for this call */ 7728c2ecf20Sopenharmony_ci ret = -ESHUTDOWN; 7738c2ecf20Sopenharmony_ci } else if (p.command == RXRPC_CMD_SEND_ABORT) { 7748c2ecf20Sopenharmony_ci ret = 0; 7758c2ecf20Sopenharmony_ci if (rxrpc_abort_call("CMD", call, 0, p.abort_code, -ECONNABORTED)) 7768c2ecf20Sopenharmony_ci ret = rxrpc_send_abort_packet(call); 7778c2ecf20Sopenharmony_ci } else if (p.command != RXRPC_CMD_SEND_DATA) { 7788c2ecf20Sopenharmony_ci ret = -EINVAL; 7798c2ecf20Sopenharmony_ci } else { 7808c2ecf20Sopenharmony_ci ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ciout_put_unlock: 7848c2ecf20Sopenharmony_ci if (!dropped_lock) 7858c2ecf20Sopenharmony_ci mutex_unlock(&call->user_mutex); 7868c2ecf20Sopenharmony_cierror_put: 7878c2ecf20Sopenharmony_ci rxrpc_put_call(call, rxrpc_call_put); 7888c2ecf20Sopenharmony_ci _leave(" = %d", ret); 7898c2ecf20Sopenharmony_ci return ret; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cierror_release_sock: 7928c2ecf20Sopenharmony_ci release_sock(&rx->sk); 7938c2ecf20Sopenharmony_ci return ret; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci/** 7978c2ecf20Sopenharmony_ci * rxrpc_kernel_send_data - Allow a kernel service to send data on a call 7988c2ecf20Sopenharmony_ci * @sock: The socket the call is on 7998c2ecf20Sopenharmony_ci * @call: The call to send data through 8008c2ecf20Sopenharmony_ci * @msg: The data to send 8018c2ecf20Sopenharmony_ci * @len: The amount of data to send 8028c2ecf20Sopenharmony_ci * @notify_end_tx: Notification that the last packet is queued. 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci * Allow a kernel service to send data on a call. The call must be in an state 8058c2ecf20Sopenharmony_ci * appropriate to sending data. No control data should be supplied in @msg, 8068c2ecf20Sopenharmony_ci * nor should an address be supplied. MSG_MORE should be flagged if there's 8078c2ecf20Sopenharmony_ci * more data to come, otherwise this data will end the transmission phase. 8088c2ecf20Sopenharmony_ci */ 8098c2ecf20Sopenharmony_ciint rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call, 8108c2ecf20Sopenharmony_ci struct msghdr *msg, size_t len, 8118c2ecf20Sopenharmony_ci rxrpc_notify_end_tx_t notify_end_tx) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci bool dropped_lock = false; 8148c2ecf20Sopenharmony_ci int ret; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci _enter("{%d,%s},", call->debug_id, rxrpc_call_states[call->state]); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci ASSERTCMP(msg->msg_name, ==, NULL); 8198c2ecf20Sopenharmony_ci ASSERTCMP(msg->msg_control, ==, NULL); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci mutex_lock(&call->user_mutex); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci _debug("CALL %d USR %lx ST %d on CONN %p", 8248c2ecf20Sopenharmony_ci call->debug_id, call->user_call_ID, call->state, call->conn); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci switch (READ_ONCE(call->state)) { 8278c2ecf20Sopenharmony_ci case RXRPC_CALL_CLIENT_SEND_REQUEST: 8288c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_ACK_REQUEST: 8298c2ecf20Sopenharmony_ci case RXRPC_CALL_SERVER_SEND_REPLY: 8308c2ecf20Sopenharmony_ci ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len, 8318c2ecf20Sopenharmony_ci notify_end_tx, &dropped_lock); 8328c2ecf20Sopenharmony_ci break; 8338c2ecf20Sopenharmony_ci case RXRPC_CALL_COMPLETE: 8348c2ecf20Sopenharmony_ci read_lock_bh(&call->state_lock); 8358c2ecf20Sopenharmony_ci ret = call->error; 8368c2ecf20Sopenharmony_ci read_unlock_bh(&call->state_lock); 8378c2ecf20Sopenharmony_ci break; 8388c2ecf20Sopenharmony_ci default: 8398c2ecf20Sopenharmony_ci /* Request phase complete for this client call */ 8408c2ecf20Sopenharmony_ci trace_rxrpc_rx_eproto(call, 0, tracepoint_string("late_send")); 8418c2ecf20Sopenharmony_ci ret = -EPROTO; 8428c2ecf20Sopenharmony_ci break; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (!dropped_lock) 8468c2ecf20Sopenharmony_ci mutex_unlock(&call->user_mutex); 8478c2ecf20Sopenharmony_ci _leave(" = %d", ret); 8488c2ecf20Sopenharmony_ci return ret; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_send_data); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci/** 8538c2ecf20Sopenharmony_ci * rxrpc_kernel_abort_call - Allow a kernel service to abort a call 8548c2ecf20Sopenharmony_ci * @sock: The socket the call is on 8558c2ecf20Sopenharmony_ci * @call: The call to be aborted 8568c2ecf20Sopenharmony_ci * @abort_code: The abort code to stick into the ABORT packet 8578c2ecf20Sopenharmony_ci * @error: Local error value 8588c2ecf20Sopenharmony_ci * @why: 3-char string indicating why. 8598c2ecf20Sopenharmony_ci * 8608c2ecf20Sopenharmony_ci * Allow a kernel service to abort a call, if it's still in an abortable state 8618c2ecf20Sopenharmony_ci * and return true if the call was aborted, false if it was already complete. 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_cibool rxrpc_kernel_abort_call(struct socket *sock, struct rxrpc_call *call, 8648c2ecf20Sopenharmony_ci u32 abort_code, int error, const char *why) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci bool aborted; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci _enter("{%d},%d,%d,%s", call->debug_id, abort_code, error, why); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci mutex_lock(&call->user_mutex); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci aborted = rxrpc_abort_call(why, call, 0, abort_code, error); 8738c2ecf20Sopenharmony_ci if (aborted) 8748c2ecf20Sopenharmony_ci rxrpc_send_abort_packet(call); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci mutex_unlock(&call->user_mutex); 8778c2ecf20Sopenharmony_ci return aborted; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_abort_call); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci/** 8828c2ecf20Sopenharmony_ci * rxrpc_kernel_set_tx_length - Set the total Tx length on a call 8838c2ecf20Sopenharmony_ci * @sock: The socket the call is on 8848c2ecf20Sopenharmony_ci * @call: The call to be informed 8858c2ecf20Sopenharmony_ci * @tx_total_len: The amount of data to be transmitted for this call 8868c2ecf20Sopenharmony_ci * 8878c2ecf20Sopenharmony_ci * Allow a kernel service to set the total transmit length on a call. This 8888c2ecf20Sopenharmony_ci * allows buffer-to-packet encrypt-and-copy to be performed. 8898c2ecf20Sopenharmony_ci * 8908c2ecf20Sopenharmony_ci * This function is primarily for use for setting the reply length since the 8918c2ecf20Sopenharmony_ci * request length can be set when beginning the call. 8928c2ecf20Sopenharmony_ci */ 8938c2ecf20Sopenharmony_civoid rxrpc_kernel_set_tx_length(struct socket *sock, struct rxrpc_call *call, 8948c2ecf20Sopenharmony_ci s64 tx_total_len) 8958c2ecf20Sopenharmony_ci{ 8968c2ecf20Sopenharmony_ci WARN_ON(call->tx_total_len != -1); 8978c2ecf20Sopenharmony_ci call->tx_total_len = tx_total_len; 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_set_tx_length); 900