diff mbox series

[RFC] wifi: mac80211: Add support for management frames stats

Message ID 20241220231611.1870613-1-quic_msinada@quicinc.com (mailing list archive)
State New
Delegated to: Johannes Berg
Headers show
Series [RFC] wifi: mac80211: Add support for management frames stats | expand

Commit Message

Muna Sinada Dec. 20, 2024, 11:16 p.m. UTC
From: Ramya Gnanasekar <quic_rgnanase@quicinc.com>

Currently there aren't statistics in mac80211 that keep track of the
management frames that are processed in both Tx and Rx. This type of
statistics is useful in tracking if management frames are successfully
transmitted or are dropped. These statistics are also needed to
provide information regarding how many management frames are received.

Add support to track number of management frames that are processed
in mac80211 driver and maintain counters for management Tx completion
status. These statistics are to be included as part of "Extra
statistics for TX/RX debugging". In order to enable them,
CONFIG_MAC80211_DEBUG_COUNTERS needs to be enabled in kernel
configuration.

This stat is a per phy device stat. It can be dumped using the below
command:

cat /sys/kernel/debug/ieee80211/phyX/statistics/mgmt_frame

When executing this command, dump management stats for all the virtual
interfaces of that particular phy device.

Signed-off-by: Ramya Gnanasekar <quic_rgnanase@quicinc.com>
Co-developed-by: Muna Sinada <quic_msinada@quicinc.com>
Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
---
 net/mac80211/debugfs.c     | 64 ++++++++++++++++++++++++++++++++++++++
 net/mac80211/ieee80211_i.h | 26 ++++++++++++++++
 net/mac80211/rx.c          |  2 ++
 net/mac80211/status.c      |  4 +++
 net/mac80211/tx.c          |  2 ++
 5 files changed, 98 insertions(+)
diff mbox series

Patch

diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index be2e486907f9..4f1d3c4fab7d 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -633,6 +633,69 @@  DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
 DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
 DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
 
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+static ssize_t mgmt_frame_read(struct file *file, char __user *userbuf,
+			       size_t count, loff_t *ppos)
+{
+	struct ieee80211_local *local = file->private_data;
+	int size = 1000;
+	int i, len = 0;
+	static const char *mgmt_frame[IEEE80211_MGMT_FRM_TYPE_NUM_MAX - 1] = {
+		"ASSOC REQ", "ASSOC RESP",
+		"REASSOC REQ", "REASSOC RESP",
+		"PROBE REQ", "PROBE RESP",
+		"TIMING ADV", NULL,
+		"BEACON", "ATIM",
+		"DISASSOC", "AUTH",
+		"DEAUTH", "ACTION",
+		"ACTION NO ACK"};
+
+	char *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	len += scnprintf(buf + len, size - len, "Tx mgmt stats:\n");
+	for (i = 0; i < IEEE80211_MGMT_FRM_TYPE_NUM_MAX - 1; i++) {
+		if (!mgmt_frame[i])
+			continue;
+		len += scnprintf(buf + len, size - len, "%s\t%u\n",
+				 mgmt_frame[i], local->tx_mgmt_pkts[i]);
+	}
+
+	len += scnprintf(buf + len, size - len, "\nRx mgmt stats:\n");
+	for (i = 0; i < IEEE80211_MGMT_FRM_TYPE_NUM_MAX - 1; i++) {
+		if (!mgmt_frame[i])
+			continue;
+		len += scnprintf(buf + len, size - len, "%s\t%u\n",
+				 mgmt_frame[i], local->rx_mgmt_pkts[i]);
+	}
+
+	len += scnprintf(buf + len, size - len, "\nTx mgmt completion success:\n");
+	for (i = 0; i < IEEE80211_MGMT_FRM_TYPE_NUM_MAX - 1; i++) {
+		if (!mgmt_frame[i])
+			continue;
+		len += scnprintf(buf + len, size - len, "%s\t%u\n",
+				 mgmt_frame[i], local->mgmt_tx_compl_succ[i]);
+	}
+
+	len += scnprintf(buf + len, size - len, "\nTx mgmt completion failure:\n");
+	for (i = 0; i < IEEE80211_MGMT_FRM_TYPE_NUM_MAX - 1; i++) {
+		if (!mgmt_frame[i])
+			continue;
+		len += scnprintf(buf + len, size - len, "%s\t%u\n",
+				 mgmt_frame[i], local->mgmt_tx_compl_fail[i]);
+	}
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+
+static const struct file_operations stats_mgmt_frame_ops = {
+	.read = mgmt_frame_read,
+	.open = simple_open,
+	.llseek = default_llseek,
+};
+#endif
+
 void debugfs_hw_add(struct ieee80211_local *local)
 {
 	struct dentry *phyd = local->hw.wiphy->debugfsdir;
@@ -692,6 +755,7 @@  void debugfs_hw_add(struct ieee80211_local *local)
 	DEBUGFS_STATS_ADD(rx_expand_skb_head_defrag);
 	DEBUGFS_STATS_ADD(rx_handlers_fragments);
 	DEBUGFS_STATS_ADD(tx_status_drop);
+	DEBUGFS_DEVSTATS_ADD(mgmt_frame);
 #endif
 	DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
 	DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9f0db39b28ff..8418acb8333f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1547,8 +1547,19 @@  struct ieee80211_local {
 	unsigned int rx_expand_skb_head_defrag;
 	unsigned int rx_handlers_fragments;
 	unsigned int tx_status_drop;
+
+	/* Management Frame statistics */
+#define IEEE80211_MGMT_FRM_TYPE_NUM_MAX	16
+	u32 tx_mgmt_pkts[IEEE80211_MGMT_FRM_TYPE_NUM_MAX];
+	u32 rx_mgmt_pkts[IEEE80211_MGMT_FRM_TYPE_NUM_MAX];
+	u32 mgmt_tx_compl_succ[IEEE80211_MGMT_FRM_TYPE_NUM_MAX];
+	u32 mgmt_tx_compl_fail[IEEE80211_MGMT_FRM_TYPE_NUM_MAX];
+
+#define I802_DEBUG_MGMT_STATS(_skb, _local, _type) \
+	ieee80211_mgmt_stats_update(_skb, (_local)->(_type))
 #define I802_DEBUG_INC(c) (c)++
 #else /* CONFIG_MAC80211_DEBUG_COUNTERS */
+#define I802_DEBUG_MGMT_STATS(skb, local, type) do { } while (0)
 #define I802_DEBUG_INC(c) do { } while (0)
 #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
 
@@ -2781,4 +2792,19 @@  void ieee80211_rearrange_tpe_psd(struct ieee80211_parsed_tpe_psd *psd,
 #define VISIBLE_IF_MAC80211_KUNIT static
 #endif
 
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+static inline void ieee80211_mgmt_stats_update(struct sk_buff *skb,
+					       u32 *mgmt_stats_type)
+{
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+	u16 stype;
+
+	if (!ieee80211_is_mgmt(mgmt->frame_control))
+		return;
+
+	stype = le16_get_bits(mgmt->frame_control, IEEE80211_FCTL_STYPE);
+	mgmt_stats_type[stype]++;
+}
+#endif
+
 #endif /* IEEE80211_I_H */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 2bec18fc1b03..acc40aa3e3e4 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3427,6 +3427,8 @@  ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
 	if (!ieee80211_is_mgmt(mgmt->frame_control))
 		return RX_DROP_MONITOR;
 
+	I802_DEBUG_MGMT_STATS(rx->skb, rx->local, rx_mgmt_pkts);
+
 	/* drop too small action frames */
 	if (ieee80211_is_action(mgmt->frame_control) &&
 	    rx->skb->len < IEEE80211_MIN_ACTION_SIZE)
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 5f28f3633fa0..d4ccf3cb484b 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -1063,6 +1063,7 @@  static void __ieee80211_tx_status(struct ieee80211_hw *hw,
 			if (retry_count > 1)
 				I802_DEBUG_INC(local->dot11MultipleRetryCount);
 		}
+		I802_DEBUG_MGMT_STATS(skb, local, mgmt_tx_compl_succ);
 
 		/* This counter shall be incremented for an acknowledged MPDU
 		 * with an individual address in the address 1 field or an MPDU
@@ -1075,6 +1076,7 @@  static void __ieee80211_tx_status(struct ieee80211_hw *hw,
 	} else {
 		if (ieee80211_is_first_frag(hdr->seq_ctrl))
 			I802_DEBUG_INC(local->dot11FailedCount);
+		I802_DEBUG_MGMT_STATS(skb, local, mgmt_tx_compl_fail);
 	}
 
 	if (ieee80211_is_any_nullfunc(fc) &&
@@ -1238,6 +1240,7 @@  void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
 
 	if (acked || noack_success) {
 		I802_DEBUG_INC(local->dot11TransmittedFrameCount);
+		I802_DEBUG_MGMT_STATS(skb, local, mgmt_tx_compl_succ);
 		if (!pubsta)
 			I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
 		if (retry_count > 0)
@@ -1246,6 +1249,7 @@  void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
 			I802_DEBUG_INC(local->dot11MultipleRetryCount);
 	} else {
 		I802_DEBUG_INC(local->dot11FailedCount);
+		I802_DEBUG_MGMT_STATS(skb, local, mgmt_tx_compl_succ);
 	}
 
 free:
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a24636bda679..173cdbca01ab 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1833,6 +1833,8 @@  static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx)
 		return -1;
 	}
 
+	I802_DEBUG_MGMT_STATS(tx->skb, tx->local, tx_mgmt_pkts);
+
 	return 0;
 }