@@ -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);
@@ -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 */
@@ -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)
@@ -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:
@@ -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;
}