summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Eckelmann <sven@narfation.org>2026-06-26 18:09:33 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-04 13:38:38 +0200
commit4ffc51b88deb630dbaf3e3a87d9c123f1f3637d8 (patch)
tree3a4b04b621ffb6295d4d80caca58d2af439ff0f2
parent39c1037e2bc08ff58d7a4168a528584330b8dbb6 (diff)
downloadlinux-4ffc51b88deb630dbaf3e3a87d9c123f1f3637d8.tar.gz
linux-4ffc51b88deb630dbaf3e3a87d9c123f1f3637d8.zip
batman-adv: tp_meter: avoid window underflow
commit 765947b81fb54b6ebb0bc1cfe55c0fa399e002b8 upstream. In batadv_tp_avail(), win_left is calculated with 32-bit unsigned arithmetic: win_left = win_limit - tp_vars->last_sent; During Fast Recovery, cwnd is inflated and last_sent advances rapidly. When Fast Recovery ends, cwnd drops abruptly back to ss_threshold. If the newly shrunk win_limit is less than last_sent, the unsigned subtraction will underflow, wrapping to a massive positive value. Instead of returning that the window is full (unavailable), it returns that the sender can continue sending. To handle this situation, it must be checked whether the windows end sequence number (win_limit) has to be compared with the last sent sequence number. If it would be before the last sent sequence number, then more acks are needed before the transmission can be started again. Cc: stable@kernel.org Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation") Signed-off-by: Sven Eckelmann <sven@narfation.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--net/batman-adv/tp_meter.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index d8ad58ccef26..10953096996a 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -825,10 +825,15 @@ out:
static bool batadv_tp_avail(struct batadv_tp_vars *tp_vars,
size_t payload_len)
{
+ u32 last_sent = READ_ONCE(tp_vars->last_sent);
u32 win_left, win_limit;
win_limit = atomic_read(&tp_vars->last_acked) + tp_vars->cwnd;
- win_left = win_limit - tp_vars->last_sent;
+
+ if (batadv_seq_before(last_sent, win_limit))
+ win_left = win_limit - last_sent;
+ else
+ win_left = 0;
return win_left >= payload_len;
}