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