18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* connection-level event handling
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/net.h>
128c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
138c2ecf20Sopenharmony_ci#include <linux/errqueue.h>
148c2ecf20Sopenharmony_ci#include <net/sock.h>
158c2ecf20Sopenharmony_ci#include <net/af_rxrpc.h>
168c2ecf20Sopenharmony_ci#include <net/ip.h>
178c2ecf20Sopenharmony_ci#include "ar-internal.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Retransmit terminal ACK or ABORT of the previous call.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_cistatic void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
238c2ecf20Sopenharmony_ci				       struct sk_buff *skb,
248c2ecf20Sopenharmony_ci				       unsigned int channel)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct rxrpc_skb_priv *sp = skb ? rxrpc_skb(skb) : NULL;
278c2ecf20Sopenharmony_ci	struct rxrpc_channel *chan;
288c2ecf20Sopenharmony_ci	struct msghdr msg;
298c2ecf20Sopenharmony_ci	struct kvec iov[3];
308c2ecf20Sopenharmony_ci	struct {
318c2ecf20Sopenharmony_ci		struct rxrpc_wire_header whdr;
328c2ecf20Sopenharmony_ci		union {
338c2ecf20Sopenharmony_ci			__be32 abort_code;
348c2ecf20Sopenharmony_ci			struct rxrpc_ackpacket ack;
358c2ecf20Sopenharmony_ci		};
368c2ecf20Sopenharmony_ci	} __attribute__((packed)) pkt;
378c2ecf20Sopenharmony_ci	struct rxrpc_ackinfo ack_info;
388c2ecf20Sopenharmony_ci	size_t len;
398c2ecf20Sopenharmony_ci	int ret, ioc;
408c2ecf20Sopenharmony_ci	u32 serial, mtu, call_id, padding;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	_enter("%d", conn->debug_id);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (sp && sp->hdr.type == RXRPC_PACKET_TYPE_ACK) {
458c2ecf20Sopenharmony_ci		if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
468c2ecf20Sopenharmony_ci				  &pkt.ack, sizeof(pkt.ack)) < 0)
478c2ecf20Sopenharmony_ci			return;
488c2ecf20Sopenharmony_ci		if (pkt.ack.reason == RXRPC_ACK_PING_RESPONSE)
498c2ecf20Sopenharmony_ci			return;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	chan = &conn->channels[channel];
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* If the last call got moved on whilst we were waiting to run, just
558c2ecf20Sopenharmony_ci	 * ignore this packet.
568c2ecf20Sopenharmony_ci	 */
578c2ecf20Sopenharmony_ci	call_id = READ_ONCE(chan->last_call);
588c2ecf20Sopenharmony_ci	/* Sync with __rxrpc_disconnect_call() */
598c2ecf20Sopenharmony_ci	smp_rmb();
608c2ecf20Sopenharmony_ci	if (skb && call_id != sp->hdr.callNumber)
618c2ecf20Sopenharmony_ci		return;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	msg.msg_name	= &conn->params.peer->srx.transport;
648c2ecf20Sopenharmony_ci	msg.msg_namelen	= conn->params.peer->srx.transport_len;
658c2ecf20Sopenharmony_ci	msg.msg_control	= NULL;
668c2ecf20Sopenharmony_ci	msg.msg_controllen = 0;
678c2ecf20Sopenharmony_ci	msg.msg_flags	= 0;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	iov[0].iov_base	= &pkt;
708c2ecf20Sopenharmony_ci	iov[0].iov_len	= sizeof(pkt.whdr);
718c2ecf20Sopenharmony_ci	iov[1].iov_base	= &padding;
728c2ecf20Sopenharmony_ci	iov[1].iov_len	= 3;
738c2ecf20Sopenharmony_ci	iov[2].iov_base	= &ack_info;
748c2ecf20Sopenharmony_ci	iov[2].iov_len	= sizeof(ack_info);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	pkt.whdr.epoch		= htonl(conn->proto.epoch);
778c2ecf20Sopenharmony_ci	pkt.whdr.cid		= htonl(conn->proto.cid | channel);
788c2ecf20Sopenharmony_ci	pkt.whdr.callNumber	= htonl(call_id);
798c2ecf20Sopenharmony_ci	pkt.whdr.seq		= 0;
808c2ecf20Sopenharmony_ci	pkt.whdr.type		= chan->last_type;
818c2ecf20Sopenharmony_ci	pkt.whdr.flags		= conn->out_clientflag;
828c2ecf20Sopenharmony_ci	pkt.whdr.userStatus	= 0;
838c2ecf20Sopenharmony_ci	pkt.whdr.securityIndex	= conn->security_ix;
848c2ecf20Sopenharmony_ci	pkt.whdr._rsvd		= 0;
858c2ecf20Sopenharmony_ci	pkt.whdr.serviceId	= htons(conn->service_id);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	len = sizeof(pkt.whdr);
888c2ecf20Sopenharmony_ci	switch (chan->last_type) {
898c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_ABORT:
908c2ecf20Sopenharmony_ci		pkt.abort_code	= htonl(chan->last_abort);
918c2ecf20Sopenharmony_ci		iov[0].iov_len += sizeof(pkt.abort_code);
928c2ecf20Sopenharmony_ci		len += sizeof(pkt.abort_code);
938c2ecf20Sopenharmony_ci		ioc = 1;
948c2ecf20Sopenharmony_ci		break;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_ACK:
978c2ecf20Sopenharmony_ci		mtu = conn->params.peer->if_mtu;
988c2ecf20Sopenharmony_ci		mtu -= conn->params.peer->hdrsize;
998c2ecf20Sopenharmony_ci		pkt.ack.bufferSpace	= 0;
1008c2ecf20Sopenharmony_ci		pkt.ack.maxSkew		= htons(skb ? skb->priority : 0);
1018c2ecf20Sopenharmony_ci		pkt.ack.firstPacket	= htonl(chan->last_seq + 1);
1028c2ecf20Sopenharmony_ci		pkt.ack.previousPacket	= htonl(chan->last_seq);
1038c2ecf20Sopenharmony_ci		pkt.ack.serial		= htonl(skb ? sp->hdr.serial : 0);
1048c2ecf20Sopenharmony_ci		pkt.ack.reason		= skb ? RXRPC_ACK_DUPLICATE : RXRPC_ACK_IDLE;
1058c2ecf20Sopenharmony_ci		pkt.ack.nAcks		= 0;
1068c2ecf20Sopenharmony_ci		ack_info.rxMTU		= htonl(rxrpc_rx_mtu);
1078c2ecf20Sopenharmony_ci		ack_info.maxMTU		= htonl(mtu);
1088c2ecf20Sopenharmony_ci		ack_info.rwind		= htonl(rxrpc_rx_window_size);
1098c2ecf20Sopenharmony_ci		ack_info.jumbo_max	= htonl(rxrpc_rx_jumbo_max);
1108c2ecf20Sopenharmony_ci		pkt.whdr.flags		|= RXRPC_SLOW_START_OK;
1118c2ecf20Sopenharmony_ci		padding			= 0;
1128c2ecf20Sopenharmony_ci		iov[0].iov_len += sizeof(pkt.ack);
1138c2ecf20Sopenharmony_ci		len += sizeof(pkt.ack) + 3 + sizeof(ack_info);
1148c2ecf20Sopenharmony_ci		ioc = 3;
1158c2ecf20Sopenharmony_ci		break;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	default:
1188c2ecf20Sopenharmony_ci		return;
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* Resync with __rxrpc_disconnect_call() and check that the last call
1228c2ecf20Sopenharmony_ci	 * didn't get advanced whilst we were filling out the packets.
1238c2ecf20Sopenharmony_ci	 */
1248c2ecf20Sopenharmony_ci	smp_rmb();
1258c2ecf20Sopenharmony_ci	if (READ_ONCE(chan->last_call) != call_id)
1268c2ecf20Sopenharmony_ci		return;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	serial = atomic_inc_return(&conn->serial);
1298c2ecf20Sopenharmony_ci	pkt.whdr.serial = htonl(serial);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	switch (chan->last_type) {
1328c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_ABORT:
1338c2ecf20Sopenharmony_ci		_proto("Tx ABORT %%%u { %d } [re]", serial, conn->abort_code);
1348c2ecf20Sopenharmony_ci		break;
1358c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_ACK:
1368c2ecf20Sopenharmony_ci		trace_rxrpc_tx_ack(chan->call_debug_id, serial,
1378c2ecf20Sopenharmony_ci				   ntohl(pkt.ack.firstPacket),
1388c2ecf20Sopenharmony_ci				   ntohl(pkt.ack.serial),
1398c2ecf20Sopenharmony_ci				   pkt.ack.reason, 0);
1408c2ecf20Sopenharmony_ci		_proto("Tx ACK %%%u [re]", serial);
1418c2ecf20Sopenharmony_ci		break;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, ioc, len);
1458c2ecf20Sopenharmony_ci	conn->params.peer->last_tx_at = ktime_get_seconds();
1468c2ecf20Sopenharmony_ci	if (ret < 0)
1478c2ecf20Sopenharmony_ci		trace_rxrpc_tx_fail(chan->call_debug_id, serial, ret,
1488c2ecf20Sopenharmony_ci				    rxrpc_tx_point_call_final_resend);
1498c2ecf20Sopenharmony_ci	else
1508c2ecf20Sopenharmony_ci		trace_rxrpc_tx_packet(chan->call_debug_id, &pkt.whdr,
1518c2ecf20Sopenharmony_ci				      rxrpc_tx_point_call_final_resend);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	_leave("");
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/*
1578c2ecf20Sopenharmony_ci * pass a connection-level abort onto all calls on that connection
1588c2ecf20Sopenharmony_ci */
1598c2ecf20Sopenharmony_cistatic void rxrpc_abort_calls(struct rxrpc_connection *conn,
1608c2ecf20Sopenharmony_ci			      enum rxrpc_call_completion compl,
1618c2ecf20Sopenharmony_ci			      rxrpc_serial_t serial)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	struct rxrpc_call *call;
1648c2ecf20Sopenharmony_ci	int i;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	_enter("{%d},%x", conn->debug_id, conn->abort_code);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	spin_lock(&conn->bundle->channel_lock);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	for (i = 0; i < RXRPC_MAXCALLS; i++) {
1718c2ecf20Sopenharmony_ci		call = rcu_dereference_protected(
1728c2ecf20Sopenharmony_ci			conn->channels[i].call,
1738c2ecf20Sopenharmony_ci			lockdep_is_held(&conn->bundle->channel_lock));
1748c2ecf20Sopenharmony_ci		if (call) {
1758c2ecf20Sopenharmony_ci			if (compl == RXRPC_CALL_LOCALLY_ABORTED)
1768c2ecf20Sopenharmony_ci				trace_rxrpc_abort(call->debug_id,
1778c2ecf20Sopenharmony_ci						  "CON", call->cid,
1788c2ecf20Sopenharmony_ci						  call->call_id, 0,
1798c2ecf20Sopenharmony_ci						  conn->abort_code,
1808c2ecf20Sopenharmony_ci						  conn->error);
1818c2ecf20Sopenharmony_ci			else
1828c2ecf20Sopenharmony_ci				trace_rxrpc_rx_abort(call, serial,
1838c2ecf20Sopenharmony_ci						     conn->abort_code);
1848c2ecf20Sopenharmony_ci			rxrpc_set_call_completion(call, compl,
1858c2ecf20Sopenharmony_ci						  conn->abort_code,
1868c2ecf20Sopenharmony_ci						  conn->error);
1878c2ecf20Sopenharmony_ci		}
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	spin_unlock(&conn->bundle->channel_lock);
1918c2ecf20Sopenharmony_ci	_leave("");
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/*
1958c2ecf20Sopenharmony_ci * generate a connection-level abort
1968c2ecf20Sopenharmony_ci */
1978c2ecf20Sopenharmony_cistatic int rxrpc_abort_connection(struct rxrpc_connection *conn,
1988c2ecf20Sopenharmony_ci				  int error, u32 abort_code)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct rxrpc_wire_header whdr;
2018c2ecf20Sopenharmony_ci	struct msghdr msg;
2028c2ecf20Sopenharmony_ci	struct kvec iov[2];
2038c2ecf20Sopenharmony_ci	__be32 word;
2048c2ecf20Sopenharmony_ci	size_t len;
2058c2ecf20Sopenharmony_ci	u32 serial;
2068c2ecf20Sopenharmony_ci	int ret;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	_enter("%d,,%u,%u", conn->debug_id, error, abort_code);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	/* generate a connection-level abort */
2118c2ecf20Sopenharmony_ci	spin_lock_bh(&conn->state_lock);
2128c2ecf20Sopenharmony_ci	if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
2138c2ecf20Sopenharmony_ci		spin_unlock_bh(&conn->state_lock);
2148c2ecf20Sopenharmony_ci		_leave(" = 0 [already dead]");
2158c2ecf20Sopenharmony_ci		return 0;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	conn->error = error;
2198c2ecf20Sopenharmony_ci	conn->abort_code = abort_code;
2208c2ecf20Sopenharmony_ci	conn->state = RXRPC_CONN_LOCALLY_ABORTED;
2218c2ecf20Sopenharmony_ci	set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
2228c2ecf20Sopenharmony_ci	spin_unlock_bh(&conn->state_lock);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	msg.msg_name	= &conn->params.peer->srx.transport;
2258c2ecf20Sopenharmony_ci	msg.msg_namelen	= conn->params.peer->srx.transport_len;
2268c2ecf20Sopenharmony_ci	msg.msg_control	= NULL;
2278c2ecf20Sopenharmony_ci	msg.msg_controllen = 0;
2288c2ecf20Sopenharmony_ci	msg.msg_flags	= 0;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	whdr.epoch	= htonl(conn->proto.epoch);
2318c2ecf20Sopenharmony_ci	whdr.cid	= htonl(conn->proto.cid);
2328c2ecf20Sopenharmony_ci	whdr.callNumber	= 0;
2338c2ecf20Sopenharmony_ci	whdr.seq	= 0;
2348c2ecf20Sopenharmony_ci	whdr.type	= RXRPC_PACKET_TYPE_ABORT;
2358c2ecf20Sopenharmony_ci	whdr.flags	= conn->out_clientflag;
2368c2ecf20Sopenharmony_ci	whdr.userStatus	= 0;
2378c2ecf20Sopenharmony_ci	whdr.securityIndex = conn->security_ix;
2388c2ecf20Sopenharmony_ci	whdr._rsvd	= 0;
2398c2ecf20Sopenharmony_ci	whdr.serviceId	= htons(conn->service_id);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	word		= htonl(conn->abort_code);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	iov[0].iov_base	= &whdr;
2448c2ecf20Sopenharmony_ci	iov[0].iov_len	= sizeof(whdr);
2458c2ecf20Sopenharmony_ci	iov[1].iov_base	= &word;
2468c2ecf20Sopenharmony_ci	iov[1].iov_len	= sizeof(word);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	len = iov[0].iov_len + iov[1].iov_len;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	serial = atomic_inc_return(&conn->serial);
2518c2ecf20Sopenharmony_ci	rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED, serial);
2528c2ecf20Sopenharmony_ci	whdr.serial = htonl(serial);
2538c2ecf20Sopenharmony_ci	_proto("Tx CONN ABORT %%%u { %d }", serial, conn->abort_code);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
2568c2ecf20Sopenharmony_ci	if (ret < 0) {
2578c2ecf20Sopenharmony_ci		trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
2588c2ecf20Sopenharmony_ci				    rxrpc_tx_point_conn_abort);
2598c2ecf20Sopenharmony_ci		_debug("sendmsg failed: %d", ret);
2608c2ecf20Sopenharmony_ci		return -EAGAIN;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	trace_rxrpc_tx_packet(conn->debug_id, &whdr, rxrpc_tx_point_conn_abort);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	conn->params.peer->last_tx_at = ktime_get_seconds();
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	_leave(" = 0");
2688c2ecf20Sopenharmony_ci	return 0;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci/*
2728c2ecf20Sopenharmony_ci * mark a call as being on a now-secured channel
2738c2ecf20Sopenharmony_ci * - must be called with BH's disabled.
2748c2ecf20Sopenharmony_ci */
2758c2ecf20Sopenharmony_cistatic void rxrpc_call_is_secure(struct rxrpc_call *call)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	_enter("%p", call);
2788c2ecf20Sopenharmony_ci	if (call) {
2798c2ecf20Sopenharmony_ci		write_lock_bh(&call->state_lock);
2808c2ecf20Sopenharmony_ci		if (call->state == RXRPC_CALL_SERVER_SECURING) {
2818c2ecf20Sopenharmony_ci			call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
2828c2ecf20Sopenharmony_ci			rxrpc_notify_socket(call);
2838c2ecf20Sopenharmony_ci		}
2848c2ecf20Sopenharmony_ci		write_unlock_bh(&call->state_lock);
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/*
2898c2ecf20Sopenharmony_ci * connection-level Rx packet processor
2908c2ecf20Sopenharmony_ci */
2918c2ecf20Sopenharmony_cistatic int rxrpc_process_event(struct rxrpc_connection *conn,
2928c2ecf20Sopenharmony_ci			       struct sk_buff *skb,
2938c2ecf20Sopenharmony_ci			       u32 *_abort_code)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
2968c2ecf20Sopenharmony_ci	__be32 wtmp;
2978c2ecf20Sopenharmony_ci	u32 abort_code;
2988c2ecf20Sopenharmony_ci	int loop, ret;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
3018c2ecf20Sopenharmony_ci		_leave(" = -ECONNABORTED [%u]", conn->state);
3028c2ecf20Sopenharmony_ci		return -ECONNABORTED;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	_enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	switch (sp->hdr.type) {
3088c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_DATA:
3098c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_ACK:
3108c2ecf20Sopenharmony_ci		rxrpc_conn_retransmit_call(conn, skb,
3118c2ecf20Sopenharmony_ci					   sp->hdr.cid & RXRPC_CHANNELMASK);
3128c2ecf20Sopenharmony_ci		return 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_BUSY:
3158c2ecf20Sopenharmony_ci		/* Just ignore BUSY packets for now. */
3168c2ecf20Sopenharmony_ci		return 0;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_ABORT:
3198c2ecf20Sopenharmony_ci		if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
3208c2ecf20Sopenharmony_ci				  &wtmp, sizeof(wtmp)) < 0) {
3218c2ecf20Sopenharmony_ci			trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
3228c2ecf20Sopenharmony_ci					      tracepoint_string("bad_abort"));
3238c2ecf20Sopenharmony_ci			return -EPROTO;
3248c2ecf20Sopenharmony_ci		}
3258c2ecf20Sopenharmony_ci		abort_code = ntohl(wtmp);
3268c2ecf20Sopenharmony_ci		_proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci		conn->error = -ECONNABORTED;
3298c2ecf20Sopenharmony_ci		conn->abort_code = abort_code;
3308c2ecf20Sopenharmony_ci		conn->state = RXRPC_CONN_REMOTELY_ABORTED;
3318c2ecf20Sopenharmony_ci		set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
3328c2ecf20Sopenharmony_ci		rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED, sp->hdr.serial);
3338c2ecf20Sopenharmony_ci		return -ECONNABORTED;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_CHALLENGE:
3368c2ecf20Sopenharmony_ci		return conn->security->respond_to_challenge(conn, skb,
3378c2ecf20Sopenharmony_ci							    _abort_code);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	case RXRPC_PACKET_TYPE_RESPONSE:
3408c2ecf20Sopenharmony_ci		ret = conn->security->verify_response(conn, skb, _abort_code);
3418c2ecf20Sopenharmony_ci		if (ret < 0)
3428c2ecf20Sopenharmony_ci			return ret;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci		ret = conn->security->init_connection_security(conn);
3458c2ecf20Sopenharmony_ci		if (ret < 0)
3468c2ecf20Sopenharmony_ci			return ret;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		ret = conn->security->prime_packet_security(conn);
3498c2ecf20Sopenharmony_ci		if (ret < 0)
3508c2ecf20Sopenharmony_ci			return ret;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		spin_lock(&conn->bundle->channel_lock);
3538c2ecf20Sopenharmony_ci		spin_lock_bh(&conn->state_lock);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci		if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
3568c2ecf20Sopenharmony_ci			conn->state = RXRPC_CONN_SERVICE;
3578c2ecf20Sopenharmony_ci			spin_unlock_bh(&conn->state_lock);
3588c2ecf20Sopenharmony_ci			for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
3598c2ecf20Sopenharmony_ci				rxrpc_call_is_secure(
3608c2ecf20Sopenharmony_ci					rcu_dereference_protected(
3618c2ecf20Sopenharmony_ci						conn->channels[loop].call,
3628c2ecf20Sopenharmony_ci						lockdep_is_held(&conn->bundle->channel_lock)));
3638c2ecf20Sopenharmony_ci		} else {
3648c2ecf20Sopenharmony_ci			spin_unlock_bh(&conn->state_lock);
3658c2ecf20Sopenharmony_ci		}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		spin_unlock(&conn->bundle->channel_lock);
3688c2ecf20Sopenharmony_ci		return 0;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	default:
3718c2ecf20Sopenharmony_ci		trace_rxrpc_rx_eproto(NULL, sp->hdr.serial,
3728c2ecf20Sopenharmony_ci				      tracepoint_string("bad_conn_pkt"));
3738c2ecf20Sopenharmony_ci		return -EPROTO;
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci/*
3788c2ecf20Sopenharmony_ci * set up security and issue a challenge
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_cistatic void rxrpc_secure_connection(struct rxrpc_connection *conn)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	u32 abort_code;
3838c2ecf20Sopenharmony_ci	int ret;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	_enter("{%d}", conn->debug_id);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	ASSERT(conn->security_ix != 0);
3888c2ecf20Sopenharmony_ci	ASSERT(conn->server_key);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (conn->security->issue_challenge(conn) < 0) {
3918c2ecf20Sopenharmony_ci		abort_code = RX_CALL_DEAD;
3928c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3938c2ecf20Sopenharmony_ci		goto abort;
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	_leave("");
3978c2ecf20Sopenharmony_ci	return;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ciabort:
4008c2ecf20Sopenharmony_ci	_debug("abort %d, %d", ret, abort_code);
4018c2ecf20Sopenharmony_ci	rxrpc_abort_connection(conn, ret, abort_code);
4028c2ecf20Sopenharmony_ci	_leave(" [aborted]");
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci/*
4068c2ecf20Sopenharmony_ci * Process delayed final ACKs that we haven't subsumed into a subsequent call.
4078c2ecf20Sopenharmony_ci */
4088c2ecf20Sopenharmony_civoid rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn, bool force)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	unsigned long j = jiffies, next_j;
4118c2ecf20Sopenharmony_ci	unsigned int channel;
4128c2ecf20Sopenharmony_ci	bool set;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ciagain:
4158c2ecf20Sopenharmony_ci	next_j = j + LONG_MAX;
4168c2ecf20Sopenharmony_ci	set = false;
4178c2ecf20Sopenharmony_ci	for (channel = 0; channel < RXRPC_MAXCALLS; channel++) {
4188c2ecf20Sopenharmony_ci		struct rxrpc_channel *chan = &conn->channels[channel];
4198c2ecf20Sopenharmony_ci		unsigned long ack_at;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		if (!test_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags))
4228c2ecf20Sopenharmony_ci			continue;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		smp_rmb(); /* vs rxrpc_disconnect_client_call */
4258c2ecf20Sopenharmony_ci		ack_at = READ_ONCE(chan->final_ack_at);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		if (time_before(j, ack_at) && !force) {
4288c2ecf20Sopenharmony_ci			if (time_before(ack_at, next_j)) {
4298c2ecf20Sopenharmony_ci				next_j = ack_at;
4308c2ecf20Sopenharmony_ci				set = true;
4318c2ecf20Sopenharmony_ci			}
4328c2ecf20Sopenharmony_ci			continue;
4338c2ecf20Sopenharmony_ci		}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		if (test_and_clear_bit(RXRPC_CONN_FINAL_ACK_0 + channel,
4368c2ecf20Sopenharmony_ci				       &conn->flags))
4378c2ecf20Sopenharmony_ci			rxrpc_conn_retransmit_call(conn, NULL, channel);
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	j = jiffies;
4418c2ecf20Sopenharmony_ci	if (time_before_eq(next_j, j))
4428c2ecf20Sopenharmony_ci		goto again;
4438c2ecf20Sopenharmony_ci	if (set)
4448c2ecf20Sopenharmony_ci		rxrpc_reduce_conn_timer(conn, next_j);
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci/*
4488c2ecf20Sopenharmony_ci * connection-level event processor
4498c2ecf20Sopenharmony_ci */
4508c2ecf20Sopenharmony_cistatic void rxrpc_do_process_connection(struct rxrpc_connection *conn)
4518c2ecf20Sopenharmony_ci{
4528c2ecf20Sopenharmony_ci	struct sk_buff *skb;
4538c2ecf20Sopenharmony_ci	u32 abort_code = RX_PROTOCOL_ERROR;
4548c2ecf20Sopenharmony_ci	int ret;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events))
4578c2ecf20Sopenharmony_ci		rxrpc_secure_connection(conn);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	/* Process delayed ACKs whose time has come. */
4608c2ecf20Sopenharmony_ci	if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK)
4618c2ecf20Sopenharmony_ci		rxrpc_process_delayed_final_acks(conn, false);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/* go through the conn-level event packets, releasing the ref on this
4648c2ecf20Sopenharmony_ci	 * connection that each one has when we've finished with it */
4658c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(&conn->rx_queue))) {
4668c2ecf20Sopenharmony_ci		rxrpc_see_skb(skb, rxrpc_skb_seen);
4678c2ecf20Sopenharmony_ci		ret = rxrpc_process_event(conn, skb, &abort_code);
4688c2ecf20Sopenharmony_ci		switch (ret) {
4698c2ecf20Sopenharmony_ci		case -EPROTO:
4708c2ecf20Sopenharmony_ci		case -EKEYEXPIRED:
4718c2ecf20Sopenharmony_ci		case -EKEYREJECTED:
4728c2ecf20Sopenharmony_ci			goto protocol_error;
4738c2ecf20Sopenharmony_ci		case -ENOMEM:
4748c2ecf20Sopenharmony_ci		case -EAGAIN:
4758c2ecf20Sopenharmony_ci			goto requeue_and_leave;
4768c2ecf20Sopenharmony_ci		case -ECONNABORTED:
4778c2ecf20Sopenharmony_ci		default:
4788c2ecf20Sopenharmony_ci			rxrpc_free_skb(skb, rxrpc_skb_freed);
4798c2ecf20Sopenharmony_ci			break;
4808c2ecf20Sopenharmony_ci		}
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	return;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cirequeue_and_leave:
4868c2ecf20Sopenharmony_ci	skb_queue_head(&conn->rx_queue, skb);
4878c2ecf20Sopenharmony_ci	return;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ciprotocol_error:
4908c2ecf20Sopenharmony_ci	if (rxrpc_abort_connection(conn, ret, abort_code) < 0)
4918c2ecf20Sopenharmony_ci		goto requeue_and_leave;
4928c2ecf20Sopenharmony_ci	rxrpc_free_skb(skb, rxrpc_skb_freed);
4938c2ecf20Sopenharmony_ci	return;
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_civoid rxrpc_process_connection(struct work_struct *work)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	struct rxrpc_connection *conn =
4998c2ecf20Sopenharmony_ci		container_of(work, struct rxrpc_connection, processor);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	rxrpc_see_connection(conn);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (__rxrpc_use_local(conn->params.local)) {
5048c2ecf20Sopenharmony_ci		rxrpc_do_process_connection(conn);
5058c2ecf20Sopenharmony_ci		rxrpc_unuse_local(conn->params.local);
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	rxrpc_put_connection(conn);
5098c2ecf20Sopenharmony_ci	_leave("");
5108c2ecf20Sopenharmony_ci	return;
5118c2ecf20Sopenharmony_ci}
512