/* Management of Tx window, Tx resend, ACKs and out-of-sequence reception
*
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/circ_buf.h>
#include <linux/net.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/udp.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include "ar-internal.h"
/*
* propose an ACK be sent
*/
void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
u32 serial, bool immediate)
{
unsigned long expiry;
s8 prior = rxrpc_ack_priority[ack_reason];
ASSERTCMP(prior, >, 0);
_enter("{%d},%s,%%%x,%u",
call->debug_id, rxrpc_acks(ack_reason), serial, immediate);
if (prior < rxrpc_ack_priority[call->ackr_reason]) {
if (immediate)
goto cancel_timer;
return;
}
/* update DELAY, IDLE, REQUESTED and PING_RESPONSE ACK serial
* numbers */
if (prior == rxrpc_ack_priority[call->ackr_reason]) {
if (prior <= 4)
call->ackr_serial = serial;
if (immediate)
goto cancel_timer;
return;
}
call->ackr_reason = ack_reason;
call->ackr_serial = serial;
switch (ack_reason) {
case RXRPC_ACK_DELAY:
_debug("run delay timer");
expiry = rxrpc_soft_ack_delay;
goto run_timer;
case RXRPC_ACK_IDLE:
if (!immediate) {
_debug("run defer timer");
expiry = rxrpc_idle_ack_delay;
goto run_timer;
}
goto cancel_timer;
case RXRPC_ACK_REQUESTED:
expiry = rxrpc_requested_ack_delay;
if (!expiry)
goto cancel_timer;
if (!immediate || serial == 1) {
_debug("run defer timer");
goto run_timer;
}
default:
_debug("immediate ACK");
goto cancel_timer;
}
run_timer:
expiry += jiffies;
if (!timer_pending(&call->ack_timer) ||
time_after(call->ack_timer.expires, expiry))
mod_timer(&call->ack_timer, expiry);
return;
cancel_timer:
_debug("cancel timer %%%u", serial);
try_to_del_timer_sync(&call