// SPDX-License-Identifier: GPL-2.0-or-later
/* Processing of received RxRPC packets
*
* Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "ar-internal.h"
/* Override priority when generating ACKs for received DATA */
static const u8 rxrpc_ack_priority[RXRPC_ACK__INVALID] = {
[RXRPC_ACK_IDLE] = 1,
[RXRPC_ACK_DELAY] = 2,
[RXRPC_ACK_REQUESTED] = 3,
[RXRPC_ACK_DUPLICATE] = 4,
[RXRPC_ACK_EXCEEDS_WINDOW] = 5,
[RXRPC_ACK_NOSPACE] = 6,
[RXRPC_ACK_OUT_OF_SEQUENCE] = 7,
};
static void rxrpc_proto_abort(struct rxrpc_call *call, rxrpc_seq_t seq,
enum rxrpc_abort_reason why)
{
rxrpc_abort_call(call, seq, RX_PROTOCOL_ERROR, -EBADMSG, why);
}
/*
* Do TCP-style congestion management [RFC5681].
*/
static void rxrpc_congestion_management(struct rxrpc_call *call,
struct rxrpc_ack_summary *summary)
{
summary->change = rxrpc_cong_no_change;
summary->in_flight = rxrpc_tx_in_flight(call);
if (test_and_clear_bit(RXRPC_CALL_RETRANS_TIMEOUT, &call->flags)) {
summary->retrans_timeo = true;
call->cong_ssthresh = umax(summary->in_flight / 2, 2);
call->cong_cwnd = 1;
if (call->cong_cwnd >= call->cong_ssthresh &&
call->cong_ca_state == RXRPC_CA_SLOW_START) {
call->cong_ca_state = RXRPC_CA_CONGEST_AVOIDANCE;
call->cong_tstamp = call->acks_latest_ts;
call->cong_cumul_acks = 0;
}
}
call->cong_cumul_acks += summary->nr_new_sacks;
call->cong_cumul_acks += summary->nr_new_hacks;
if (call->cong_cumul_acks > 255)
call->cong_cumul_acks = 255;
switch (call->cong_ca_state) {
case RXRPC_CA_SLOW_START:
if (call->acks_nr_snacks > 0)
goto packet_loss_detected;
if (call->cong_cumul_acks > 0)
call->cong_cwnd += 1;
if (call->cong_cwnd >= call->cong_ssthresh) {
call->cong_ca_state = RXRPC_CA_CONGEST_AVOIDANCE;
call->cong_tstamp = call->acks_latest_ts;
}
goto out;
case RXRPC_CA_CONGEST_AVOIDANCE:
if (call->acks_nr_snacks > 0)
goto packet_loss_detected;
/* We analyse the number of packets that get ACK'd per RTT
* period and increase the window if we managed to fill it.
*/
if (call->rtt_count == 0)
goto out;
if (ktime_before(call->acks_latest_ts,
ktime_add_us(call->cong_tstamp,
call->srtt_us >> 3)))
goto out_no_clear_ca;
summary->change = rxrpc_cong_rtt_window_end;
call->cong_tstamp = call->acks_latest_ts;
if (call->cong_cumul_acks >= call->cong_cwnd)
call->cong_cwnd++;
goto out;
case RXRPC_CA_PACKET_LOSS:
if (call->acks_nr_snacks == 0)
goto resume_normality;
if (summary->new_low_snac