net/rxrpc/recvmsg.c

Source file repositories/reference/linux-study-clean/net/rxrpc/recvmsg.c

File Facts

System
Linux kernel
Corpus path
net/rxrpc/recvmsg.c
Extension
.c
Size
18915 bytes
Lines
713
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

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);

Annotation

Implementation Notes