196b2d69bSDavid Howells // SPDX-License-Identifier: GPL-2.0-or-later 296b2d69bSDavid Howells /* RxRPC packet reception 396b2d69bSDavid Howells * 4a275da62SDavid Howells * Copyright (C) 2007, 2016, 2022 Red Hat, Inc. All Rights Reserved. 596b2d69bSDavid Howells * Written by David Howells (dhowells@redhat.com) 696b2d69bSDavid Howells */ 796b2d69bSDavid Howells 896b2d69bSDavid Howells #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 996b2d69bSDavid Howells 1096b2d69bSDavid Howells #include "ar-internal.h" 1196b2d69bSDavid Howells 125e6ef4f1SDavid Howells static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn, 135e6ef4f1SDavid Howells struct sockaddr_rxrpc *peer_srx, 145e6ef4f1SDavid Howells struct sk_buff *skb); 155e6ef4f1SDavid Howells 1696b2d69bSDavid Howells /* 17446b3e14SDavid Howells * handle data received on the local endpoint 18446b3e14SDavid Howells * - may be called in interrupt context 19446b3e14SDavid Howells * 20446b3e14SDavid Howells * [!] Note that as this is called from the encap_rcv hook, the socket is not 21446b3e14SDavid Howells * held locked by the caller and nothing prevents sk_user_data on the UDP from 22446b3e14SDavid Howells * being cleared in the middle of processing this function. 23446b3e14SDavid Howells * 24446b3e14SDavid Howells * Called with the RCU read lock held from the IP layer via UDP. 25446b3e14SDavid Howells */ 26446b3e14SDavid Howells int rxrpc_encap_rcv(struct sock *udp_sk, struct sk_buff *skb) 27446b3e14SDavid Howells { 28446b3e14SDavid Howells struct rxrpc_local *local = rcu_dereference_sk_user_data(udp_sk); 29446b3e14SDavid Howells 30446b3e14SDavid Howells if (unlikely(!local)) { 31446b3e14SDavid Howells kfree_skb(skb); 32446b3e14SDavid Howells return 0; 33446b3e14SDavid Howells } 34446b3e14SDavid Howells if (skb->tstamp == 0) 35446b3e14SDavid Howells skb->tstamp = ktime_get_real(); 36446b3e14SDavid Howells 37446b3e14SDavid Howells skb->mark = RXRPC_SKB_MARK_PACKET; 38446b3e14SDavid Howells rxrpc_new_skb(skb, rxrpc_skb_new_encap_rcv); 39446b3e14SDavid Howells skb_queue_tail(&local->rx_queue, skb); 40446b3e14SDavid Howells rxrpc_wake_up_io_thread(local); 41446b3e14SDavid Howells return 0; 42446b3e14SDavid Howells } 43446b3e14SDavid Howells 44446b3e14SDavid Howells /* 45ff734825SDavid Howells * Handle an error received on the local endpoint. 46ff734825SDavid Howells */ 47ff734825SDavid Howells void rxrpc_error_report(struct sock *sk) 48ff734825SDavid Howells { 49ff734825SDavid Howells struct rxrpc_local *local; 50ff734825SDavid Howells struct sk_buff *skb; 51ff734825SDavid Howells 52ff734825SDavid Howells rcu_read_lock(); 53ff734825SDavid Howells local = rcu_dereference_sk_user_data(sk); 54ff734825SDavid Howells if (unlikely(!local)) { 55ff734825SDavid Howells rcu_read_unlock(); 56ff734825SDavid Howells return; 57ff734825SDavid Howells } 58ff734825SDavid Howells 59ff734825SDavid Howells while ((skb = skb_dequeue(&sk->sk_error_queue))) { 60ff734825SDavid Howells skb->mark = RXRPC_SKB_MARK_ERROR; 61ff734825SDavid Howells rxrpc_new_skb(skb, rxrpc_skb_new_error_report); 62ff734825SDavid Howells skb_queue_tail(&local->rx_queue, skb); 63ff734825SDavid Howells } 64ff734825SDavid Howells 65ff734825SDavid Howells rxrpc_wake_up_io_thread(local); 66ff734825SDavid Howells rcu_read_unlock(); 67ff734825SDavid Howells } 68ff734825SDavid Howells 69ff734825SDavid Howells /* 705e6ef4f1SDavid Howells * Process event packets targeted at a local endpoint. 7196b2d69bSDavid Howells */ 725e6ef4f1SDavid Howells static void rxrpc_input_version(struct rxrpc_local *local, struct sk_buff *skb) 7396b2d69bSDavid Howells { 745e6ef4f1SDavid Howells struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 755e6ef4f1SDavid Howells char v; 7696b2d69bSDavid Howells 775e6ef4f1SDavid Howells _enter(""); 7896b2d69bSDavid Howells 795e6ef4f1SDavid Howells rxrpc_see_skb(skb, rxrpc_skb_see_version); 805e6ef4f1SDavid Howells if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), &v, 1) >= 0) { 815e6ef4f1SDavid Howells if (v == 0) 825e6ef4f1SDavid Howells rxrpc_send_version_request(local, &sp->hdr, skb); 8396b2d69bSDavid Howells } 8496b2d69bSDavid Howells } 8596b2d69bSDavid Howells 8696b2d69bSDavid Howells /* 8796b2d69bSDavid Howells * Extract the wire header from a packet and translate the byte order. 8896b2d69bSDavid Howells */ 8996b2d69bSDavid Howells static noinline 9096b2d69bSDavid Howells int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb) 9196b2d69bSDavid Howells { 9296b2d69bSDavid Howells struct rxrpc_wire_header whdr; 9396b2d69bSDavid Howells 9496b2d69bSDavid Howells /* dig out the RxRPC connection details */ 9596b2d69bSDavid Howells if (skb_copy_bits(skb, 0, &whdr, sizeof(whdr)) < 0) { 9696b2d69bSDavid Howells trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, 9796b2d69bSDavid Howells tracepoint_string("bad_hdr")); 9896b2d69bSDavid Howells return -EBADMSG; 9996b2d69bSDavid Howells } 10096b2d69bSDavid Howells 10196b2d69bSDavid Howells memset(sp, 0, sizeof(*sp)); 10296b2d69bSDavid Howells sp->hdr.epoch = ntohl(whdr.epoch); 10396b2d69bSDavid Howells sp->hdr.cid = ntohl(whdr.cid); 10496b2d69bSDavid Howells sp->hdr.callNumber = ntohl(whdr.callNumber); 10596b2d69bSDavid Howells sp->hdr.seq = ntohl(whdr.seq); 10696b2d69bSDavid Howells sp->hdr.serial = ntohl(whdr.serial); 10796b2d69bSDavid Howells sp->hdr.flags = whdr.flags; 10896b2d69bSDavid Howells sp->hdr.type = whdr.type; 10996b2d69bSDavid Howells sp->hdr.userStatus = whdr.userStatus; 11096b2d69bSDavid Howells sp->hdr.securityIndex = whdr.securityIndex; 11196b2d69bSDavid Howells sp->hdr._rsvd = ntohs(whdr._rsvd); 11296b2d69bSDavid Howells sp->hdr.serviceId = ntohs(whdr.serviceId); 11396b2d69bSDavid Howells return 0; 11496b2d69bSDavid Howells } 11596b2d69bSDavid Howells 11696b2d69bSDavid Howells /* 11796b2d69bSDavid Howells * Extract the abort code from an ABORT packet and stash it in skb->priority. 11896b2d69bSDavid Howells */ 11996b2d69bSDavid Howells static bool rxrpc_extract_abort(struct sk_buff *skb) 12096b2d69bSDavid Howells { 12196b2d69bSDavid Howells __be32 wtmp; 12296b2d69bSDavid Howells 12396b2d69bSDavid Howells if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), 12496b2d69bSDavid Howells &wtmp, sizeof(wtmp)) < 0) 12596b2d69bSDavid Howells return false; 12696b2d69bSDavid Howells skb->priority = ntohl(wtmp); 12796b2d69bSDavid Howells return true; 12896b2d69bSDavid Howells } 12996b2d69bSDavid Howells 13096b2d69bSDavid Howells /* 131446b3e14SDavid Howells * Process packets received on the local endpoint 13296b2d69bSDavid Howells */ 1332d1faf7aSDavid Howells static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) 13496b2d69bSDavid Howells { 13596b2d69bSDavid Howells struct rxrpc_connection *conn; 136393a2a20SDavid Howells struct sockaddr_rxrpc peer_srx; 13796b2d69bSDavid Howells struct rxrpc_skb_priv *sp; 13896b2d69bSDavid Howells struct rxrpc_peer *peer = NULL; 1392d1faf7aSDavid Howells struct sk_buff *skb = *_skb; 1405e6ef4f1SDavid Howells int ret = 0; 14196b2d69bSDavid Howells 14296b2d69bSDavid Howells skb_pull(skb, sizeof(struct udphdr)); 14396b2d69bSDavid Howells 14496b2d69bSDavid Howells sp = rxrpc_skb(skb); 14596b2d69bSDavid Howells 14696b2d69bSDavid Howells /* dig out the RxRPC connection details */ 14796b2d69bSDavid Howells if (rxrpc_extract_header(sp, skb) < 0) 14896b2d69bSDavid Howells goto bad_message; 14996b2d69bSDavid Howells 15096b2d69bSDavid Howells if (IS_ENABLED(CONFIG_AF_RXRPC_INJECT_LOSS)) { 15196b2d69bSDavid Howells static int lose; 15296b2d69bSDavid Howells if ((lose++ & 7) == 7) { 15396b2d69bSDavid Howells trace_rxrpc_rx_lose(sp); 15496b2d69bSDavid Howells return 0; 15596b2d69bSDavid Howells } 15696b2d69bSDavid Howells } 15796b2d69bSDavid Howells 15896b2d69bSDavid Howells trace_rxrpc_rx_packet(sp); 15996b2d69bSDavid Howells 16096b2d69bSDavid Howells switch (sp->hdr.type) { 16196b2d69bSDavid Howells case RXRPC_PACKET_TYPE_VERSION: 16296b2d69bSDavid Howells if (rxrpc_to_client(sp)) 1632d1faf7aSDavid Howells return 0; 1645e6ef4f1SDavid Howells rxrpc_input_version(local, skb); 1652d1faf7aSDavid Howells return 0; 16696b2d69bSDavid Howells 16796b2d69bSDavid Howells case RXRPC_PACKET_TYPE_BUSY: 16896b2d69bSDavid Howells if (rxrpc_to_server(sp)) 1692d1faf7aSDavid Howells return 0; 17096b2d69bSDavid Howells fallthrough; 17196b2d69bSDavid Howells case RXRPC_PACKET_TYPE_ACK: 17296b2d69bSDavid Howells case RXRPC_PACKET_TYPE_ACKALL: 17396b2d69bSDavid Howells if (sp->hdr.callNumber == 0) 17496b2d69bSDavid Howells goto bad_message; 17596b2d69bSDavid Howells break; 17696b2d69bSDavid Howells case RXRPC_PACKET_TYPE_ABORT: 17796b2d69bSDavid Howells if (!rxrpc_extract_abort(skb)) 1782d1faf7aSDavid Howells return 0; /* Just discard if malformed */ 17996b2d69bSDavid Howells break; 18096b2d69bSDavid Howells 18196b2d69bSDavid Howells case RXRPC_PACKET_TYPE_DATA: 18296b2d69bSDavid Howells if (sp->hdr.callNumber == 0 || 18396b2d69bSDavid Howells sp->hdr.seq == 0) 18496b2d69bSDavid Howells goto bad_message; 18596b2d69bSDavid Howells 18696b2d69bSDavid Howells /* Unshare the packet so that it can be modified for in-place 18796b2d69bSDavid Howells * decryption. 18896b2d69bSDavid Howells */ 18996b2d69bSDavid Howells if (sp->hdr.securityIndex != 0) { 1902d1faf7aSDavid Howells skb = skb_unshare(skb, GFP_ATOMIC); 1912d1faf7aSDavid Howells if (!skb) { 1922d1faf7aSDavid Howells rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem); 1932d1faf7aSDavid Howells *_skb = NULL; 1942d1faf7aSDavid Howells return 0; 19596b2d69bSDavid Howells } 19696b2d69bSDavid Howells 1972d1faf7aSDavid Howells if (skb != *_skb) { 1982d1faf7aSDavid Howells rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare); 1992d1faf7aSDavid Howells *_skb = skb; 20096b2d69bSDavid Howells rxrpc_new_skb(skb, rxrpc_skb_new_unshared); 20196b2d69bSDavid Howells sp = rxrpc_skb(skb); 20296b2d69bSDavid Howells } 20396b2d69bSDavid Howells } 20496b2d69bSDavid Howells break; 20596b2d69bSDavid Howells 20696b2d69bSDavid Howells case RXRPC_PACKET_TYPE_CHALLENGE: 20796b2d69bSDavid Howells if (rxrpc_to_server(sp)) 2082d1faf7aSDavid Howells return 0; 20996b2d69bSDavid Howells break; 21096b2d69bSDavid Howells case RXRPC_PACKET_TYPE_RESPONSE: 21196b2d69bSDavid Howells if (rxrpc_to_client(sp)) 2122d1faf7aSDavid Howells return 0; 21396b2d69bSDavid Howells break; 21496b2d69bSDavid Howells 21596b2d69bSDavid Howells /* Packet types 9-11 should just be ignored. */ 21696b2d69bSDavid Howells case RXRPC_PACKET_TYPE_PARAMS: 21796b2d69bSDavid Howells case RXRPC_PACKET_TYPE_10: 21896b2d69bSDavid Howells case RXRPC_PACKET_TYPE_11: 2192d1faf7aSDavid Howells return 0; 22096b2d69bSDavid Howells 22196b2d69bSDavid Howells default: 22296b2d69bSDavid Howells goto bad_message; 22396b2d69bSDavid Howells } 22496b2d69bSDavid Howells 22596b2d69bSDavid Howells if (sp->hdr.serviceId == 0) 22696b2d69bSDavid Howells goto bad_message; 22796b2d69bSDavid Howells 228393a2a20SDavid Howells if (WARN_ON_ONCE(rxrpc_extract_addr_from_skb(&peer_srx, skb) < 0)) 2295e6ef4f1SDavid Howells return true; /* Unsupported address type - discard. */ 230393a2a20SDavid Howells 231393a2a20SDavid Howells if (peer_srx.transport.family != local->srx.transport.family && 232393a2a20SDavid Howells (peer_srx.transport.family == AF_INET && 233393a2a20SDavid Howells local->srx.transport.family != AF_INET6)) { 234393a2a20SDavid Howells pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n", 235393a2a20SDavid Howells peer_srx.transport.family, 236393a2a20SDavid Howells local->srx.transport.family); 2375e6ef4f1SDavid Howells return true; /* Wrong address type - discard. */ 238393a2a20SDavid Howells } 239393a2a20SDavid Howells 2405e6ef4f1SDavid Howells if (rxrpc_to_client(sp)) { 2415e6ef4f1SDavid Howells rcu_read_lock(); 2425e6ef4f1SDavid Howells conn = rxrpc_find_client_connection_rcu(local, &peer_srx, skb); 2435e6ef4f1SDavid Howells conn = rxrpc_get_connection_maybe(conn, rxrpc_conn_get_call_input); 2445e6ef4f1SDavid Howells rcu_read_unlock(); 2455e6ef4f1SDavid Howells if (!conn) { 2465e6ef4f1SDavid Howells trace_rxrpc_abort(0, "NCC", sp->hdr.cid, 2475e6ef4f1SDavid Howells sp->hdr.callNumber, sp->hdr.seq, 2485e6ef4f1SDavid Howells RXKADINCONSISTENCY, EBADMSG); 2495e6ef4f1SDavid Howells goto protocol_error; 2505e6ef4f1SDavid Howells } 2515e6ef4f1SDavid Howells 2525e6ef4f1SDavid Howells ret = rxrpc_input_packet_on_conn(conn, &peer_srx, skb); 2535e6ef4f1SDavid Howells rxrpc_put_connection(conn, rxrpc_conn_put_call_input); 2545e6ef4f1SDavid Howells return ret; 2555e6ef4f1SDavid Howells } 2565e6ef4f1SDavid Howells 2575e6ef4f1SDavid Howells /* We need to look up service connections by the full protocol 2585e6ef4f1SDavid Howells * parameter set. We look up the peer first as an intermediate step 2595e6ef4f1SDavid Howells * and then the connection from the peer's tree. 2605e6ef4f1SDavid Howells */ 261cd21effbSDavid Howells rcu_read_lock(); 262cd21effbSDavid Howells 2635e6ef4f1SDavid Howells peer = rxrpc_lookup_peer_rcu(local, &peer_srx); 2645e6ef4f1SDavid Howells if (!peer) { 265cd21effbSDavid Howells rcu_read_unlock(); 2665e6ef4f1SDavid Howells return rxrpc_new_incoming_call(local, NULL, NULL, &peer_srx, skb); 26796b2d69bSDavid Howells } 26896b2d69bSDavid Howells 2695e6ef4f1SDavid Howells conn = rxrpc_find_service_conn_rcu(peer, skb); 2705e6ef4f1SDavid Howells conn = rxrpc_get_connection_maybe(conn, rxrpc_conn_get_call_input); 27196b2d69bSDavid Howells if (conn) { 2725e6ef4f1SDavid Howells rcu_read_unlock(); 2735e6ef4f1SDavid Howells ret = rxrpc_input_packet_on_conn(conn, &peer_srx, skb); 2745e6ef4f1SDavid Howells rxrpc_put_connection(conn, rxrpc_conn_put_call_input); 2755e6ef4f1SDavid Howells return ret; 2765e6ef4f1SDavid Howells } 2775e6ef4f1SDavid Howells 2785e6ef4f1SDavid Howells peer = rxrpc_get_peer_maybe(peer, rxrpc_peer_get_input); 2795e6ef4f1SDavid Howells rcu_read_unlock(); 2805e6ef4f1SDavid Howells 2815e6ef4f1SDavid Howells ret = rxrpc_new_incoming_call(local, peer, NULL, &peer_srx, skb); 2825e6ef4f1SDavid Howells rxrpc_put_peer(peer, rxrpc_peer_put_input); 2835e6ef4f1SDavid Howells if (ret < 0) 2845e6ef4f1SDavid Howells goto reject_packet; 2855e6ef4f1SDavid Howells return 0; 2865e6ef4f1SDavid Howells 2875e6ef4f1SDavid Howells bad_message: 2885e6ef4f1SDavid Howells trace_rxrpc_abort(0, "BAD", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, 2895e6ef4f1SDavid Howells RX_PROTOCOL_ERROR, EBADMSG); 2905e6ef4f1SDavid Howells protocol_error: 2915e6ef4f1SDavid Howells skb->priority = RX_PROTOCOL_ERROR; 2925e6ef4f1SDavid Howells skb->mark = RXRPC_SKB_MARK_REJECT_ABORT; 2935e6ef4f1SDavid Howells reject_packet: 2945e6ef4f1SDavid Howells rxrpc_reject_packet(local, skb); 2955e6ef4f1SDavid Howells return ret; 2965e6ef4f1SDavid Howells } 2975e6ef4f1SDavid Howells 2985e6ef4f1SDavid Howells /* 2995e6ef4f1SDavid Howells * Deal with a packet that's associated with an extant connection. 3005e6ef4f1SDavid Howells */ 3015e6ef4f1SDavid Howells static int rxrpc_input_packet_on_conn(struct rxrpc_connection *conn, 3025e6ef4f1SDavid Howells struct sockaddr_rxrpc *peer_srx, 3035e6ef4f1SDavid Howells struct sk_buff *skb) 3045e6ef4f1SDavid Howells { 3055e6ef4f1SDavid Howells struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 3065e6ef4f1SDavid Howells struct rxrpc_channel *chan; 3075e6ef4f1SDavid Howells struct rxrpc_call *call = NULL; 3085e6ef4f1SDavid Howells unsigned int channel; 3095e6ef4f1SDavid Howells 31096b2d69bSDavid Howells if (sp->hdr.securityIndex != conn->security_ix) 31196b2d69bSDavid Howells goto wrong_security; 31296b2d69bSDavid Howells 31396b2d69bSDavid Howells if (sp->hdr.serviceId != conn->service_id) { 31496b2d69bSDavid Howells int old_id; 31596b2d69bSDavid Howells 31696b2d69bSDavid Howells if (!test_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags)) 31796b2d69bSDavid Howells goto reupgrade; 31896b2d69bSDavid Howells old_id = cmpxchg(&conn->service_id, conn->orig_service_id, 31996b2d69bSDavid Howells sp->hdr.serviceId); 32096b2d69bSDavid Howells 32196b2d69bSDavid Howells if (old_id != conn->orig_service_id && 32296b2d69bSDavid Howells old_id != sp->hdr.serviceId) 32396b2d69bSDavid Howells goto reupgrade; 32496b2d69bSDavid Howells } 32596b2d69bSDavid Howells 3265e6ef4f1SDavid Howells if (after(sp->hdr.serial, conn->hi_serial)) 32796b2d69bSDavid Howells conn->hi_serial = sp->hdr.serial; 32896b2d69bSDavid Howells 3295e6ef4f1SDavid Howells /* It's a connection-level packet if the call number is 0. */ 3305e6ef4f1SDavid Howells if (sp->hdr.callNumber == 0) 3315e6ef4f1SDavid Howells return rxrpc_input_conn_packet(conn, skb); 3325e6ef4f1SDavid Howells 33396b2d69bSDavid Howells /* Call-bound packets are routed by connection channel. */ 33496b2d69bSDavid Howells channel = sp->hdr.cid & RXRPC_CHANNELMASK; 33596b2d69bSDavid Howells chan = &conn->channels[channel]; 33696b2d69bSDavid Howells 33796b2d69bSDavid Howells /* Ignore really old calls */ 3385e6ef4f1SDavid Howells if (sp->hdr.callNumber < chan->last_call) 3392d1faf7aSDavid Howells return 0; 34096b2d69bSDavid Howells 34196b2d69bSDavid Howells if (sp->hdr.callNumber == chan->last_call) { 34296b2d69bSDavid Howells if (chan->call || 3435e6ef4f1SDavid Howells sp->hdr.type == RXRPC_PACKET_TYPE_ABORT) 3442d1faf7aSDavid Howells return 0; 34596b2d69bSDavid Howells 3465e6ef4f1SDavid Howells /* For the previous service call, if completed successfully, we 3475e6ef4f1SDavid Howells * discard all further packets. 34896b2d69bSDavid Howells */ 34996b2d69bSDavid Howells if (rxrpc_conn_is_service(conn) && 3505e6ef4f1SDavid Howells chan->last_type == RXRPC_PACKET_TYPE_ACK) 3512d1faf7aSDavid Howells return 0; 35296b2d69bSDavid Howells 3535e6ef4f1SDavid Howells /* But otherwise we need to retransmit the final packet from 3545e6ef4f1SDavid Howells * data cached in the connection record. 35596b2d69bSDavid Howells */ 35696b2d69bSDavid Howells if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA) 35796b2d69bSDavid Howells trace_rxrpc_rx_data(chan->call_debug_id, 35896b2d69bSDavid Howells sp->hdr.seq, 35996b2d69bSDavid Howells sp->hdr.serial, 36096b2d69bSDavid Howells sp->hdr.flags); 3615e6ef4f1SDavid Howells rxrpc_input_conn_packet(conn, skb); 3622d1faf7aSDavid Howells return 0; 36396b2d69bSDavid Howells } 36496b2d69bSDavid Howells 3655e6ef4f1SDavid Howells rcu_read_lock(); 3665e6ef4f1SDavid Howells call = rxrpc_try_get_call(rcu_dereference(chan->call), 3675e6ef4f1SDavid Howells rxrpc_call_get_input); 3685e6ef4f1SDavid Howells rcu_read_unlock(); 36996b2d69bSDavid Howells 37096b2d69bSDavid Howells if (sp->hdr.callNumber > chan->call_id) { 371cd21effbSDavid Howells if (rxrpc_to_client(sp)) { 3725e6ef4f1SDavid Howells rxrpc_put_call(call, rxrpc_call_put_input); 37396b2d69bSDavid Howells goto reject_packet; 374cd21effbSDavid Howells } 37596b2d69bSDavid Howells 37696b2d69bSDavid Howells if (call) { 3775e6ef4f1SDavid Howells rxrpc_implicit_end_call(call, skb); 3785e6ef4f1SDavid Howells rxrpc_put_call(call, rxrpc_call_put_input); 3795e6ef4f1SDavid Howells call = NULL; 38096b2d69bSDavid Howells } 38196b2d69bSDavid Howells } 38296b2d69bSDavid Howells 383cd21effbSDavid Howells if (!call) { 3845e6ef4f1SDavid Howells if (rxrpc_to_client(sp)) 38596b2d69bSDavid Howells goto bad_message; 3865e6ef4f1SDavid Howells if (rxrpc_new_incoming_call(conn->local, conn->peer, conn, 3875e6ef4f1SDavid Howells peer_srx, skb)) 3882d1faf7aSDavid Howells return 0; 38996b2d69bSDavid Howells goto reject_packet; 39096b2d69bSDavid Howells } 391cd21effbSDavid Howells 39215f661dcSDavid Howells rxrpc_input_call_event(call, skb); 393cd21effbSDavid Howells rxrpc_put_call(call, rxrpc_call_put_input); 39496b2d69bSDavid Howells return 0; 39596b2d69bSDavid Howells 39696b2d69bSDavid Howells wrong_security: 39796b2d69bSDavid Howells trace_rxrpc_abort(0, "SEC", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, 39896b2d69bSDavid Howells RXKADINCONSISTENCY, EBADMSG); 39996b2d69bSDavid Howells skb->priority = RXKADINCONSISTENCY; 40096b2d69bSDavid Howells goto post_abort; 40196b2d69bSDavid Howells 40296b2d69bSDavid Howells reupgrade: 40396b2d69bSDavid Howells trace_rxrpc_abort(0, "UPG", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, 40496b2d69bSDavid Howells RX_PROTOCOL_ERROR, EBADMSG); 40596b2d69bSDavid Howells goto protocol_error; 40696b2d69bSDavid Howells 40796b2d69bSDavid Howells bad_message: 40896b2d69bSDavid Howells trace_rxrpc_abort(0, "BAD", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, 40996b2d69bSDavid Howells RX_PROTOCOL_ERROR, EBADMSG); 41096b2d69bSDavid Howells protocol_error: 41196b2d69bSDavid Howells skb->priority = RX_PROTOCOL_ERROR; 41296b2d69bSDavid Howells post_abort: 41396b2d69bSDavid Howells skb->mark = RXRPC_SKB_MARK_REJECT_ABORT; 41496b2d69bSDavid Howells reject_packet: 4155e6ef4f1SDavid Howells rxrpc_reject_packet(conn->local, skb); 41696b2d69bSDavid Howells return 0; 41796b2d69bSDavid Howells } 418a275da62SDavid Howells 419a275da62SDavid Howells /* 420a275da62SDavid Howells * I/O and event handling thread. 421a275da62SDavid Howells */ 422a275da62SDavid Howells int rxrpc_io_thread(void *data) 423a275da62SDavid Howells { 424a275da62SDavid Howells struct sk_buff_head rx_queue; 425a275da62SDavid Howells struct rxrpc_local *local = data; 42615f661dcSDavid Howells struct rxrpc_call *call; 427a275da62SDavid Howells struct sk_buff *skb; 428*743d1768SDavid Howells bool should_stop; 429a275da62SDavid Howells 4308fbcc833SDavid Howells complete(&local->io_thread_ready); 4318fbcc833SDavid Howells 432a275da62SDavid Howells skb_queue_head_init(&rx_queue); 433a275da62SDavid Howells 434a275da62SDavid Howells set_user_nice(current, MIN_NICE); 435a275da62SDavid Howells 436a275da62SDavid Howells for (;;) { 437a275da62SDavid Howells rxrpc_inc_stat(local->rxnet, stat_io_loop); 438a275da62SDavid Howells 43915f661dcSDavid Howells /* Deal with calls that want immediate attention. */ 44015f661dcSDavid Howells if ((call = list_first_entry_or_null(&local->call_attend_q, 44115f661dcSDavid Howells struct rxrpc_call, 44215f661dcSDavid Howells attend_link))) { 44315f661dcSDavid Howells spin_lock_bh(&local->lock); 44415f661dcSDavid Howells list_del_init(&call->attend_link); 44515f661dcSDavid Howells spin_unlock_bh(&local->lock); 44615f661dcSDavid Howells 44715f661dcSDavid Howells trace_rxrpc_call_poked(call); 44815f661dcSDavid Howells rxrpc_input_call_event(call, NULL); 44915f661dcSDavid Howells rxrpc_put_call(call, rxrpc_call_put_poke); 45015f661dcSDavid Howells continue; 45115f661dcSDavid Howells } 45215f661dcSDavid Howells 453a275da62SDavid Howells /* Process received packets and errors. */ 454a275da62SDavid Howells if ((skb = __skb_dequeue(&rx_queue))) { 455446b3e14SDavid Howells switch (skb->mark) { 456446b3e14SDavid Howells case RXRPC_SKB_MARK_PACKET: 4572d1faf7aSDavid Howells skb->priority = 0; 4582d1faf7aSDavid Howells rxrpc_input_packet(local, &skb); 4592d1faf7aSDavid Howells trace_rxrpc_rx_done(skb->mark, skb->priority); 4602d1faf7aSDavid Howells rxrpc_free_skb(skb, rxrpc_skb_put_input); 461446b3e14SDavid Howells break; 462ff734825SDavid Howells case RXRPC_SKB_MARK_ERROR: 463ff734825SDavid Howells rxrpc_input_error(local, skb); 464ff734825SDavid Howells rxrpc_free_skb(skb, rxrpc_skb_put_error_report); 465ff734825SDavid Howells break; 466446b3e14SDavid Howells default: 467446b3e14SDavid Howells WARN_ON_ONCE(1); 468446b3e14SDavid Howells rxrpc_free_skb(skb, rxrpc_skb_put_unknown); 469446b3e14SDavid Howells break; 470446b3e14SDavid Howells } 471a275da62SDavid Howells continue; 472a275da62SDavid Howells } 473a275da62SDavid Howells 474a275da62SDavid Howells if (!skb_queue_empty(&local->rx_queue)) { 475a275da62SDavid Howells spin_lock_irq(&local->rx_queue.lock); 476a275da62SDavid Howells skb_queue_splice_tail_init(&local->rx_queue, &rx_queue); 477a275da62SDavid Howells spin_unlock_irq(&local->rx_queue.lock); 478a275da62SDavid Howells continue; 479a275da62SDavid Howells } 480a275da62SDavid Howells 481a275da62SDavid Howells set_current_state(TASK_INTERRUPTIBLE); 482*743d1768SDavid Howells should_stop = kthread_should_stop(); 48315f661dcSDavid Howells if (!skb_queue_empty(&local->rx_queue) || 48415f661dcSDavid Howells !list_empty(&local->call_attend_q)) { 485a275da62SDavid Howells __set_current_state(TASK_RUNNING); 486a275da62SDavid Howells continue; 487a275da62SDavid Howells } 488a275da62SDavid Howells 489*743d1768SDavid Howells if (should_stop) 490a275da62SDavid Howells break; 491a275da62SDavid Howells schedule(); 492a275da62SDavid Howells } 493a275da62SDavid Howells 494a275da62SDavid Howells __set_current_state(TASK_RUNNING); 495a275da62SDavid Howells rxrpc_see_local(local, rxrpc_local_stop); 496a275da62SDavid Howells rxrpc_destroy_local(local); 497a275da62SDavid Howells local->io_thread = NULL; 498a275da62SDavid Howells rxrpc_see_local(local, rxrpc_local_stopped); 499a275da62SDavid Howells return 0; 500a275da62SDavid Howells } 501