mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-28 02:34:57 +00:00
Compare commits
9 Commits
v4.2.0
...
staging-WI
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
233cc97b99 | ||
|
|
98c177928e | ||
|
|
c4bdc763d1 | ||
|
|
fc5f00817d | ||
|
|
a3ac7deced | ||
|
|
50eee0ef3c | ||
|
|
d359213bf0 | ||
|
|
c026b2d448 | ||
|
|
531a0c0b97 |
@@ -0,0 +1,22 @@
|
||||
Index: backports-20210222_001-5.4.164-b157d2276/drivers/net/wireless/ath/ath11k/dp_rx.c
|
||||
===================================================================
|
||||
--- backports-20210222_001-5.4.164-b157d2276.orig/drivers/net/wireless/ath/ath11k/dp_rx.c
|
||||
+++ backports-20210222_001-5.4.164-b157d2276/drivers/net/wireless/ath/ath11k/dp_rx.c
|
||||
@@ -2847,8 +2847,6 @@ static void ath11k_dp_rx_h_mpdu(struct a
|
||||
}
|
||||
}
|
||||
|
||||
- *fast_rx = false;
|
||||
-
|
||||
if (rxcb->is_mcbc)
|
||||
enctype = peer->sec_type_grp;
|
||||
else
|
||||
@@ -2858,6 +2856,8 @@ static void ath11k_dp_rx_h_mpdu(struct a
|
||||
}
|
||||
spin_unlock_bh(&ar->ab->base_lock);
|
||||
|
||||
+ *fast_rx = false;
|
||||
+
|
||||
rx_attention = ath11k_dp_rx_get_attention(ar->ab, rx_desc);
|
||||
err_bitmap = ath11k_dp_rx_h_attn_mpdu_err(rx_attention);
|
||||
if (enctype != HAL_ENCRYPT_TYPE_OPEN && !err_bitmap)
|
||||
@@ -0,0 +1,53 @@
|
||||
From 375d0d25e6c02991392e44956c81cbac84909f49 Mon Sep 17 00:00:00 2001
|
||||
From: Venkat Chimata <venkat@nearhop.com>
|
||||
Date: Thu, 4 Sep 2025 00:09:17 +0530
|
||||
Subject: [PATCH] wifi: ap: mitigate peer-delete WMI timeout to reduce blind
|
||||
period & prevent peer leaks
|
||||
|
||||
1. When a connected client roams to another AP, the AP is trying to delete the peer
|
||||
but for some reason the WMI command times out and while driver is waiting for
|
||||
the response, we observed that the AP doesn't respond to any frames from STA
|
||||
(probe requests, authentication etc) and once the response times out (3seconds default)
|
||||
then AP starts responding to the older requets but client has already connected to
|
||||
another AP. As the root cause for the response timing out is in the FW, we added
|
||||
a WAR to reduce the timeout to minimize this blind period, with this AP responds
|
||||
after 100ms and client connects successfully. And 100ms timeout is also reasonable
|
||||
for this internal operation.
|
||||
2. In case of peer deletion timeout, the driver peer database is not cleared, so,
|
||||
if this happens often (which it is) then eventually we hit the max peers in the
|
||||
driver and all subsequent operations fail, so, in case of timeout ignore the failure
|
||||
and proceed with driver peer database cleanup.
|
||||
|
||||
Signed-off-by: Venkat Chimata <venkat@nearhop.com>
|
||||
---
|
||||
drivers/net/wireless/ath/ath11k/peer.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c
|
||||
index 1907067..aefc6ba 100644
|
||||
--- a/drivers/net/wireless/ath/ath11k/peer.c
|
||||
+++ b/drivers/net/wireless/ath/ath11k/peer.c
|
||||
@@ -771,7 +771,7 @@ int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id,
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&ar->peer_delete_done,
|
||||
- 3 * HZ);
|
||||
+ 100 * HZ / 1000);
|
||||
if (time_left == 0) {
|
||||
ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n");
|
||||
return -ETIMEDOUT;
|
||||
@@ -857,7 +857,10 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
|
||||
}
|
||||
|
||||
ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr);
|
||||
- if (ret)
|
||||
+ /* WAR: For the timeout case, proceed to delete the peer anyway, as FW is
|
||||
+ * still functional, without this, driver ends up hitting max peers
|
||||
+ */
|
||||
+ if (ret && ret != -ETIMEDOUT)
|
||||
return ret;
|
||||
|
||||
ATH11K_MEMORY_STATS_DEC(ar->ab, per_peer_object,
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Date: Thu, 2 Oct 2025 09:00:00 +0000
|
||||
Subject: [PATCH] ath11k: fix num_peers counter corruption and add debug
|
||||
logging
|
||||
|
||||
The num_peers counter becomes corrupted during peer deletion due to race
|
||||
conditions between ath11k_peer_delete() and ath11k_peer_unmap_event().
|
||||
The firmware may or may not send unmap events, and the timing varies,
|
||||
causing the counter to either leak (increment without decrement) or
|
||||
underflow (double decrement).
|
||||
|
||||
Root causes:
|
||||
1. ath11k_peer_delete() doesn't decrement num_peers, relying on
|
||||
ath11k_peer_unmap_event() to do it
|
||||
2. Firmware sometimes doesn't send unmap events, leaving num_peers
|
||||
inflated
|
||||
3. When unmap events do arrive, timing races with ath11k_peer_delete()
|
||||
can cause missed decrements
|
||||
4. Cleanup paths may double-decrement if delete_in_progress not checked
|
||||
5. num_peers modified outside proper locking in some paths
|
||||
|
||||
This fix:
|
||||
- Moves num_peers decrement into ath11k_peer_delete() after successful
|
||||
peer deletion wait, ensuring exactly one decrement per deletion
|
||||
- Handles both cases: peer removed by unmap event, or peer still in list
|
||||
- Removes num_peers decrement from ath11k_peer_unmap_event() to prevent
|
||||
double-decrement when unmap event arrives
|
||||
- Adds ath11k_dp_peer_cleanup() call before ath11k_peer_delete() in
|
||||
roaming path to ensure datapath structures properly cleaned up
|
||||
- Adds delete_in_progress checks in cleanup paths to prevent
|
||||
double-delete
|
||||
- Ensures all num_peers modifications happen under base_lock
|
||||
- Adds comprehensive debug logging to track num_peers throughout peer
|
||||
lifecycle
|
||||
|
||||
Signed-off-by: Arif Alam <arif.alam@netexperience.com>
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||
@@ -5742,14 +5742,22 @@ static int ath11k_mac_op_sta_state(struc
|
||||
mutex_lock(&ar->ab->tbl_mtx_lock);
|
||||
spin_lock_bh(&ar->ab->base_lock);
|
||||
peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
|
||||
- if (peer && peer->sta == sta) {
|
||||
+ /* Skip if peer deletion already in progress to prevent
|
||||
+ * double-delete and num_peers underflow
|
||||
+ */
|
||||
+ if (peer && peer->sta == sta && !peer->delete_in_progress) {
|
||||
ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n",
|
||||
vif->addr, arvif->vdev_id);
|
||||
ath11k_peer_rhash_delete(ar->ab, peer);
|
||||
peer->sta = NULL;
|
||||
+ /* num_peers decrement now happens under base_lock when
|
||||
+ * peer is actually removed from list
|
||||
+ */
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
ar->num_peers--;
|
||||
+ ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "%s peer deleted %pM vdev_id: %d num_peers: %d\n",
|
||||
+ __func__, sta->addr, arvif->vdev_id, ar->num_peers);
|
||||
}
|
||||
spin_unlock_bh(&ar->ab->base_lock);
|
||||
mutex_unlock(&ar->ab->tbl_mtx_lock);
|
||||
@@ -7847,6 +7855,8 @@ err_peer_del:
|
||||
goto err_keyid;
|
||||
|
||||
ar->num_peers--;
|
||||
+ ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "%s vif peer deleted %pM vdev_id: %d num_peers: %d\n",
|
||||
+ __func__, vif->addr, arvif->vdev_id, ar->num_peers);
|
||||
}
|
||||
|
||||
err_vdev_del:
|
||||
--- a/drivers/net/wireless/ath/ath11k/peer.c
|
||||
+++ b/drivers/net/wireless/ath/ath11k/peer.c
|
||||
@@ -461,6 +461,9 @@ void ath11k_peer_unmap_event(struct ath1
|
||||
ath11k_dbg(ab, ATH11K_DBG_PEER, "peer unmap vdev %d peer %pM id %d\n",
|
||||
peer->vdev_id, peer->addr, peer_id);
|
||||
|
||||
+ /* Don't decrement num_peers here - it's already decremented in
|
||||
+ * ath11k_peer_delete() after successful wait. Just clean up the peer.
|
||||
+ */
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
wake_up(&ab->peer_mapping_wq);
|
||||
@@ -726,6 +729,10 @@ void ath11k_peer_cleanup(struct ath11k *
|
||||
if (peer->vdev_id != vdev_id)
|
||||
continue;
|
||||
|
||||
+ /* Skip peers that are being deleted to prevent double-free */
|
||||
+ if (peer->delete_in_progress)
|
||||
+ continue;
|
||||
+
|
||||
ath11k_warn(ab, "removing stale peer %pM from vdev_id %d\n",
|
||||
peer->addr, vdev_id);
|
||||
|
||||
@@ -743,7 +750,10 @@ void ath11k_peer_cleanup(struct ath11k *
|
||||
ath11k_peer_rhash_delete(ab, peer);
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
+ /* num_peers decrement happens here under base_lock */
|
||||
ar->num_peers--;
|
||||
+ ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "%s peer cleanup %pM vdev_id: %d num_peers: %d\n",
|
||||
+ __func__, peer->addr, vdev_id, ar->num_peers);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
@@ -824,6 +834,12 @@ int ath11k_peer_delete(struct ath11k *ar
|
||||
|
||||
#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
||||
peer->delete_in_progress = true;
|
||||
+#else
|
||||
+ if (peer)
|
||||
+ peer->delete_in_progress = true;
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CPTCFG_ATH11K_NSS_SUPPORT
|
||||
if (peer->self_ast_entry) {
|
||||
ath11k_peer_del_ast(ar, peer->self_ast_entry);
|
||||
peer->self_ast_entry = NULL;
|
||||
@@ -863,10 +879,51 @@ int ath11k_peer_delete(struct ath11k *ar
|
||||
if (ret && ret != -ETIMEDOUT)
|
||||
return ret;
|
||||
|
||||
- ATH11K_MEMORY_STATS_DEC(ar->ab, per_peer_object,
|
||||
- sizeof(struct ath11k_peer));
|
||||
+ /* If timeout occurred, manually remove peer from list since firmware
|
||||
+ * won't send unmap event. This prevents peer leaks and num_peers corruption.
|
||||
+ */
|
||||
+ if (ret == -ETIMEDOUT) {
|
||||
+ ath11k_warn(ar->ab, "peer delete timeout %pM vdev %d, manually cleaning up\n",
|
||||
+ addr, vdev_id);
|
||||
|
||||
- ar->num_peers--;
|
||||
+ mutex_lock(&ar->ab->tbl_mtx_lock);
|
||||
+ spin_lock_bh(&ar->ab->base_lock);
|
||||
+ peer = ath11k_peer_find(ar->ab, vdev_id, addr);
|
||||
+ if (peer) {
|
||||
+ list_del(&peer->list);
|
||||
+ kfree(peer);
|
||||
+ ar->num_peers--;
|
||||
+ ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
|
||||
+ "%s peer deleted (timeout) %pM vdev_id: %d num_peers: %d\n",
|
||||
+ __func__, addr, vdev_id, ar->num_peers);
|
||||
+ }
|
||||
+ spin_unlock_bh(&ar->ab->base_lock);
|
||||
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
|
||||
+ } else {
|
||||
+ /* Normal path - but firmware may not send unmap event, so decrement here
|
||||
+ * after successful peer deletion wait
|
||||
+ */
|
||||
+ mutex_lock(&ar->ab->tbl_mtx_lock);
|
||||
+ spin_lock_bh(&ar->ab->base_lock);
|
||||
+ peer = ath11k_peer_find(ar->ab, vdev_id, addr);
|
||||
+ if (peer) {
|
||||
+ /* Peer still in list - firmware didn't send unmap event yet */
|
||||
+ list_del(&peer->list);
|
||||
+ kfree(peer);
|
||||
+ ar->num_peers--;
|
||||
+ ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
|
||||
+ "%s peer deleted (no unmap event) %pM vdev_id: %d num_peers: %d\n",
|
||||
+ __func__, addr, vdev_id, ar->num_peers);
|
||||
+ } else {
|
||||
+ /* Peer already removed by unmap event - still need to decrement */
|
||||
+ ar->num_peers--;
|
||||
+ ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
|
||||
+ "%s peer deleted (via unmap event) %pM vdev_id: %d num_peers: %d\n",
|
||||
+ __func__, addr, vdev_id, ar->num_peers);
|
||||
+ }
|
||||
+ spin_unlock_bh(&ar->ab->base_lock);
|
||||
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
|
||||
+ }
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -905,6 +962,7 @@ int ath11k_peer_create(struct ath11k *ar
|
||||
if (vdev_id == param->vdev_id)
|
||||
return -EINVAL;
|
||||
|
||||
+ ath11k_dp_peer_cleanup(ar, vdev_id, param->peer_addr);
|
||||
ath11k_peer_delete(ar, vdev_id, param->peer_addr);
|
||||
}
|
||||
|
||||
@@ -970,7 +1028,8 @@ int ath11k_peer_create(struct ath11k *ar
|
||||
ar->num_peers++;
|
||||
|
||||
if (ath11k_mac_sta_level_info(arvif, sta)) {
|
||||
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "peer created %pM\n", param->peer_addr);
|
||||
+ ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "peer created %pM vdev_id: %d num_peers: %d\n",
|
||||
+ param->peer_addr, param->vdev_id, ar->num_peers);
|
||||
peer->peer_logging_enabled = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
From 625b8692332ee44e514be88400646e900710644b Mon Sep 17 00:00:00 2001
|
||||
From: Venkat Chimata <venkat@nearhop.com>
|
||||
Date: Tue, 25 Nov 2025 20:34:34 +0530
|
||||
Subject: [PATCH] This is a work in progress patch.
|
||||
|
||||
num_peers was decremented at one place and list_del was called at another place.
|
||||
There are chances that they miss sync.
|
||||
|
||||
So reset num_peers when out of sync
|
||||
|
||||
Signed-off-by: Venkat Chimata <venkat@nearhop.com>
|
||||
---
|
||||
drivers/net/wireless/ath/ath11k/mac.c | 39 ++++++++----
|
||||
drivers/net/wireless/ath/ath11k/peer.c | 82 +++++++++++++++++++++++---
|
||||
2 files changed, 102 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
|
||||
index f300c4f..a3eeac8 100644
|
||||
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
||||
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
||||
@@ -5383,6 +5383,8 @@ static int ath11k_mac_station_add(struct ath11k *ar,
|
||||
peer_param.peer_addr = sta->addr;
|
||||
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
|
||||
|
||||
+ ath11k_warn(ab, "%s: Peer will be added: %pM for VDEV: %d\n", __func__,
|
||||
+ sta->addr, arvif->vdev_id);
|
||||
ret = ath11k_peer_create(ar, arvif, sta, &peer_param);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n",
|
||||
@@ -5457,7 +5459,13 @@ free_tx_stats:
|
||||
kfree(arsta->wbm_tx_stats);
|
||||
arsta->wbm_tx_stats = NULL;
|
||||
free_peer:
|
||||
- ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
|
||||
+ ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
|
||||
+ if (ret)
|
||||
+ ath11k_warn(ar->ab, "%s: Failed to delete peer: %pM for VDEV: %d\n", __func__,
|
||||
+ sta->addr, arvif->vdev_id);
|
||||
+ else
|
||||
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
|
||||
+ sta->addr, arvif->vdev_id);
|
||||
free_rx_stats:
|
||||
kfree(arsta->rx_stats);
|
||||
arsta->rx_stats = NULL;
|
||||
@@ -5735,18 +5743,15 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
|
||||
ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
else
|
||||
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER, "Removed peer: %pM for VDEV: %d\n",
|
||||
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
|
||||
sta->addr, arvif->vdev_id);
|
||||
|
||||
ath11k_mac_dec_num_stations(arvif, sta);
|
||||
mutex_lock(&ar->ab->tbl_mtx_lock);
|
||||
spin_lock_bh(&ar->ab->base_lock);
|
||||
peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
|
||||
- /* Skip if peer deletion already in progress to prevent
|
||||
- * double-delete and num_peers underflow
|
||||
- */
|
||||
- if (peer && peer->sta == sta && !peer->delete_in_progress) {
|
||||
- ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n",
|
||||
+ if (peer && peer->sta == sta) {
|
||||
+ ath11k_warn(ar->ab, "%s: Found peer entry %pM n vdev %i after it was supposedly removed\n", __func__,
|
||||
vif->addr, arvif->vdev_id);
|
||||
ath11k_peer_rhash_delete(ar->ab, peer);
|
||||
peer->sta = NULL;
|
||||
@@ -7746,6 +7751,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
|
||||
peer_param.vdev_id = arvif->vdev_id;
|
||||
peer_param.peer_addr = vif->addr;
|
||||
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
|
||||
+ ath11k_warn(ab, "%s: Peer will be added: %pM for VDEV: %d\n", __func__,
|
||||
+ vif->addr, arvif->vdev_id);
|
||||
ret = ath11k_peer_create(ar, arvif, NULL, &peer_param);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "failed to vdev %d create peer for AP: %d\n",
|
||||
@@ -7947,8 +7954,11 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||
ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
|
||||
if (ret)
|
||||
- ath11k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n",
|
||||
+ ath11k_warn(ab, "%s: failed to submit AP self-peer removal on vdev %d: %d\n", __func__,
|
||||
arvif->vdev_id, ret);
|
||||
+ else
|
||||
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
|
||||
+ vif->addr, arvif->vdev_id);
|
||||
|
||||
list_for_each_entry_safe(ap_vlan_arvif, tmp, &arvif->ap_vlan_arvifs,
|
||||
list) {
|
||||
@@ -9305,6 +9315,8 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
|
||||
param.peer_type = WMI_PEER_TYPE_DEFAULT;
|
||||
param.peer_addr = ar->mac_addr;
|
||||
|
||||
+ ath11k_warn(ab, "%s: Peer will be added: %pM for VDEV: %d\n", __func__,
|
||||
+ ar->mac_addr, arvif->vdev_id);
|
||||
ret = ath11k_peer_create(ar, arvif, NULL, ¶m);
|
||||
if (ret) {
|
||||
ath11k_warn(ab, "failed to create peer after vdev start delay: %d",
|
||||
@@ -9380,8 +9392,15 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
||||
|
||||
if (ab->hw_params.vdev_start_delay &&
|
||||
arvif->vdev_type == WMI_VDEV_TYPE_MONITOR &&
|
||||
- ath11k_peer_find_by_addr(ab, ar->mac_addr))
|
||||
- ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr);
|
||||
+ ath11k_peer_find_by_addr(ab, ar->mac_addr)) {
|
||||
+ ret = ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr);
|
||||
+ if (ret)
|
||||
+ ath11k_warn(ar->ab, "%s: Failed to delete peer: %pM for VDEV: %d\n", __func__,
|
||||
+ ar->mac_addr, arvif->vdev_id);
|
||||
+ else
|
||||
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
|
||||
+ ar->mac_addr, arvif->vdev_id);
|
||||
+ }
|
||||
|
||||
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
|
||||
ret = ath11k_mac_monitor_stop(ar);
|
||||
diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c
|
||||
index 877ea30..9ec297f 100644
|
||||
--- a/drivers/net/wireless/ath/ath11k/peer.c
|
||||
+++ b/drivers/net/wireless/ath/ath11k/peer.c
|
||||
@@ -457,8 +457,8 @@ void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
- if (peer->peer_logging_enabled)
|
||||
- ath11k_dbg(ab, ATH11K_DBG_PEER, "peer unmap vdev %d peer %pM id %d\n",
|
||||
+// if (peer->peer_logging_enabled)
|
||||
+ ath11k_warn(ab, "peer unmap vdev %d peer %pM id %d\n",
|
||||
peer->vdev_id, peer->addr, peer_id);
|
||||
|
||||
/* Don't decrement num_peers here - it's already decremented in
|
||||
@@ -466,6 +466,7 @@ void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id)
|
||||
*/
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
+ ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);
|
||||
wake_up(&ab->peer_mapping_wq);
|
||||
|
||||
exit:
|
||||
@@ -617,7 +618,14 @@ void ath11k_peer_map_v2_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id,
|
||||
peer_free:
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
- ath11k_peer_delete(ar, vdev_id, mac_addr);
|
||||
+ ret = ath11k_peer_delete(ar, vdev_id, mac_addr);
|
||||
+ if (ret)
|
||||
+ ath11k_warn(ar->ab, "%s: Failed to delete peer: %pM for VDEV: %d\n", __func__,
|
||||
+ mac_addr, vdev_id);
|
||||
+ else
|
||||
+ ath11k_warn(ar->ab, "%s: Removed peer: %pM for VDEV: %d\n", __func__,
|
||||
+ mac_addr, vdev_id);
|
||||
+
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
@@ -893,9 +901,16 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
ar->num_peers--;
|
||||
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
|
||||
+ ath11k_warn(ar->ab,
|
||||
"%s peer deleted (timeout) %pM vdev_id: %d num_peers: %d\n",
|
||||
__func__, addr, vdev_id, ar->num_peers);
|
||||
+ } else {
|
||||
+ // Peer already deleted
|
||||
+ // Who deleted it? Firmware unmap event after the timeout?
|
||||
+ ar->num_peers--;
|
||||
+ ath11k_warn(ar->ab,
|
||||
+ "%s peer already deleted (timeout) %pM vdev_id: %d num_peers: %d\n",
|
||||
+ __func__, addr, vdev_id, ar->num_peers);
|
||||
}
|
||||
spin_unlock_bh(&ar->ab->base_lock);
|
||||
mutex_unlock(&ar->ab->tbl_mtx_lock);
|
||||
@@ -911,13 +926,13 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr)
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
ar->num_peers--;
|
||||
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
|
||||
+ ath11k_warn(ar->ab,
|
||||
"%s peer deleted (no unmap event) %pM vdev_id: %d num_peers: %d\n",
|
||||
__func__, addr, vdev_id, ar->num_peers);
|
||||
} else {
|
||||
/* Peer already removed by unmap event - still need to decrement */
|
||||
ar->num_peers--;
|
||||
- ath11k_dbg(ar->ab, ATH11K_DBG_PEER,
|
||||
+ ath11k_warn(ar->ab,
|
||||
"%s peer deleted (via unmap event) %pM vdev_id: %d num_peers: %d\n",
|
||||
__func__, addr, vdev_id, ar->num_peers);
|
||||
}
|
||||
@@ -933,6 +948,31 @@ static int ath11k_wait_for_peer_created(struct ath11k *ar, int vdev_id, const u8
|
||||
return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
|
||||
}
|
||||
|
||||
+static int ath11k_get_peer_count(struct rhashtable *ht)
|
||||
+{
|
||||
+ struct rhashtable_iter iter;
|
||||
+ struct rhash_head *pos;
|
||||
+ int count = 0;
|
||||
+
|
||||
+ rhashtable_walk_enter(ht, &iter);
|
||||
+ rhashtable_walk_start(&iter);
|
||||
+
|
||||
+ while ((pos = rhashtable_walk_next(&iter))) {
|
||||
+ if (IS_ERR(pos)) {
|
||||
+ if (PTR_ERR(pos) == -EAGAIN)
|
||||
+ continue; // retry due to resize
|
||||
+ break; // some other error
|
||||
+ }
|
||||
+ count++;
|
||||
+ }
|
||||
+
|
||||
+ rhashtable_walk_stop(&iter);
|
||||
+ rhashtable_walk_exit(&iter);
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+
|
||||
int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
|
||||
struct ieee80211_sta *sta, struct peer_create_params *param)
|
||||
{
|
||||
@@ -941,13 +981,37 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
|
||||
struct ath11k_sta *arsta;
|
||||
int ret, fbret;
|
||||
u8 vdev_id = 0;
|
||||
+ int rhash_count;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
- if (ar->num_peers > (ar->max_num_peers - 1)) {
|
||||
+ mutex_lock(&ar->ab->tbl_mtx_lock);
|
||||
+ spin_lock_bh(&ar->ab->base_lock);
|
||||
+ rhash_count = ath11k_get_peer_count(ar->ab->rhead_peer_addr);
|
||||
+ spin_unlock_bh(&ar->ab->base_lock);
|
||||
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
|
||||
+ ath11k_warn(ar->ab, "address = %pM rhash_count = %d ar->num_peers = %d "
|
||||
+ "ar->max_num_peers = %d ar->num_stations = %d\n", param->peer_addr, rhash_count, ar->num_peers, ar->max_num_peers, ar->num_stations);
|
||||
+ // Check for peer count desynchronization
|
||||
+ // If num_peers is negative or exceeds max_num_peers -1, recalculate from rhashtable
|
||||
+ if ((ar->num_peers < 0) || (ar->num_peers > (ar->max_num_peers - 1))) {
|
||||
+ // This can happen if rhash table and num_peers get out of sync
|
||||
+ // e.g. during peer delete for some unknown reason
|
||||
+ // Recalculate num_peers from rhash table
|
||||
ath11k_warn(ar->ab,
|
||||
- "failed to create peer due to insufficient peer entry resource in firmware\n");
|
||||
- return -ENOBUFS;
|
||||
+ "failed to create peer due to insufficient peer entry resource in firmware ar->num_peers = %d "
|
||||
+ "ar->max_num_peers = %d ar->num_stations = %d\n", ar->num_peers, ar->max_num_peers, ar->num_stations);
|
||||
+ mutex_lock(&ar->ab->tbl_mtx_lock);
|
||||
+ spin_lock_bh(&ar->ab->base_lock);
|
||||
+ rhash_count = ath11k_get_peer_count(ar->ab->rhead_peer_addr);
|
||||
+ spin_unlock_bh(&ar->ab->base_lock);
|
||||
+ mutex_unlock(&ar->ab->tbl_mtx_lock);
|
||||
+ if (rhash_count > ar->max_num_peers -1 ) {
|
||||
+ ath11k_warn(ar->ab,
|
||||
+ "rhash_count %d exceeds max_num_peers %d\n", rhash_count, ar->max_num_peers);
|
||||
+ return -ENOBUFS;
|
||||
+ }
|
||||
+ ar->num_peers = rhash_count;
|
||||
}
|
||||
|
||||
mutex_lock(&ar->ab->tbl_mtx_lock);
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
From ed3f83b3459a67a3ab9d806490ac304b567b1c2d Mon Sep 17 00:00:00 2001
|
||||
From: Miaoqian Lin <linmq006@gmail.com>
|
||||
Date: Mon, 2 Jan 2023 12:11:42 +0400
|
||||
Subject: wifi: ath11k: Fix memory leak in ath11k_peer_rx_frag_setup
|
||||
|
||||
crypto_alloc_shash() allocates resources, which should be released by
|
||||
crypto_free_shash(). When ath11k_peer_find() fails, there has memory
|
||||
leak. Add missing crypto_free_shash() to fix this.
|
||||
|
||||
Fixes: 243874c64c81 ("ath11k: handle RX fragments")
|
||||
Signed-off-by: Miaoqian Lin <linmq006@gmail.com>
|
||||
Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
|
||||
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
||||
Link: https://lore.kernel.org/r/20230102081142.3937570-1-linmq006@gmail.com
|
||||
---
|
||||
drivers/net/wireless/ath/ath11k/dp_rx.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
|
||||
index be391322956fec..b65a84a8826413 100644
|
||||
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
|
||||
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
|
||||
@@ -3126,6 +3126,7 @@ int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id
|
||||
if (!peer) {
|
||||
ath11k_warn(ab, "failed to find the peer to set up fragment info\n");
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
+ crypto_free_shash(tfm);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
--
|
||||
cgit 1.2.3-korg
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
From 72de799aa9e3e064b35238ef053d2f0a49db055a Mon Sep 17 00:00:00 2001
|
||||
From: Baochen Qiang <bqiang@codeaurora.org>
|
||||
Date: Tue, 28 Sep 2021 14:00:44 +0300
|
||||
Subject: ath11k: Fix memory leak in ath11k_qmi_driver_event_work
|
||||
|
||||
The buffer pointed to by event is not freed in case
|
||||
ATH11K_FLAG_UNREGISTERING bit is set, resulting in
|
||||
memory leak, so fix it.
|
||||
|
||||
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-01720.1-QCAHSPSWPL_V1_V2_SILICONZ_LITE-1
|
||||
|
||||
Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
|
||||
Signed-off-by: Baochen Qiang <bqiang@codeaurora.org>
|
||||
Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
Link: https://lore.kernel.org/r/20210913180246.193388-4-jouni@codeaurora.org
|
||||
---
|
||||
drivers/net/wireless/ath/ath11k/qmi.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
|
||||
index babadd574e4b9c..8c615bc788cacf 100644
|
||||
--- a/drivers/net/wireless/ath/ath11k/qmi.c
|
||||
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
|
||||
@@ -2759,8 +2759,10 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
|
||||
list_del(&event->list);
|
||||
spin_unlock(&qmi->event_lock);
|
||||
|
||||
- if (test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags))
|
||||
+ if (test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)) {
|
||||
+ kfree(event);
|
||||
return;
|
||||
+ }
|
||||
|
||||
switch (event->type) {
|
||||
case ATH11K_QMI_EVENT_SERVER_ARRIVE:
|
||||
--
|
||||
cgit 1.2.3-korg
|
||||
|
||||
Reference in New Issue
Block a user