mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-11 10:25:43 +00:00
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>
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
Reference in New Issue
Block a user