xref: /openbmc/linux/net/rxrpc/conn_event.c (revision 59881e57)
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 /*
20a00ce28bSDavid Howells  * Set the completion state on an aborted connection.
21a00ce28bSDavid Howells  */
rxrpc_set_conn_aborted(struct rxrpc_connection * conn,struct sk_buff * skb,s32 abort_code,int err,enum rxrpc_call_completion compl)22a00ce28bSDavid Howells static bool rxrpc_set_conn_aborted(struct rxrpc_connection *conn, struct sk_buff *skb,
23a00ce28bSDavid Howells 				   s32 abort_code, int err,
24a00ce28bSDavid Howells 				   enum rxrpc_call_completion compl)
25a00ce28bSDavid Howells {
26a00ce28bSDavid Howells 	bool aborted = false;
27a00ce28bSDavid Howells 
28a00ce28bSDavid Howells 	if (conn->state != RXRPC_CONN_ABORTED) {
29a00ce28bSDavid Howells 		spin_lock(&conn->state_lock);
30a00ce28bSDavid Howells 		if (conn->state != RXRPC_CONN_ABORTED) {
31a00ce28bSDavid Howells 			conn->abort_code = abort_code;
32a00ce28bSDavid Howells 			conn->error	 = err;
33a00ce28bSDavid Howells 			conn->completion = compl;
34a00ce28bSDavid Howells 			/* Order the abort info before the state change. */
35a00ce28bSDavid Howells 			smp_store_release(&conn->state, RXRPC_CONN_ABORTED);
36a00ce28bSDavid Howells 			set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
37a00ce28bSDavid Howells 			set_bit(RXRPC_CONN_EV_ABORT_CALLS, &conn->events);
38a00ce28bSDavid Howells 			aborted = true;
39a00ce28bSDavid Howells 		}
40a00ce28bSDavid Howells 		spin_unlock(&conn->state_lock);
41a00ce28bSDavid Howells 	}
42a00ce28bSDavid Howells 
43a00ce28bSDavid Howells 	return aborted;
44a00ce28bSDavid Howells }
45a00ce28bSDavid Howells 
46a00ce28bSDavid Howells /*
47a00ce28bSDavid Howells  * Mark a socket buffer to indicate that the connection it's on should be aborted.
48a00ce28bSDavid Howells  */
rxrpc_abort_conn(struct rxrpc_connection * conn,struct sk_buff * skb,s32 abort_code,int err,enum rxrpc_abort_reason why)49a00ce28bSDavid Howells int rxrpc_abort_conn(struct rxrpc_connection *conn, struct sk_buff *skb,
5057af281eSDavid Howells 		     s32 abort_code, int err, enum rxrpc_abort_reason why)
51a00ce28bSDavid Howells {
52a00ce28bSDavid Howells 	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
53a00ce28bSDavid Howells 
54a00ce28bSDavid Howells 	if (rxrpc_set_conn_aborted(conn, skb, abort_code, err,
55a00ce28bSDavid Howells 				   RXRPC_CALL_LOCALLY_ABORTED)) {
56a00ce28bSDavid Howells 		trace_rxrpc_abort(0, why, sp->hdr.cid, sp->hdr.callNumber,
57a00ce28bSDavid Howells 				  sp->hdr.seq, abort_code, err);
58a00ce28bSDavid Howells 		rxrpc_poke_conn(conn, rxrpc_conn_get_poke_abort);
59a00ce28bSDavid Howells 	}
60a00ce28bSDavid Howells 	return -EPROTO;
61a00ce28bSDavid Howells }
62a00ce28bSDavid Howells 
63a00ce28bSDavid Howells /*
64a00ce28bSDavid Howells  * Mark a connection as being remotely aborted.
65a00ce28bSDavid Howells  */
rxrpc_input_conn_abort(struct rxrpc_connection * conn,struct sk_buff * skb)66a00ce28bSDavid Howells static bool rxrpc_input_conn_abort(struct rxrpc_connection *conn,
67a00ce28bSDavid Howells 				   struct sk_buff *skb)
68a00ce28bSDavid Howells {
69a00ce28bSDavid Howells 	return rxrpc_set_conn_aborted(conn, skb, skb->priority, -ECONNABORTED,
70a00ce28bSDavid Howells 				      RXRPC_CALL_REMOTELY_ABORTED);
71a00ce28bSDavid Howells }
72a00ce28bSDavid Howells 
73a00ce28bSDavid Howells /*
7418bfeba5SDavid Howells  * Retransmit terminal ACK or ABORT of the previous call.
7518bfeba5SDavid Howells  */
rxrpc_conn_retransmit_call(struct rxrpc_connection * conn,struct sk_buff * skb,unsigned int channel)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;
9159881e57SDavid Howells 	struct rxrpc_acktrailer trailer;
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 
982868b8e4SDavid Howells 	if (sp && sp->hdr.type == RXRPC_PACKET_TYPE_ACK) {
992868b8e4SDavid Howells 		if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
1002868b8e4SDavid Howells 				  &pkt.ack, sizeof(pkt.ack)) < 0)
1012868b8e4SDavid Howells 			return;
1022868b8e4SDavid Howells 		if (pkt.ack.reason == RXRPC_ACK_PING_RESPONSE)
1032868b8e4SDavid Howells 			return;
1042868b8e4SDavid Howells 	}
1052868b8e4SDavid Howells 
1063136ef49SDavid Howells 	chan = &conn->channels[channel];
10718bfeba5SDavid Howells 
10818bfeba5SDavid Howells 	/* If the last call got moved on whilst we were waiting to run, just
10918bfeba5SDavid Howells 	 * ignore this packet.
11018bfeba5SDavid Howells 	 */
1119d35d880SDavid Howells 	call_id = chan->last_call;
1123136ef49SDavid Howells 	if (skb && call_id != sp->hdr.callNumber)
11318bfeba5SDavid Howells 		return;
11418bfeba5SDavid Howells 
1152cc80086SDavid Howells 	msg.msg_name	= &conn->peer->srx.transport;
1162cc80086SDavid Howells 	msg.msg_namelen	= conn->peer->srx.transport_len;
11718bfeba5SDavid Howells 	msg.msg_control	= NULL;
11818bfeba5SDavid Howells 	msg.msg_controllen = 0;
11918bfeba5SDavid Howells 	msg.msg_flags	= 0;
12018bfeba5SDavid Howells 
1215fc62f6aSDavid Howells 	iov[0].iov_base	= &pkt;
1225fc62f6aSDavid Howells 	iov[0].iov_len	= sizeof(pkt.whdr);
1235fc62f6aSDavid Howells 	iov[1].iov_base	= &padding;
1245fc62f6aSDavid Howells 	iov[1].iov_len	= 3;
12559881e57SDavid Howells 	iov[2].iov_base	= &trailer;
12659881e57SDavid Howells 	iov[2].iov_len	= sizeof(trailer);
1275fc62f6aSDavid Howells 
1282c9dc472SDavid Howells 	serial = rxrpc_get_next_serial(conn);
1299d35d880SDavid Howells 
1303136ef49SDavid Howells 	pkt.whdr.epoch		= htonl(conn->proto.epoch);
131fb1967a6SDavid Howells 	pkt.whdr.cid		= htonl(conn->proto.cid | channel);
1323136ef49SDavid Howells 	pkt.whdr.callNumber	= htonl(call_id);
1339d35d880SDavid Howells 	pkt.whdr.serial		= htonl(serial);
13418bfeba5SDavid Howells 	pkt.whdr.seq		= 0;
13518bfeba5SDavid Howells 	pkt.whdr.type		= chan->last_type;
13618bfeba5SDavid Howells 	pkt.whdr.flags		= conn->out_clientflag;
13718bfeba5SDavid Howells 	pkt.whdr.userStatus	= 0;
13818bfeba5SDavid Howells 	pkt.whdr.securityIndex	= conn->security_ix;
13918bfeba5SDavid Howells 	pkt.whdr._rsvd		= 0;
14068d6d1aeSDavid Howells 	pkt.whdr.serviceId	= htons(conn->service_id);
14118bfeba5SDavid Howells 
14218bfeba5SDavid Howells 	len = sizeof(pkt.whdr);
14318bfeba5SDavid Howells 	switch (chan->last_type) {
14418bfeba5SDavid Howells 	case RXRPC_PACKET_TYPE_ABORT:
1455fc62f6aSDavid Howells 		pkt.abort_code	= htonl(chan->last_abort);
1465fc62f6aSDavid Howells 		iov[0].iov_len += sizeof(pkt.abort_code);
1475fc62f6aSDavid Howells 		len += sizeof(pkt.abort_code);
1485fc62f6aSDavid Howells 		ioc = 1;
14918bfeba5SDavid Howells 		break;
15018bfeba5SDavid Howells 
15118bfeba5SDavid Howells 	case RXRPC_PACKET_TYPE_ACK:
1522cc80086SDavid Howells 		mtu = conn->peer->if_mtu;
1532cc80086SDavid Howells 		mtu -= conn->peer->hdrsize;
15418bfeba5SDavid Howells 		pkt.ack.bufferSpace	= 0;
1553136ef49SDavid Howells 		pkt.ack.maxSkew		= htons(skb ? skb->priority : 0);
1563136ef49SDavid Howells 		pkt.ack.firstPacket	= htonl(chan->last_seq + 1);
1573136ef49SDavid Howells 		pkt.ack.previousPacket	= htonl(chan->last_seq);
1583136ef49SDavid Howells 		pkt.ack.serial		= htonl(skb ? sp->hdr.serial : 0);
1593136ef49SDavid Howells 		pkt.ack.reason		= skb ? RXRPC_ACK_DUPLICATE : RXRPC_ACK_IDLE;
16018bfeba5SDavid Howells 		pkt.ack.nAcks		= 0;
16159881e57SDavid Howells 		trailer.maxMTU		= htonl(rxrpc_rx_mtu);
16259881e57SDavid Howells 		trailer.ifMTU		= htonl(mtu);
16359881e57SDavid Howells 		trailer.rwind		= htonl(rxrpc_rx_window_size);
16459881e57SDavid Howells 		trailer.jumbo_max	= htonl(rxrpc_rx_jumbo_max);
16557494343SDavid Howells 		pkt.whdr.flags		|= RXRPC_SLOW_START_OK;
1665fc62f6aSDavid Howells 		padding			= 0;
1675fc62f6aSDavid Howells 		iov[0].iov_len += sizeof(pkt.ack);
16859881e57SDavid Howells 		len += sizeof(pkt.ack) + 3 + sizeof(trailer);
1695fc62f6aSDavid Howells 		ioc = 3;
1705fc62f6aSDavid Howells 
1714764c0daSDavid Howells 		trace_rxrpc_tx_ack(chan->call_debug_id, serial,
172f3f8337cSDavid Howells 				   ntohl(pkt.ack.firstPacket),
173f3f8337cSDavid Howells 				   ntohl(pkt.ack.serial),
174f789bff2SDavid Howells 				   pkt.ack.reason, 0, rxrpc_rx_window_size);
17518bfeba5SDavid Howells 		break;
1769d35d880SDavid Howells 
1779d35d880SDavid Howells 	default:
1789d35d880SDavid Howells 		return;
17918bfeba5SDavid Howells 	}
18018bfeba5SDavid Howells 
1812cc80086SDavid Howells 	ret = kernel_sendmsg(conn->local->socket, &msg, iov, ioc, len);
1822cc80086SDavid Howells 	conn->peer->last_tx_at = ktime_get_seconds();
1836b47fe1dSDavid Howells 	if (ret < 0)
1844764c0daSDavid Howells 		trace_rxrpc_tx_fail(chan->call_debug_id, serial, ret,
1854764c0daSDavid Howells 				    rxrpc_tx_point_call_final_resend);
1864764c0daSDavid Howells 	else
1874764c0daSDavid Howells 		trace_rxrpc_tx_packet(chan->call_debug_id, &pkt.whdr,
1884764c0daSDavid Howells 				      rxrpc_tx_point_call_final_resend);
1896b47fe1dSDavid Howells 
19018bfeba5SDavid Howells 	_leave("");
19118bfeba5SDavid Howells }
19218bfeba5SDavid Howells 
19318bfeba5SDavid Howells /*
1948c3e34a4SDavid Howells  * pass a connection-level abort onto all calls on that connection
1958c3e34a4SDavid Howells  */
rxrpc_abort_calls(struct rxrpc_connection * conn)196a00ce28bSDavid Howells static void rxrpc_abort_calls(struct rxrpc_connection *conn)
1978c3e34a4SDavid Howells {
1988c3e34a4SDavid Howells 	struct rxrpc_call *call;
199248f219cSDavid Howells 	int i;
2008c3e34a4SDavid Howells 
20164753092SDavid Howells 	_enter("{%d},%x", conn->debug_id, conn->abort_code);
2028c3e34a4SDavid Howells 
203a1399f8bSDavid Howells 	for (i = 0; i < RXRPC_MAXCALLS; i++) {
2049d35d880SDavid Howells 		call = conn->channels[i].call;
205a00ce28bSDavid Howells 		if (call)
206a00ce28bSDavid Howells 			rxrpc_set_call_completion(call,
207a00ce28bSDavid Howells 						  conn->completion,
20864753092SDavid Howells 						  conn->abort_code,
20964753092SDavid Howells 						  conn->error);
210ccbd3dbeSDavid Howells 	}
2118c3e34a4SDavid Howells 
2128c3e34a4SDavid Howells 	_leave("");
2138c3e34a4SDavid Howells }
2148c3e34a4SDavid Howells 
2158c3e34a4SDavid Howells /*
2168c3e34a4SDavid Howells  * mark a call as being on a now-secured channel
217248f219cSDavid Howells  * - must be called with BH's disabled.
2188c3e34a4SDavid Howells  */
rxrpc_call_is_secure(struct rxrpc_call * call)2198c3e34a4SDavid Howells static void rxrpc_call_is_secure(struct rxrpc_call *call)
2208c3e34a4SDavid Howells {
22196b4059fSDavid Howells 	if (call && __rxrpc_call_state(call) == RXRPC_CALL_SERVER_SECURING) {
22296b4059fSDavid Howells 		rxrpc_set_call_state(call, RXRPC_CALL_SERVER_RECV_REQUEST);
223248f219cSDavid Howells 		rxrpc_notify_socket(call);
224248f219cSDavid Howells 	}
2258c3e34a4SDavid Howells }
2268c3e34a4SDavid Howells 
2278c3e34a4SDavid Howells /*
2288c3e34a4SDavid Howells  * connection-level Rx packet processor
2298c3e34a4SDavid Howells  */
rxrpc_process_event(struct rxrpc_connection * conn,struct sk_buff * skb)2308c3e34a4SDavid Howells static int rxrpc_process_event(struct rxrpc_connection *conn,
231a00ce28bSDavid Howells 			       struct sk_buff *skb)
2328c3e34a4SDavid Howells {
2338c3e34a4SDavid Howells 	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
2342953d3b8SDavid Howells 	int ret;
2358c3e34a4SDavid Howells 
236a00ce28bSDavid Howells 	if (conn->state == RXRPC_CONN_ABORTED)
2378c3e34a4SDavid Howells 		return -ECONNABORTED;
2388c3e34a4SDavid Howells 
2398c3e34a4SDavid Howells 	_enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial);
2408c3e34a4SDavid Howells 
2418c3e34a4SDavid Howells 	switch (sp->hdr.type) {
2428c3e34a4SDavid Howells 	case RXRPC_PACKET_TYPE_CHALLENGE:
243a00ce28bSDavid Howells 		return conn->security->respond_to_challenge(conn, skb);
2448c3e34a4SDavid Howells 
2458c3e34a4SDavid Howells 	case RXRPC_PACKET_TYPE_RESPONSE:
246a00ce28bSDavid Howells 		ret = conn->security->verify_response(conn, skb);
2478c3e34a4SDavid Howells 		if (ret < 0)
2488c3e34a4SDavid Howells 			return ret;
2498c3e34a4SDavid Howells 
25041057ebdSDavid Howells 		ret = conn->security->init_connection_security(
2512cc80086SDavid Howells 			conn, conn->key->payload.data[0]);
2528c3e34a4SDavid Howells 		if (ret < 0)
2538c3e34a4SDavid Howells 			return ret;
2548c3e34a4SDavid Howells 
2553dd9c8b5SDavid Howells 		spin_lock(&conn->state_lock);
2562953d3b8SDavid Howells 		if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING)
257bba304dbSDavid Howells 			conn->state = RXRPC_CONN_SERVICE;
2583dd9c8b5SDavid Howells 		spin_unlock(&conn->state_lock);
2598c3e34a4SDavid Howells 
2602953d3b8SDavid Howells 		if (conn->state == RXRPC_CONN_SERVICE) {
2612953d3b8SDavid Howells 			/* Offload call state flipping to the I/O thread.  As
2622953d3b8SDavid Howells 			 * we've already received the packet, put it on the
2632953d3b8SDavid Howells 			 * front of the queue.
2642953d3b8SDavid Howells 			 */
2652953d3b8SDavid Howells 			skb->mark = RXRPC_SKB_MARK_SERVICE_CONN_SECURED;
2662953d3b8SDavid Howells 			rxrpc_get_skb(skb, rxrpc_skb_get_conn_secured);
2672953d3b8SDavid Howells 			skb_queue_head(&conn->local->rx_queue, skb);
2682953d3b8SDavid Howells 			rxrpc_wake_up_io_thread(conn->local);
2692953d3b8SDavid Howells 		}
2708c3e34a4SDavid Howells 		return 0;
2718c3e34a4SDavid Howells 
2728c3e34a4SDavid Howells 	default:
27357af281eSDavid Howells 		WARN_ON_ONCE(1);
2748c3e34a4SDavid Howells 		return -EPROTO;
2758c3e34a4SDavid Howells 	}
2768c3e34a4SDavid Howells }
2778c3e34a4SDavid Howells 
2788c3e34a4SDavid Howells /*
2798c3e34a4SDavid Howells  * set up security and issue a challenge
2808c3e34a4SDavid Howells  */
rxrpc_secure_connection(struct rxrpc_connection * conn)2818c3e34a4SDavid Howells static void rxrpc_secure_connection(struct rxrpc_connection *conn)
2828c3e34a4SDavid Howells {
283a00ce28bSDavid Howells 	if (conn->security->issue_challenge(conn) < 0)
28457af281eSDavid Howells 		rxrpc_abort_conn(conn, NULL, RX_CALL_DEAD, -ENOMEM,
28557af281eSDavid Howells 				 rxrpc_abort_nomem);
2868c3e34a4SDavid Howells }
2878c3e34a4SDavid Howells 
2888c3e34a4SDavid Howells /*
2893136ef49SDavid Howells  * Process delayed final ACKs that we haven't subsumed into a subsequent call.
2903136ef49SDavid Howells  */
rxrpc_process_delayed_final_acks(struct rxrpc_connection * conn,bool force)291ddc7834aSDavid Howells void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force)
2923136ef49SDavid Howells {
2933136ef49SDavid Howells 	unsigned long j = jiffies, next_j;
2943136ef49SDavid Howells 	unsigned int channel;
2953136ef49SDavid Howells 	bool set;
2963136ef49SDavid Howells 
2973136ef49SDavid Howells again:
2983136ef49SDavid Howells 	next_j = j + LONG_MAX;
2993136ef49SDavid Howells 	set = false;
3003136ef49SDavid Howells 	for (channel = 0; channel < RXRPC_MAXCALLS; channel++) {
3013136ef49SDavid Howells 		struct rxrpc_channel *chan = &conn->channels[channel];
3023136ef49SDavid Howells 		unsigned long ack_at;
3033136ef49SDavid Howells 
3043136ef49SDavid Howells 		if (!test_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags))
3053136ef49SDavid Howells 			continue;
3063136ef49SDavid Howells 
3079d35d880SDavid Howells 		ack_at = chan->final_ack_at;
308ddc7834aSDavid Howells 		if (time_before(j, ack_at) && !force) {
3093136ef49SDavid Howells 			if (time_before(ack_at, next_j)) {
3103136ef49SDavid Howells 				next_j = ack_at;
3113136ef49SDavid Howells 				set = true;
3123136ef49SDavid Howells 			}
3133136ef49SDavid Howells 			continue;
3143136ef49SDavid Howells 		}
3153136ef49SDavid Howells 
3163136ef49SDavid Howells 		if (test_and_clear_bit(RXRPC_CONN_FINAL_ACK_0 + channel,
3173136ef49SDavid Howells 				       &conn->flags))
3183136ef49SDavid Howells 			rxrpc_conn_retransmit_call(conn, NULL, channel);
3193136ef49SDavid Howells 	}
3203136ef49SDavid Howells 
3213136ef49SDavid Howells 	j = jiffies;
3223136ef49SDavid Howells 	if (time_before_eq(next_j, j))
3233136ef49SDavid Howells 		goto again;
3243136ef49SDavid Howells 	if (set)
3253136ef49SDavid Howells 		rxrpc_reduce_conn_timer(conn, next_j);
3263136ef49SDavid Howells }
3273136ef49SDavid Howells 
3283136ef49SDavid Howells /*
3298c3e34a4SDavid Howells  * connection-level event processor
3308c3e34a4SDavid Howells  */
rxrpc_do_process_connection(struct rxrpc_connection * conn)33104d36d74SDavid Howells static void rxrpc_do_process_connection(struct rxrpc_connection *conn)
3328c3e34a4SDavid Howells {
3338c3e34a4SDavid Howells 	struct sk_buff *skb;
3348c3e34a4SDavid Howells 	int ret;
3358c3e34a4SDavid Howells 
3362c4579e4SDavid Howells 	if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events))
3378c3e34a4SDavid Howells 		rxrpc_secure_connection(conn);
3388c3e34a4SDavid Howells 
3398c3e34a4SDavid Howells 	/* go through the conn-level event packets, releasing the ref on this
3408c3e34a4SDavid Howells 	 * connection that each one has when we've finished with it */
3418c3e34a4SDavid Howells 	while ((skb = skb_dequeue(&conn->rx_queue))) {
3429a36a6bcSDavid Howells 		rxrpc_see_skb(skb, rxrpc_skb_see_conn_work);
343a00ce28bSDavid Howells 		ret = rxrpc_process_event(conn, skb);
3448c3e34a4SDavid Howells 		switch (ret) {
3458c2f826dSDavid Howells 		case -ENOMEM:
3468c3e34a4SDavid Howells 		case -EAGAIN:
347a00ce28bSDavid Howells 			skb_queue_head(&conn->rx_queue, skb);
348a00ce28bSDavid Howells 			rxrpc_queue_conn(conn, rxrpc_conn_queue_retry_work);
349a00ce28bSDavid Howells 			break;
3508c3e34a4SDavid Howells 		default:
3519a36a6bcSDavid Howells 			rxrpc_free_skb(skb, rxrpc_skb_put_conn_work);
3528c3e34a4SDavid Howells 			break;
3538c3e34a4SDavid Howells 		}
3548c3e34a4SDavid Howells 	}
35504d36d74SDavid Howells }
35604d36d74SDavid Howells 
rxrpc_process_connection(struct work_struct * work)35704d36d74SDavid Howells void rxrpc_process_connection(struct work_struct *work)
35804d36d74SDavid Howells {
35904d36d74SDavid Howells 	struct rxrpc_connection *conn =
36004d36d74SDavid Howells 		container_of(work, struct rxrpc_connection, processor);
36104d36d74SDavid Howells 
3627fa25105SDavid Howells 	rxrpc_see_connection(conn, rxrpc_conn_see_work);
36304d36d74SDavid Howells 
3640fde882fSDavid Howells 	if (__rxrpc_use_local(conn->local, rxrpc_local_use_conn_work)) {
36504d36d74SDavid Howells 		rxrpc_do_process_connection(conn);
3660fde882fSDavid Howells 		rxrpc_unuse_local(conn->local, rxrpc_local_unuse_conn_work);
36704d36d74SDavid Howells 	}
3688c3e34a4SDavid Howells }
3695e6ef4f1SDavid Howells 
3705e6ef4f1SDavid Howells /*
3715e6ef4f1SDavid Howells  * post connection-level events to the connection
3725e6ef4f1SDavid Howells  * - this includes challenges, responses, some aborts and call terminal packet
3735e6ef4f1SDavid Howells  *   retransmission.
3745e6ef4f1SDavid Howells  */
rxrpc_post_packet_to_conn(struct rxrpc_connection * conn,struct sk_buff * skb)3755e6ef4f1SDavid Howells static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
3765e6ef4f1SDavid Howells 				      struct sk_buff *skb)
3775e6ef4f1SDavid Howells {
3785e6ef4f1SDavid Howells 	_enter("%p,%p", conn, skb);
3795e6ef4f1SDavid Howells 
3805e6ef4f1SDavid Howells 	rxrpc_get_skb(skb, rxrpc_skb_get_conn_work);
3815e6ef4f1SDavid Howells 	skb_queue_tail(&conn->rx_queue, skb);
3825e6ef4f1SDavid Howells 	rxrpc_queue_conn(conn, rxrpc_conn_queue_rx_work);
3835e6ef4f1SDavid Howells }
3845e6ef4f1SDavid Howells 
3855e6ef4f1SDavid Howells /*
3865e6ef4f1SDavid Howells  * Input a connection-level packet.
3875e6ef4f1SDavid Howells  */
rxrpc_input_conn_packet(struct rxrpc_connection * conn,struct sk_buff * skb)38857af281eSDavid Howells bool rxrpc_input_conn_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
3895e6ef4f1SDavid Howells {
3905e6ef4f1SDavid Howells 	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
3915e6ef4f1SDavid Howells 
3925e6ef4f1SDavid Howells 	switch (sp->hdr.type) {
3935e6ef4f1SDavid Howells 	case RXRPC_PACKET_TYPE_BUSY:
3945e6ef4f1SDavid Howells 		/* Just ignore BUSY packets for now. */
39557af281eSDavid Howells 		return true;
3965e6ef4f1SDavid Howells 
3975e6ef4f1SDavid Howells 	case RXRPC_PACKET_TYPE_ABORT:
398a00ce28bSDavid Howells 		if (rxrpc_is_conn_aborted(conn))
399a00ce28bSDavid Howells 			return true;
400a00ce28bSDavid Howells 		rxrpc_input_conn_abort(conn, skb);
401a00ce28bSDavid Howells 		rxrpc_abort_calls(conn);
402a00ce28bSDavid Howells 		return true;
4035e6ef4f1SDavid Howells 
4045e6ef4f1SDavid Howells 	case RXRPC_PACKET_TYPE_CHALLENGE:
4055e6ef4f1SDavid Howells 	case RXRPC_PACKET_TYPE_RESPONSE:
406a00ce28bSDavid Howells 		if (rxrpc_is_conn_aborted(conn)) {
407a00ce28bSDavid Howells 			if (conn->completion == RXRPC_CALL_LOCALLY_ABORTED)
408a00ce28bSDavid Howells 				rxrpc_send_conn_abort(conn);
409a00ce28bSDavid Howells 			return true;
410a00ce28bSDavid Howells 		}
4115e6ef4f1SDavid Howells 		rxrpc_post_packet_to_conn(conn, skb);
41257af281eSDavid Howells 		return true;
4135e6ef4f1SDavid Howells 
4145e6ef4f1SDavid Howells 	default:
41557af281eSDavid Howells 		WARN_ON_ONCE(1);
41657af281eSDavid Howells 		return true;
4175e6ef4f1SDavid Howells 	}
4185e6ef4f1SDavid Howells }
419f2cce89aSDavid Howells 
420f2cce89aSDavid Howells /*
421f2cce89aSDavid Howells  * Input a connection event.
422f2cce89aSDavid Howells  */
rxrpc_input_conn_event(struct rxrpc_connection * conn,struct sk_buff * skb)423f2cce89aSDavid Howells void rxrpc_input_conn_event(struct rxrpc_connection *conn, struct sk_buff *skb)
424f2cce89aSDavid Howells {
4252953d3b8SDavid Howells 	unsigned int loop;
4262953d3b8SDavid Howells 
427a00ce28bSDavid Howells 	if (test_and_clear_bit(RXRPC_CONN_EV_ABORT_CALLS, &conn->events))
428a00ce28bSDavid Howells 		rxrpc_abort_calls(conn);
429a00ce28bSDavid Howells 
4302953d3b8SDavid Howells 	switch (skb->mark) {
4312953d3b8SDavid Howells 	case RXRPC_SKB_MARK_SERVICE_CONN_SECURED:
4322953d3b8SDavid Howells 		if (conn->state != RXRPC_CONN_SERVICE)
4332953d3b8SDavid Howells 			break;
4342953d3b8SDavid Howells 
4352953d3b8SDavid Howells 		for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
4369d35d880SDavid Howells 			rxrpc_call_is_secure(conn->channels[loop].call);
4372953d3b8SDavid Howells 		break;
4382953d3b8SDavid Howells 	}
4392953d3b8SDavid Howells 
440f2cce89aSDavid Howells 	/* Process delayed ACKs whose time has come. */
441f2cce89aSDavid Howells 	if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK)
442f2cce89aSDavid Howells 		rxrpc_process_delayed_final_acks(conn, false);
443f2cce89aSDavid Howells }
444