162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* AF_RXRPC sendmsg() implementation. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2007, 2016 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/gfp.h> 1262306a36Sopenharmony_ci#include <linux/skbuff.h> 1362306a36Sopenharmony_ci#include <linux/export.h> 1462306a36Sopenharmony_ci#include <linux/sched/signal.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <net/sock.h> 1762306a36Sopenharmony_ci#include <net/af_rxrpc.h> 1862306a36Sopenharmony_ci#include "ar-internal.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * Propose an abort to be made in the I/O thread. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cibool rxrpc_propose_abort(struct rxrpc_call *call, s32 abort_code, int error, 2462306a36Sopenharmony_ci enum rxrpc_abort_reason why) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci _enter("{%d},%d,%d,%u", call->debug_id, abort_code, error, why); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (!call->send_abort && !rxrpc_call_is_complete(call)) { 2962306a36Sopenharmony_ci call->send_abort_why = why; 3062306a36Sopenharmony_ci call->send_abort_err = error; 3162306a36Sopenharmony_ci call->send_abort_seq = 0; 3262306a36Sopenharmony_ci /* Request abort locklessly vs rxrpc_input_call_event(). */ 3362306a36Sopenharmony_ci smp_store_release(&call->send_abort, abort_code); 3462306a36Sopenharmony_ci rxrpc_poke_call(call, rxrpc_call_poke_abort); 3562306a36Sopenharmony_ci return true; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci return false; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Wait for a call to become connected. Interruption here doesn't cause the 4362306a36Sopenharmony_ci * call to be aborted. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_cistatic int rxrpc_wait_to_be_connected(struct rxrpc_call *call, long *timeo) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci DECLARE_WAITQUEUE(myself, current); 4862306a36Sopenharmony_ci int ret = 0; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci _enter("%d", call->debug_id); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (rxrpc_call_state(call) != RXRPC_CALL_CLIENT_AWAIT_CONN) 5362306a36Sopenharmony_ci goto no_wait; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci add_wait_queue_exclusive(&call->waitq, &myself); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci for (;;) { 5862306a36Sopenharmony_ci switch (call->interruptibility) { 5962306a36Sopenharmony_ci case RXRPC_INTERRUPTIBLE: 6062306a36Sopenharmony_ci case RXRPC_PREINTERRUPTIBLE: 6162306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci case RXRPC_UNINTERRUPTIBLE: 6462306a36Sopenharmony_ci default: 6562306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (rxrpc_call_state(call) != RXRPC_CALL_CLIENT_AWAIT_CONN) 7062306a36Sopenharmony_ci break; 7162306a36Sopenharmony_ci if ((call->interruptibility == RXRPC_INTERRUPTIBLE || 7262306a36Sopenharmony_ci call->interruptibility == RXRPC_PREINTERRUPTIBLE) && 7362306a36Sopenharmony_ci signal_pending(current)) { 7462306a36Sopenharmony_ci ret = sock_intr_errno(*timeo); 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci *timeo = schedule_timeout(*timeo); 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci remove_wait_queue(&call->waitq, &myself); 8162306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cino_wait: 8462306a36Sopenharmony_ci if (ret == 0 && rxrpc_call_is_complete(call)) 8562306a36Sopenharmony_ci ret = call->error; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci _leave(" = %d", ret); 8862306a36Sopenharmony_ci return ret; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * Return true if there's sufficient Tx queue space. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistatic bool rxrpc_check_tx_space(struct rxrpc_call *call, rxrpc_seq_t *_tx_win) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci if (_tx_win) 9762306a36Sopenharmony_ci *_tx_win = call->tx_bottom; 9862306a36Sopenharmony_ci return call->tx_prepared - call->tx_bottom < 256; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * Wait for space to appear in the Tx queue or a signal to occur. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx, 10562306a36Sopenharmony_ci struct rxrpc_call *call, 10662306a36Sopenharmony_ci long *timeo) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci for (;;) { 10962306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 11062306a36Sopenharmony_ci if (rxrpc_check_tx_space(call, NULL)) 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (rxrpc_call_is_complete(call)) 11462306a36Sopenharmony_ci return call->error; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (signal_pending(current)) 11762306a36Sopenharmony_ci return sock_intr_errno(*timeo); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci trace_rxrpc_txqueue(call, rxrpc_txqueue_wait); 12062306a36Sopenharmony_ci *timeo = schedule_timeout(*timeo); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* 12562306a36Sopenharmony_ci * Wait for space to appear in the Tx queue uninterruptibly, but with 12662306a36Sopenharmony_ci * a timeout of 2*RTT if no progress was made and a signal occurred. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_cistatic int rxrpc_wait_for_tx_window_waitall(struct rxrpc_sock *rx, 12962306a36Sopenharmony_ci struct rxrpc_call *call) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci rxrpc_seq_t tx_start, tx_win; 13262306a36Sopenharmony_ci signed long rtt, timeout; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci rtt = READ_ONCE(call->peer->srtt_us) >> 3; 13562306a36Sopenharmony_ci rtt = usecs_to_jiffies(rtt) * 2; 13662306a36Sopenharmony_ci if (rtt < 2) 13762306a36Sopenharmony_ci rtt = 2; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci timeout = rtt; 14062306a36Sopenharmony_ci tx_start = smp_load_acquire(&call->acks_hard_ack); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci for (;;) { 14362306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (rxrpc_check_tx_space(call, &tx_win)) 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (rxrpc_call_is_complete(call)) 14962306a36Sopenharmony_ci return call->error; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (timeout == 0 && 15262306a36Sopenharmony_ci tx_win == tx_start && signal_pending(current)) 15362306a36Sopenharmony_ci return -EINTR; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (tx_win != tx_start) { 15662306a36Sopenharmony_ci timeout = rtt; 15762306a36Sopenharmony_ci tx_start = tx_win; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci trace_rxrpc_txqueue(call, rxrpc_txqueue_wait); 16162306a36Sopenharmony_ci timeout = schedule_timeout(timeout); 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* 16662306a36Sopenharmony_ci * Wait for space to appear in the Tx queue uninterruptibly. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_cistatic int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx, 16962306a36Sopenharmony_ci struct rxrpc_call *call, 17062306a36Sopenharmony_ci long *timeo) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci for (;;) { 17362306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 17462306a36Sopenharmony_ci if (rxrpc_check_tx_space(call, NULL)) 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (rxrpc_call_is_complete(call)) 17862306a36Sopenharmony_ci return call->error; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci trace_rxrpc_txqueue(call, rxrpc_txqueue_wait); 18162306a36Sopenharmony_ci *timeo = schedule_timeout(*timeo); 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* 18662306a36Sopenharmony_ci * wait for space to appear in the transmit/ACK window 18762306a36Sopenharmony_ci * - caller holds the socket locked 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_cistatic int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx, 19062306a36Sopenharmony_ci struct rxrpc_call *call, 19162306a36Sopenharmony_ci long *timeo, 19262306a36Sopenharmony_ci bool waitall) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci DECLARE_WAITQUEUE(myself, current); 19562306a36Sopenharmony_ci int ret; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci _enter(",{%u,%u,%u,%u}", 19862306a36Sopenharmony_ci call->tx_bottom, call->acks_hard_ack, call->tx_top, call->tx_winsize); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci add_wait_queue(&call->waitq, &myself); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci switch (call->interruptibility) { 20362306a36Sopenharmony_ci case RXRPC_INTERRUPTIBLE: 20462306a36Sopenharmony_ci if (waitall) 20562306a36Sopenharmony_ci ret = rxrpc_wait_for_tx_window_waitall(rx, call); 20662306a36Sopenharmony_ci else 20762306a36Sopenharmony_ci ret = rxrpc_wait_for_tx_window_intr(rx, call, timeo); 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci case RXRPC_PREINTERRUPTIBLE: 21062306a36Sopenharmony_ci case RXRPC_UNINTERRUPTIBLE: 21162306a36Sopenharmony_ci default: 21262306a36Sopenharmony_ci ret = rxrpc_wait_for_tx_window_nonintr(rx, call, timeo); 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci remove_wait_queue(&call->waitq, &myself); 21762306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 21862306a36Sopenharmony_ci _leave(" = %d", ret); 21962306a36Sopenharmony_ci return ret; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 22362306a36Sopenharmony_ci * Notify the owner of the call that the transmit phase is ended and the last 22462306a36Sopenharmony_ci * packet has been queued. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_cistatic void rxrpc_notify_end_tx(struct rxrpc_sock *rx, struct rxrpc_call *call, 22762306a36Sopenharmony_ci rxrpc_notify_end_tx_t notify_end_tx) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci if (notify_end_tx) 23062306a36Sopenharmony_ci notify_end_tx(&rx->sk, call, call->user_call_ID); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* 23462306a36Sopenharmony_ci * Queue a DATA packet for transmission, set the resend timeout and send 23562306a36Sopenharmony_ci * the packet immediately. Returns the error from rxrpc_send_data_packet() 23662306a36Sopenharmony_ci * in case the caller wants to do something with it. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_cistatic void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call, 23962306a36Sopenharmony_ci struct rxrpc_txbuf *txb, 24062306a36Sopenharmony_ci rxrpc_notify_end_tx_t notify_end_tx) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci rxrpc_seq_t seq = txb->seq; 24362306a36Sopenharmony_ci bool last = test_bit(RXRPC_TXBUF_LAST, &txb->flags), poke; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci rxrpc_inc_stat(call->rxnet, stat_tx_data); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci ASSERTCMP(txb->seq, ==, call->tx_prepared + 1); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* We have to set the timestamp before queueing as the retransmit 25062306a36Sopenharmony_ci * algorithm can see the packet as soon as we queue it. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci txb->last_sent = ktime_get_real(); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (last) 25562306a36Sopenharmony_ci trace_rxrpc_txqueue(call, rxrpc_txqueue_queue_last); 25662306a36Sopenharmony_ci else 25762306a36Sopenharmony_ci trace_rxrpc_txqueue(call, rxrpc_txqueue_queue); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Add the packet to the call's output buffer */ 26062306a36Sopenharmony_ci spin_lock(&call->tx_lock); 26162306a36Sopenharmony_ci poke = list_empty(&call->tx_sendmsg); 26262306a36Sopenharmony_ci list_add_tail(&txb->call_link, &call->tx_sendmsg); 26362306a36Sopenharmony_ci call->tx_prepared = seq; 26462306a36Sopenharmony_ci if (last) 26562306a36Sopenharmony_ci rxrpc_notify_end_tx(rx, call, notify_end_tx); 26662306a36Sopenharmony_ci spin_unlock(&call->tx_lock); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (poke) 26962306a36Sopenharmony_ci rxrpc_poke_call(call, rxrpc_call_poke_start); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* 27362306a36Sopenharmony_ci * send data through a socket 27462306a36Sopenharmony_ci * - must be called in process context 27562306a36Sopenharmony_ci * - The caller holds the call user access mutex, but not the socket lock. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_cistatic int rxrpc_send_data(struct rxrpc_sock *rx, 27862306a36Sopenharmony_ci struct rxrpc_call *call, 27962306a36Sopenharmony_ci struct msghdr *msg, size_t len, 28062306a36Sopenharmony_ci rxrpc_notify_end_tx_t notify_end_tx, 28162306a36Sopenharmony_ci bool *_dropped_lock) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct rxrpc_txbuf *txb; 28462306a36Sopenharmony_ci struct sock *sk = &rx->sk; 28562306a36Sopenharmony_ci enum rxrpc_call_state state; 28662306a36Sopenharmony_ci long timeo; 28762306a36Sopenharmony_ci bool more = msg->msg_flags & MSG_MORE; 28862306a36Sopenharmony_ci int ret, copied = 0; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ret = rxrpc_wait_to_be_connected(call, &timeo); 29362306a36Sopenharmony_ci if (ret < 0) 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) { 29762306a36Sopenharmony_ci ret = rxrpc_init_client_conn_security(call->conn); 29862306a36Sopenharmony_ci if (ret < 0) 29962306a36Sopenharmony_ci return ret; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* this should be in poll */ 30362306a36Sopenharmony_ci sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cireload: 30662306a36Sopenharmony_ci ret = -EPIPE; 30762306a36Sopenharmony_ci if (sk->sk_shutdown & SEND_SHUTDOWN) 30862306a36Sopenharmony_ci goto maybe_error; 30962306a36Sopenharmony_ci state = rxrpc_call_state(call); 31062306a36Sopenharmony_ci ret = -ESHUTDOWN; 31162306a36Sopenharmony_ci if (state >= RXRPC_CALL_COMPLETE) 31262306a36Sopenharmony_ci goto maybe_error; 31362306a36Sopenharmony_ci ret = -EPROTO; 31462306a36Sopenharmony_ci if (state != RXRPC_CALL_CLIENT_SEND_REQUEST && 31562306a36Sopenharmony_ci state != RXRPC_CALL_SERVER_ACK_REQUEST && 31662306a36Sopenharmony_ci state != RXRPC_CALL_SERVER_SEND_REPLY) { 31762306a36Sopenharmony_ci /* Request phase complete for this client call */ 31862306a36Sopenharmony_ci trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send, 31962306a36Sopenharmony_ci call->cid, call->call_id, call->rx_consumed, 32062306a36Sopenharmony_ci 0, -EPROTO); 32162306a36Sopenharmony_ci goto maybe_error; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ret = -EMSGSIZE; 32562306a36Sopenharmony_ci if (call->tx_total_len != -1) { 32662306a36Sopenharmony_ci if (len - copied > call->tx_total_len) 32762306a36Sopenharmony_ci goto maybe_error; 32862306a36Sopenharmony_ci if (!more && len - copied != call->tx_total_len) 32962306a36Sopenharmony_ci goto maybe_error; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci txb = call->tx_pending; 33362306a36Sopenharmony_ci call->tx_pending = NULL; 33462306a36Sopenharmony_ci if (txb) 33562306a36Sopenharmony_ci rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci do { 33862306a36Sopenharmony_ci if (!txb) { 33962306a36Sopenharmony_ci size_t remain, bufsize, chunk, offset; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci _debug("alloc"); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!rxrpc_check_tx_space(call, NULL)) 34462306a36Sopenharmony_ci goto wait_for_space; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Work out the maximum size of a packet. Assume that 34762306a36Sopenharmony_ci * the security header is going to be in the padded 34862306a36Sopenharmony_ci * region (enc blocksize), but the trailer is not. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ci remain = more ? INT_MAX : msg_data_left(msg); 35162306a36Sopenharmony_ci ret = call->conn->security->how_much_data(call, remain, 35262306a36Sopenharmony_ci &bufsize, &chunk, &offset); 35362306a36Sopenharmony_ci if (ret < 0) 35462306a36Sopenharmony_ci goto maybe_error; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci _debug("SIZE: %zu/%zu @%zu", chunk, bufsize, offset); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* create a buffer that we can retain until it's ACK'd */ 35962306a36Sopenharmony_ci ret = -ENOMEM; 36062306a36Sopenharmony_ci txb = rxrpc_alloc_txbuf(call, RXRPC_PACKET_TYPE_DATA, 36162306a36Sopenharmony_ci GFP_KERNEL); 36262306a36Sopenharmony_ci if (!txb) 36362306a36Sopenharmony_ci goto maybe_error; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci txb->offset = offset; 36662306a36Sopenharmony_ci txb->space -= offset; 36762306a36Sopenharmony_ci txb->space = min_t(size_t, chunk, txb->space); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci _debug("append"); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* append next segment of data to the current buffer */ 37362306a36Sopenharmony_ci if (msg_data_left(msg) > 0) { 37462306a36Sopenharmony_ci size_t copy = min_t(size_t, txb->space, msg_data_left(msg)); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci _debug("add %zu", copy); 37762306a36Sopenharmony_ci if (!copy_from_iter_full(txb->data + txb->offset, copy, 37862306a36Sopenharmony_ci &msg->msg_iter)) 37962306a36Sopenharmony_ci goto efault; 38062306a36Sopenharmony_ci _debug("added"); 38162306a36Sopenharmony_ci txb->space -= copy; 38262306a36Sopenharmony_ci txb->len += copy; 38362306a36Sopenharmony_ci txb->offset += copy; 38462306a36Sopenharmony_ci copied += copy; 38562306a36Sopenharmony_ci if (call->tx_total_len != -1) 38662306a36Sopenharmony_ci call->tx_total_len -= copy; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* check for the far side aborting the call or a network error 39062306a36Sopenharmony_ci * occurring */ 39162306a36Sopenharmony_ci if (rxrpc_call_is_complete(call)) 39262306a36Sopenharmony_ci goto call_terminated; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* add the packet to the send queue if it's now full */ 39562306a36Sopenharmony_ci if (!txb->space || 39662306a36Sopenharmony_ci (msg_data_left(msg) == 0 && !more)) { 39762306a36Sopenharmony_ci if (msg_data_left(msg) == 0 && !more) { 39862306a36Sopenharmony_ci txb->wire.flags |= RXRPC_LAST_PACKET; 39962306a36Sopenharmony_ci __set_bit(RXRPC_TXBUF_LAST, &txb->flags); 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci else if (call->tx_top - call->acks_hard_ack < 40262306a36Sopenharmony_ci call->tx_winsize) 40362306a36Sopenharmony_ci txb->wire.flags |= RXRPC_MORE_PACKETS; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ret = call->security->secure_packet(call, txb); 40662306a36Sopenharmony_ci if (ret < 0) 40762306a36Sopenharmony_ci goto out; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci rxrpc_queue_packet(rx, call, txb, notify_end_tx); 41062306a36Sopenharmony_ci txb = NULL; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci } while (msg_data_left(msg) > 0); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cisuccess: 41562306a36Sopenharmony_ci ret = copied; 41662306a36Sopenharmony_ci if (rxrpc_call_is_complete(call) && 41762306a36Sopenharmony_ci call->error < 0) 41862306a36Sopenharmony_ci ret = call->error; 41962306a36Sopenharmony_ciout: 42062306a36Sopenharmony_ci call->tx_pending = txb; 42162306a36Sopenharmony_ci _leave(" = %d", ret); 42262306a36Sopenharmony_ci return ret; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cicall_terminated: 42562306a36Sopenharmony_ci rxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted); 42662306a36Sopenharmony_ci _leave(" = %d", call->error); 42762306a36Sopenharmony_ci return call->error; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cimaybe_error: 43062306a36Sopenharmony_ci if (copied) 43162306a36Sopenharmony_ci goto success; 43262306a36Sopenharmony_ci goto out; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ciefault: 43562306a36Sopenharmony_ci ret = -EFAULT; 43662306a36Sopenharmony_ci goto out; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ciwait_for_space: 43962306a36Sopenharmony_ci ret = -EAGAIN; 44062306a36Sopenharmony_ci if (msg->msg_flags & MSG_DONTWAIT) 44162306a36Sopenharmony_ci goto maybe_error; 44262306a36Sopenharmony_ci mutex_unlock(&call->user_mutex); 44362306a36Sopenharmony_ci *_dropped_lock = true; 44462306a36Sopenharmony_ci ret = rxrpc_wait_for_tx_window(rx, call, &timeo, 44562306a36Sopenharmony_ci msg->msg_flags & MSG_WAITALL); 44662306a36Sopenharmony_ci if (ret < 0) 44762306a36Sopenharmony_ci goto maybe_error; 44862306a36Sopenharmony_ci if (call->interruptibility == RXRPC_INTERRUPTIBLE) { 44962306a36Sopenharmony_ci if (mutex_lock_interruptible(&call->user_mutex) < 0) { 45062306a36Sopenharmony_ci ret = sock_intr_errno(timeo); 45162306a36Sopenharmony_ci goto maybe_error; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci } else { 45462306a36Sopenharmony_ci mutex_lock(&call->user_mutex); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci *_dropped_lock = false; 45762306a36Sopenharmony_ci goto reload; 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* 46162306a36Sopenharmony_ci * extract control messages from the sendmsg() control buffer 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_cistatic int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct cmsghdr *cmsg; 46662306a36Sopenharmony_ci bool got_user_ID = false; 46762306a36Sopenharmony_ci int len; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (msg->msg_controllen == 0) 47062306a36Sopenharmony_ci return -EINVAL; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci for_each_cmsghdr(cmsg, msg) { 47362306a36Sopenharmony_ci if (!CMSG_OK(msg, cmsg)) 47462306a36Sopenharmony_ci return -EINVAL; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci len = cmsg->cmsg_len - sizeof(struct cmsghdr); 47762306a36Sopenharmony_ci _debug("CMSG %d, %d, %d", 47862306a36Sopenharmony_ci cmsg->cmsg_level, cmsg->cmsg_type, len); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (cmsg->cmsg_level != SOL_RXRPC) 48162306a36Sopenharmony_ci continue; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci switch (cmsg->cmsg_type) { 48462306a36Sopenharmony_ci case RXRPC_USER_CALL_ID: 48562306a36Sopenharmony_ci if (msg->msg_flags & MSG_CMSG_COMPAT) { 48662306a36Sopenharmony_ci if (len != sizeof(u32)) 48762306a36Sopenharmony_ci return -EINVAL; 48862306a36Sopenharmony_ci p->call.user_call_ID = *(u32 *)CMSG_DATA(cmsg); 48962306a36Sopenharmony_ci } else { 49062306a36Sopenharmony_ci if (len != sizeof(unsigned long)) 49162306a36Sopenharmony_ci return -EINVAL; 49262306a36Sopenharmony_ci p->call.user_call_ID = *(unsigned long *) 49362306a36Sopenharmony_ci CMSG_DATA(cmsg); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci got_user_ID = true; 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci case RXRPC_ABORT: 49962306a36Sopenharmony_ci if (p->command != RXRPC_CMD_SEND_DATA) 50062306a36Sopenharmony_ci return -EINVAL; 50162306a36Sopenharmony_ci p->command = RXRPC_CMD_SEND_ABORT; 50262306a36Sopenharmony_ci if (len != sizeof(p->abort_code)) 50362306a36Sopenharmony_ci return -EINVAL; 50462306a36Sopenharmony_ci p->abort_code = *(unsigned int *)CMSG_DATA(cmsg); 50562306a36Sopenharmony_ci if (p->abort_code == 0) 50662306a36Sopenharmony_ci return -EINVAL; 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci case RXRPC_CHARGE_ACCEPT: 51062306a36Sopenharmony_ci if (p->command != RXRPC_CMD_SEND_DATA) 51162306a36Sopenharmony_ci return -EINVAL; 51262306a36Sopenharmony_ci p->command = RXRPC_CMD_CHARGE_ACCEPT; 51362306a36Sopenharmony_ci if (len != 0) 51462306a36Sopenharmony_ci return -EINVAL; 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci case RXRPC_EXCLUSIVE_CALL: 51862306a36Sopenharmony_ci p->exclusive = true; 51962306a36Sopenharmony_ci if (len != 0) 52062306a36Sopenharmony_ci return -EINVAL; 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci case RXRPC_UPGRADE_SERVICE: 52462306a36Sopenharmony_ci p->upgrade = true; 52562306a36Sopenharmony_ci if (len != 0) 52662306a36Sopenharmony_ci return -EINVAL; 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci case RXRPC_TX_LENGTH: 53062306a36Sopenharmony_ci if (p->call.tx_total_len != -1 || len != sizeof(__s64)) 53162306a36Sopenharmony_ci return -EINVAL; 53262306a36Sopenharmony_ci p->call.tx_total_len = *(__s64 *)CMSG_DATA(cmsg); 53362306a36Sopenharmony_ci if (p->call.tx_total_len < 0) 53462306a36Sopenharmony_ci return -EINVAL; 53562306a36Sopenharmony_ci break; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci case RXRPC_SET_CALL_TIMEOUT: 53862306a36Sopenharmony_ci if (len & 3 || len < 4 || len > 12) 53962306a36Sopenharmony_ci return -EINVAL; 54062306a36Sopenharmony_ci memcpy(&p->call.timeouts, CMSG_DATA(cmsg), len); 54162306a36Sopenharmony_ci p->call.nr_timeouts = len / 4; 54262306a36Sopenharmony_ci if (p->call.timeouts.hard > INT_MAX / HZ) 54362306a36Sopenharmony_ci return -ERANGE; 54462306a36Sopenharmony_ci if (p->call.nr_timeouts >= 2 && p->call.timeouts.idle > 60 * 60 * 1000) 54562306a36Sopenharmony_ci return -ERANGE; 54662306a36Sopenharmony_ci if (p->call.nr_timeouts >= 3 && p->call.timeouts.normal > 60 * 60 * 1000) 54762306a36Sopenharmony_ci return -ERANGE; 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci default: 55162306a36Sopenharmony_ci return -EINVAL; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (!got_user_ID) 55662306a36Sopenharmony_ci return -EINVAL; 55762306a36Sopenharmony_ci if (p->call.tx_total_len != -1 && p->command != RXRPC_CMD_SEND_DATA) 55862306a36Sopenharmony_ci return -EINVAL; 55962306a36Sopenharmony_ci _leave(" = 0"); 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci/* 56462306a36Sopenharmony_ci * Create a new client call for sendmsg(). 56562306a36Sopenharmony_ci * - Called with the socket lock held, which it must release. 56662306a36Sopenharmony_ci * - If it returns a call, the call's lock will need releasing by the caller. 56762306a36Sopenharmony_ci */ 56862306a36Sopenharmony_cistatic struct rxrpc_call * 56962306a36Sopenharmony_cirxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, 57062306a36Sopenharmony_ci struct rxrpc_send_params *p) 57162306a36Sopenharmony_ci __releases(&rx->sk.sk_lock.slock) 57262306a36Sopenharmony_ci __acquires(&call->user_mutex) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct rxrpc_conn_parameters cp; 57562306a36Sopenharmony_ci struct rxrpc_call *call; 57662306a36Sopenharmony_ci struct key *key; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_rxrpc *, srx, msg->msg_name); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci _enter(""); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (!msg->msg_name) { 58362306a36Sopenharmony_ci release_sock(&rx->sk); 58462306a36Sopenharmony_ci return ERR_PTR(-EDESTADDRREQ); 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci key = rx->key; 58862306a36Sopenharmony_ci if (key && !rx->key->payload.data[0]) 58962306a36Sopenharmony_ci key = NULL; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci memset(&cp, 0, sizeof(cp)); 59262306a36Sopenharmony_ci cp.local = rx->local; 59362306a36Sopenharmony_ci cp.key = rx->key; 59462306a36Sopenharmony_ci cp.security_level = rx->min_sec_level; 59562306a36Sopenharmony_ci cp.exclusive = rx->exclusive | p->exclusive; 59662306a36Sopenharmony_ci cp.upgrade = p->upgrade; 59762306a36Sopenharmony_ci cp.service_id = srx->srx_service; 59862306a36Sopenharmony_ci call = rxrpc_new_client_call(rx, &cp, srx, &p->call, GFP_KERNEL, 59962306a36Sopenharmony_ci atomic_inc_return(&rxrpc_debug_id)); 60062306a36Sopenharmony_ci /* The socket is now unlocked */ 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci _leave(" = %p\n", call); 60362306a36Sopenharmony_ci return call; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci/* 60762306a36Sopenharmony_ci * send a message forming part of a client call through an RxRPC socket 60862306a36Sopenharmony_ci * - caller holds the socket locked 60962306a36Sopenharmony_ci * - the socket may be either a client socket or a server socket 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_ciint rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len) 61262306a36Sopenharmony_ci __releases(&rx->sk.sk_lock.slock) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct rxrpc_call *call; 61562306a36Sopenharmony_ci unsigned long now, j; 61662306a36Sopenharmony_ci bool dropped_lock = false; 61762306a36Sopenharmony_ci int ret; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci struct rxrpc_send_params p = { 62062306a36Sopenharmony_ci .call.tx_total_len = -1, 62162306a36Sopenharmony_ci .call.user_call_ID = 0, 62262306a36Sopenharmony_ci .call.nr_timeouts = 0, 62362306a36Sopenharmony_ci .call.interruptibility = RXRPC_INTERRUPTIBLE, 62462306a36Sopenharmony_ci .abort_code = 0, 62562306a36Sopenharmony_ci .command = RXRPC_CMD_SEND_DATA, 62662306a36Sopenharmony_ci .exclusive = false, 62762306a36Sopenharmony_ci .upgrade = false, 62862306a36Sopenharmony_ci }; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci _enter(""); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci ret = rxrpc_sendmsg_cmsg(msg, &p); 63362306a36Sopenharmony_ci if (ret < 0) 63462306a36Sopenharmony_ci goto error_release_sock; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (p.command == RXRPC_CMD_CHARGE_ACCEPT) { 63762306a36Sopenharmony_ci ret = -EINVAL; 63862306a36Sopenharmony_ci if (rx->sk.sk_state != RXRPC_SERVER_LISTENING) 63962306a36Sopenharmony_ci goto error_release_sock; 64062306a36Sopenharmony_ci ret = rxrpc_user_charge_accept(rx, p.call.user_call_ID); 64162306a36Sopenharmony_ci goto error_release_sock; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci call = rxrpc_find_call_by_user_ID(rx, p.call.user_call_ID); 64562306a36Sopenharmony_ci if (!call) { 64662306a36Sopenharmony_ci ret = -EBADSLT; 64762306a36Sopenharmony_ci if (p.command != RXRPC_CMD_SEND_DATA) 64862306a36Sopenharmony_ci goto error_release_sock; 64962306a36Sopenharmony_ci call = rxrpc_new_client_call_for_sendmsg(rx, msg, &p); 65062306a36Sopenharmony_ci /* The socket is now unlocked... */ 65162306a36Sopenharmony_ci if (IS_ERR(call)) 65262306a36Sopenharmony_ci return PTR_ERR(call); 65362306a36Sopenharmony_ci /* ... and we have the call lock. */ 65462306a36Sopenharmony_ci p.call.nr_timeouts = 0; 65562306a36Sopenharmony_ci ret = 0; 65662306a36Sopenharmony_ci if (rxrpc_call_is_complete(call)) 65762306a36Sopenharmony_ci goto out_put_unlock; 65862306a36Sopenharmony_ci } else { 65962306a36Sopenharmony_ci switch (rxrpc_call_state(call)) { 66062306a36Sopenharmony_ci case RXRPC_CALL_CLIENT_AWAIT_CONN: 66162306a36Sopenharmony_ci case RXRPC_CALL_SERVER_SECURING: 66262306a36Sopenharmony_ci if (p.command == RXRPC_CMD_SEND_ABORT) 66362306a36Sopenharmony_ci break; 66462306a36Sopenharmony_ci fallthrough; 66562306a36Sopenharmony_ci case RXRPC_CALL_UNINITIALISED: 66662306a36Sopenharmony_ci case RXRPC_CALL_SERVER_PREALLOC: 66762306a36Sopenharmony_ci rxrpc_put_call(call, rxrpc_call_put_sendmsg); 66862306a36Sopenharmony_ci ret = -EBUSY; 66962306a36Sopenharmony_ci goto error_release_sock; 67062306a36Sopenharmony_ci default: 67162306a36Sopenharmony_ci break; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci ret = mutex_lock_interruptible(&call->user_mutex); 67562306a36Sopenharmony_ci release_sock(&rx->sk); 67662306a36Sopenharmony_ci if (ret < 0) { 67762306a36Sopenharmony_ci ret = -ERESTARTSYS; 67862306a36Sopenharmony_ci goto error_put; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (p.call.tx_total_len != -1) { 68262306a36Sopenharmony_ci ret = -EINVAL; 68362306a36Sopenharmony_ci if (call->tx_total_len != -1 || 68462306a36Sopenharmony_ci call->tx_pending || 68562306a36Sopenharmony_ci call->tx_top != 0) 68662306a36Sopenharmony_ci goto out_put_unlock; 68762306a36Sopenharmony_ci call->tx_total_len = p.call.tx_total_len; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci switch (p.call.nr_timeouts) { 69262306a36Sopenharmony_ci case 3: 69362306a36Sopenharmony_ci j = msecs_to_jiffies(p.call.timeouts.normal); 69462306a36Sopenharmony_ci if (p.call.timeouts.normal > 0 && j == 0) 69562306a36Sopenharmony_ci j = 1; 69662306a36Sopenharmony_ci WRITE_ONCE(call->next_rx_timo, j); 69762306a36Sopenharmony_ci fallthrough; 69862306a36Sopenharmony_ci case 2: 69962306a36Sopenharmony_ci j = msecs_to_jiffies(p.call.timeouts.idle); 70062306a36Sopenharmony_ci if (p.call.timeouts.idle > 0 && j == 0) 70162306a36Sopenharmony_ci j = 1; 70262306a36Sopenharmony_ci WRITE_ONCE(call->next_req_timo, j); 70362306a36Sopenharmony_ci fallthrough; 70462306a36Sopenharmony_ci case 1: 70562306a36Sopenharmony_ci if (p.call.timeouts.hard > 0) { 70662306a36Sopenharmony_ci j = p.call.timeouts.hard * HZ; 70762306a36Sopenharmony_ci now = jiffies; 70862306a36Sopenharmony_ci j += now; 70962306a36Sopenharmony_ci WRITE_ONCE(call->expect_term_by, j); 71062306a36Sopenharmony_ci rxrpc_reduce_call_timer(call, j, now, 71162306a36Sopenharmony_ci rxrpc_timer_set_for_hard); 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci break; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (rxrpc_call_is_complete(call)) { 71762306a36Sopenharmony_ci /* it's too late for this call */ 71862306a36Sopenharmony_ci ret = -ESHUTDOWN; 71962306a36Sopenharmony_ci } else if (p.command == RXRPC_CMD_SEND_ABORT) { 72062306a36Sopenharmony_ci rxrpc_propose_abort(call, p.abort_code, -ECONNABORTED, 72162306a36Sopenharmony_ci rxrpc_abort_call_sendmsg); 72262306a36Sopenharmony_ci ret = 0; 72362306a36Sopenharmony_ci } else if (p.command != RXRPC_CMD_SEND_DATA) { 72462306a36Sopenharmony_ci ret = -EINVAL; 72562306a36Sopenharmony_ci } else { 72662306a36Sopenharmony_ci ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock); 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ciout_put_unlock: 73062306a36Sopenharmony_ci if (!dropped_lock) 73162306a36Sopenharmony_ci mutex_unlock(&call->user_mutex); 73262306a36Sopenharmony_cierror_put: 73362306a36Sopenharmony_ci rxrpc_put_call(call, rxrpc_call_put_sendmsg); 73462306a36Sopenharmony_ci _leave(" = %d", ret); 73562306a36Sopenharmony_ci return ret; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cierror_release_sock: 73862306a36Sopenharmony_ci release_sock(&rx->sk); 73962306a36Sopenharmony_ci return ret; 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci/** 74362306a36Sopenharmony_ci * rxrpc_kernel_send_data - Allow a kernel service to send data on a call 74462306a36Sopenharmony_ci * @sock: The socket the call is on 74562306a36Sopenharmony_ci * @call: The call to send data through 74662306a36Sopenharmony_ci * @msg: The data to send 74762306a36Sopenharmony_ci * @len: The amount of data to send 74862306a36Sopenharmony_ci * @notify_end_tx: Notification that the last packet is queued. 74962306a36Sopenharmony_ci * 75062306a36Sopenharmony_ci * Allow a kernel service to send data on a call. The call must be in an state 75162306a36Sopenharmony_ci * appropriate to sending data. No control data should be supplied in @msg, 75262306a36Sopenharmony_ci * nor should an address be supplied. MSG_MORE should be flagged if there's 75362306a36Sopenharmony_ci * more data to come, otherwise this data will end the transmission phase. 75462306a36Sopenharmony_ci */ 75562306a36Sopenharmony_ciint rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call, 75662306a36Sopenharmony_ci struct msghdr *msg, size_t len, 75762306a36Sopenharmony_ci rxrpc_notify_end_tx_t notify_end_tx) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci bool dropped_lock = false; 76062306a36Sopenharmony_ci int ret; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci _enter("{%d},", call->debug_id); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci ASSERTCMP(msg->msg_name, ==, NULL); 76562306a36Sopenharmony_ci ASSERTCMP(msg->msg_control, ==, NULL); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci mutex_lock(&call->user_mutex); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len, 77062306a36Sopenharmony_ci notify_end_tx, &dropped_lock); 77162306a36Sopenharmony_ci if (ret == -ESHUTDOWN) 77262306a36Sopenharmony_ci ret = call->error; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (!dropped_lock) 77562306a36Sopenharmony_ci mutex_unlock(&call->user_mutex); 77662306a36Sopenharmony_ci _leave(" = %d", ret); 77762306a36Sopenharmony_ci return ret; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_send_data); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci/** 78262306a36Sopenharmony_ci * rxrpc_kernel_abort_call - Allow a kernel service to abort a call 78362306a36Sopenharmony_ci * @sock: The socket the call is on 78462306a36Sopenharmony_ci * @call: The call to be aborted 78562306a36Sopenharmony_ci * @abort_code: The abort code to stick into the ABORT packet 78662306a36Sopenharmony_ci * @error: Local error value 78762306a36Sopenharmony_ci * @why: Indication as to why. 78862306a36Sopenharmony_ci * 78962306a36Sopenharmony_ci * Allow a kernel service to abort a call, if it's still in an abortable state 79062306a36Sopenharmony_ci * and return true if the call was aborted, false if it was already complete. 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_cibool rxrpc_kernel_abort_call(struct socket *sock, struct rxrpc_call *call, 79362306a36Sopenharmony_ci u32 abort_code, int error, enum rxrpc_abort_reason why) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci bool aborted; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci _enter("{%d},%d,%d,%u", call->debug_id, abort_code, error, why); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci mutex_lock(&call->user_mutex); 80062306a36Sopenharmony_ci aborted = rxrpc_propose_abort(call, abort_code, error, why); 80162306a36Sopenharmony_ci mutex_unlock(&call->user_mutex); 80262306a36Sopenharmony_ci return aborted; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_abort_call); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci/** 80762306a36Sopenharmony_ci * rxrpc_kernel_set_tx_length - Set the total Tx length on a call 80862306a36Sopenharmony_ci * @sock: The socket the call is on 80962306a36Sopenharmony_ci * @call: The call to be informed 81062306a36Sopenharmony_ci * @tx_total_len: The amount of data to be transmitted for this call 81162306a36Sopenharmony_ci * 81262306a36Sopenharmony_ci * Allow a kernel service to set the total transmit length on a call. This 81362306a36Sopenharmony_ci * allows buffer-to-packet encrypt-and-copy to be performed. 81462306a36Sopenharmony_ci * 81562306a36Sopenharmony_ci * This function is primarily for use for setting the reply length since the 81662306a36Sopenharmony_ci * request length can be set when beginning the call. 81762306a36Sopenharmony_ci */ 81862306a36Sopenharmony_civoid rxrpc_kernel_set_tx_length(struct socket *sock, struct rxrpc_call *call, 81962306a36Sopenharmony_ci s64 tx_total_len) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci WARN_ON(call->tx_total_len != -1); 82262306a36Sopenharmony_ci call->tx_total_len = tx_total_len; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ciEXPORT_SYMBOL(rxrpc_kernel_set_tx_length); 825