mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-20 10:51:27 +00:00
674 lines
20 KiB
Diff
674 lines
20 KiB
Diff
From dda25e914cf8f077d1ab8bcaa5600f483976cac5 Mon Sep 17 00:00:00 2001
|
|
From: saleemuddin shaik <quic_saleemud@quicinc.com>
|
|
Date: Thu, 16 Mar 2023 13:56:43 +0530
|
|
Subject: [PATCH] ath11k: add support to get rssi value of non-associated
|
|
client
|
|
|
|
Monitor the surrounding network to get RSSI of non-associated
|
|
client(for example, if Neighbor-Peer associated to neighboring AP's).
|
|
Obtaining the RSSI it is useful for roaming between AP's in a
|
|
network and on deciding which AP the client should associate
|
|
with.
|
|
This is achieved through debugfs by providing the mac address
|
|
of a npr(neighbor peer) which creates a neighbor-peer object to store's the
|
|
data associated with the npr such as its mac, RSSI and timestamp.
|
|
Once the npr is added a file with the mac-address of npr as its
|
|
filename is created.
|
|
Each time the file is read a peer object is created for the
|
|
NPR and filter is set to get its ppdu_info for home channel
|
|
thereby obtaining the RSSI and a corresponding unix
|
|
timestamp is created, once the data collection is completed the
|
|
peer object is destroyed to free-up peer count.
|
|
Upto 6 NPR's can be created to keep the load and peer-count low.
|
|
Once the rssi and timestamp are obtained the peer object
|
|
created for NPR is deleted to free the peer id.
|
|
In case the NPR packets are unavailable during scan the
|
|
previous timestamped value is returned.
|
|
|
|
Command to add a Neighbor-Peer:
|
|
echo "add,<mac-addr-of-npr>" >
|
|
/sys/kernel/debug/ieee80211/phyX/ath11k/neighbor_peer
|
|
|
|
Command to delete a Neighbor-Peer:
|
|
echo "del,<mac-addr-of-npr>" >
|
|
/sys/kernel/debug/ieee80211/phyX/ath11k/neighbor_peer
|
|
|
|
Command to display RSSI of Neighbor-Peer:
|
|
cat /sys/kernel/debug/ieee80211/phyX/ath11k/nrp_rssi/<mac-addr-of-npr>
|
|
|
|
Signed-off-by: saleemuddin shaik <quic_saleemud@quicinc.com>
|
|
---
|
|
drivers/net/wireless/ath/ath11k/core.c | 5 +
|
|
drivers/net/wireless/ath/ath11k/core.h | 4 +
|
|
drivers/net/wireless/ath/ath11k/debugfs.c | 401 ++++++++++++++++++++++
|
|
drivers/net/wireless/ath/ath11k/debugfs.h | 30 ++
|
|
drivers/net/wireless/ath/ath11k/dp_rx.c | 14 +
|
|
drivers/net/wireless/ath/ath11k/mac.c | 32 ++
|
|
6 files changed, 486 insertions(+)
|
|
|
|
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
|
|
index 504e390..0bdee41 100644
|
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
|
@@ -2177,6 +2177,10 @@ static void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab)
|
|
complete(&ar->scan.on_channel);
|
|
complete(&ar->peer_assoc_done);
|
|
complete(&ar->peer_delete_done);
|
|
+
|
|
+ if (!list_empty(&ab->neighbor_peers))
|
|
+ ath11k_debugfs_nrp_cleanup_all(ar);
|
|
+
|
|
complete(&ar->install_key_done);
|
|
complete(&ar->vdev_setup_done);
|
|
complete(&ar->vdev_delete_done);
|
|
@@ -2467,6 +2471,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
|
|
init_completion(&ab->recovery_start);
|
|
|
|
INIT_LIST_HEAD(&ab->peers);
|
|
+ INIT_LIST_HEAD(&ab->neighbor_peers);
|
|
init_waitqueue_head(&ab->peer_mapping_wq);
|
|
init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
|
|
init_waitqueue_head(&ab->qmi.cold_boot_waitq);
|
|
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
|
|
index e543442..2b8b4b8 100644
|
|
--- a/drivers/net/wireless/ath/ath11k/core.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.h
|
|
@@ -830,6 +830,7 @@ struct ath11k_debug {
|
|
struct dentry *debugfs_smartant;
|
|
u32 coex_priority_level[ATH11K_MAX_COEX_PRIORITY_LEVEL];
|
|
enum wmi_bss_chan_info_req_type bss_survey_mode;
|
|
+ struct dentry *debugfs_nrp;
|
|
};
|
|
|
|
struct ath11k_per_peer_tx_stats {
|
|
@@ -1323,6 +1324,9 @@ struct ath11k_base {
|
|
#endif
|
|
struct ath11k_soc_dp_stats soc_stats;
|
|
|
|
+ struct list_head neighbor_peers;
|
|
+ int num_nrps;
|
|
+
|
|
unsigned long dev_flags;
|
|
struct completion driver_recovery;
|
|
struct workqueue_struct *workqueue;
|
|
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
index 44a4e5a..a6b998c 100644
|
|
--- a/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
@@ -1424,6 +1424,404 @@ static const struct file_operations fops_extd_rx_stats = {
|
|
.open = simple_open,
|
|
};
|
|
|
|
+static int ath11k_reset_nrp_filter(struct ath11k *ar,
|
|
+ bool reset)
|
|
+{
|
|
+ int i = 0;
|
|
+ int ret = 0;
|
|
+ u32 ring_id = 0;
|
|
+ struct htt_rx_ring_tlv_filter tlv_filter = {0};
|
|
+ struct ath11k_pdev_dp *dp = &ar->dp;
|
|
+ struct ath11k_base *ab = ar->ab;
|
|
+
|
|
+ if (ab->hw_params.full_monitor_mode) {
|
|
+ ret = ath11k_dp_tx_htt_rx_full_mon_setup(ab,
|
|
+ dp->mac_id, !reset);
|
|
+ if (ret < 0) {
|
|
+ ath11k_err(ab, "failed to setup full monitor %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id;
|
|
+ tlv_filter.offset_valid = false;
|
|
+ if (!reset) {
|
|
+ tlv_filter.pkt_filter_flags0 =
|
|
+ HTT_RX_MON_MO_MGMT_FILTER_FLAGS0;
|
|
+ tlv_filter.pkt_filter_flags1 =
|
|
+ HTT_RX_MON_MO_MGMT_FILTER_FLAGS1;
|
|
+ tlv_filter.pkt_filter_flags2 =
|
|
+ HTT_RX_MON_MO_CTRL_FILTER_FLASG2;
|
|
+ tlv_filter.pkt_filter_flags3 =
|
|
+ HTT_RX_MON_MO_CTRL_FILTER_FLASG3 |
|
|
+ HTT_RX_MON_MO_DATA_FILTER_FLASG3;
|
|
+ }
|
|
+
|
|
+ if (ar->ab->hw_params.rxdma1_enable) {
|
|
+ ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
|
|
+ HAL_RXDMA_MONITOR_BUF,
|
|
+ DP_RXDMA_REFILL_RING_SIZE,
|
|
+ &tlv_filter);
|
|
+ } else if (!reset) {
|
|
+ for (i = 0; i < ar->ab->hw_params.num_rxmda_per_pdev; i++) {
|
|
+ ring_id = ar->dp.rx_mac_buf_ring[i].ring_id;
|
|
+ ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id,
|
|
+ ar->dp.mac_id + i,
|
|
+ HAL_RXDMA_BUF,
|
|
+ 1024,
|
|
+ &tlv_filter);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ for (i = 0; i < ar->ab->hw_params.num_rxmda_per_pdev; i++) {
|
|
+ ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
|
|
+ if (!reset) {
|
|
+ tlv_filter.rx_filter =
|
|
+ HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING;
|
|
+ } else {
|
|
+ tlv_filter = ath11k_mac_mon_status_filter_default;
|
|
+
|
|
+ if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))
|
|
+ tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar);
|
|
+ }
|
|
+
|
|
+ ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id,
|
|
+ ar->dp.mac_id + i,
|
|
+ HAL_RXDMA_MONITOR_STATUS,
|
|
+ DP_RXDMA_REFILL_RING_SIZE,
|
|
+ &tlv_filter);
|
|
+ }
|
|
+
|
|
+ if (!ar->ab->hw_params.rxdma1_enable)
|
|
+ mod_timer(&ar->ab->mon_reap_timer, jiffies +
|
|
+ msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL));
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void ath11k_debugfs_nrp_cleanup_all(struct ath11k *ar)
|
|
+{
|
|
+ struct ath11k_base *ab = ar->ab;
|
|
+ struct ath11k_neighbor_peer *nrp, *tmp;
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ list_for_each_entry_safe(nrp, tmp, &ab->neighbor_peers, list) {
|
|
+ if (nrp->is_filter_on)
|
|
+ complete(&nrp->filter_done);
|
|
+ list_del(&nrp->list);
|
|
+ kfree(nrp);
|
|
+ }
|
|
+
|
|
+ ab->num_nrps = 0;
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ debugfs_remove_recursive(ar->debug.debugfs_nrp);
|
|
+}
|
|
+
|
|
+void ath11k_debugfs_nrp_clean(struct ath11k *ar, const u8 *addr)
|
|
+{
|
|
+ int i, j;
|
|
+ char fname[MAC_UNIT_LEN * ETH_ALEN] = {0};
|
|
+
|
|
+ for (i = 0, j = 0; i < (MAC_UNIT_LEN * ETH_ALEN); i += MAC_UNIT_LEN, j++) {
|
|
+ if (j == ETH_ALEN - 1) {
|
|
+ snprintf(fname + i, sizeof(fname) - i, "%02x", *(addr + j));
|
|
+ break;
|
|
+ }
|
|
+ snprintf(fname + i, sizeof(fname) - i, "%02x:", *(addr + j));
|
|
+ }
|
|
+
|
|
+ spin_lock_bh(&ar->ab->base_lock);
|
|
+ ar->ab->num_nrps--;
|
|
+ spin_unlock_bh(&ar->ab->base_lock);
|
|
+
|
|
+ debugfs_lookup_and_remove(fname, ar->debug.debugfs_nrp);
|
|
+ if (!ar->ab->num_nrps) {
|
|
+ debugfs_remove_recursive(ar->debug.debugfs_nrp);
|
|
+ ath11k_reset_nrp_filter(ar, true);
|
|
+ }
|
|
+}
|
|
+
|
|
+static ssize_t ath11k_read_nrp_rssi(struct file *file,
|
|
+ char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ struct ath11k_base *ab = ar->ab;
|
|
+ struct ath11k_vif *arvif = NULL;
|
|
+ struct ath11k_neighbor_peer *nrp = NULL, *tmp;
|
|
+ struct peer_create_params peer_param = {0};
|
|
+ u8 macaddr[ETH_ALEN] = {0};
|
|
+ loff_t file_pos = *ppos;
|
|
+ struct path *fpath = &file->f_path;
|
|
+ char *fname = fpath->dentry->d_iname;
|
|
+ char buf[128] = {0};
|
|
+ int i = 0;
|
|
+ int j = 0;
|
|
+ int len = 0;
|
|
+ int vdev_id = -1;
|
|
+ bool nrp_found = false;
|
|
+ int ret;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+ if (ar->state != ATH11K_STATE_ON) {
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ return -ENETDOWN;
|
|
+ }
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+
|
|
+ if (file_pos > 0)
|
|
+ return 0;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+ list_for_each_entry(arvif, &ar->arvifs, list) {
|
|
+ if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
|
+ vdev_id = arvif->vdev_id;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+
|
|
+ if (vdev_id < 0) {
|
|
+ ath11k_warn(ab, "unable to get vdev for AP interface\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ for (i = 0, j = 0; i < MAC_UNIT_LEN * ETH_ALEN; i += MAC_UNIT_LEN, j++) {
|
|
+ if (sscanf(fname + i, "%hhX", &macaddr[j]) <= 0)
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ list_for_each_entry(nrp, &ab->neighbor_peers, list) {
|
|
+ if (ether_addr_equal(macaddr, nrp->addr)) {
|
|
+ reinit_completion(&nrp->filter_done);
|
|
+ nrp->vdev_id = vdev_id;
|
|
+ nrp->is_filter_on = false;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ peer_param.vdev_id = nrp->vdev_id;
|
|
+ peer_param.peer_addr = nrp->addr;
|
|
+ peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
|
|
+
|
|
+ ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_SET_PROMISC_MODE_CMDID,
|
|
+ 1, ar->pdev->pdev_id);
|
|
+ if (ret)
|
|
+ ath11k_err(ar->ab, "failed to enable promisc mode: %d\n", ret);
|
|
+
|
|
+ if (!ath11k_peer_create(ar, arvif, NULL, &peer_param)) {
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ list_for_each_entry_safe(nrp, tmp, &ab->neighbor_peers, list) {
|
|
+ if (ether_addr_equal(nrp->addr, peer_param.peer_addr)) {
|
|
+ nrp_found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ if (nrp_found) {
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ nrp->is_filter_on = true;
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ wait_for_completion_interruptible_timeout(&nrp->filter_done, 15 * HZ);
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ nrp->is_filter_on = false;
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ len = scnprintf(buf, sizeof(buf),
|
|
+ "Neighbor Peer MAC\t\tRSSI\t\tTime\n");
|
|
+ len += scnprintf(buf + len, sizeof(buf) - len, "%pM\t\t%u\t\t%lld\n",
|
|
+ nrp->addr, nrp->rssi, nrp->timestamp);
|
|
+ } else {
|
|
+ ath11k_peer_delete(ar, vdev_id, macaddr);
|
|
+ ath11k_warn(ab, "%pM not found in nrp list\n", macaddr);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_SET_PROMISC_MODE_CMDID,
|
|
+ 0, ar->pdev->pdev_id);
|
|
+ if (ret)
|
|
+ ath11k_err(ar->ab, "failed to disable promisc mode: %d\n", ret);
|
|
+
|
|
+ ath11k_peer_delete(ar, vdev_id, macaddr);
|
|
+ } else {
|
|
+ ath11k_warn(ab, "unable to create peer for nrp[%pM]\n", macaddr);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_read_nrp_rssi = {
|
|
+ .read = ath11k_read_nrp_rssi,
|
|
+ .open = simple_open,
|
|
+};
|
|
+
|
|
+static ssize_t ath11k_write_nrp_mac(struct file *file,
|
|
+ const char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ struct ath11k_base *ab = ar->ab;
|
|
+ struct ath11k_peer *peer = NULL;
|
|
+ struct ath11k_neighbor_peer *nrp = NULL, *tmp = NULL;
|
|
+ u8 mac[ETH_ALEN] = {0};
|
|
+ char fname[MAC_UNIT_LEN * ETH_ALEN] = {0};
|
|
+ char *str = NULL;
|
|
+ char *buf = vmalloc(count);
|
|
+ char *ptr = buf;
|
|
+ int i = 0;
|
|
+ int j = 0;
|
|
+ int ret = count;
|
|
+ int action = 0;
|
|
+ ssize_t rc = 0;
|
|
+ bool del_nrp = false;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+
|
|
+ rc = simple_write_to_buffer(buf, count, ppos, ubuf, count);
|
|
+ if (rc <= 0)
|
|
+ goto exit;
|
|
+
|
|
+ buf[count - 1] = '\0';
|
|
+
|
|
+ if (ar->state != ATH11K_STATE_ON) {
|
|
+ ret = -ENETDOWN;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ str = strsep(&buf, ",");
|
|
+ if (!strcmp(str, "add"))
|
|
+ action = NRP_ACTION_ADD;
|
|
+ else if (!strcmp(str, "del"))
|
|
+ action = NRP_ACTION_DEL;
|
|
+ else {
|
|
+ ath11k_err(ab, "error: invalid argument\n");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ memset(mac, 0, sizeof(mac));
|
|
+ while ((str = strsep(&buf, ":")) != NULL) {
|
|
+ if (i >= ETH_ALEN || kstrtou8(str, 16, mac + i)) {
|
|
+ ath11k_warn(ab, "error: invalid mac address\n");
|
|
+ goto exit;
|
|
+ }
|
|
+ i++;
|
|
+ }
|
|
+
|
|
+ if (i != ETH_ALEN) {
|
|
+ ath11k_warn(ab, "error: invalid mac address\n");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ if (!is_valid_ether_addr(mac)) {
|
|
+ ath11k_err(ab, "error: invalid mac address\n");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ for (i = 0, j = 0; i < (MAC_UNIT_LEN * ETH_ALEN); i += MAC_UNIT_LEN, j++) {
|
|
+ if (j == ETH_ALEN - 1) {
|
|
+ snprintf(fname + i, sizeof(fname) - i, "%02x", mac[j]);
|
|
+ break;
|
|
+ }
|
|
+ snprintf(fname + i, sizeof(fname) - i, "%02x:", mac[j]);
|
|
+ }
|
|
+
|
|
+ switch (action) {
|
|
+ case NRP_ACTION_ADD:
|
|
+ if (ab->num_nrps == (ATH11K_MAX_NRPS - 1)) {
|
|
+ ath11k_warn(ab, "max nrp reached, cannot create more\n");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ list_for_each_entry(nrp, &ab->neighbor_peers, list) {
|
|
+ if (ether_addr_equal(nrp->addr, mac)) {
|
|
+ ath11k_warn(ab, "cannot add existing neighbor peer\n");
|
|
+ goto exit;
|
|
+ }
|
|
+ }
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ peer = ath11k_peer_find_by_addr(ab, mac);
|
|
+ if (peer) {
|
|
+ ath11k_warn(ab, "cannot add exisitng peer [%pM] as nrp\n", mac);
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+ goto exit;
|
|
+ }
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ nrp = kzalloc(sizeof(*nrp), GFP_KERNEL);
|
|
+ if (!nrp)
|
|
+ goto exit;
|
|
+
|
|
+ init_completion(&nrp->filter_done);
|
|
+ ether_addr_copy(nrp->addr, mac);
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ list_add_tail(&nrp->list, &ab->neighbor_peers);
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ if (!ab->num_nrps) {
|
|
+ ar->debug.debugfs_nrp = debugfs_create_dir("nrp_rssi",
|
|
+ ar->debug.debugfs_pdev);
|
|
+ ath11k_reset_nrp_filter(ar, false);
|
|
+ }
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ ab->num_nrps++;
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ debugfs_create_file(fname, 0644,
|
|
+ ar->debug.debugfs_nrp, ar,
|
|
+ &fops_read_nrp_rssi);
|
|
+ break;
|
|
+ case NRP_ACTION_DEL:
|
|
+ if (!ar->ab->num_nrps) {
|
|
+ ath11k_err(ab, "error: no nac added\n");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ list_for_each_entry_safe(nrp, tmp, &ab->neighbor_peers, list) {
|
|
+ if (ether_addr_equal(nrp->addr, mac)) {
|
|
+ list_del(&nrp->list);
|
|
+ kfree(nrp);
|
|
+ del_nrp = true;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ }
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ if (!del_nrp)
|
|
+ ath11k_warn(ab, "cannot delete %pM not added to list\n", mac);
|
|
+ else
|
|
+ ath11k_debugfs_nrp_clean(ar, mac);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ exit:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+
|
|
+ vfree(ptr);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_write_nrp_mac = {
|
|
+ .write = ath11k_write_nrp_mac,
|
|
+ .open = simple_open,
|
|
+};
|
|
+
|
|
static int ath11k_fill_bp_stats(struct ath11k_base *ab,
|
|
struct ath11k_bp_stats *bp_stats,
|
|
char *buf, int len, int size)
|
|
@@ -4698,6 +5096,9 @@ int ath11k_debugfs_register(struct ath11k *ar)
|
|
ar->debug.debugfs_pdev, ar,
|
|
&fops_wmm_stats);
|
|
|
|
+ debugfs_create_file("neighbor_peer", 0644,
|
|
+ ar->debug.debugfs_pdev, ar,
|
|
+ &fops_write_nrp_mac);
|
|
debugfs_create_file("ext_tx_stats", 0644,
|
|
ar->debug.debugfs_pdev, ar,
|
|
&fops_extd_tx_stats);
|
|
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.h b/drivers/net/wireless/ath/ath11k/debugfs.h
|
|
index 57c8255..72d446b 100644
|
|
--- a/drivers/net/wireless/ath/ath11k/debugfs.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/debugfs.h
|
|
@@ -12,6 +12,9 @@
|
|
#define ATH11K_TX_POWER_MIN_VAL 0
|
|
#define ATH11K_DEBUG_ENABLE_MEMORY_STATS 1
|
|
|
|
+#define ATH11K_MAX_NRPS 7
|
|
+#define MAC_UNIT_LEN 3
|
|
+
|
|
/* htt_dbg_ext_stats_type */
|
|
enum ath11k_dbg_htt_ext_stats_type {
|
|
ATH11K_DBG_HTT_EXT_STATS_RESET = 0,
|
|
@@ -190,6 +193,11 @@ enum ath11k_dbg_aggr_mode {
|
|
ATH11K_DBG_AGGR_MODE_MAX,
|
|
};
|
|
|
|
+enum ath11k_nrp_action {
|
|
+ NRP_ACTION_ADD,
|
|
+ NRP_ACTION_DEL,
|
|
+};
|
|
+
|
|
enum fw_dbglog_wlan_module_id {
|
|
WLAN_MODULE_ID_MIN = 0,
|
|
WLAN_MODULE_INF = WLAN_MODULE_ID_MIN,
|
|
@@ -298,6 +306,17 @@ enum fw_dbglog_log_level {
|
|
ATH11K_FW_DBGLOG_LVL_MAX
|
|
};
|
|
|
|
+struct ath11k_neighbor_peer {
|
|
+ struct list_head list;
|
|
+ struct completion filter_done;
|
|
+ bool is_filter_on;
|
|
+ int vdev_id;
|
|
+ u8 addr[ETH_ALEN];
|
|
+ u8 rssi;
|
|
+ s64 timestamp;
|
|
+ bool rssi_valid;
|
|
+};
|
|
+
|
|
struct ath11k_fw_dbglog {
|
|
enum wmi_debug_log_param param;
|
|
union {
|
|
@@ -361,6 +380,8 @@ ssize_t ath11k_debugfs_dump_soc_ring_bp_stats(struct ath11k_base *ab,
|
|
char *buf, int size);
|
|
int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id,
|
|
u32 vdev_id, u32 stats_id);
|
|
+void ath11k_debugfs_nrp_clean(struct ath11k *ar, const u8 *addr);
|
|
+void ath11k_debugfs_nrp_cleanup_all(struct ath11k *ar);
|
|
|
|
static inline bool ath11k_debugfs_is_pktlog_lite_mode_enabled(struct ath11k *ar)
|
|
{
|
|
@@ -536,6 +557,15 @@ ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
|
|
static inline void ath11k_smart_ant_debugfs_init(struct ath11k *ar)
|
|
{
|
|
}
|
|
+
|
|
+static inline void ath11k_debugfs_nrp_clean(struct ath11k *ar, const u8 *addr)
|
|
+{
|
|
+}
|
|
+
|
|
+static inline void ath11k_debugfs_nrp_cleanup_all(struct ath11k *ar)
|
|
+{
|
|
+}
|
|
+
|
|
#endif /* CPTCFG_ATH11K_DEBUGFS*/
|
|
|
|
#ifdef CPTCFG_ATH11K_PKTLOG
|
|
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
index 5e85a2e..4a3f6fa 100644
|
|
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
@@ -6368,6 +6368,7 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
|
|
struct sk_buff *skb;
|
|
struct sk_buff_head skb_list;
|
|
struct ath11k_peer *peer;
|
|
+ struct ath11k_neighbor_peer *nrp, *tmp;
|
|
struct ath11k_sta *arsta = NULL;
|
|
int num_buffs_reaped = 0;
|
|
u32 rx_buf_sz;
|
|
@@ -6427,6 +6428,19 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
|
|
spin_lock_bh(&ab->base_lock);
|
|
peer = ath11k_peer_find_by_id(ab, ppdu_info->peer_id);
|
|
|
|
+ if (!list_empty(&ab->neighbor_peers)) {
|
|
+ if (peer && !peer->sta) {
|
|
+ list_for_each_entry_safe(nrp, tmp, &ab->neighbor_peers, list) {
|
|
+ if (nrp->is_filter_on && ether_addr_equal(nrp->addr, peer->addr)) {
|
|
+ nrp->rssi = ppdu_info->rssi_comb;
|
|
+ nrp->timestamp = ktime_to_ms(ktime_get_real());
|
|
+ complete(&nrp->filter_done);
|
|
+ }
|
|
+ }
|
|
+ goto next_skb;
|
|
+ }
|
|
+ }
|
|
+
|
|
if (!peer || !peer->sta) {
|
|
ath11k_dbg(ab, ATH11K_DBG_DATA,
|
|
"failed to find the peer with peer_id %d\n",
|
|
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
|
|
index fb7e411..d97a309 100644
|
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
|
@@ -1069,6 +1069,9 @@ void ath11k_mac_peer_cleanup_all(struct ath11k *ar)
|
|
spin_unlock_bh(&ab->base_lock);
|
|
mutex_unlock(&ab->tbl_mtx_lock);
|
|
|
|
+ if (!list_empty(&ab->neighbor_peers))
|
|
+ ath11k_debugfs_nrp_cleanup_all(ar);
|
|
+
|
|
ar->num_peers = 0;
|
|
ar->num_stations = 0;
|
|
}
|
|
@@ -5755,6 +5758,9 @@ static int ath11k_mac_station_add(struct ath11k *ar,
|
|
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
|
|
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
|
|
struct peer_create_params peer_param;
|
|
+ struct ath11k_neighbor_peer *nrp, *tmp;
|
|
+ int nvdev_id;
|
|
+ bool del_nrp = false;
|
|
bool peer_dbg_info;
|
|
int ret;
|
|
|
|
@@ -5778,6 +5784,32 @@ static int ath11k_mac_station_add(struct ath11k *ar,
|
|
peer_param.peer_addr = sta->addr;
|
|
peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
|
|
|
|
+ /*
|
|
+ * When the neighbor peer associates with this AP and successfully
|
|
+ * becomes a station, check and clear the corresponding MAC from
|
|
+ * NRP list and failing to do so would inadvertently cause the
|
|
+ * STA association(peer creation for STA) to fail due to the NRP
|
|
+ * having created a peer already for the same MAC address
|
|
+ */
|
|
+ if (!list_empty(&ab->neighbor_peers)) {
|
|
+ spin_lock_bh(&ab->base_lock);
|
|
+ list_for_each_entry_safe(nrp, tmp, &ab->neighbor_peers, list) {
|
|
+ if (ether_addr_equal(nrp->addr, sta->addr)) {
|
|
+ nvdev_id = nrp->vdev_id;
|
|
+ list_del(&nrp->list);
|
|
+ kfree(nrp);
|
|
+ del_nrp = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ spin_unlock_bh(&ab->base_lock);
|
|
+
|
|
+ if (del_nrp) {
|
|
+ ath11k_peer_delete(ar, nvdev_id, sta->addr);
|
|
+ ath11k_debugfs_nrp_clean(ar, sta->addr);
|
|
+ }
|
|
+ }
|
|
+
|
|
ret = ath11k_peer_create(ar, arvif, sta, &peer_param);
|
|
if (ret) {
|
|
ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n",
|
|
--
|
|
2.17.1
|
|
|