ath11k_peer_delete() only decrements ar->num_peers when __ath11k_peer_delete() returns 0. On a peer-delete-confirmation timeout __ath11k_peer_delete() returns -ETIMEDOUT, so the decrement is skipped and one ar->num_peers slot is leaked. Once enough slots have leaked the ar->num_peers > (ar->max_num_peers - 1) gate in ath11k_peer_create() rejects every new station with "insufficient peer entry resource in firmware", and the AP stops accepting associations until the radio is restarted with a wifi down/up. This was observed in the field on an AP after hours of uptime with frequent roaming and reconnects: clients could no longer associate even though the firmware peer table was not actually exhausted, only the host-side ar->num_peers accounting had leaked. The delete-confirmation timeout itself is otherwise harmless. The host first waits for the peer unmap event in ath11k_wait_for_peer_deleted(), so by the time the delete-response completion times out the peer has already been removed from ab->peers and freed by ath11k_peer_unmap_event(). Only the ar->num_peers counter is left inconsistent. The timeout is reached when the peer unmap event arrives but the peer delete response is missed, e.g. because the response event is dropped in ath11k_peer_delete_resp_event() on an unresolved vdev id (logged as "invalid vdev id in peer delete resp ev"). Do not treat the delete confirmation timeout as fatal so that ath11k_peer_delete() releases the ar->num_peers slot instead of leaking it. Fixes: 690ace20ff79 ("ath11k: peer delete synchronization with firmware") Cc: stable@vger.kernel.org Signed-off-by: Michael Pfeifroth --- v3: - Drop the defensive peer list_del()/kfree() branch; it is dead code since the peer is already freed via the unmap event or on recovery (Baochen Qiang), leaving a minimal fix that just ignores the delete timeout. - Reframe the commit message around the field-observed num_peers leak and the resulting station association failures. v2: - Correct the root-cause description and switch to netdev comment style. drivers/net/wireless/ath/ath11k/peer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index b30a906..f573a2c 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c @@ -340,9 +340,10 @@ static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr) return ret; } - ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr); - if (ret) - return ret; + /* Ignore the return value: the peer is already freed, only its + * ar->num_peers slot would otherwise leak on a delete timeout. + */ + ath11k_wait_for_peer_delete_done(ar, vdev_id, addr); return 0; } -- 2.34.1