ath12k_htt_pull_ppdu_stats() rejects a PPDU stats message when the common TLV reports num_users >= HTT_PPDU_STATS_MAX_USERS. The check guards a loop that iterates i < num_users over user_stats[], which has HTT_PPDU_STATS_MAX_USERS entries, so num_users equal to HTT_PPDU_STATS_MAX_USERS stays in bounds. Commit 1bc44a505a22 ("wifi: ath12k: fix possible out-of-bound read in ath12k_htt_pull_ppdu_stats()") rejects that value, which is off by one. QCN9274 firmware WLAN.WBE.1.6-01243 sends num_users 8 in messages that otherwise parse cleanly. One AP with two Wi-Fi 7 clients logged the resulting warning 468 times between 2026-08-17 and 2026-11-01, always with the value 8, and never logged "Failed to parse tlv": HTT PPDU STATS event has unexpected num_users 8, should be smaller than 8 A diagnostic build that logs the TLVs of these messages shows that all of them are BE MU BSRP trigger PPDUs (frame type 25) carrying user TLVs for the two clients, up to four records per client, and that num_users matches the number of user records in the message. The same firmware reports max_user_per_ppdu_ofdma of 8 in WMI_SERVICE_READY_EXT2, so 8 is the largest value it produces. Accept num_users == HTT_PPDU_STATS_MAX_USERS. Keep the warning for larger values, which indicate a firmware that supports more users than the driver stores, and adjust its text accordingly. Fixes: 1bc44a505a22 ("wifi: ath12k: fix possible out-of-bound read in ath12k_htt_pull_ppdu_stats()") Signed-off-by: Goran Sustek --- drivers/net/wireless/ath/ath12k/dp_htt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.c b/drivers/net/wireless/ath/ath12k/dp_htt.c index 72069640bd38..f5c526bf82d8 100644 --- a/drivers/net/wireless/ath/ath12k/dp_htt.c +++ b/drivers/net/wireless/ath/ath12k/dp_htt.c @@ -487,10 +487,10 @@ static int ath12k_htt_pull_ppdu_stats(struct ath12k_base *ab, goto exit; } - if (ppdu_info->ppdu_stats.common.num_users >= HTT_PPDU_STATS_MAX_USERS) { + if (ppdu_info->ppdu_stats.common.num_users > HTT_PPDU_STATS_MAX_USERS) { spin_unlock_bh(&dp_pdev->ppdu_list_lock); ath12k_warn(ab, - "HTT PPDU STATS event has unexpected num_users %u, should be smaller than %u\n", + "HTT PPDU STATS event has unexpected num_users %u, should not exceed %u\n", ppdu_info->ppdu_stats.common.num_users, HTT_PPDU_STATS_MAX_USERS); ret = -EINVAL; -- 2.56.0 user_stats[] in struct htt_ppdu_stats has HTT_PPDU_STATS_MAX_USERS entries, but ath12k_get_ppdu_user_index() searches only the first HTT_PPDU_STATS_MAX_USERS - 1 of them for a peer's slot, and ath12k_htt_update_ppdu_stats() applies only the first HTT_PPDU_STATS_MAX_USERS - 1 slots to the per-peer TX statistics. The last slot is never used: a message with HTT_PPDU_STATS_MAX_USERS distinct peers has the statistics of one of them dropped, and the remaining slot is dead memory. Both loops have had the "- 1" since the initial driver. Iterate over all HTT_PPDU_STATS_MAX_USERS slots in both functions. The messages with num_users 8 seen on a QCN9274 AP carry user TLVs for two peers, so this case has not been observed in the field; the fix follows from the array size. Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Signed-off-by: Goran Sustek --- drivers/net/wireless/ath/ath12k/dp_htt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_htt.c b/drivers/net/wireless/ath/ath12k/dp_htt.c index f5c526bf82d8..a0f98259ee64 100644 --- a/drivers/net/wireless/ath/ath12k/dp_htt.c +++ b/drivers/net/wireless/ath/ath12k/dp_htt.c @@ -46,7 +46,7 @@ static int ath12k_get_ppdu_user_index(struct htt_ppdu_stats *ppdu_stats, { int i; - for (i = 0; i < HTT_PPDU_STATS_MAX_USERS - 1; i++) { + for (i = 0; i < HTT_PPDU_STATS_MAX_USERS; i++) { if (ppdu_stats->user_stats[i].is_valid_peer_id) { if (peer_id == ppdu_stats->user_stats[i].peer_id) return i; @@ -362,7 +362,7 @@ static void ath12k_htt_update_ppdu_stats(struct ath12k_pdev_dp *dp_pdev, { u8 user; - for (user = 0; user < HTT_PPDU_STATS_MAX_USERS - 1; user++) + for (user = 0; user < HTT_PPDU_STATS_MAX_USERS; user++) ath12k_update_per_peer_tx_stats(dp_pdev, ppdu_stats, user); } -- 2.56.0