xref: /openbmc/linux/net/rxrpc/conn_event.c (revision a00ce28b)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28c3e34a4SDavid Howells /* connection-level event handling
38c3e34a4SDavid Howells  *
48c3e34a4SDavid Howells  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
58c3e34a4SDavid Howells  * Written by David Howells (dhowells@redhat.com)
68c3e34a4SDavid Howells  */
78c3e34a4SDavid Howells 
88c3e34a4SDavid Howells #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c3e34a4SDavid Howells 
108c3e34a4SDavid Howells #include <linux/module.h>
118c3e34a4SDavid Howells #include <linux/net.h>
128c3e34a4SDavid Howells #include <linux/skbuff.h>
138c3e34a4SDavid Howells #include <linux/errqueue.h>
148c3e34a4SDavid Howells #include <net/sock.h>
158c3e34a4SDavid Howells #include <net/af_rxrpc.h>
168c3e34a4SDavid Howells #include <net/ip.h>
178c3e34a4SDavid Howells #include "ar-internal.h"
188c3e34a4SDavid Howells 
198c3e34a4SDavid Howells /*
20*a00ce28bSDavid Howells  * Set the completion state on an aborted connection.
21*a00ce28bSDavid Howells  */
22*a00ce28bSDavid Howells static bool rxrpc_set_conn_aborted(struct rxrpc_connection *conn, struct sk_buff *skb,
23*a00ce28bSDavid Howells 				   s32 abort_code, int err,
24*a00ce28bSDavid Howells 				   enum rxrpc_call_completion compl)
25*a00ce28bSDavid Howells {
26*a00ce28bSDavid Howells 	bool aborted = false;
27*a00ce28bSDavid Howells 
28*a00ce28bSDavid Howells 	if (conn->state != RXRPC_CONN_ABORTED) {
29*a00ce28bSDavid Howells 		spin_lock(&conn->state_lock);
30*a00ce28bSDavid Howells 		if (conn->state != RXRPC_CONN_ABORTED) {
31*a00ce28bSDavid Howells 			conn->abort_code = abort_code;
32*a00ce28bSDavid Howells 			conn->error	 = err;
33*a00ce28bSDavid Howells 			conn->completion = compl;
34*a00ce28bSDavid Howells 			/* Order the abort info before the state change. */
35*a00ce28bSDavid Howells 			smp_store_release(&conn->state, RXRPC_CONN_ABORTED);
36*a00ce28bSDavid Howells 			set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
37*a00ce28bSDavid Howells 			set_bit(RXRPC_CONN_EV_ABORT_CALLS, &conn->events);
38*a00ce28bSDavid Howells 			aborted = true;
39*a00ce28bSDavid Howells 		}
40*a00ce28bSDavid Howells 		spin_unlock(&conn->state_lock);
41*a00ce28bSDavid Howells 	}
42*a00ce28bSDavid Howells 
43*a00ce28bSDavid Howells 	return aborted;
44*a00ce28bSDavid Howells }
45*a00ce28bSDavid Howells 
46*a00ce28bSDavid Howells /*
47*a00ce28bSDavid Howells  * Mark a socket buffer to indicate that the connection it's on should be aborted.
48*a00ce28bSDavid Howells  */
49*a00ce28bSDavid Howells int rxrpc_abort_conn(struct rxrpc_connection *conn, struct sk_buff *skb,
50*a00ce28bSDavid Howells 		     s32 abort_code, int err, const char *why)
51*a00ce28bSDavid Howells {
52*a00ce28bSDavid Howells 	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
53*a00ce28bSDavid Howells 
54*a00ce28bSDavid Howells 	if (rxrpc_set_conn_aborted(conn, skb, abort_code, err,
55*a00ce28bSDavid Howells 				   RXRPC_CALL_LOCALLY_ABORTED)) {
56*a00ce28bSDavid Howells 		trace_rxrpc_abort(0, why, sp->hdr.cid, sp->hdr.callNumber,
57*a00ce28bSDavid Howells 				  sp->hdr.seq, abort_code, err);
58*a00ce28bSDavid Howells 		rxrpc_poke_conn(conn, rxrpc_conn_get_poke_abort);
59*a00ce28bSDavid Howells 	}
60*a00ce28bSDavid Howells 	return -EPROTO;
61*a00ce28bSDavid Howells }
62*a00ce28bSDavid Howells 
63*a00ce28bSDavid Howells /*
64*a00ce28bSDavid Howells  * Mark a connection as being remotely aborted.
65*a00ce28bSDavid Howells  */
66*a00ce28bSDavid Howells static bool rxrpc_input_conn_abort(struct rxrpc_connection *conn,
67*a00ce28bSDavid Howells 				   struct sk_buff *skb)
68*a00ce28bSDavid Howells {
69*a00ce28bSDavid Howells 	return rxrpc_set_conn_aborted(conn, skb, skb->priority, -ECONNABORTED,
70*a00ce28bSDavid Howells 				      RXRPC_CALL_REMOTELY_ABORTED);
71*a00ce28bSDavid Howells }
72*a00ce28bSDavid Howells 
73*a00ce28bSDavid Howells /*
7418bfeba5SDavid Howells  * Retransmit terminal ACK or ABORT of the previous call.
7518bfeba5SDavid Howells  */
7630df927bSDavid Howells void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
773136ef49SDavid Howells 				struct sk_buff *skb,
783136ef49SDavid Howells 				unsigned int channel)
7918bfeba5SDavid Howells {
803136ef49SDavid Howells 	struct rxrpc_skb_priv *sp = skb ? rxrpc_skb(skb) : NULL;
8118bfeba5SDavid Howells 	struct rxrpc_channel *chan;
8218bfeba5SDavid Howells 	struct msghdr msg;
835fc62f6aSDavid Howells 	struct kvec iov[3];
8418bfeba5SDavid Howells 	struct {
8518bfeba5SDavid Howells 		struct rxrpc_wire_header whdr;
8618bfeba5SDavid Howells 		union {
875fc62f6aSDavid Howells 			__be32 abort_code;
8818bfeba5SDavid Howells 			struct rxrpc_ackpacket ack;
8918bfeba5SDavid Howells 		};
9018bfeba5SDavid Howells 	} __attribute__((packed)) pkt;
915fc62f6aSDavid Howells 	struct rxrpc_ackinfo ack_info;
9218bfeba5SDavid Howells 	size_t len;
936b47fe1dSDavid Howells 	int ret, ioc;
945fc62f6aSDavid Howells 	u32 serial, mtu, call_id, padding;
9518bfeba5SDavid Howells 
9618bfeba5SDavid Howells 	_enter("%d", conn->debug_id);
9718bfeba5SDavid Howells 
983136ef49SDavid Howells 	chan = &conn->channels[channel];
9918bfeba5SDavid Howells 
10018bfeba5SDavid Howells 	/* If the last call got moved on whilst we were waiting to run, just
10118bfeba5SDavid Howells 	 * ignore this packet.
10218bfeba5SDavid Howells 	 */
10318bfeba5SDavid Howells 	call_id = READ_ONCE(chan->last_call);
10418bfeba5SDavid Howells 	/* Sync with __rxrpc_disconnect_call() */
10518bfeba5SDavid Howells 	smp_rmb();
1063136ef49SDavid Howells 	if (skb && call_id != sp->hdr.callNumber)
10718bfeba5SDavid Howells 		return;
10818bfeba5SDavid Howells 
1092cc80086SDavid Howells 	msg.msg_name	= &conn->peer->srx.transport;
1102cc80086SDavid Howells 	msg.msg_namelen	= conn->peer->srx.transport_len;
11118bfeba5SDavid Howells 	msg.msg_control	= NULL;
11218bfeba5SDavid Howells 	msg.msg_controllen = 0;
11318bfeba5SDavid Howells 	msg.msg_flags	= 0;
11418bfeba5SDavid Howells 
1155fc62f6aSDavid Howells 	iov[0].iov_base	= &pkt;
1165fc62f6aSDavid Howells 	iov[0].iov_len	= sizeof(pkt.whdr);
1175fc62f6aSDavid Howells 	iov[1].iov_base	= &padding;
1185fc62f6aSDavid Howells 	iov[1].iov_len	= 3;
1195fc62f6aSDavid Howells 	iov[2].iov_base	= &ack_info;
1205fc62f6aSDavid Howells 	iov[2].iov_len	= sizeof(ack_info);
1215fc62f6aSDavid Howells 
1223136ef49SDavid Howells 	pkt.whdr.epoch		= htonl(conn->proto.epoch);
123fb1967a6SDavid Howells 	pkt.whdr.cid		= htonl(conn->proto.cid | channel);
1243136ef49SDavid Howells 	pkt.whdr.callNumber	= htonl(call_id);
12518bfeba5SDavid Howells 	pkt.whdr.seq		= 0;
12618bfeba5SDavid Howells 	pkt.whdr.type		= chan->last_type;
12718bfeba5SDavid Howells 	pkt.whdr.flags		= conn->out_clientflag;
12818bfeba5SDavid Howells 	pkt.whdr.userStatus	= 0;
12918bfeba5SDavid Howells 	pkt.whdr.securityIndex	= conn->security_ix;
13018bfeba5SDavid Howells 	pkt.whdr._rsvd		= 0;
13168d6d1aeSDavid Howells 	pkt.whdr.serviceId	= htons(conn->service_id);
13218bfeba5SDavid Howells 
13318bfeba5SDavid Howells 	len = sizeof(pkt.whdr);
13418bfeba5SDavid Howells 	switch (chan->last_type) {
13518bfeba5SDavid Howells 	case RXRPC_PACKET_TYPE_ABORT:
1365fc62f6aSDavid Howells 		pkt.abort_code	= htonl(chan->last_abort);
1375fc62f6aSDavid Howells 		iov[0].iov_len += sizeof(pkt.abort_code);
1385fc62f6aSDavid Howells 		len += sizeof(pkt.abort_code);
1395fc62f6aSDavid Howells 		ioc = 1;
14018bfeba5SDavid Howells 		break;
14118bfeba5SDavid Howells 
14218bfeba5SDavid Howells 	case RXRPC_PACKET_TYPE_ACK:
1432cc80086SDavid Howells 		mtu = conn->peer->if_mtu;
1442cc80086SDavid Howells 		mtu -= conn->peer->hdrsize;
14518bfeba5SDavid Howells 		pkt.ack.bufferSpace	= 0;
1463136ef49SDavid Howells 		pkt.ack.maxSkew		= htons(skb ? skb->priority : 0);
1473136ef49SDavid Howells 		pkt.ack.firstPacket	= htonl(chan->last_seq + 1);
1483136ef49SDavid Howells 		pkt.ack.previousPacket	= htonl(chan->last_seq);
1493136ef49SDavid Howells 		pkt.ack.serial		= htonl(skb ? sp->hdr.serial : 0);
1503136ef49SDavid Howells 		pkt.ack.reason		= skb ? RXRPC_ACK_DUPLICATE : RXRPC_ACK_IDLE;
15118bfeba5SDavid Howells 		pkt.ack.nAcks		= 0;
1525fc62f6aSDavid Howells 		ack_info.rxMTU		= htonl(rxrpc_rx_mtu);
1535fc62f6aSDavid Howells 		ack_info.maxMTU		= htonl(mtu);
1545fc62f6aSDavid Howells 		ack_info.rwind		= htonl(rxrpc_rx_window_size);
1555fc62f6aSDavid Howells 		ack_info.jumbo_max	= htonl(rxrpc_rx_jumbo_max);
15657494343SDavid Howells 		pkt.whdr.flags		|= RXRPC_SLOW_START_OK;
1575fc62f6aSDavid Howells 		padding			= 0;
1585fc62f6aSDavid Howells 		iov[0].iov_len += sizeof(pkt.ack);
1595fc62f6aSDavid Howells 		len += sizeof(pkt.ack) + 3 + sizeof(ack_info);
1605fc62f6aSDavid Howells 		ioc = 3;
16118bfeba5SDavid Howells 		break;
1625fc62f6aSDavid Howells 
1635fc62f6aSDavid Howells 	default:
1645fc62f6aSDavid Howells 		return;
16518bfeba5SDavid Howells 	}
16618bfeba5SDavid Howells 
16718bfeba5SDavid Howells 	/* Resync with __rxrpc_disconnect_call() and check that the last call
16818bfeba5SDavid Howells 	 * didn't get advanced whilst we were filling out the packets.
16918bfeba5SDavid Howells 	 */
17018bfeba5SDavid Howells 	smp_rmb();
17118bfeba5SDavid Howells 	if (READ_ONCE(chan->last_call) != call_id)
17218bfeba5SDavid Howells 		return;
17318bfeba5SDavid Howells 
17418bfeba5SDavid Howells 	serial = atomic_inc_return(&conn->serial);
17518bfeba5SDavid Howells 	pkt.whdr.serial = htonl(serial);
17618bfeba5SDavid Howells 
17718bfeba5SDavid Howells 	switch (chan->last_type) {
17818bfeba5SDavid Howells 	case RXRPC_PACKET_TYPE_ABORT:
17918bfeba5SDavid Howells 		break;
18018bfeba5SDavid Howells 	case RXRPC_PACKET_TYPE_ACK:
1814764c0daSDavid Howells 		trace_rxrpc_tx_ack(chan->call_debug_id, serial,
182f3f8337cSDavid Howells 				   ntohl(pkt.ack.firstPacket),
183f3f8337cSDavid Howells 				   ntohl(pkt.ack.serial),
184f3f8337cSDavid Howells 				   pkt.ack.reason, 0);
18518bfeba5SDavid Howells 		break;
18618bfeba5SDavid Howells 	}
18718bfeba5SDavid Howells 
1882cc80086SDavid Howells 	ret = kernel_sendmsg(conn->local->socket, &msg, iov, ioc, len);
1892cc80086SDavid Howells 	conn->peer->last_tx_at = ktime_get_seconds();
1906b47fe1dSDavid Howells 	if (ret < 0)
1914764c0daSDavid Howells 		trace_rxrpc_tx_fail(chan->call_debug_id, serial, ret,
1924764c0daSDavid Howells 				    rxrpc_tx_point_call_final_resend);
1934764c0daSDavid Howells 	else
1944764c0daSDavid Howells 		trace_rxrpc_tx_packet(chan->call_debug_id, &pkt.whdr,
1954764c0daSDavid Howells 				      rxrpc_tx_point_call_final_resend);
1966b47fe1dSDavid Howells 
19718bfeba5SDavid Howells 	_leave("");
19818bfeba5SDavid Howells }
19918bfeba5SDavid Howells 
20018bfeba5SDavid Howells /*
2018c3e34a4SDavid Howells  * pass a connection-level abort onto all calls on that connection
2028c3e34a4SDavid Howells  */
203*a00ce28bSDavid Howells static void rxrpc_abort_calls(struct rxrpc_connection *conn)
2048c3e34a4SDavid Howells {
2058c3e34a4SDavid Howells 	struct rxrpc_call *call;
206248f219cSDavid Howells 	int i;
2078c3e34a4SDavid Howells 
20864753092SDavid Howells 	_enter("{%d},%x", conn->debug_id, conn->abort_code);
2098c3e34a4SDavid Howells 
210245500d8SDavid Howells 	spin_lock(&conn->bundle->channel_lock);
2118c3e34a4SDavid Howells 
212a1399f8bSDavid Howells 	for (i = 0; i < RXRPC_MAXCALLS; i++) {
213a1399f8bSDavid Howells 		call = rcu_dereference_protected(
214a1399f8bSDavid Howells 			conn->channels[i].call,
215245500d8SDavid Howells 			lockdep_is_held(&conn->bundle->channel_lock));
216*a00ce28bSDavid Howells 		if (call)
217*a00ce28bSDavid Howells 			rxrpc_set_call_completion(call,
218*a00ce28bSDavid Howells 						  conn->completion,
21964753092SDavid Howells 						  conn->abort_code,
22064753092SDavid Howells 						  conn->error);
221ccbd3dbeSDavid Howells 	}
2228c3e34a4SDavid Howells 
223245500d8SDavid Howells 	spin_unlock(&conn->bundle->channel_lock);
2248c3e34a4SDavid Howells 	_leave("");
2258c3e34a4SDavid Howells }
2268c3e34a4SDavid Howells 
2278c3e34a4SDavid Howells /*
2288c3e34a4SDavid Howells  * mark a call as being on a now-secured channel
229248f219cSDavid Howells  * - must be called with BH's disabled.
2308c3e34a4SDavid Howells  */
2318c3e34a4SDavid Howells static void rxrpc_call_is_secure(struct rxrpc_call *call)
2328c3e34a4SDavid Howells {
2338c3e34a4SDavid Howells 	_enter("%p", call);
2348c3e34a4SDavid Howells 	if (call) {
2353dd9c8b5SDavid Howells 		write_lock(&call->state_lock);
236248f219cSDavid Howells 		if (call->state == RXRPC_CALL_SERVER_SECURING) {
2372d914c1bSDavid Howells 			call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
238248f219cSDavid Howells 			rxrpc_notify_socket(call);
239248f219cSDavid Howells 		}
2403dd9c8b5SDavid Howells 		write_unlock(&call->state_lock);
2418c3e34a4SDavid Howells 	}
2428c3e34a4SDavid Howells }
2438c3e34a4SDavid Howells 
2448c3e34a4SDavid Howells /*
2458c3e34a4SDavid Howells  * connection-level Rx packet processor
2468c3e34a4SDavid Howells  */
2478c3e34a4SDavid Howells static int rxrpc_process_event(struct rxrpc_connection *conn,
248*a00ce28bSDavid Howells 			       struct sk_buff *skb)
2498c3e34a4SDavid Howells {
2508c3e34a4SDavid Howells 	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
2518c3e34a4SDavid Howells 	int loop, ret;
2528c3e34a4SDavid Howells 
253*a00ce28bSDavid Howells 	if (conn->state == RXRPC_CONN_ABORTED)
2548c3e34a4SDavid Howells 		return -ECONNABORTED;
2558c3e34a4SDavid Howells 
2568c3e34a4SDavid Howells 	_enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial);
2578c3e34a4SDavid Howells 
2588c3e34a4SDavid Howells 	switch (sp->hdr.type) {
2598c3e34a4SDavid Howells 	case RXRPC_PACKET_TYPE_CHALLENGE:
260*a00ce28bSDavid Howells 		return conn->security->respond_to_challenge(conn, skb);
2618c3e34a4SDavid Howells 
2628c3e34a4SDavid Howells 	case RXRPC_PACKET_TYPE_RESPONSE:
263*a00ce28bSDavid Howells 		ret = conn->security->verify_response(conn, skb);
2648c3e34a4SDavid Howells 		if (ret < 0)
2658c3e34a4SDavid Howells 			return ret;
2668c3e34a4SDavid Howells 
26741057ebdSDavid Howells 		ret = conn->security->init_connection_security(
2682cc80086SDavid Howells 			conn, conn->key->payload.data[0]);
2698c3e34a4SDavid Howells 		if (ret < 0)
2708c3e34a4SDavid Howells 			return ret;
2718c3e34a4SDavid Howells 
272245500d8SDavid Howells 		spin_lock(&conn->bundle->channel_lock);
2733dd9c8b5SDavid Howells 		spin_lock(&conn->state_lock);
2748c3e34a4SDavid Howells 
275bba304dbSDavid Howells 		if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
276bba304dbSDavid Howells 			conn->state = RXRPC_CONN_SERVICE;
2773dd9c8b5SDavid Howells 			spin_unlock(&conn->state_lock);
2788c3e34a4SDavid Howells 			for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
279dee46364SDavid Howells 				rxrpc_call_is_secure(
280dee46364SDavid Howells 					rcu_dereference_protected(
281a1399f8bSDavid Howells 						conn->channels[loop].call,
282245500d8SDavid Howells 						lockdep_is_held(&conn->bundle->channel_lock)));
283248f219cSDavid Howells 		} else {
2843dd9c8b5SDavid Howells 			spin_unlock(&conn->state_lock);
2858c3e34a4SDavid Howells 		}
2868c3e34a4SDavid Howells 
287245500d8SDavid Howells 		spin_unlock(&conn->bundle->channel_lock);
2888c3e34a4SDavid Howells 		return 0;
2898c3e34a4SDavid Howells 
2908c3e34a4SDavid Howells 	default:
291fb46f6eeSDavid Howells 		trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
292fb46f6eeSDavid Howells 				      tracepoint_string("bad_conn_pkt"));
2938c3e34a4SDavid Howells 		return -EPROTO;
2948c3e34a4SDavid Howells 	}
2958c3e34a4SDavid Howells }
2968c3e34a4SDavid Howells 
2978c3e34a4SDavid Howells /*
2988c3e34a4SDavid Howells  * set up security and issue a challenge
2998c3e34a4SDavid Howells  */
3008c3e34a4SDavid Howells static void rxrpc_secure_connection(struct rxrpc_connection *conn)
3018c3e34a4SDavid Howells {
302*a00ce28bSDavid Howells 	if (conn->security->issue_challenge(conn) < 0)
303*a00ce28bSDavid Howells 		rxrpc_abort_conn(conn, NULL, RX_CALL_DEAD, -ENOMEM, "OOM");
3048c3e34a4SDavid Howells }
3058c3e34a4SDavid Howells 
3068c3e34a4SDavid Howells /*
3073136ef49SDavid Howells  * Process delayed final ACKs that we haven't subsumed into a subsequent call.
3083136ef49SDavid Howells  */
309ddc7834aSDavid Howells void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force)
3103136ef49SDavid Howells {
3113136ef49SDavid Howells 	unsigned long j = jiffies, next_j;
3123136ef49SDavid Howells 	unsigned int channel;
3133136ef49SDavid Howells 	bool set;
3143136ef49SDavid Howells 
3153136ef49SDavid Howells again:
3163136ef49SDavid Howells 	next_j = j + LONG_MAX;
3173136ef49SDavid Howells 	set = false;
3183136ef49SDavid Howells 	for (channel = 0; channel < RXRPC_MAXCALLS; channel++) {
3193136ef49SDavid Howells 		struct rxrpc_channel *chan = &conn->channels[channel];
3203136ef49SDavid Howells 		unsigned long ack_at;
3213136ef49SDavid Howells 
3223136ef49SDavid Howells 		if (!test_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags))
3233136ef49SDavid Howells 			continue;
3243136ef49SDavid Howells 
3253136ef49SDavid Howells 		smp_rmb(); /* vs rxrpc_disconnect_client_call */
3263136ef49SDavid Howells 		ack_at = READ_ONCE(chan->final_ack_at);
3273136ef49SDavid Howells 
328ddc7834aSDavid Howells 		if (time_before(j, ack_at) && !force) {
3293136ef49SDavid Howells 			if (time_before(ack_at, next_j)) {
3303136ef49SDavid Howells 				next_j = ack_at;
3313136ef49SDavid Howells 				set = true;
3323136ef49SDavid Howells 			}
3333136ef49SDavid Howells 			continue;
3343136ef49SDavid Howells 		}
3353136ef49SDavid Howells 
3363136ef49SDavid Howells 		if (test_and_clear_bit(RXRPC_CONN_FINAL_ACK_0 + channel,
3373136ef49SDavid Howells 				       &conn->flags))
3383136ef49SDavid Howells 			rxrpc_conn_retransmit_call(conn, NULL, channel);
3393136ef49SDavid Howells 	}
3403136ef49SDavid Howells 
3413136ef49SDavid Howells 	j = jiffies;
3423136ef49SDavid Howells 	if (time_before_eq(next_j, j))
3433136ef49SDavid Howells 		goto again;
3443136ef49SDavid Howells 	if (set)
3453136ef49SDavid Howells 		rxrpc_reduce_conn_timer(conn, next_j);
3463136ef49SDavid Howells }
3473136ef49SDavid Howells 
3483136ef49SDavid Howells /*
3498c3e34a4SDavid Howells  * connection-level event processor
3508c3e34a4SDavid Howells  */
35104d36d74SDavid Howells static void rxrpc_do_process_connection(struct rxrpc_connection *conn)
3528c3e34a4SDavid Howells {
3538c3e34a4SDavid Howells 	struct sk_buff *skb;
3548c3e34a4SDavid Howells 	int ret;
3558c3e34a4SDavid Howells 
3562c4579e4SDavid Howells 	if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events))
3578c3e34a4SDavid Howells 		rxrpc_secure_connection(conn);
3588c3e34a4SDavid Howells 
3598c3e34a4SDavid Howells 	/* go through the conn-level event packets, releasing the ref on this
3608c3e34a4SDavid Howells 	 * connection that each one has when we've finished with it */
3618c3e34a4SDavid Howells 	while ((skb = skb_dequeue(&conn->rx_queue))) {
3629a36a6bcSDavid Howells 		rxrpc_see_skb(skb, rxrpc_skb_see_conn_work);
363*a00ce28bSDavid Howells 		ret = rxrpc_process_event(conn, skb);
3648c3e34a4SDavid Howells 		switch (ret) {
3658c2f826dSDavid Howells 		case -ENOMEM:
3668c3e34a4SDavid Howells 		case -EAGAIN:
367*a00ce28bSDavid Howells 			skb_queue_head(&conn->rx_queue, skb);
368*a00ce28bSDavid Howells 			rxrpc_queue_conn(conn, rxrpc_conn_queue_retry_work);
369*a00ce28bSDavid Howells 			break;
3708c3e34a4SDavid Howells 		default:
3719a36a6bcSDavid Howells 			rxrpc_free_skb(skb, rxrpc_skb_put_conn_work);
3728c3e34a4SDavid Howells 			break;
3738c3e34a4SDavid Howells 		}
3748c3e34a4SDavid Howells 	}
37504d36d74SDavid Howells }
37604d36d74SDavid Howells 
37704d36d74SDavid Howells void rxrpc_process_connection(struct work_struct *work)
37804d36d74SDavid Howells {
37904d36d74SDavid Howells 	struct rxrpc_connection *conn =
38004d36d74SDavid Howells 		container_of(work, struct rxrpc_connection, processor);
38104d36d74SDavid Howells 
3827fa25105SDavid Howells 	rxrpc_see_connection(conn, rxrpc_conn_see_work);
38304d36d74SDavid Howells 
3840fde882fSDavid Howells 	if (__rxrpc_use_local(conn->local, rxrpc_local_use_conn_work)) {
38504d36d74SDavid Howells 		rxrpc_do_process_connection(conn);
3860fde882fSDavid Howells 		rxrpc_unuse_local(conn->local, rxrpc_local_unuse_conn_work);
38704d36d74SDavid Howells 	}
3888c3e34a4SDavid Howells }
3895e6ef4f1SDavid Howells 
3905e6ef4f1SDavid Howells /*
3915e6ef4f1SDavid Howells  * post connection-level events to the connection
3925e6ef4f1SDavid Howells  * - this includes challenges, responses, some aborts and call terminal packet
3935e6ef4f1SDavid Howells  *   retransmission.
3945e6ef4f1SDavid Howells  */
3955e6ef4f1SDavid Howells static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
3965e6ef4f1SDavid Howells 				      struct sk_buff *skb)
3975e6ef4f1SDavid Howells {
3985e6ef4f1SDavid Howells 	_enter("%p,%p", conn, skb);
3995e6ef4f1SDavid Howells 
4005e6ef4f1SDavid Howells 	rxrpc_get_skb(skb, rxrpc_skb_get_conn_work);
4015e6ef4f1SDavid Howells 	skb_queue_tail(&conn->rx_queue, skb);
4025e6ef4f1SDavid Howells 	rxrpc_queue_conn(conn, rxrpc_conn_queue_rx_work);
4035e6ef4f1SDavid Howells }
4045e6ef4f1SDavid Howells 
4055e6ef4f1SDavid Howells /*
4065e6ef4f1SDavid Howells  * Input a connection-level packet.
4075e6ef4f1SDavid Howells  */
4085e6ef4f1SDavid Howells int rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
4095e6ef4f1SDavid Howells {
4105e6ef4f1SDavid Howells 	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
4115e6ef4f1SDavid Howells 
4125e6ef4f1SDavid Howells 	switch (sp->hdr.type) {
4135e6ef4f1SDavid Howells 	case RXRPC_PACKET_TYPE_BUSY:
4145e6ef4f1SDavid Howells 		/* Just ignore BUSY packets for now. */
4155e6ef4f1SDavid Howells 		return 0;
4165e6ef4f1SDavid Howells 
4175e6ef4f1SDavid Howells 	case RXRPC_PACKET_TYPE_ABORT:
418*a00ce28bSDavid Howells 		if (rxrpc_is_conn_aborted(conn))
419*a00ce28bSDavid Howells 			return true;
420*a00ce28bSDavid Howells 		rxrpc_input_conn_abort(conn, skb);
421*a00ce28bSDavid Howells 		rxrpc_abort_calls(conn);
422*a00ce28bSDavid Howells 		return true;
4235e6ef4f1SDavid Howells 
4245e6ef4f1SDavid Howells 	case RXRPC_PACKET_TYPE_CHALLENGE:
4255e6ef4f1SDavid Howells 	case RXRPC_PACKET_TYPE_RESPONSE:
426*a00ce28bSDavid Howells 		if (rxrpc_is_conn_aborted(conn)) {
427*a00ce28bSDavid Howells 			if (conn->completion == RXRPC_CALL_LOCALLY_ABORTED)
428*a00ce28bSDavid Howells 				rxrpc_send_conn_abort(conn);
429*a00ce28bSDavid Howells 			return true;
430*a00ce28bSDavid Howells 		}
4315e6ef4f1SDavid Howells 		rxrpc_post_packet_to_conn(conn, skb);
4325e6ef4f1SDavid Howells 		return 0;
4335e6ef4f1SDavid Howells 
4345e6ef4f1SDavid Howells 	default:
4355e6ef4f1SDavid Howells 		trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
4365e6ef4f1SDavid Howells 				      tracepoint_string("bad_conn_pkt"));
4375e6ef4f1SDavid Howells 		return -EPROTO;
4385e6ef4f1SDavid Howells 	}
4395e6ef4f1SDavid Howells }
440f2cce89aSDavid Howells 
441f2cce89aSDavid Howells /*
442f2cce89aSDavid Howells  * Input a connection event.
443f2cce89aSDavid Howells  */
444f2cce89aSDavid Howells void rxrpc_input_conn_event(struct rxrpc_connection *conn, struct sk_buff *skb)
445f2cce89aSDavid Howells {
446*a00ce28bSDavid Howells 	if (test_and_clear_bit(RXRPC_CONN_EV_ABORT_CALLS, &conn->events))
447*a00ce28bSDavid Howells 		rxrpc_abort_calls(conn);
448*a00ce28bSDavid Howells 
449f2cce89aSDavid Howells 	/* Process delayed ACKs whose time has come. */
450f2cce89aSDavid Howells 	if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK)
451f2cce89aSDavid Howells 		rxrpc_process_delayed_final_acks(conn, false);
452f2cce89aSDavid Howells }
453