1b4d0d230SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20b58b8a1SDavid Howells /* AF_RXRPC sendmsg() implementation.
30b58b8a1SDavid Howells *
40b58b8a1SDavid Howells * Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved.
50b58b8a1SDavid Howells * Written by David Howells (dhowells@redhat.com)
60b58b8a1SDavid Howells */
70b58b8a1SDavid Howells
80b58b8a1SDavid Howells #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
90b58b8a1SDavid Howells
100b58b8a1SDavid Howells #include <linux/net.h>
110b58b8a1SDavid Howells #include <linux/gfp.h>
120b58b8a1SDavid Howells #include <linux/skbuff.h>
130b58b8a1SDavid Howells #include <linux/export.h>
14174cd4b1SIngo Molnar #include <linux/sched/signal.h>
15174cd4b1SIngo Molnar
160b58b8a1SDavid Howells #include <net/sock.h>
170b58b8a1SDavid Howells #include <net/af_rxrpc.h>
180b58b8a1SDavid Howells #include "ar-internal.h"
190b58b8a1SDavid Howells
200b58b8a1SDavid Howells /*
21a343b174SDavid Howells * Propose an abort to be made in the I/O thread.
22a343b174SDavid Howells */
rxrpc_propose_abort(struct rxrpc_call * call,s32 abort_code,int error,enum rxrpc_abort_reason why)2357af281eSDavid Howells bool rxrpc_propose_abort(struct rxrpc_call *call, s32 abort_code, int error,
2457af281eSDavid Howells enum rxrpc_abort_reason why)
25a343b174SDavid Howells {
2657af281eSDavid Howells _enter("{%d},%d,%d,%u", call->debug_id, abort_code, error, why);
27a343b174SDavid Howells
28d41b3f5bSDavid Howells if (!call->send_abort && !rxrpc_call_is_complete(call)) {
29a343b174SDavid Howells call->send_abort_why = why;
30a343b174SDavid Howells call->send_abort_err = error;
3157af281eSDavid Howells call->send_abort_seq = 0;
32a343b174SDavid Howells /* Request abort locklessly vs rxrpc_input_call_event(). */
33a343b174SDavid Howells smp_store_release(&call->send_abort, abort_code);
34a343b174SDavid Howells rxrpc_poke_call(call, rxrpc_call_poke_abort);
35a343b174SDavid Howells return true;
36a343b174SDavid Howells }
37a343b174SDavid Howells
38a343b174SDavid Howells return false;
39a343b174SDavid Howells }
40a343b174SDavid Howells
41a343b174SDavid Howells /*
429d35d880SDavid Howells * Wait for a call to become connected. Interruption here doesn't cause the
439d35d880SDavid Howells * call to be aborted.
449d35d880SDavid Howells */
rxrpc_wait_to_be_connected(struct rxrpc_call * call,long * timeo)459d35d880SDavid Howells static int rxrpc_wait_to_be_connected(struct rxrpc_call *call, long *timeo)
469d35d880SDavid Howells {
479d35d880SDavid Howells DECLARE_WAITQUEUE(myself, current);
489d35d880SDavid Howells int ret = 0;
499d35d880SDavid Howells
509d35d880SDavid Howells _enter("%d", call->debug_id);
519d35d880SDavid Howells
529d35d880SDavid Howells if (rxrpc_call_state(call) != RXRPC_CALL_CLIENT_AWAIT_CONN)
532b5fdc0fSDavid Howells goto no_wait;
549d35d880SDavid Howells
559d35d880SDavid Howells add_wait_queue_exclusive(&call->waitq, &myself);
569d35d880SDavid Howells
579d35d880SDavid Howells for (;;) {
589d35d880SDavid Howells switch (call->interruptibility) {
599d35d880SDavid Howells case RXRPC_INTERRUPTIBLE:
609d35d880SDavid Howells case RXRPC_PREINTERRUPTIBLE:
619d35d880SDavid Howells set_current_state(TASK_INTERRUPTIBLE);
629d35d880SDavid Howells break;
639d35d880SDavid Howells case RXRPC_UNINTERRUPTIBLE:
649d35d880SDavid Howells default:
659d35d880SDavid Howells set_current_state(TASK_UNINTERRUPTIBLE);
669d35d880SDavid Howells break;
679d35d880SDavid Howells }
682b5fdc0fSDavid Howells
692b5fdc0fSDavid Howells if (rxrpc_call_state(call) != RXRPC_CALL_CLIENT_AWAIT_CONN)
709d35d880SDavid Howells break;
719d35d880SDavid Howells if ((call->interruptibility == RXRPC_INTERRUPTIBLE ||
729d35d880SDavid Howells call->interruptibility == RXRPC_PREINTERRUPTIBLE) &&
739d35d880SDavid Howells signal_pending(current)) {
749d35d880SDavid Howells ret = sock_intr_errno(*timeo);
759d35d880SDavid Howells break;
769d35d880SDavid Howells }
779d35d880SDavid Howells *timeo = schedule_timeout(*timeo);
789d35d880SDavid Howells }
799d35d880SDavid Howells
809d35d880SDavid Howells remove_wait_queue(&call->waitq, &myself);
819d35d880SDavid Howells __set_current_state(TASK_RUNNING);
829d35d880SDavid Howells
832b5fdc0fSDavid Howells no_wait:
849d35d880SDavid Howells if (ret == 0 && rxrpc_call_is_complete(call))
859d35d880SDavid Howells ret = call->error;
869d35d880SDavid Howells
879d35d880SDavid Howells _leave(" = %d", ret);
889d35d880SDavid Howells return ret;
899d35d880SDavid Howells }
909d35d880SDavid Howells
919d35d880SDavid Howells /*
92158fe666SDavid Howells * Return true if there's sufficient Tx queue space.
93158fe666SDavid Howells */
rxrpc_check_tx_space(struct rxrpc_call * call,rxrpc_seq_t * _tx_win)94158fe666SDavid Howells static bool rxrpc_check_tx_space(struct rxrpc_call *call, rxrpc_seq_t *_tx_win)
95158fe666SDavid Howells {
96158fe666SDavid Howells if (_tx_win)
97cf37b598SDavid Howells *_tx_win = call->tx_bottom;
98cf37b598SDavid Howells return call->tx_prepared - call->tx_bottom < 256;
99158fe666SDavid Howells }
100158fe666SDavid Howells
101158fe666SDavid Howells /*
102bc5e3a54SDavid Howells * Wait for space to appear in the Tx queue or a signal to occur.
103bc5e3a54SDavid Howells */
rxrpc_wait_for_tx_window_intr(struct rxrpc_sock * rx,struct rxrpc_call * call,long * timeo)104bc5e3a54SDavid Howells static int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx,
105bc5e3a54SDavid Howells struct rxrpc_call *call,
106bc5e3a54SDavid Howells long *timeo)
107bc5e3a54SDavid Howells {
108bc5e3a54SDavid Howells for (;;) {
109bc5e3a54SDavid Howells set_current_state(TASK_INTERRUPTIBLE);
110158fe666SDavid Howells if (rxrpc_check_tx_space(call, NULL))
111bc5e3a54SDavid Howells return 0;
112bc5e3a54SDavid Howells
113d41b3f5bSDavid Howells if (rxrpc_call_is_complete(call))
114bc5e3a54SDavid Howells return call->error;
115bc5e3a54SDavid Howells
116bc5e3a54SDavid Howells if (signal_pending(current))
117bc5e3a54SDavid Howells return sock_intr_errno(*timeo);
118bc5e3a54SDavid Howells
119a4ea4c47SDavid Howells trace_rxrpc_txqueue(call, rxrpc_txqueue_wait);
120bc5e3a54SDavid Howells *timeo = schedule_timeout(*timeo);
121bc5e3a54SDavid Howells }
122bc5e3a54SDavid Howells }
123bc5e3a54SDavid Howells
124bc5e3a54SDavid Howells /*
125bc5e3a54SDavid Howells * Wait for space to appear in the Tx queue uninterruptibly, but with
126bc5e3a54SDavid Howells * a timeout of 2*RTT if no progress was made and a signal occurred.
127bc5e3a54SDavid Howells */
rxrpc_wait_for_tx_window_waitall(struct rxrpc_sock * rx,struct rxrpc_call * call)128e138aa7dSDavid Howells static int rxrpc_wait_for_tx_window_waitall(struct rxrpc_sock *rx,
129bc5e3a54SDavid Howells struct rxrpc_call *call)
130bc5e3a54SDavid Howells {
131bc5e3a54SDavid Howells rxrpc_seq_t tx_start, tx_win;
132c410bf01SDavid Howells signed long rtt, timeout;
133bc5e3a54SDavid Howells
134c410bf01SDavid Howells rtt = READ_ONCE(call->peer->srtt_us) >> 3;
135c410bf01SDavid Howells rtt = usecs_to_jiffies(rtt) * 2;
136c410bf01SDavid Howells if (rtt < 2)
137c410bf01SDavid Howells rtt = 2;
138bc5e3a54SDavid Howells
139c410bf01SDavid Howells timeout = rtt;
140a4ea4c47SDavid Howells tx_start = smp_load_acquire(&call->acks_hard_ack);
141bc5e3a54SDavid Howells
142bc5e3a54SDavid Howells for (;;) {
143bc5e3a54SDavid Howells set_current_state(TASK_UNINTERRUPTIBLE);
144bc5e3a54SDavid Howells
145158fe666SDavid Howells if (rxrpc_check_tx_space(call, &tx_win))
146bc5e3a54SDavid Howells return 0;
147bc5e3a54SDavid Howells
148d41b3f5bSDavid Howells if (rxrpc_call_is_complete(call))
149bc5e3a54SDavid Howells return call->error;
150bc5e3a54SDavid Howells
151e138aa7dSDavid Howells if (timeout == 0 &&
152bc5e3a54SDavid Howells tx_win == tx_start && signal_pending(current))
153bc5e3a54SDavid Howells return -EINTR;
154bc5e3a54SDavid Howells
155bc5e3a54SDavid Howells if (tx_win != tx_start) {
156c410bf01SDavid Howells timeout = rtt;
157bc5e3a54SDavid Howells tx_start = tx_win;
158bc5e3a54SDavid Howells }
159bc5e3a54SDavid Howells
160a4ea4c47SDavid Howells trace_rxrpc_txqueue(call, rxrpc_txqueue_wait);
161bc5e3a54SDavid Howells timeout = schedule_timeout(timeout);
162bc5e3a54SDavid Howells }
163bc5e3a54SDavid Howells }
164bc5e3a54SDavid Howells
165bc5e3a54SDavid Howells /*
166e138aa7dSDavid Howells * Wait for space to appear in the Tx queue uninterruptibly.
167e138aa7dSDavid Howells */
rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock * rx,struct rxrpc_call * call,long * timeo)168e138aa7dSDavid Howells static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
169e138aa7dSDavid Howells struct rxrpc_call *call,
170e138aa7dSDavid Howells long *timeo)
171e138aa7dSDavid Howells {
172e138aa7dSDavid Howells for (;;) {
173e138aa7dSDavid Howells set_current_state(TASK_UNINTERRUPTIBLE);
174e138aa7dSDavid Howells if (rxrpc_check_tx_space(call, NULL))
175e138aa7dSDavid Howells return 0;
176e138aa7dSDavid Howells
177d41b3f5bSDavid Howells if (rxrpc_call_is_complete(call))
178e138aa7dSDavid Howells return call->error;
179e138aa7dSDavid Howells
180a4ea4c47SDavid Howells trace_rxrpc_txqueue(call, rxrpc_txqueue_wait);
181e138aa7dSDavid Howells *timeo = schedule_timeout(*timeo);
182e138aa7dSDavid Howells }
183e138aa7dSDavid Howells }
184e138aa7dSDavid Howells
185e138aa7dSDavid Howells /*
1860b58b8a1SDavid Howells * wait for space to appear in the transmit/ACK window
1870b58b8a1SDavid Howells * - caller holds the socket locked
1880b58b8a1SDavid Howells */
rxrpc_wait_for_tx_window(struct rxrpc_sock * rx,struct rxrpc_call * call,long * timeo,bool waitall)1890b58b8a1SDavid Howells static int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx,
1900b58b8a1SDavid Howells struct rxrpc_call *call,
191bc5e3a54SDavid Howells long *timeo,
192bc5e3a54SDavid Howells bool waitall)
1930b58b8a1SDavid Howells {
1940b58b8a1SDavid Howells DECLARE_WAITQUEUE(myself, current);
1950b58b8a1SDavid Howells int ret;
1960b58b8a1SDavid Howells
197a4ea4c47SDavid Howells _enter(",{%u,%u,%u,%u}",
198a4ea4c47SDavid Howells call->tx_bottom, call->acks_hard_ack, call->tx_top, call->tx_winsize);
1990b58b8a1SDavid Howells
2000b58b8a1SDavid Howells add_wait_queue(&call->waitq, &myself);
2010b58b8a1SDavid Howells
202e138aa7dSDavid Howells switch (call->interruptibility) {
203e138aa7dSDavid Howells case RXRPC_INTERRUPTIBLE:
204bc5e3a54SDavid Howells if (waitall)
205e138aa7dSDavid Howells ret = rxrpc_wait_for_tx_window_waitall(rx, call);
206bc5e3a54SDavid Howells else
207bc5e3a54SDavid Howells ret = rxrpc_wait_for_tx_window_intr(rx, call, timeo);
208e138aa7dSDavid Howells break;
209e138aa7dSDavid Howells case RXRPC_PREINTERRUPTIBLE:
210e138aa7dSDavid Howells case RXRPC_UNINTERRUPTIBLE:
211e138aa7dSDavid Howells default:
212e138aa7dSDavid Howells ret = rxrpc_wait_for_tx_window_nonintr(rx, call, timeo);
213e138aa7dSDavid Howells break;
214e138aa7dSDavid Howells }
2150b58b8a1SDavid Howells
2160b58b8a1SDavid Howells remove_wait_queue(&call->waitq, &myself);
2170b58b8a1SDavid Howells set_current_state(TASK_RUNNING);
2180b58b8a1SDavid Howells _leave(" = %d", ret);
2190b58b8a1SDavid Howells return ret;
2200b58b8a1SDavid Howells }
2210b58b8a1SDavid Howells
2220b58b8a1SDavid Howells /*
223e833251aSDavid Howells * Notify the owner of the call that the transmit phase is ended and the last
224e833251aSDavid Howells * packet has been queued.
225e833251aSDavid Howells */
rxrpc_notify_end_tx(struct rxrpc_sock * rx,struct rxrpc_call * call,rxrpc_notify_end_tx_t notify_end_tx)226e833251aSDavid Howells static void rxrpc_notify_end_tx(struct rxrpc_sock *rx, struct rxrpc_call *call,
227e833251aSDavid Howells rxrpc_notify_end_tx_t notify_end_tx)
228e833251aSDavid Howells {
229e833251aSDavid Howells if (notify_end_tx)
230e833251aSDavid Howells notify_end_tx(&rx->sk, call, call->user_call_ID);
231e833251aSDavid Howells }
232e833251aSDavid Howells
233e833251aSDavid Howells /*
2348e8715aaSMarc Dionne * Queue a DATA packet for transmission, set the resend timeout and send
2358e8715aaSMarc Dionne * the packet immediately. Returns the error from rxrpc_send_data_packet()
2368e8715aaSMarc Dionne * in case the caller wants to do something with it.
2370b58b8a1SDavid Howells */
rxrpc_queue_packet(struct rxrpc_sock * rx,struct rxrpc_call * call,struct rxrpc_txbuf * txb,rxrpc_notify_end_tx_t notify_end_tx)238a4ea4c47SDavid Howells static void rxrpc_queue_packet(struct rxrpc_sock *rx, struct rxrpc_call *call,
239a4ea4c47SDavid Howells struct rxrpc_txbuf *txb,
240e833251aSDavid Howells rxrpc_notify_end_tx_t notify_end_tx)
2410b58b8a1SDavid Howells {
242a4ea4c47SDavid Howells rxrpc_seq_t seq = txb->seq;
2435e6ef4f1SDavid Howells bool last = test_bit(RXRPC_TXBUF_LAST, &txb->flags), poke;
2440b58b8a1SDavid Howells
245b0154246SDavid Howells rxrpc_inc_stat(call->rxnet, stat_tx_data);
246b0154246SDavid Howells
247cf37b598SDavid Howells ASSERTCMP(txb->seq, ==, call->tx_prepared + 1);
248248f219cSDavid Howells
249b24d2891SDavid Howells /* We have to set the timestamp before queueing as the retransmit
250b24d2891SDavid Howells * algorithm can see the packet as soon as we queue it.
251b24d2891SDavid Howells */
252a4ea4c47SDavid Howells txb->last_sent = ktime_get_real();
253b24d2891SDavid Howells
25470790dbeSDavid Howells if (last)
255a4ea4c47SDavid Howells trace_rxrpc_txqueue(call, rxrpc_txqueue_queue_last);
25670790dbeSDavid Howells else
257a4ea4c47SDavid Howells trace_rxrpc_txqueue(call, rxrpc_txqueue_queue);
2580b58b8a1SDavid Howells
259cf37b598SDavid Howells /* Add the packet to the call's output buffer */
260cf37b598SDavid Howells spin_lock(&call->tx_lock);
2615e6ef4f1SDavid Howells poke = list_empty(&call->tx_sendmsg);
262cf37b598SDavid Howells list_add_tail(&txb->call_link, &call->tx_sendmsg);
263cf37b598SDavid Howells call->tx_prepared = seq;
2642d689424SDavid Howells if (last)
2652d689424SDavid Howells rxrpc_notify_end_tx(rx, call, notify_end_tx);
266cf37b598SDavid Howells spin_unlock(&call->tx_lock);
267cf37b598SDavid Howells
2685e6ef4f1SDavid Howells if (poke)
2695e6ef4f1SDavid Howells rxrpc_poke_call(call, rxrpc_call_poke_start);
2700b58b8a1SDavid Howells }
2710b58b8a1SDavid Howells
2720b58b8a1SDavid Howells /*
2730b58b8a1SDavid Howells * send data through a socket
2740b58b8a1SDavid Howells * - must be called in process context
275540b1c48SDavid Howells * - The caller holds the call user access mutex, but not the socket lock.
2760b58b8a1SDavid Howells */
rxrpc_send_data(struct rxrpc_sock * rx,struct rxrpc_call * call,struct msghdr * msg,size_t len,rxrpc_notify_end_tx_t notify_end_tx,bool * _dropped_lock)2770b58b8a1SDavid Howells static int rxrpc_send_data(struct rxrpc_sock *rx,
2780b58b8a1SDavid Howells struct rxrpc_call *call,
279e833251aSDavid Howells struct msghdr *msg, size_t len,
280b0f571ecSDavid Howells rxrpc_notify_end_tx_t notify_end_tx,
281b0f571ecSDavid Howells bool *_dropped_lock)
2820b58b8a1SDavid Howells {
283a4ea4c47SDavid Howells struct rxrpc_txbuf *txb;
2840b58b8a1SDavid Howells struct sock *sk = &rx->sk;
285b0f571ecSDavid Howells enum rxrpc_call_state state;
2860b58b8a1SDavid Howells long timeo;
287b0f571ecSDavid Howells bool more = msg->msg_flags & MSG_MORE;
288b0f571ecSDavid Howells int ret, copied = 0;
2890b58b8a1SDavid Howells
2900b58b8a1SDavid Howells timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
2910b58b8a1SDavid Howells
2929d35d880SDavid Howells ret = rxrpc_wait_to_be_connected(call, &timeo);
2939d35d880SDavid Howells if (ret < 0)
2949d35d880SDavid Howells return ret;
2959d35d880SDavid Howells
2969d35d880SDavid Howells if (call->conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
2979d35d880SDavid Howells ret = rxrpc_init_client_conn_security(call->conn);
2989d35d880SDavid Howells if (ret < 0)
2999d35d880SDavid Howells return ret;
3009d35d880SDavid Howells }
3019d35d880SDavid Howells
3020b58b8a1SDavid Howells /* this should be in poll */
3030b58b8a1SDavid Howells sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
3040b58b8a1SDavid Howells
305b0f571ecSDavid Howells reload:
306446be550SDavid Howells txb = call->tx_pending;
307446be550SDavid Howells call->tx_pending = NULL;
308446be550SDavid Howells if (txb)
309446be550SDavid Howells rxrpc_see_txbuf(txb, rxrpc_txbuf_see_send_more);
310446be550SDavid Howells
311b0f571ecSDavid Howells ret = -EPIPE;
312639f181fSDavid Howells if (sk->sk_shutdown & SEND_SHUTDOWN)
313b0f571ecSDavid Howells goto maybe_error;
314d41b3f5bSDavid Howells state = rxrpc_call_state(call);
315b0f571ecSDavid Howells ret = -ESHUTDOWN;
316b0f571ecSDavid Howells if (state >= RXRPC_CALL_COMPLETE)
317b0f571ecSDavid Howells goto maybe_error;
318b0f571ecSDavid Howells ret = -EPROTO;
319b0f571ecSDavid Howells if (state != RXRPC_CALL_CLIENT_SEND_REQUEST &&
320b0f571ecSDavid Howells state != RXRPC_CALL_SERVER_ACK_REQUEST &&
3212d689424SDavid Howells state != RXRPC_CALL_SERVER_SEND_REPLY) {
3222d689424SDavid Howells /* Request phase complete for this client call */
3232d689424SDavid Howells trace_rxrpc_abort(call->debug_id, rxrpc_sendmsg_late_send,
3242d689424SDavid Howells call->cid, call->call_id, call->rx_consumed,
3252d689424SDavid Howells 0, -EPROTO);
326b0f571ecSDavid Howells goto maybe_error;
3272d689424SDavid Howells }
3280b58b8a1SDavid Howells
329b0f571ecSDavid Howells ret = -EMSGSIZE;
330e754eba6SDavid Howells if (call->tx_total_len != -1) {
331b0f571ecSDavid Howells if (len - copied > call->tx_total_len)
332b0f571ecSDavid Howells goto maybe_error;
333b0f571ecSDavid Howells if (!more && len - copied != call->tx_total_len)
334b0f571ecSDavid Howells goto maybe_error;
335e754eba6SDavid Howells }
336e754eba6SDavid Howells
3370b58b8a1SDavid Howells do {
338a4ea4c47SDavid Howells if (!txb) {
339d7d775b1SDavid Howells size_t remain, bufsize, chunk, offset;
3400b58b8a1SDavid Howells
3410b58b8a1SDavid Howells _debug("alloc");
3420b58b8a1SDavid Howells
343b0f571ecSDavid Howells if (!rxrpc_check_tx_space(call, NULL))
344b0f571ecSDavid Howells goto wait_for_space;
3450b58b8a1SDavid Howells
346d7d775b1SDavid Howells /* Work out the maximum size of a packet. Assume that
347d7d775b1SDavid Howells * the security header is going to be in the padded
348d7d775b1SDavid Howells * region (enc blocksize), but the trailer is not.
349d7d775b1SDavid Howells */
350d7d775b1SDavid Howells remain = more ? INT_MAX : msg_data_left(msg);
351d7d775b1SDavid Howells ret = call->conn->security->how_much_data(call, remain,
352d7d775b1SDavid Howells &bufsize, &chunk, &offset);
353d7d775b1SDavid Howells if (ret < 0)
354d7d775b1SDavid Howells goto maybe_error;
3550b58b8a1SDavid Howells
356d7d775b1SDavid Howells _debug("SIZE: %zu/%zu @%zu", chunk, bufsize, offset);
3570b58b8a1SDavid Howells
3580b58b8a1SDavid Howells /* create a buffer that we can retain until it's ACK'd */
359a4ea4c47SDavid Howells ret = -ENOMEM;
360a4ea4c47SDavid Howells txb = rxrpc_alloc_txbuf(call, RXRPC_PACKET_TYPE_DATA,
361a4ea4c47SDavid Howells GFP_KERNEL);
362a4ea4c47SDavid Howells if (!txb)
3630b58b8a1SDavid Howells goto maybe_error;
3640b58b8a1SDavid Howells
365a4ea4c47SDavid Howells txb->offset = offset;
366a4ea4c47SDavid Howells txb->space -= offset;
367a4ea4c47SDavid Howells txb->space = min_t(size_t, chunk, txb->space);
3680b58b8a1SDavid Howells }
3690b58b8a1SDavid Howells
3700b58b8a1SDavid Howells _debug("append");
3710b58b8a1SDavid Howells
3720b58b8a1SDavid Howells /* append next segment of data to the current buffer */
3730b58b8a1SDavid Howells if (msg_data_left(msg) > 0) {
374a4ea4c47SDavid Howells size_t copy = min_t(size_t, txb->space, msg_data_left(msg));
3750b58b8a1SDavid Howells
376a4ea4c47SDavid Howells _debug("add %zu", copy);
377a4ea4c47SDavid Howells if (!copy_from_iter_full(txb->data + txb->offset, copy,
378a4ea4c47SDavid Howells &msg->msg_iter))
3790b58b8a1SDavid Howells goto efault;
380a4ea4c47SDavid Howells _debug("added");
381a4ea4c47SDavid Howells txb->space -= copy;
382a4ea4c47SDavid Howells txb->len += copy;
383a4ea4c47SDavid Howells txb->offset += copy;
3840b58b8a1SDavid Howells copied += copy;
385e754eba6SDavid Howells if (call->tx_total_len != -1)
386e754eba6SDavid Howells call->tx_total_len -= copy;
3870b58b8a1SDavid Howells }
3880b58b8a1SDavid Howells
389e122d845SDavid Howells /* check for the far side aborting the call or a network error
390e122d845SDavid Howells * occurring */
391d41b3f5bSDavid Howells if (rxrpc_call_is_complete(call))
392e122d845SDavid Howells goto call_terminated;
393e122d845SDavid Howells
3940b58b8a1SDavid Howells /* add the packet to the send queue if it's now full */
395a4ea4c47SDavid Howells if (!txb->space ||
3960b58b8a1SDavid Howells (msg_data_left(msg) == 0 && !more)) {
397a4ea4c47SDavid Howells if (msg_data_left(msg) == 0 && !more) {
398a4ea4c47SDavid Howells txb->wire.flags |= RXRPC_LAST_PACKET;
399a4ea4c47SDavid Howells __set_bit(RXRPC_TXBUF_LAST, &txb->flags);
400a4ea4c47SDavid Howells }
401a4ea4c47SDavid Howells else if (call->tx_top - call->acks_hard_ack <
402248f219cSDavid Howells call->tx_winsize)
403a4ea4c47SDavid Howells txb->wire.flags |= RXRPC_MORE_PACKETS;
4040b58b8a1SDavid Howells
405a4ea4c47SDavid Howells ret = call->security->secure_packet(call, txb);
4060b58b8a1SDavid Howells if (ret < 0)
4070b58b8a1SDavid Howells goto out;
4080b58b8a1SDavid Howells
409a4ea4c47SDavid Howells rxrpc_queue_packet(rx, call, txb, notify_end_tx);
410a4ea4c47SDavid Howells txb = NULL;
4110b58b8a1SDavid Howells }
4120b58b8a1SDavid Howells } while (msg_data_left(msg) > 0);
4130b58b8a1SDavid Howells
4140b58b8a1SDavid Howells success:
4150b58b8a1SDavid Howells ret = copied;
416d41b3f5bSDavid Howells if (rxrpc_call_is_complete(call) &&
417d41b3f5bSDavid Howells call->error < 0)
4184ba68c51SDavid Howells ret = call->error;
4190b58b8a1SDavid Howells out:
420a4ea4c47SDavid Howells call->tx_pending = txb;
4210b58b8a1SDavid Howells _leave(" = %d", ret);
4220b58b8a1SDavid Howells return ret;
4230b58b8a1SDavid Howells
424e122d845SDavid Howells call_terminated:
425a4ea4c47SDavid Howells rxrpc_put_txbuf(txb, rxrpc_txbuf_put_send_aborted);
426e122d845SDavid Howells _leave(" = %d", call->error);
427e122d845SDavid Howells return call->error;
428e122d845SDavid Howells
4290b58b8a1SDavid Howells maybe_error:
4300b58b8a1SDavid Howells if (copied)
4310b58b8a1SDavid Howells goto success;
4320b58b8a1SDavid Howells goto out;
4330b58b8a1SDavid Howells
4340b58b8a1SDavid Howells efault:
4350b58b8a1SDavid Howells ret = -EFAULT;
4360b58b8a1SDavid Howells goto out;
437b0f571ecSDavid Howells
438b0f571ecSDavid Howells wait_for_space:
439b0f571ecSDavid Howells ret = -EAGAIN;
440b0f571ecSDavid Howells if (msg->msg_flags & MSG_DONTWAIT)
441b0f571ecSDavid Howells goto maybe_error;
442b0f571ecSDavid Howells mutex_unlock(&call->user_mutex);
443b0f571ecSDavid Howells *_dropped_lock = true;
444b0f571ecSDavid Howells ret = rxrpc_wait_for_tx_window(rx, call, &timeo,
445b0f571ecSDavid Howells msg->msg_flags & MSG_WAITALL);
446b0f571ecSDavid Howells if (ret < 0)
447b0f571ecSDavid Howells goto maybe_error;
448b0f571ecSDavid Howells if (call->interruptibility == RXRPC_INTERRUPTIBLE) {
449b0f571ecSDavid Howells if (mutex_lock_interruptible(&call->user_mutex) < 0) {
450b0f571ecSDavid Howells ret = sock_intr_errno(timeo);
451b0f571ecSDavid Howells goto maybe_error;
452b0f571ecSDavid Howells }
453b0f571ecSDavid Howells } else {
454b0f571ecSDavid Howells mutex_lock(&call->user_mutex);
455b0f571ecSDavid Howells }
456b0f571ecSDavid Howells *_dropped_lock = false;
457b0f571ecSDavid Howells goto reload;
4580b58b8a1SDavid Howells }
459df423a4aSDavid Howells
460df423a4aSDavid Howells /*
461df423a4aSDavid Howells * extract control messages from the sendmsg() control buffer
462df423a4aSDavid Howells */
rxrpc_sendmsg_cmsg(struct msghdr * msg,struct rxrpc_send_params * p)4633ab26a6fSDavid Howells static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)
464df423a4aSDavid Howells {
465df423a4aSDavid Howells struct cmsghdr *cmsg;
466df423a4aSDavid Howells bool got_user_ID = false;
467df423a4aSDavid Howells int len;
468df423a4aSDavid Howells
469df423a4aSDavid Howells if (msg->msg_controllen == 0)
470df423a4aSDavid Howells return -EINVAL;
471df423a4aSDavid Howells
472df423a4aSDavid Howells for_each_cmsghdr(cmsg, msg) {
473df423a4aSDavid Howells if (!CMSG_OK(msg, cmsg))
474df423a4aSDavid Howells return -EINVAL;
475df423a4aSDavid Howells
4761ff8cebfSyuan linyu len = cmsg->cmsg_len - sizeof(struct cmsghdr);
477df423a4aSDavid Howells _debug("CMSG %d, %d, %d",
478df423a4aSDavid Howells cmsg->cmsg_level, cmsg->cmsg_type, len);
479df423a4aSDavid Howells
480df423a4aSDavid Howells if (cmsg->cmsg_level != SOL_RXRPC)
481df423a4aSDavid Howells continue;
482df423a4aSDavid Howells
483df423a4aSDavid Howells switch (cmsg->cmsg_type) {
484df423a4aSDavid Howells case RXRPC_USER_CALL_ID:
485df423a4aSDavid Howells if (msg->msg_flags & MSG_CMSG_COMPAT) {
486df423a4aSDavid Howells if (len != sizeof(u32))
487df423a4aSDavid Howells return -EINVAL;
48848124178SDavid Howells p->call.user_call_ID = *(u32 *)CMSG_DATA(cmsg);
489df423a4aSDavid Howells } else {
490df423a4aSDavid Howells if (len != sizeof(unsigned long))
491df423a4aSDavid Howells return -EINVAL;
49248124178SDavid Howells p->call.user_call_ID = *(unsigned long *)
493df423a4aSDavid Howells CMSG_DATA(cmsg);
494df423a4aSDavid Howells }
495df423a4aSDavid Howells got_user_ID = true;
496df423a4aSDavid Howells break;
497df423a4aSDavid Howells
498df423a4aSDavid Howells case RXRPC_ABORT:
4993ab26a6fSDavid Howells if (p->command != RXRPC_CMD_SEND_DATA)
500df423a4aSDavid Howells return -EINVAL;
5013ab26a6fSDavid Howells p->command = RXRPC_CMD_SEND_ABORT;
5023ab26a6fSDavid Howells if (len != sizeof(p->abort_code))
503df423a4aSDavid Howells return -EINVAL;
5043ab26a6fSDavid Howells p->abort_code = *(unsigned int *)CMSG_DATA(cmsg);
5053ab26a6fSDavid Howells if (p->abort_code == 0)
506df423a4aSDavid Howells return -EINVAL;
507df423a4aSDavid Howells break;
508df423a4aSDavid Howells
5092d914c1bSDavid Howells case RXRPC_CHARGE_ACCEPT:
5103ab26a6fSDavid Howells if (p->command != RXRPC_CMD_SEND_DATA)
511df423a4aSDavid Howells return -EINVAL;
5122d914c1bSDavid Howells p->command = RXRPC_CMD_CHARGE_ACCEPT;
513df423a4aSDavid Howells if (len != 0)
514df423a4aSDavid Howells return -EINVAL;
515df423a4aSDavid Howells break;
516df423a4aSDavid Howells
517df423a4aSDavid Howells case RXRPC_EXCLUSIVE_CALL:
5183ab26a6fSDavid Howells p->exclusive = true;
519df423a4aSDavid Howells if (len != 0)
520df423a4aSDavid Howells return -EINVAL;
521df423a4aSDavid Howells break;
5224e255721SDavid Howells
5234e255721SDavid Howells case RXRPC_UPGRADE_SERVICE:
5243ab26a6fSDavid Howells p->upgrade = true;
5254e255721SDavid Howells if (len != 0)
5264e255721SDavid Howells return -EINVAL;
5274e255721SDavid Howells break;
5284e255721SDavid Howells
529e754eba6SDavid Howells case RXRPC_TX_LENGTH:
53048124178SDavid Howells if (p->call.tx_total_len != -1 || len != sizeof(__s64))
531e754eba6SDavid Howells return -EINVAL;
53248124178SDavid Howells p->call.tx_total_len = *(__s64 *)CMSG_DATA(cmsg);
53348124178SDavid Howells if (p->call.tx_total_len < 0)
534e754eba6SDavid Howells return -EINVAL;
535e754eba6SDavid Howells break;
536e754eba6SDavid Howells
537a158bdd3SDavid Howells case RXRPC_SET_CALL_TIMEOUT:
538a158bdd3SDavid Howells if (len & 3 || len < 4 || len > 12)
539a158bdd3SDavid Howells return -EINVAL;
540a158bdd3SDavid Howells memcpy(&p->call.timeouts, CMSG_DATA(cmsg), len);
541a158bdd3SDavid Howells p->call.nr_timeouts = len / 4;
542a158bdd3SDavid Howells if (p->call.timeouts.hard > INT_MAX / HZ)
543a158bdd3SDavid Howells return -ERANGE;
544a158bdd3SDavid Howells if (p->call.nr_timeouts >= 2 && p->call.timeouts.idle > 60 * 60 * 1000)
545a158bdd3SDavid Howells return -ERANGE;
546a158bdd3SDavid Howells if (p->call.nr_timeouts >= 3 && p->call.timeouts.normal > 60 * 60 * 1000)
547a158bdd3SDavid Howells return -ERANGE;
548a158bdd3SDavid Howells break;
549a158bdd3SDavid Howells
550df423a4aSDavid Howells default:
551df423a4aSDavid Howells return -EINVAL;
552df423a4aSDavid Howells }
553df423a4aSDavid Howells }
554df423a4aSDavid Howells
555df423a4aSDavid Howells if (!got_user_ID)
556df423a4aSDavid Howells return -EINVAL;
55748124178SDavid Howells if (p->call.tx_total_len != -1 && p->command != RXRPC_CMD_SEND_DATA)
558e754eba6SDavid Howells return -EINVAL;
559df423a4aSDavid Howells _leave(" = 0");
560df423a4aSDavid Howells return 0;
561df423a4aSDavid Howells }
562df423a4aSDavid Howells
563df423a4aSDavid Howells /*
564df423a4aSDavid Howells * Create a new client call for sendmsg().
565540b1c48SDavid Howells * - Called with the socket lock held, which it must release.
566540b1c48SDavid Howells * - If it returns a call, the call's lock will need releasing by the caller.
567df423a4aSDavid Howells */
568df423a4aSDavid Howells static struct rxrpc_call *
rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock * rx,struct msghdr * msg,struct rxrpc_send_params * p)569df423a4aSDavid Howells rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg,
5703ab26a6fSDavid Howells struct rxrpc_send_params *p)
571540b1c48SDavid Howells __releases(&rx->sk.sk_lock.slock)
57288f2a825SDavid Howells __acquires(&call->user_mutex)
573df423a4aSDavid Howells {
574df423a4aSDavid Howells struct rxrpc_conn_parameters cp;
575df423a4aSDavid Howells struct rxrpc_call *call;
576df423a4aSDavid Howells struct key *key;
577df423a4aSDavid Howells
578df423a4aSDavid Howells DECLARE_SOCKADDR(struct sockaddr_rxrpc *, srx, msg->msg_name);
579df423a4aSDavid Howells
580df423a4aSDavid Howells _enter("");
581df423a4aSDavid Howells
582540b1c48SDavid Howells if (!msg->msg_name) {
583540b1c48SDavid Howells release_sock(&rx->sk);
584df423a4aSDavid Howells return ERR_PTR(-EDESTADDRREQ);
585540b1c48SDavid Howells }
586df423a4aSDavid Howells
587df423a4aSDavid Howells key = rx->key;
588df423a4aSDavid Howells if (key && !rx->key->payload.data[0])
589df423a4aSDavid Howells key = NULL;
590df423a4aSDavid Howells
591df423a4aSDavid Howells memset(&cp, 0, sizeof(cp));
592df423a4aSDavid Howells cp.local = rx->local;
593df423a4aSDavid Howells cp.key = rx->key;
594df423a4aSDavid Howells cp.security_level = rx->min_sec_level;
5953ab26a6fSDavid Howells cp.exclusive = rx->exclusive | p->exclusive;
5963ab26a6fSDavid Howells cp.upgrade = p->upgrade;
597df423a4aSDavid Howells cp.service_id = srx->srx_service;
598a25e21f0SDavid Howells call = rxrpc_new_client_call(rx, &cp, srx, &p->call, GFP_KERNEL,
599a25e21f0SDavid Howells atomic_inc_return(&rxrpc_debug_id));
600540b1c48SDavid Howells /* The socket is now unlocked */
601df423a4aSDavid Howells
602df423a4aSDavid Howells _leave(" = %p\n", call);
603df423a4aSDavid Howells return call;
604df423a4aSDavid Howells }
605df423a4aSDavid Howells
606df423a4aSDavid Howells /*
607df423a4aSDavid Howells * send a message forming part of a client call through an RxRPC socket
608df423a4aSDavid Howells * - caller holds the socket locked
609df423a4aSDavid Howells * - the socket may be either a client socket or a server socket
610df423a4aSDavid Howells */
rxrpc_do_sendmsg(struct rxrpc_sock * rx,struct msghdr * msg,size_t len)611df423a4aSDavid Howells int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
612540b1c48SDavid Howells __releases(&rx->sk.sk_lock.slock)
613df423a4aSDavid Howells {
614df423a4aSDavid Howells struct rxrpc_call *call;
615a158bdd3SDavid Howells unsigned long now, j;
616b0f571ecSDavid Howells bool dropped_lock = false;
617df423a4aSDavid Howells int ret;
618df423a4aSDavid Howells
6193ab26a6fSDavid Howells struct rxrpc_send_params p = {
62048124178SDavid Howells .call.tx_total_len = -1,
62148124178SDavid Howells .call.user_call_ID = 0,
622a158bdd3SDavid Howells .call.nr_timeouts = 0,
623e138aa7dSDavid Howells .call.interruptibility = RXRPC_INTERRUPTIBLE,
6243ab26a6fSDavid Howells .abort_code = 0,
6253ab26a6fSDavid Howells .command = RXRPC_CMD_SEND_DATA,
6263ab26a6fSDavid Howells .exclusive = false,
62748ca2463SDavid Howells .upgrade = false,
6283ab26a6fSDavid Howells };
6293ab26a6fSDavid Howells
630df423a4aSDavid Howells _enter("");
631df423a4aSDavid Howells
6323ab26a6fSDavid Howells ret = rxrpc_sendmsg_cmsg(msg, &p);
633df423a4aSDavid Howells if (ret < 0)
634540b1c48SDavid Howells goto error_release_sock;
635df423a4aSDavid Howells
6362d914c1bSDavid Howells if (p.command == RXRPC_CMD_CHARGE_ACCEPT) {
637540b1c48SDavid Howells ret = -EINVAL;
638df423a4aSDavid Howells if (rx->sk.sk_state != RXRPC_SERVER_LISTENING)
639540b1c48SDavid Howells goto error_release_sock;
6402d914c1bSDavid Howells ret = rxrpc_user_charge_accept(rx, p.call.user_call_ID);
6412d914c1bSDavid Howells goto error_release_sock;
642df423a4aSDavid Howells }
643df423a4aSDavid Howells
64448124178SDavid Howells call = rxrpc_find_call_by_user_ID(rx, p.call.user_call_ID);
645df423a4aSDavid Howells if (!call) {
646540b1c48SDavid Howells ret = -EBADSLT;
6473ab26a6fSDavid Howells if (p.command != RXRPC_CMD_SEND_DATA)
648540b1c48SDavid Howells goto error_release_sock;
6493ab26a6fSDavid Howells call = rxrpc_new_client_call_for_sendmsg(rx, msg, &p);
650540b1c48SDavid Howells /* The socket is now unlocked... */
651df423a4aSDavid Howells if (IS_ERR(call))
652df423a4aSDavid Howells return PTR_ERR(call);
653540b1c48SDavid Howells /* ... and we have the call lock. */
654db099c62SDavid Howells p.call.nr_timeouts = 0;
65565550098SDavid Howells ret = 0;
656d41b3f5bSDavid Howells if (rxrpc_call_is_complete(call))
65765550098SDavid Howells goto out_put_unlock;
658540b1c48SDavid Howells } else {
659d41b3f5bSDavid Howells switch (rxrpc_call_state(call)) {
660146d8fefSDavid Howells case RXRPC_CALL_CLIENT_AWAIT_CONN:
661*7770b221SDavid Howells case RXRPC_CALL_SERVER_RECV_REQUEST:
6620eb362d2SDavid Howells if (p.command == RXRPC_CMD_SEND_ABORT)
6630eb362d2SDavid Howells break;
6640eb362d2SDavid Howells fallthrough;
6650eb362d2SDavid Howells case RXRPC_CALL_UNINITIALISED:
6660eb362d2SDavid Howells case RXRPC_CALL_SERVER_PREALLOC:
667cb0fc0c9SDavid Howells rxrpc_put_call(call, rxrpc_call_put_sendmsg);
66837411cadSDavid Howells ret = -EBUSY;
66937411cadSDavid Howells goto error_release_sock;
670146d8fefSDavid Howells default:
671146d8fefSDavid Howells break;
672146d8fefSDavid Howells }
67337411cadSDavid Howells
674540b1c48SDavid Howells ret = mutex_lock_interruptible(&call->user_mutex);
675540b1c48SDavid Howells release_sock(&rx->sk);
676540b1c48SDavid Howells if (ret < 0) {
677540b1c48SDavid Howells ret = -ERESTARTSYS;
678540b1c48SDavid Howells goto error_put;
679540b1c48SDavid Howells }
680e754eba6SDavid Howells
68148124178SDavid Howells if (p.call.tx_total_len != -1) {
682e754eba6SDavid Howells ret = -EINVAL;
683e754eba6SDavid Howells if (call->tx_total_len != -1 ||
684e754eba6SDavid Howells call->tx_pending ||
685e754eba6SDavid Howells call->tx_top != 0)
6864feb2c44SDavid Howells goto out_put_unlock;
68748124178SDavid Howells call->tx_total_len = p.call.tx_total_len;
688e754eba6SDavid Howells }
689df423a4aSDavid Howells }
690df423a4aSDavid Howells
691a158bdd3SDavid Howells switch (p.call.nr_timeouts) {
692a158bdd3SDavid Howells case 3:
693a158bdd3SDavid Howells j = msecs_to_jiffies(p.call.timeouts.normal);
694a158bdd3SDavid Howells if (p.call.timeouts.normal > 0 && j == 0)
695a158bdd3SDavid Howells j = 1;
696a158bdd3SDavid Howells WRITE_ONCE(call->next_rx_timo, j);
697df561f66SGustavo A. R. Silva fallthrough;
698a158bdd3SDavid Howells case 2:
699a158bdd3SDavid Howells j = msecs_to_jiffies(p.call.timeouts.idle);
700a158bdd3SDavid Howells if (p.call.timeouts.idle > 0 && j == 0)
701a158bdd3SDavid Howells j = 1;
702a158bdd3SDavid Howells WRITE_ONCE(call->next_req_timo, j);
703df561f66SGustavo A. R. Silva fallthrough;
704a158bdd3SDavid Howells case 1:
705a158bdd3SDavid Howells if (p.call.timeouts.hard > 0) {
7060d098d83SDavid Howells j = p.call.timeouts.hard * HZ;
707a158bdd3SDavid Howells now = jiffies;
708a158bdd3SDavid Howells j += now;
709a158bdd3SDavid Howells WRITE_ONCE(call->expect_term_by, j);
710a158bdd3SDavid Howells rxrpc_reduce_call_timer(call, j, now,
711a158bdd3SDavid Howells rxrpc_timer_set_for_hard);
712a158bdd3SDavid Howells }
713a158bdd3SDavid Howells break;
714a158bdd3SDavid Howells }
715a158bdd3SDavid Howells
7162d689424SDavid Howells if (rxrpc_call_is_complete(call)) {
717df423a4aSDavid Howells /* it's too late for this call */
718df423a4aSDavid Howells ret = -ESHUTDOWN;
7193ab26a6fSDavid Howells } else if (p.command == RXRPC_CMD_SEND_ABORT) {
72057af281eSDavid Howells rxrpc_propose_abort(call, p.abort_code, -ECONNABORTED,
72157af281eSDavid Howells rxrpc_abort_call_sendmsg);
722df423a4aSDavid Howells ret = 0;
7233ab26a6fSDavid Howells } else if (p.command != RXRPC_CMD_SEND_DATA) {
724df423a4aSDavid Howells ret = -EINVAL;
725df423a4aSDavid Howells } else {
726b0f571ecSDavid Howells ret = rxrpc_send_data(rx, call, msg, len, NULL, &dropped_lock);
727df423a4aSDavid Howells }
728df423a4aSDavid Howells
72903a6c822SDavid Howells out_put_unlock:
730b0f571ecSDavid Howells if (!dropped_lock)
731540b1c48SDavid Howells mutex_unlock(&call->user_mutex);
732540b1c48SDavid Howells error_put:
733cb0fc0c9SDavid Howells rxrpc_put_call(call, rxrpc_call_put_sendmsg);
734df423a4aSDavid Howells _leave(" = %d", ret);
735df423a4aSDavid Howells return ret;
736540b1c48SDavid Howells
737540b1c48SDavid Howells error_release_sock:
738540b1c48SDavid Howells release_sock(&rx->sk);
739540b1c48SDavid Howells return ret;
740df423a4aSDavid Howells }
741df423a4aSDavid Howells
742df423a4aSDavid Howells /**
743df423a4aSDavid Howells * rxrpc_kernel_send_data - Allow a kernel service to send data on a call
744df423a4aSDavid Howells * @sock: The socket the call is on
745df423a4aSDavid Howells * @call: The call to send data through
746df423a4aSDavid Howells * @msg: The data to send
747df423a4aSDavid Howells * @len: The amount of data to send
748e833251aSDavid Howells * @notify_end_tx: Notification that the last packet is queued.
749df423a4aSDavid Howells *
750df423a4aSDavid Howells * Allow a kernel service to send data on a call. The call must be in an state
751df423a4aSDavid Howells * appropriate to sending data. No control data should be supplied in @msg,
752df423a4aSDavid Howells * nor should an address be supplied. MSG_MORE should be flagged if there's
753df423a4aSDavid Howells * more data to come, otherwise this data will end the transmission phase.
754df423a4aSDavid Howells */
rxrpc_kernel_send_data(struct socket * sock,struct rxrpc_call * call,struct msghdr * msg,size_t len,rxrpc_notify_end_tx_t notify_end_tx)755df423a4aSDavid Howells int rxrpc_kernel_send_data(struct socket *sock, struct rxrpc_call *call,
756e833251aSDavid Howells struct msghdr *msg, size_t len,
757e833251aSDavid Howells rxrpc_notify_end_tx_t notify_end_tx)
758df423a4aSDavid Howells {
759b0f571ecSDavid Howells bool dropped_lock = false;
760df423a4aSDavid Howells int ret;
761df423a4aSDavid Howells
7622d689424SDavid Howells _enter("{%d},", call->debug_id);
763df423a4aSDavid Howells
764df423a4aSDavid Howells ASSERTCMP(msg->msg_name, ==, NULL);
765df423a4aSDavid Howells ASSERTCMP(msg->msg_control, ==, NULL);
766df423a4aSDavid Howells
767540b1c48SDavid Howells mutex_lock(&call->user_mutex);
768df423a4aSDavid Howells
769e833251aSDavid Howells ret = rxrpc_send_data(rxrpc_sk(sock->sk), call, msg, len,
770b0f571ecSDavid Howells notify_end_tx, &dropped_lock);
7712d689424SDavid Howells if (ret == -ESHUTDOWN)
772bd2db2d2SDavid Howells ret = call->error;
773df423a4aSDavid Howells
774b0f571ecSDavid Howells if (!dropped_lock)
775540b1c48SDavid Howells mutex_unlock(&call->user_mutex);
776df423a4aSDavid Howells _leave(" = %d", ret);
777df423a4aSDavid Howells return ret;
778df423a4aSDavid Howells }
779df423a4aSDavid Howells EXPORT_SYMBOL(rxrpc_kernel_send_data);
780df423a4aSDavid Howells
781df423a4aSDavid Howells /**
782df423a4aSDavid Howells * rxrpc_kernel_abort_call - Allow a kernel service to abort a call
783df423a4aSDavid Howells * @sock: The socket the call is on
784df423a4aSDavid Howells * @call: The call to be aborted
785df423a4aSDavid Howells * @abort_code: The abort code to stick into the ABORT packet
7865a42976dSDavid Howells * @error: Local error value
78757af281eSDavid Howells * @why: Indication as to why.
788df423a4aSDavid Howells *
78984a4c09cSDavid Howells * Allow a kernel service to abort a call, if it's still in an abortable state
79084a4c09cSDavid Howells * and return true if the call was aborted, false if it was already complete.
791df423a4aSDavid Howells */
rxrpc_kernel_abort_call(struct socket * sock,struct rxrpc_call * call,u32 abort_code,int error,enum rxrpc_abort_reason why)79284a4c09cSDavid Howells bool rxrpc_kernel_abort_call(struct socket *sock, struct rxrpc_call *call,
79357af281eSDavid Howells u32 abort_code, int error, enum rxrpc_abort_reason why)
794df423a4aSDavid Howells {
79584a4c09cSDavid Howells bool aborted;
79684a4c09cSDavid Howells
79757af281eSDavid Howells _enter("{%d},%d,%d,%u", call->debug_id, abort_code, error, why);
798df423a4aSDavid Howells
799540b1c48SDavid Howells mutex_lock(&call->user_mutex);
800a343b174SDavid Howells aborted = rxrpc_propose_abort(call, abort_code, error, why);
801540b1c48SDavid Howells mutex_unlock(&call->user_mutex);
80284a4c09cSDavid Howells return aborted;
803df423a4aSDavid Howells }
804df423a4aSDavid Howells EXPORT_SYMBOL(rxrpc_kernel_abort_call);
805e754eba6SDavid Howells
806e754eba6SDavid Howells /**
807e754eba6SDavid Howells * rxrpc_kernel_set_tx_length - Set the total Tx length on a call
808e754eba6SDavid Howells * @sock: The socket the call is on
809e754eba6SDavid Howells * @call: The call to be informed
810e754eba6SDavid Howells * @tx_total_len: The amount of data to be transmitted for this call
811e754eba6SDavid Howells *
812e754eba6SDavid Howells * Allow a kernel service to set the total transmit length on a call. This
813e754eba6SDavid Howells * allows buffer-to-packet encrypt-and-copy to be performed.
814e754eba6SDavid Howells *
815e754eba6SDavid Howells * This function is primarily for use for setting the reply length since the
816e754eba6SDavid Howells * request length can be set when beginning the call.
817e754eba6SDavid Howells */
rxrpc_kernel_set_tx_length(struct socket * sock,struct rxrpc_call * call,s64 tx_total_len)818e754eba6SDavid Howells void rxrpc_kernel_set_tx_length(struct socket *sock, struct rxrpc_call *call,
819e754eba6SDavid Howells s64 tx_total_len)
820e754eba6SDavid Howells {
821e754eba6SDavid Howells WARN_ON(call->tx_total_len != -1);
822e754eba6SDavid Howells call->tx_total_len = tx_total_len;
823e754eba6SDavid Howells }
824e754eba6SDavid Howells EXPORT_SYMBOL(rxrpc_kernel_set_tx_length);
825