710 lines · 18.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* RxRPC recvmsg() implementation * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/net.h>#include <linux/skbuff.h>#include <linux/export.h>#include <linux/sched/signal.h> #include <net/sock.h>#include <net/af_rxrpc.h>#include "ar-internal.h" /* * Post a call for attention by the socket or kernel service.  Further * notifications are suppressed by putting recvmsg_link on a dummy queue. */void rxrpc_notify_socket(struct rxrpc_call *call){	struct rxrpc_sock *rx;	struct sock *sk; 	_enter("%d", call->debug_id); 	if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {		rxrpc_see_call(call, rxrpc_call_see_notify_released);		return;	} 	rcu_read_lock(); 	rx = rcu_dereference(call->socket);	sk = &rx->sk;	if (rx && sk->sk_state < RXRPC_CLOSE) {		if (call->notify_rx) {			spin_lock_irq(&call->notify_lock);			call->notify_rx(sk, call, call->user_call_ID);			spin_unlock_irq(&call->notify_lock);		} else {			spin_lock_irq(&rx->recvmsg_lock);			if (list_empty(&call->recvmsg_link)) {				rxrpc_get_call(call, rxrpc_call_get_notify_socket);				list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);			}			spin_unlock_irq(&rx->recvmsg_lock); 			if (!sock_flag(sk, SOCK_DEAD)) {				_debug("call %ps", sk->sk_data_ready);				sk->sk_data_ready(sk);			}		}	} 	rcu_read_unlock();	_leave("");} /* * Pass a call terminating message to userspace. */static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg){	u32 tmp = 0;	int ret; 	switch (call->completion) {	case RXRPC_CALL_SUCCEEDED:		ret = 0;		if (rxrpc_is_service_call(call))			ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ACK, 0, &tmp);		break;	case RXRPC_CALL_REMOTELY_ABORTED:		tmp = call->abort_code;		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ABORT, 4, &tmp);		break;	case RXRPC_CALL_LOCALLY_ABORTED:		tmp = call->abort_code;		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_ABORT, 4, &tmp);		break;	case RXRPC_CALL_NETWORK_ERROR:		tmp = -call->error;		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_NET_ERROR, 4, &tmp);		break;	case RXRPC_CALL_LOCAL_ERROR:		tmp = -call->error;		ret = put_cmsg(msg, SOL_RXRPC, RXRPC_LOCAL_ERROR, 4, &tmp);		break;	default:		pr_err("Invalid terminal call state %u\n", call->completion);		BUG();		break;	} 	trace_rxrpc_recvdata(call, rxrpc_recvmsg_terminal,			     call->ackr_window - 1,			     call->rx_pkt_offset, call->rx_pkt_len, ret);	return ret;} /* * Discard a packet we've used up and advance the Rx window by one. */static void rxrpc_rotate_rx_window(struct rxrpc_call *call){	struct rxrpc_skb_priv *sp;	struct sk_buff *skb;	rxrpc_serial_t serial;	rxrpc_seq_t old_consumed = call->rx_consumed, tseq;	bool last;	int acked; 	_enter("%d", call->debug_id); 	skb = skb_dequeue(&call->recvmsg_queue);	rxrpc_see_skb(skb, rxrpc_skb_see_rotate); 	sp = rxrpc_skb(skb);	tseq   = sp->hdr.seq;	serial = sp->hdr.serial;	last   = sp->hdr.flags & RXRPC_LAST_PACKET; 	/* Barrier against rxrpc_input_data(). */	if (after(tseq, call->rx_consumed))		smp_store_release(&call->rx_consumed, tseq); 	rxrpc_free_skb(skb, rxrpc_skb_put_rotate); 	trace_rxrpc_receive(call, last ? rxrpc_receive_rotate_last : rxrpc_receive_rotate,			    serial, call->rx_consumed); 	if (last)		set_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags); 	/* Check to see if there's an ACK that needs sending. */	acked = atomic_add_return(call->rx_consumed - old_consumed,				  &call->ackr_nr_consumed);	if (acked > 8 &&	    !test_and_set_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags))		rxrpc_poke_call(call, rxrpc_call_poke_idle);} /* * Decrypt and verify a DATA packet.  The content of the packet is pulled out * into a flat buffer rather than decrypting in place in the skbuff.  This also * has the advantage of aligning the buffer correctly for the crypto routines. * * We keep track of the sequence number of the packet currently decrypted into * the buffer in ->rx_dec_seq.  If MSG_PEEK is used and steps onto a new * packet, subsequent recvmsg() calls will have to go back and re-decrypt the * current packet. */static int rxrpc_verify_data(struct rxrpc_call *call, struct sk_buff *skb){	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);	int ret; 	if (sp->len > call->rx_dec_bsize || !call->rx_dec_buffer) {		/* Make sure we can hold a 1412-byte jumbo subpacket and make		 * sure that the buffer size is aligned to a crypto blocksize.		 */		size_t size = clamp(round_up(sp->len, 32), 2048, 65535);		void *buffer = krealloc(call->rx_dec_buffer, size, GFP_NOFS); 		if (!buffer)			return -ENOMEM;		call->rx_dec_buffer = buffer;		call->rx_dec_bsize = size;	} 	ret = -EFAULT;	if (skb_copy_bits(skb, sp->offset, call->rx_dec_buffer, sp->len) < 0)		goto err; 	call->rx_dec_offset = 0;	call->rx_dec_len = sp->len;	call->rx_dec_seq = sp->hdr.seq;	ret = call->security->verify_packet(call, skb);	if (ret < 0)		goto err;	return 0; err:	kfree(call->rx_dec_buffer);	call->rx_dec_buffer = NULL;	call->rx_dec_bsize = 0;	call->rx_dec_offset = 0;	call->rx_dec_len = 0;	return ret;} /* * Transcribe a call's user ID to a control message. */static int rxrpc_recvmsg_user_id(struct rxrpc_call *call, struct msghdr *msg,				 int flags){	if (!test_bit(RXRPC_CALL_HAS_USERID, &call->flags))		return 0; 	if (flags & MSG_CMSG_COMPAT) {		unsigned int id32 = call->user_call_ID; 		return put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID,				sizeof(unsigned int), &id32);	} else {		unsigned long idl = call->user_call_ID; 		return put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID,				sizeof(unsigned long), &idl);	}} /* * Deal with a CHALLENGE packet. */static int rxrpc_recvmsg_challenge(struct socket *sock, struct msghdr *msg,				   struct sk_buff *challenge, unsigned int flags){	struct rxrpc_skb_priv *sp = rxrpc_skb(challenge);	struct rxrpc_connection *conn = sp->chall.conn; 	return conn->security->challenge_to_recvmsg(conn, challenge, msg);} /* * Process OOB packets.  Called with the socket locked. */static int rxrpc_recvmsg_oob(struct socket *sock, struct msghdr *msg,			     unsigned int flags){	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);	struct sk_buff *skb;	bool need_response = false;	int ret; 	skb = skb_peek(&rx->recvmsg_oobq);	if (!skb)		return -EAGAIN;	rxrpc_see_skb(skb, rxrpc_skb_see_recvmsg); 	ret = put_cmsg(msg, SOL_RXRPC, RXRPC_OOB_ID, sizeof(u64),		       &skb->skb_mstamp_ns);	if (ret < 0)		return ret; 	switch ((enum rxrpc_oob_type)skb->mark) {	case RXRPC_OOB_CHALLENGE:		need_response = true;		ret = rxrpc_recvmsg_challenge(sock, msg, skb, flags);		break;	default:		WARN_ONCE(1, "recvmsg() can't process unknown OOB type %u\n",			  skb->mark);		ret = -EIO;		break;	} 	if (!(flags & MSG_PEEK)) {		skb_unlink(skb, &rx->recvmsg_oobq);		if (need_response)			rxrpc_add_pending_oob(rx, skb);		else			rxrpc_free_skb(skb, rxrpc_skb_put_oob);	}	return ret;} /* * Deliver messages to a call.  This keeps processing packets until the buffer * is filled and we find either more DATA (returns 0) or the end of the DATA * (returns 1).  If more packets are required, it returns -EAGAIN and if the * call has failed it returns -EIO. */static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,			      struct msghdr *msg, struct iov_iter *iter,			      size_t len, int flags, size_t *_offset){	struct rxrpc_skb_priv *sp;	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);	struct sk_buff *skb;	rxrpc_seq_t seq = 0;	size_t remain;	unsigned int rx_pkt_offset, rx_pkt_len;	int copy, ret = -EAGAIN, ret2; 	rx_pkt_offset = call->rx_pkt_offset;	rx_pkt_len = call->rx_pkt_len; 	if (rxrpc_call_has_failed(call)) {		seq = call->ackr_window - 1;		ret = -EIO;		goto done;	} 	if (test_bit(RXRPC_CALL_RECVMSG_READ_ALL, &call->flags)) {		seq = call->ackr_window - 1;		ret = 1;		goto done;	} 	/* No one else can be removing stuff from the queue, so we shouldn't	 * need the Rx lock to walk it.	 */	skb = skb_peek(&call->recvmsg_queue);	while (skb) {		rxrpc_see_skb(skb, rxrpc_skb_see_recvmsg);		sp = rxrpc_skb(skb);		seq = sp->hdr.seq; 		if (!(flags & MSG_PEEK))			trace_rxrpc_receive(call, rxrpc_receive_front,					    sp->hdr.serial, seq); 		if (msg)			sock_recv_timestamp(msg, sock->sk, skb); 		if (call->rx_dec_seq != sp->hdr.seq ||		    !call->rx_dec_buffer) {			ret2 = rxrpc_verify_data(call, skb);			trace_rxrpc_recvdata(call, rxrpc_recvmsg_next, seq,					     call->rx_dec_offset,					     call->rx_dec_len, ret2);			if (ret2 < 0) {				ret = ret2;				goto out;			}		} 		if (rx_pkt_offset == USHRT_MAX) {			rx_pkt_offset = call->rx_dec_offset;			rx_pkt_len = call->rx_dec_len;		} else {			trace_rxrpc_recvdata(call, rxrpc_recvmsg_cont, seq,					     rx_pkt_offset, rx_pkt_len, 0);		} 		/* We have to handle short, empty and used-up DATA packets. */		remain = len - *_offset;		copy = rx_pkt_len;		if (copy > remain)			copy = remain;		if (copy > 0) {			ret2 = copy_to_iter(call->rx_dec_buffer + rx_pkt_offset,					    copy, iter);			if (ret2 != copy) {				ret = -EFAULT;				goto out;			} 			/* handle piecemeal consumption of data packets */			rx_pkt_offset += copy;			rx_pkt_len -= copy;			*_offset += copy;		} 		if (rx_pkt_len > 0) {			trace_rxrpc_recvdata(call, rxrpc_recvmsg_full, seq,					     rx_pkt_offset, rx_pkt_len, 0);			ASSERTCMP(*_offset, ==, len);			ret = 0;			break;		} 		/* The whole packet has been transferred. */		if (sp->hdr.flags & RXRPC_LAST_PACKET)			ret = 1;		rx_pkt_offset = USHRT_MAX;		rx_pkt_len = 0; 		skb = skb_peek_next(skb, &call->recvmsg_queue); 		if (!(flags & MSG_PEEK))			rxrpc_rotate_rx_window(call); 		if (!rx->app_ops &&		    !skb_queue_empty_lockless(&rx->recvmsg_oobq)) {			trace_rxrpc_recvdata(call, rxrpc_recvmsg_oobq, seq,					     rx_pkt_offset, rx_pkt_len, ret);			break;		}	} out:	if (!(flags & MSG_PEEK)) {		call->rx_pkt_offset = rx_pkt_offset;		call->rx_pkt_len = rx_pkt_len;	} done:	trace_rxrpc_recvdata(call, rxrpc_recvmsg_data_return, seq,			     rx_pkt_offset, rx_pkt_len, ret);	if (ret == -EAGAIN)		set_bit(RXRPC_CALL_RX_IS_IDLE, &call->flags);	return ret;} /* * Receive a message from an RxRPC socket * - we need to be careful about two or more threads calling recvmsg *   simultaneously */int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,		  int flags){	struct rxrpc_call *call;	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);	struct list_head *l;	unsigned int call_debug_id = 0;	size_t copied = 0;	long timeo;	int ret; 	DEFINE_WAIT(wait); 	trace_rxrpc_recvmsg(0, rxrpc_recvmsg_enter, 0); 	if (flags & (MSG_OOB | MSG_TRUNC))		return -EOPNOTSUPP; 	timeo = sock_rcvtimeo(&rx->sk, flags & MSG_DONTWAIT); try_again:	lock_sock(&rx->sk); 	/* Return immediately if a client socket has no outstanding calls */	if (RB_EMPTY_ROOT(&rx->calls) &&	    list_empty(&rx->recvmsg_q) &&	    skb_queue_empty_lockless(&rx->recvmsg_oobq) &&	    rx->sk.sk_state != RXRPC_SERVER_LISTENING) {		release_sock(&rx->sk);		return -EAGAIN;	} 	if (list_empty(&rx->recvmsg_q) &&	    skb_queue_empty_lockless(&rx->recvmsg_oobq)) {		ret = -EWOULDBLOCK;		if (timeo == 0) {			call = NULL;			goto error_no_call;		} 		release_sock(&rx->sk); 		/* Wait for something to happen */		prepare_to_wait_exclusive(sk_sleep(&rx->sk), &wait,					  TASK_INTERRUPTIBLE);		ret = sock_error(&rx->sk);		if (ret)			goto wait_error; 		if (list_empty(&rx->recvmsg_q) &&		    skb_queue_empty_lockless(&rx->recvmsg_oobq)) {			if (signal_pending(current))				goto wait_interrupted;			trace_rxrpc_recvmsg(0, rxrpc_recvmsg_wait, 0);			timeo = schedule_timeout(timeo);		}		finish_wait(sk_sleep(&rx->sk), &wait);		goto try_again;	} 	/* Deal with OOB messages before we consider getting normal data. */	if (!skb_queue_empty_lockless(&rx->recvmsg_oobq)) {		ret = rxrpc_recvmsg_oob(sock, msg, flags);		release_sock(&rx->sk);		if (ret == -EAGAIN)			goto try_again;		goto error_trace;	} 	/* Find the next call and dequeue it if we're not just peeking.  If we	 * do dequeue it, that comes with a ref that we will need to release.	 * We also want to weed out calls that got requeued whilst we were	 * shovelling data out.	 */	spin_lock_irq(&rx->recvmsg_lock);	l = rx->recvmsg_q.next;	call = list_entry(l, struct rxrpc_call, recvmsg_link); 	if (!rxrpc_call_is_complete(call) &&	    skb_queue_empty(&call->recvmsg_queue) &&	    skb_queue_empty(&rx->recvmsg_oobq)) {		list_del_init(&call->recvmsg_link);		spin_unlock_irq(&rx->recvmsg_lock);		release_sock(&rx->sk);		trace_rxrpc_recvmsg(call->debug_id, rxrpc_recvmsg_unqueue, 0);		rxrpc_put_call(call, rxrpc_call_put_recvmsg);		goto try_again;	} 	rxrpc_see_call(call, rxrpc_call_see_recvmsg);	if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {		rxrpc_see_call(call, rxrpc_call_see_already_released);		list_del_init(&call->recvmsg_link);		spin_unlock_irq(&rx->recvmsg_lock);

Lines 1–500 of 710.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t