Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
17926a79 DH |
2 | /* RxRPC recvmsg() implementation |
3 | * | |
4 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
5 | * Written by David Howells (dhowells@redhat.com) | |
17926a79 DH |
6 | */ |
7 | ||
9b6d5398 JP |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9 | ||
17926a79 DH |
10 | #include <linux/net.h> |
11 | #include <linux/skbuff.h> | |
bc3b2d7f | 12 | #include <linux/export.h> |
174cd4b1 IM |
13 | #include <linux/sched/signal.h> |
14 | ||
17926a79 DH |
15 | #include <net/sock.h> |
16 | #include <net/af_rxrpc.h> | |
17 | #include "ar-internal.h" | |
18 | ||
17926a79 | 19 | /* |
248f219c DH |
20 | * Post a call for attention by the socket or kernel service. Further |
21 | * notifications are suppressed by putting recvmsg_link on a dummy queue. | |
17926a79 | 22 | */ |
248f219c | 23 | void rxrpc_notify_socket(struct rxrpc_call *call) |
17926a79 | 24 | { |
248f219c DH |
25 | struct rxrpc_sock *rx; |
26 | struct sock *sk; | |
17926a79 | 27 | |
248f219c | 28 | _enter("%d", call->debug_id); |
17926a79 | 29 | |
248f219c DH |
30 | if (!list_empty(&call->recvmsg_link)) |
31 | return; | |
32 | ||
33 | rcu_read_lock(); | |
34 | ||
35 | rx = rcu_dereference(call->socket); | |
36 | sk = &rx->sk; | |
37 | if (rx && sk->sk_state < RXRPC_CLOSE) { | |
38 | if (call->notify_rx) { | |
3dd9c8b5 | 39 | spin_lock(&call->notify_lock); |
248f219c | 40 | call->notify_rx(sk, call, call->user_call_ID); |
3dd9c8b5 | 41 | spin_unlock(&call->notify_lock); |
248f219c | 42 | } else { |
223f5901 | 43 | spin_lock(&rx->recvmsg_lock); |
248f219c | 44 | if (list_empty(&call->recvmsg_link)) { |
cb0fc0c9 | 45 | rxrpc_get_call(call, rxrpc_call_get_notify_socket); |
248f219c DH |
46 | list_add_tail(&call->recvmsg_link, &rx->recvmsg_q); |
47 | } | |
223f5901 | 48 | spin_unlock(&rx->recvmsg_lock); |
17926a79 | 49 | |
248f219c DH |
50 | if (!sock_flag(sk, SOCK_DEAD)) { |
51 | _debug("call %ps", sk->sk_data_ready); | |
52 | sk->sk_data_ready(sk); | |
53 | } | |
54 | } | |
55 | } | |
17926a79 | 56 | |
248f219c DH |
57 | rcu_read_unlock(); |
58 | _leave(""); | |
59 | } | |
17926a79 | 60 | |
248f219c DH |
61 | /* |
62 | * Pass a call terminating message to userspace. | |
63 | */ | |
64 | static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg) | |
65 | { | |
66 | u32 tmp = 0; | |
67 | int ret; | |
17926a79 | 68 | |
248f219c DH |
69 | switch (call->completion) { |
70 | case RXRPC_CALL_SUCCEEDED: | |
71 | ret = 0; | |
72 | if (rxrpc_is_service_call(call)) | |
73 | ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ACK, 0, &tmp); | |
74 | break; | |
75 | case RXRPC_CALL_REMOTELY_ABORTED: | |
76 | tmp = call->abort_code; | |
77 | ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ABORT, 4, &tmp); | |
78 | break; | |
79 | case RXRPC_CALL_LOCALLY_ABORTED: | |
80 | tmp = call->abort_code; | |
81 | ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ABORT, 4, &tmp); | |
82 | break; | |
83 | case RXRPC_CALL_NETWORK_ERROR: | |
3a92789a | 84 | tmp = -call->error; |
248f219c DH |
85 | ret = put_cmsg(msg, SOL_RXRPC, RXRPC_NET_ERROR, 4, &tmp); |
86 | break; | |
87 | case RXRPC_CALL_LOCAL_ERROR: | |
3a92789a | 88 | tmp = -call->error; |
248f219c DH |
89 | ret = put_cmsg(msg, SOL_RXRPC, RXRPC_LOCAL_ERROR, 4, &tmp); |
90 | break; | |
91 | default: | |
d41b3f5b | 92 | pr_err("Invalid terminal call state %u\n", call->completion); |
248f219c DH |
93 | BUG(); |
94 | break; | |
95 | } | |
17926a79 | 96 | |
5d7edbc9 | 97 | trace_rxrpc_recvdata(call, rxrpc_recvmsg_terminal, |
5bbf9533 | 98 | call->ackr_window - 1, |
faf92e8d | 99 | call->rx_pkt_offset, call->rx_pkt_len, ret); |
248f219c DH |
100 | return ret; |
101 | } | |
17926a79 | 102 | |
248f219c DH |
103 | /* |
104 | * Discard a packet we've used up and advance the Rx window by one. | |
105 | */ | |
106 | static void rxrpc_rotate_rx_window(struct rxrpc_call *call) | |
107 | { | |
816c9fce | 108 | struct rxrpc_skb_priv *sp; |
248f219c | 109 | struct sk_buff *skb; |
58dc63c9 | 110 | rxrpc_serial_t serial; |
5d7edbc9 DH |
111 | rxrpc_seq_t old_consumed = call->rx_consumed, tseq; |
112 | bool last; | |
113 | int acked; | |
248f219c DH |
114 | |
115 | _enter("%d", call->debug_id); | |
116 | ||
5d7edbc9 | 117 | skb = skb_dequeue(&call->recvmsg_queue); |
9a36a6bc | 118 | rxrpc_see_skb(skb, rxrpc_skb_see_rotate); |
e2de6c40 | 119 | |
5d7edbc9 DH |
120 | sp = rxrpc_skb(skb); |
121 | tseq = sp->hdr.seq; | |
d4d02d8b | 122 | serial = sp->hdr.serial; |
5d7edbc9 | 123 | last = sp->hdr.flags & RXRPC_LAST_PACKET; |
e2de6c40 | 124 | |
248f219c | 125 | /* Barrier against rxrpc_input_data(). */ |
5d7edbc9 DH |
126 | if (after(tseq, call->rx_consumed)) |
127 | smp_store_release(&call->rx_consumed, tseq); | |
17926a79 | 128 | |
9a36a6bc | 129 | rxrpc_free_skb(skb, rxrpc_skb_put_rotate); |
17926a79 | 130 | |
5d7edbc9 DH |
131 | trace_rxrpc_receive(call, last ? rxrpc_receive_rotate_last : rxrpc_receive_rotate, |
132 | serial, call->rx_consumed); | |
93368b6b DH |
133 | |
134 | if (last) | |
135 | set_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags); | |
5d7edbc9 | 136 | |
5d7edbc9 DH |
137 | /* Check to see if there's an ACK that needs sending. */ |
138 | acked = atomic_add_return(call->rx_consumed - old_consumed, | |
139 | &call->ackr_nr_consumed); | |
5a2c5a5b | 140 | if (acked > 8 && |
5e6ef4f1 DH |
141 | !test_and_set_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags)) |
142 | rxrpc_poke_call(call, rxrpc_call_poke_idle); | |
248f219c DH |
143 | } |
144 | ||
145 | /* | |
d4d02d8b | 146 | * Decrypt and verify a DATA packet. |
248f219c | 147 | */ |
d4d02d8b | 148 | static int rxrpc_verify_data(struct rxrpc_call *call, struct sk_buff *skb) |
248f219c DH |
149 | { |
150 | struct rxrpc_skb_priv *sp = rxrpc_skb(skb); | |
17926a79 | 151 | |
d4d02d8b DH |
152 | if (sp->flags & RXRPC_RX_VERIFIED) |
153 | return 0; | |
154 | return call->security->verify_packet(call, skb); | |
248f219c | 155 | } |
17926a79 | 156 | |
248f219c DH |
157 | /* |
158 | * Deliver messages to a call. This keeps processing packets until the buffer | |
159 | * is filled and we find either more DATA (returns 0) or the end of the DATA | |
93368b6b DH |
160 | * (returns 1). If more packets are required, it returns -EAGAIN and if the |
161 | * call has failed it returns -EIO. | |
248f219c DH |
162 | */ |
163 | static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, | |
164 | struct msghdr *msg, struct iov_iter *iter, | |
165 | size_t len, int flags, size_t *_offset) | |
166 | { | |
167 | struct rxrpc_skb_priv *sp; | |
168 | struct sk_buff *skb; | |
5d7edbc9 | 169 | rxrpc_seq_t seq = 0; |
248f219c | 170 | size_t remain; |
248f219c | 171 | unsigned int rx_pkt_offset, rx_pkt_len; |
5d7edbc9 | 172 | int copy, ret = -EAGAIN, ret2; |
248f219c | 173 | |
248f219c DH |
174 | rx_pkt_offset = call->rx_pkt_offset; |
175 | rx_pkt_len = call->rx_pkt_len; | |
176 | ||
93368b6b | 177 | if (rxrpc_call_has_failed(call)) { |
5bbf9533 | 178 | seq = call->ackr_window - 1; |
93368b6b DH |
179 | ret = -EIO; |
180 | goto done; | |
181 | } | |
182 | ||
183 | if (test_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags)) { | |
5bbf9533 | 184 | seq = call->ackr_window - 1; |
816c9fce DH |
185 | ret = 1; |
186 | goto done; | |
187 | } | |
188 | ||
5d7edbc9 DH |
189 | /* No one else can be removing stuff from the queue, so we shouldn't |
190 | * need the Rx lock to walk it. | |
191 | */ | |
192 | skb = skb_peek(&call->recvmsg_queue); | |
193 | while (skb) { | |
9a36a6bc | 194 | rxrpc_see_skb(skb, rxrpc_skb_see_recvmsg); |
248f219c | 195 | sp = rxrpc_skb(skb); |
5d7edbc9 | 196 | seq = sp->hdr.seq; |
17926a79 | 197 | |
5d7edbc9 DH |
198 | if (!(flags & MSG_PEEK)) |
199 | trace_rxrpc_receive(call, rxrpc_receive_front, | |
200 | sp->hdr.serial, seq); | |
201 | ||
248f219c DH |
202 | if (msg) |
203 | sock_recv_timestamp(msg, sock->sk, skb); | |
204 | ||
2e2ea51d | 205 | if (rx_pkt_offset == 0) { |
d4d02d8b | 206 | ret2 = rxrpc_verify_data(call, skb); |
faf92e8d | 207 | trace_rxrpc_recvdata(call, rxrpc_recvmsg_next, seq, |
93368b6b | 208 | sp->offset, sp->len, ret2); |
816c9fce | 209 | if (ret2 < 0) { |
93368b6b | 210 | kdebug("verify = %d", ret2); |
816c9fce | 211 | ret = ret2; |
2e2ea51d | 212 | goto out; |
816c9fce | 213 | } |
93368b6b DH |
214 | rx_pkt_offset = sp->offset; |
215 | rx_pkt_len = sp->len; | |
84997905 | 216 | } else { |
faf92e8d DH |
217 | trace_rxrpc_recvdata(call, rxrpc_recvmsg_cont, seq, |
218 | rx_pkt_offset, rx_pkt_len, 0); | |
2e2ea51d | 219 | } |
248f219c DH |
220 | |
221 | /* We have to handle short, empty and used-up DATA packets. */ | |
222 | remain = len - *_offset; | |
223 | copy = rx_pkt_len; | |
224 | if (copy > remain) | |
225 | copy = remain; | |
226 | if (copy > 0) { | |
816c9fce DH |
227 | ret2 = skb_copy_datagram_iter(skb, rx_pkt_offset, iter, |
228 | copy); | |
229 | if (ret2 < 0) { | |
230 | ret = ret2; | |
248f219c | 231 | goto out; |
816c9fce | 232 | } |
248f219c DH |
233 | |
234 | /* handle piecemeal consumption of data packets */ | |
248f219c DH |
235 | rx_pkt_offset += copy; |
236 | rx_pkt_len -= copy; | |
237 | *_offset += copy; | |
238 | } | |
17926a79 | 239 | |
248f219c | 240 | if (rx_pkt_len > 0) { |
faf92e8d DH |
241 | trace_rxrpc_recvdata(call, rxrpc_recvmsg_full, seq, |
242 | rx_pkt_offset, rx_pkt_len, 0); | |
248f219c | 243 | ASSERTCMP(*_offset, ==, len); |
816c9fce | 244 | ret = 0; |
17926a79 DH |
245 | break; |
246 | } | |
247 | ||
248f219c | 248 | /* The whole packet has been transferred. */ |
d4d02d8b DH |
249 | if (sp->hdr.flags & RXRPC_LAST_PACKET) |
250 | ret = 1; | |
248f219c DH |
251 | rx_pkt_offset = 0; |
252 | rx_pkt_len = 0; | |
17926a79 | 253 | |
5d7edbc9 DH |
254 | skb = skb_peek_next(skb, &call->recvmsg_queue); |
255 | ||
d4d02d8b DH |
256 | if (!(flags & MSG_PEEK)) |
257 | rxrpc_rotate_rx_window(call); | |
248f219c | 258 | } |
816c9fce | 259 | |
248f219c DH |
260 | out: |
261 | if (!(flags & MSG_PEEK)) { | |
262 | call->rx_pkt_offset = rx_pkt_offset; | |
263 | call->rx_pkt_len = rx_pkt_len; | |
264 | } | |
816c9fce | 265 | done: |
faf92e8d DH |
266 | trace_rxrpc_recvdata(call, rxrpc_recvmsg_data_return, seq, |
267 | rx_pkt_offset, rx_pkt_len, ret); | |
d0b35a42 | 268 | if (ret == -EAGAIN) |
5e6ef4f1 | 269 | set_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags); |
248f219c DH |
270 | return ret; |
271 | } | |
17926a79 | 272 | |
248f219c DH |
273 | /* |
274 | * Receive a message from an RxRPC socket | |
275 | * - we need to be careful about two or more threads calling recvmsg | |
276 | * simultaneously | |
277 | */ | |
278 | int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, | |
279 | int flags) | |
280 | { | |
281 | struct rxrpc_call *call; | |
282 | struct rxrpc_sock *rx = rxrpc_sk(sock->sk); | |
283 | struct list_head *l; | |
0e50d999 | 284 | unsigned int call_debug_id = 0; |
248f219c DH |
285 | size_t copied = 0; |
286 | long timeo; | |
287 | int ret; | |
288 | ||
289 | DEFINE_WAIT(wait); | |
290 | ||
0e50d999 | 291 | trace_rxrpc_recvmsg(0, rxrpc_recvmsg_enter, 0); |
248f219c DH |
292 | |
293 | if (flags & (MSG_OOB | MSG_TRUNC)) | |
294 | return -EOPNOTSUPP; | |
295 | ||
296 | timeo = sock_rcvtimeo(&rx->sk, flags & MSG_DONTWAIT); | |
297 | ||
298 | try_again: | |
299 | lock_sock(&rx->sk); | |
300 | ||
301 | /* Return immediately if a client socket has no outstanding calls */ | |
302 | if (RB_EMPTY_ROOT(&rx->calls) && | |
303 | list_empty(&rx->recvmsg_q) && | |
304 | rx->sk.sk_state != RXRPC_SERVER_LISTENING) { | |
305 | release_sock(&rx->sk); | |
639f181f | 306 | return -EAGAIN; |
17926a79 DH |
307 | } |
308 | ||
248f219c DH |
309 | if (list_empty(&rx->recvmsg_q)) { |
310 | ret = -EWOULDBLOCK; | |
84997905 DH |
311 | if (timeo == 0) { |
312 | call = NULL; | |
248f219c | 313 | goto error_no_call; |
84997905 | 314 | } |
248f219c DH |
315 | |
316 | release_sock(&rx->sk); | |
317 | ||
318 | /* Wait for something to happen */ | |
319 | prepare_to_wait_exclusive(sk_sleep(&rx->sk), &wait, | |
320 | TASK_INTERRUPTIBLE); | |
321 | ret = sock_error(&rx->sk); | |
322 | if (ret) | |
323 | goto wait_error; | |
324 | ||
325 | if (list_empty(&rx->recvmsg_q)) { | |
326 | if (signal_pending(current)) | |
327 | goto wait_interrupted; | |
0e50d999 | 328 | trace_rxrpc_recvmsg(0, rxrpc_recvmsg_wait, 0); |
248f219c | 329 | timeo = schedule_timeout(timeo); |
17926a79 | 330 | } |
248f219c DH |
331 | finish_wait(sk_sleep(&rx->sk), &wait); |
332 | goto try_again; | |
17926a79 DH |
333 | } |
334 | ||
248f219c DH |
335 | /* Find the next call and dequeue it if we're not just peeking. If we |
336 | * do dequeue it, that comes with a ref that we will need to release. | |
c0783818 DH |
337 | * We also want to weed out calls that got requeued whilst we were |
338 | * shovelling data out. | |
248f219c | 339 | */ |
223f5901 | 340 | spin_lock(&rx->recvmsg_lock); |
248f219c DH |
341 | l = rx->recvmsg_q.next; |
342 | call = list_entry(l, struct rxrpc_call, recvmsg_link); | |
c0783818 DH |
343 | |
344 | if (!rxrpc_call_is_complete(call) && | |
345 | skb_queue_empty(&call->recvmsg_queue)) { | |
346 | list_del_init(&call->recvmsg_link); | |
347 | spin_unlock(&rx->recvmsg_lock); | |
348 | release_sock(&rx->sk); | |
349 | trace_rxrpc_recvmsg(call->debug_id, rxrpc_recvmsg_unqueue, 0); | |
350 | rxrpc_put_call(call, rxrpc_call_put_recvmsg); | |
351 | goto try_again; | |
352 | } | |
353 | ||
248f219c DH |
354 | if (!(flags & MSG_PEEK)) |
355 | list_del_init(&call->recvmsg_link); | |
356 | else | |
cb0fc0c9 | 357 | rxrpc_get_call(call, rxrpc_call_get_recvmsg); |
223f5901 | 358 | spin_unlock(&rx->recvmsg_lock); |
17926a79 | 359 | |
0e50d999 DH |
360 | call_debug_id = call->debug_id; |
361 | trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_dequeue, 0); | |
248f219c | 362 | |
540b1c48 DH |
363 | /* We're going to drop the socket lock, so we need to lock the call |
364 | * against interference by sendmsg. | |
365 | */ | |
366 | if (!mutex_trylock(&call->user_mutex)) { | |
367 | ret = -EWOULDBLOCK; | |
368 | if (flags & MSG_DONTWAIT) | |
369 | goto error_requeue_call; | |
370 | ret = -ERESTARTSYS; | |
371 | if (mutex_lock_interruptible(&call->user_mutex) < 0) | |
372 | goto error_requeue_call; | |
373 | } | |
374 | ||
375 | release_sock(&rx->sk); | |
376 | ||
248f219c | 377 | if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) |
17926a79 | 378 | BUG(); |
248f219c DH |
379 | |
380 | if (test_bit(RXRPC_CALL_HAS_USERID, &call->flags)) { | |
381 | if (flags & MSG_CMSG_COMPAT) { | |
382 | unsigned int id32 = call->user_call_ID; | |
383 | ||
384 | ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, | |
385 | sizeof(unsigned int), &id32); | |
386 | } else { | |
a16b8d0c DH |
387 | unsigned long idl = call->user_call_ID; |
388 | ||
248f219c | 389 | ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID, |
a16b8d0c | 390 | sizeof(unsigned long), &idl); |
f5c17aae | 391 | } |
248f219c | 392 | if (ret < 0) |
540b1c48 | 393 | goto error_unlock_call; |
248f219c DH |
394 | } |
395 | ||
65550098 | 396 | if (msg->msg_name && call->peer) { |
f3441d41 | 397 | size_t len = sizeof(call->dest_srx); |
68d6d1ae | 398 | |
f3441d41 | 399 | memcpy(msg->msg_name, &call->dest_srx, len); |
248f219c DH |
400 | msg->msg_namelen = len; |
401 | } | |
402 | ||
93368b6b DH |
403 | ret = rxrpc_recvmsg_data(sock, call, msg, &msg->msg_iter, len, |
404 | flags, &copied); | |
405 | if (ret == -EAGAIN) | |
248f219c | 406 | ret = 0; |
93368b6b DH |
407 | if (ret == -EIO) |
408 | goto call_failed; | |
17926a79 | 409 | if (ret < 0) |
540b1c48 | 410 | goto error_unlock_call; |
17926a79 | 411 | |
93368b6b DH |
412 | if (rxrpc_call_is_complete(call) && |
413 | skb_queue_empty(&call->recvmsg_queue)) | |
414 | goto call_complete; | |
415 | if (rxrpc_call_has_failed(call)) | |
416 | goto call_failed; | |
17926a79 | 417 | |
c0783818 DH |
418 | if (!skb_queue_empty(&call->recvmsg_queue)) |
419 | rxrpc_notify_socket(call); | |
93368b6b DH |
420 | goto not_yet_complete; |
421 | ||
422 | call_failed: | |
423 | rxrpc_purge_queue(&call->recvmsg_queue); | |
424 | call_complete: | |
425 | ret = rxrpc_recvmsg_term(call, msg); | |
426 | if (ret < 0) | |
427 | goto error_unlock_call; | |
428 | if (!(flags & MSG_PEEK)) | |
429 | rxrpc_release_call(rx, call); | |
430 | msg->msg_flags |= MSG_EOR; | |
431 | ret = 1; | |
432 | ||
433 | not_yet_complete: | |
248f219c DH |
434 | if (ret == 0) |
435 | msg->msg_flags |= MSG_MORE; | |
436 | else | |
437 | msg->msg_flags &= ~MSG_MORE; | |
438 | ret = copied; | |
17926a79 | 439 | |
540b1c48 DH |
440 | error_unlock_call: |
441 | mutex_unlock(&call->user_mutex); | |
cb0fc0c9 | 442 | rxrpc_put_call(call, rxrpc_call_put_recvmsg); |
0e50d999 | 443 | trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_return, ret); |
540b1c48 DH |
444 | return ret; |
445 | ||
446 | error_requeue_call: | |
447 | if (!(flags & MSG_PEEK)) { | |
223f5901 | 448 | spin_lock(&rx->recvmsg_lock); |
540b1c48 | 449 | list_add(&call->recvmsg_link, &rx->recvmsg_q); |
223f5901 | 450 | spin_unlock(&rx->recvmsg_lock); |
0e50d999 | 451 | trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_requeue, 0); |
540b1c48 | 452 | } else { |
cb0fc0c9 | 453 | rxrpc_put_call(call, rxrpc_call_put_recvmsg); |
540b1c48 | 454 | } |
248f219c DH |
455 | error_no_call: |
456 | release_sock(&rx->sk); | |
6dce3c20 | 457 | error_trace: |
0e50d999 | 458 | trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_return, ret); |
17926a79 DH |
459 | return ret; |
460 | ||
17926a79 DH |
461 | wait_interrupted: |
462 | ret = sock_intr_errno(timeo); | |
463 | wait_error: | |
4a4771a5 | 464 | finish_wait(sk_sleep(&rx->sk), &wait); |
84997905 | 465 | call = NULL; |
6dce3c20 | 466 | goto error_trace; |
d001648e | 467 | } |
651350d1 DH |
468 | |
469 | /** | |
d001648e DH |
470 | * rxrpc_kernel_recv_data - Allow a kernel service to receive data/info |
471 | * @sock: The socket that the call exists on | |
472 | * @call: The call to send data through | |
eb9950eb | 473 | * @iter: The buffer to receive into |
f105da1a | 474 | * @_len: The amount of data we want to receive (decreased on return) |
d001648e DH |
475 | * @want_more: True if more data is expected to be read |
476 | * @_abort: Where the abort code is stored if -ECONNABORTED is returned | |
a68f4a27 | 477 | * @_service: Where to store the actual service ID (may be upgraded) |
d001648e DH |
478 | * |
479 | * Allow a kernel service to receive data and pick up information about the | |
480 | * state of a call. Returns 0 if got what was asked for and there's more | |
481 | * available, 1 if we got what was asked for and we're at the end of the data | |
482 | * and -EAGAIN if we need more data. | |
483 | * | |
484 | * Note that we may return -EAGAIN to drain empty packets at the end of the | |
485 | * data, even if we've already copied over the requested data. | |
651350d1 | 486 | * |
d001648e | 487 | * *_abort should also be initialised to 0. |
651350d1 | 488 | */ |
d001648e | 489 | int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, |
f105da1a | 490 | struct iov_iter *iter, size_t *_len, |
a68f4a27 | 491 | bool want_more, u32 *_abort, u16 *_service) |
651350d1 | 492 | { |
eb9950eb | 493 | size_t offset = 0; |
d001648e | 494 | int ret; |
651350d1 | 495 | |
93368b6b | 496 | _enter("{%d},%zu,%d", call->debug_id, *_len, want_more); |
651350d1 | 497 | |
540b1c48 | 498 | mutex_lock(&call->user_mutex); |
d001648e | 499 | |
93368b6b DH |
500 | ret = rxrpc_recvmsg_data(sock, call, NULL, iter, *_len, 0, &offset); |
501 | *_len -= offset; | |
502 | if (ret == -EIO) | |
503 | goto call_failed; | |
504 | if (ret < 0) | |
d001648e DH |
505 | goto out; |
506 | ||
93368b6b DH |
507 | /* We can only reach here with a partially full buffer if we have |
508 | * reached the end of the data. We must otherwise have a full buffer | |
509 | * or have been given -EAGAIN. | |
510 | */ | |
511 | if (ret == 1) { | |
512 | if (iov_iter_count(iter) > 0) | |
513 | goto short_data; | |
514 | if (!want_more) | |
515 | goto read_phase_complete; | |
516 | ret = 0; | |
d001648e DH |
517 | goto out; |
518 | } | |
519 | ||
93368b6b DH |
520 | if (!want_more) |
521 | goto excess_data; | |
522 | goto out; | |
523 | ||
d001648e DH |
524 | read_phase_complete: |
525 | ret = 1; | |
526 | out: | |
a68f4a27 | 527 | if (_service) |
f3441d41 | 528 | *_service = call->dest_srx.srx_service; |
540b1c48 | 529 | mutex_unlock(&call->user_mutex); |
eb9950eb | 530 | _leave(" = %d [%zu,%d]", ret, iov_iter_count(iter), *_abort); |
d001648e DH |
531 | return ret; |
532 | ||
533 | short_data: | |
57af281e DH |
534 | trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_short_data, |
535 | call->cid, call->call_id, call->rx_consumed, | |
536 | 0, -EBADMSG); | |
d001648e DH |
537 | ret = -EBADMSG; |
538 | goto out; | |
539 | excess_data: | |
57af281e DH |
540 | trace_rxrpc_abort(call->debug_id, rxrpc_recvmsg_excess_data, |
541 | call->cid, call->call_id, call->rx_consumed, | |
542 | 0, -EMSGSIZE); | |
d001648e DH |
543 | ret = -EMSGSIZE; |
544 | goto out; | |
93368b6b | 545 | call_failed: |
d001648e | 546 | *_abort = call->abort_code; |
3a92789a | 547 | ret = call->error; |
d001648e DH |
548 | if (call->completion == RXRPC_CALL_SUCCEEDED) { |
549 | ret = 1; | |
eb9950eb | 550 | if (iov_iter_count(iter) > 0) |
d001648e DH |
551 | ret = -ECONNRESET; |
552 | } | |
553 | goto out; | |
554 | } | |
555 | EXPORT_SYMBOL(rxrpc_kernel_recv_data); |