2021-03-24 18:16:36

by Ben Greear

[permalink] [raw]
Subject: [PATCH-v2 1/6] mac80211: Fix station rx-packets counters.

From: Ben Greear <[email protected]>

I noticed 'iw dev wlan6 station dump' showed almost no rx-packets
one one of my radios. The rx-amsdu path did not appear to gather
any stats, and after code inspection, neither did the rx-data
handler.

Add common method to deal with these stats. Verified in AX
and /a mode, stats look at least generally correct now.

Signed-off-by: Ben Greear <[email protected]>
---
net/mac80211/rx.c | 54 ++++++++++++++++++++++++++++++++---------------
1 file changed, 37 insertions(+), 17 deletions(-)

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index eb8225209005..4a64c2183a27 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1713,6 +1713,27 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
}

+static void ieee80211_update_data_rx_stats(struct ieee80211_rx_data *rx,
+ struct ieee80211_sta_rx_stats *stats,
+ struct ieee80211_rx_status *status,
+ int skb_len)
+{
+ stats->fragments++;
+ stats->packets++;
+ stats->last_rx = jiffies;
+ stats->last_rate = sta_stats_encode_rate(status);
+
+ /* The seqno index has the same property as needed
+ * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
+ * for non-QoS-data frames. Here we know it's a data
+ * frame, so count MSDUs.
+ */
+ u64_stats_update_begin(&stats->syncp);
+ stats->msdu[rx->seqno_idx]++;
+ stats->bytes += skb_len;
+ u64_stats_update_end(&stats->syncp);
+}
+
static ieee80211_rx_result debug_noinline
ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
{
@@ -2706,6 +2727,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
+ ieee80211_rx_result rv;
+ int orig_len = skb->len;

if (!(status->rx_flags & IEEE80211_RX_AMSDU))
return RX_CONTINUE;
@@ -2734,7 +2757,12 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
if (is_multicast_ether_addr(hdr->addr1))
return RX_DROP_UNUSABLE;

- return __ieee80211_rx_h_amsdu(rx, 0);
+ rv = __ieee80211_rx_h_amsdu(rx, 0);
+ if ((rv == RX_QUEUED) && (rx->sta)) {
+ struct ieee80211_sta_rx_stats *stats = &rx->sta->rx_stats;
+ ieee80211_update_data_rx_stats(rx, stats, status, orig_len);
+ }
+ return rv;
}

#ifdef CONFIG_MAC80211_MESH
@@ -2958,6 +2986,13 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));

+
+ if (rx->sta) {
+ struct ieee80211_sta_rx_stats *stats = &rx->sta->rx_stats;
+ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
+ ieee80211_update_data_rx_stats(rx, stats, status, rx->skb->len);
+ }
+
ieee80211_deliver_skb(rx);

return RX_QUEUED;
@@ -4400,12 +4435,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
return true;
}

- stats->last_rx = jiffies;
- stats->last_rate = sta_stats_encode_rate(status);
-
- stats->fragments++;
- stats->packets++;
-
/* do the header conversion - first grab the addresses */
ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs);
ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs);
@@ -4416,18 +4445,9 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,

skb->dev = fast_rx->dev;

+ ieee80211_update_data_rx_stats(rx, stats, status, orig_len);
dev_sw_netstats_rx_add(fast_rx->dev, skb->len);

- /* The seqno index has the same property as needed
- * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
- * for non-QoS-data frames. Here we know it's a data
- * frame, so count MSDUs.
- */
- u64_stats_update_begin(&stats->syncp);
- stats->msdu[rx->seqno_idx]++;
- stats->bytes += orig_len;
- u64_stats_update_end(&stats->syncp);
-
if (fast_rx->internal_forward) {
struct sk_buff *xmit_skb = NULL;
if (is_multicast_ether_addr(addrs.da)) {
--
2.20.1


2021-03-24 18:16:51

by Ben Greear

[permalink] [raw]
Subject: [PATCH-v2 5/6] mac80211: Add some additional tx-stats to debugfs

From: Ben Greear <[email protected]>

Give a better idea of TX behaviour. Currently this code does not
deal with HE tx rates properly. I'm not sure exactly where to
find that info, not sure that ax200 driver that I'm testing properly
provides it up to the tx-status logic.

Signed-off-by: Ben Greear <[email protected]>
---
net/mac80211/debugfs_sta.c | 24 ++++++++++++++++++-
net/mac80211/rx.c | 1 +
net/mac80211/sta_info.h | 16 +++++++++++++
net/mac80211/status.c | 47 ++++++++++++++++++++++++++++++++++++++
4 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 9dd29fe94bde..ed6380bb6270 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -107,7 +107,7 @@ static ssize_t sta_stats_read(struct file *file, char __user *userbuf,
{
struct sta_info *sta = file->private_data;
unsigned int len = 0;
- const int buf_len = 8000;
+ const int buf_len = 12000;
char *buf = kzalloc(buf_len, GFP_KERNEL);
unsigned long sum;
char tmp[60];
@@ -186,6 +186,7 @@ static ssize_t sta_stats_read(struct file *file, char __user *userbuf,
PRINT_MY_STATS("rx-bw-40", rx_stats.msdu_40);
PRINT_MY_STATS("rx-bw-80", rx_stats.msdu_80);
PRINT_MY_STATS("rx-bw-160", rx_stats.msdu_160);
+ PRINT_MY_STATS("rx-bw-he-ru", rx_stats.msdu_he_ru);

PRINT_MY_STATS("rx-he-total", rx_stats.msdu_he_tot);
PRINT_MY_STATS("rx-he-su", rx_stats.msdu_he_su);
@@ -213,6 +214,27 @@ static ssize_t sta_stats_read(struct file *file, char __user *userbuf,
sprintf(tmp, "rx-rate-idx[%3i]", i);
PRINT_MY_STATS(tmp, rx_stats.msdu_rate_idx[i]);
}
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ PRINT_MY_STATS("tx-bw-20", sta->tx_stats.msdu_20);
+ PRINT_MY_STATS("tx-bw-40", sta->tx_stats.msdu_40);
+ PRINT_MY_STATS("tx-bw-80", sta->tx_stats.msdu_80);
+ PRINT_MY_STATS("tx-bw-160", sta->tx_stats.msdu_160);
+ PRINT_MY_STATS("tx-bw-he-ru", sta->tx_stats.msdu_he_ru);
+
+ PRINT_MY_STATS("tx-vht", sta->tx_stats.msdu_vht);
+ PRINT_MY_STATS("tx-ht", sta->tx_stats.msdu_ht);
+ PRINT_MY_STATS("tx-legacy", sta->tx_stats.msdu_legacy);
+
+ for (i = 0; i < ARRAY_SIZE(sta->tx_stats.msdu_nss); i++) {
+ sprintf(tmp, "tx-msdu-nss[%i]", i);
+ PRINT_MY_STATS(tmp, sta->tx_stats.msdu_nss[i]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sta->tx_stats.msdu_rate_idx); i++) {
+ sprintf(tmp, "tx-rate-idx[%3i]", i);
+ PRINT_MY_STATS(tmp, sta->tx_stats.msdu_rate_idx[i]);
+ }
#endif

#undef PRINT_MY_STATS
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index c83428b5bb5a..be05abc77292 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1767,6 +1767,7 @@ static void ieee80211_update_data_rx_stats(struct ieee80211_rx_data *rx,
stats->msdu_160++;
break;
case RATE_INFO_BW_HE_RU:
+ stats->msdu_he_ru++;
stats->msdu_he_ru_alloc[status->he_ru]++;
break;
};
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 90fcebf199ad..6fc6ad6248e6 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -445,6 +445,7 @@ struct ieee80211_sta_rx_stats {
u32 msdu_40;
u32 msdu_80;
u32 msdu_160;
+ u32 msdu_he_ru;
u32 msdu_he_ru_alloc[NL80211_RATE_INFO_HE_RU_ALLOC_LAST];
u32 msdu_he_tot;
u32 msdu_he_su;
@@ -636,6 +637,21 @@ struct sta_info {
struct ieee80211_tx_rate last_rate;
struct rate_info last_rate_info;
u64 msdu[IEEE80211_NUM_TIDS + 1];
+#ifdef CONFIG_MAC80211_DEBUG_STA_COUNTERS
+ /* these take liberty with how things are defined, and are
+ * designed to give a rough idea of how things are going.
+ */
+ u32 msdu_20;
+ u32 msdu_40;
+ u32 msdu_80;
+ u32 msdu_160;
+ u32 msdu_he_ru;
+ u32 msdu_vht;
+ u32 msdu_ht;
+ u32 msdu_legacy;
+ u32 msdu_nss[8];
+ u32 msdu_rate_idx[13];
+#endif
} tx_stats;
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];

diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 3460154cf4fe..e7ee13f82355 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -1112,6 +1112,9 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,

if (pubsta) {
struct ieee80211_sub_if_data *sdata = sta->sdata;
+#ifdef CONFIG_MAC80211_DEBUG_STA_COUNTERS
+ bool do_stats = false;
+#endif

if (!acked && !noack_success)
sta->status_stats.retry_failed++;
@@ -1124,6 +1127,9 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
acked, info->status.tx_time);

if (acked) {
+#ifdef CONFIG_MAC80211_DEBUG_STA_COUNTERS
+ do_stats = true;
+#endif
sta->status_stats.last_ack = jiffies;

if (sta->status_stats.lost_packets)
@@ -1154,11 +1160,52 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
return;
} else if (noack_success) {
/* nothing to do here, do not account as lost */
+#ifdef CONFIG_MAC80211_DEBUG_STA_COUNTERS
+ do_stats = true;
+#endif
} else {
ieee80211_lost_packet(sta, info);
}
}

+#ifdef CONFIG_MAC80211_DEBUG_STA_COUNTERS
+ if (do_stats && (rates_idx != -1)) {
+ u8 nss = 0;
+ u8 mcs = 0;
+ struct ieee80211_tx_rate *txrt = &(info->status.rates[rates_idx]);
+ if (txrt->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ sta->tx_stats.msdu_40++;
+ else if (txrt->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ sta->tx_stats.msdu_80++;
+ else if (txrt->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+ sta->tx_stats.msdu_160++;
+ else
+ sta->tx_stats.msdu_20++;
+
+ if (txrt->flags & IEEE80211_TX_RC_MCS) {
+ nss = (txrt->idx / 8);
+ mcs = txrt->idx - (nss * 8);
+ sta->tx_stats.msdu_ht++;
+ }
+ else if (txrt->flags & IEEE80211_TX_RC_VHT_MCS) {
+ mcs = ieee80211_rate_get_vht_mcs(txrt);
+ nss = ieee80211_rate_get_vht_nss(txrt);
+ nss -= 1;
+ sta->tx_stats.msdu_vht++;
+ }
+ else {
+ mcs = txrt->idx;
+ sta->tx_stats.msdu_legacy++;
+ }
+
+ if (nss > (ARRAY_SIZE(sta->tx_stats.msdu_nss) - 1))
+ nss = ARRAY_SIZE(sta->tx_stats.msdu_nss) - 1;
+ if (mcs > (ARRAY_SIZE(sta->tx_stats.msdu_rate_idx) - 1))
+ mcs = ARRAY_SIZE(sta->tx_stats.msdu_rate_idx) - 1;
+ sta->tx_stats.msdu_nss[nss]++;
+ sta->tx_stats.msdu_rate_idx[mcs]++;
+ }
+#endif
rate_control_tx_status(local, sband, status);
if (ieee80211_vif_is_mesh(&sta->sdata->vif))
ieee80211s_update_metric(local, sta, status);
--
2.20.1

2021-03-24 18:19:02

by Ben Greear

[permalink] [raw]
Subject: [PATCH-v2 6/6] mac80211: last_rate is 32-bit number.

From: Ben Greear <[email protected]>

Assign it to 32-bit holding variable instead of 16 when processing
the rx rate.

Signed-off-by: Ben Greear <[email protected]>
---
net/mac80211/sta_info.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 6dd62ba40133..a28a562a8fb4 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2246,7 +2246,7 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate,

static int sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
{
- u16 rate = READ_ONCE(sta_get_last_rx_stats(sta)->last_rate);
+ u32 rate = READ_ONCE(sta_get_last_rx_stats(sta)->last_rate);

if (rate == STA_STATS_RATE_INVALID)
return -EINVAL;
--
2.20.1

2021-03-24 18:19:02

by Ben Greear

[permalink] [raw]
Subject: [PATCH-v2 2/6] mac80211: Provide per-station stats in debugfs

From: Ben Greear <[email protected]>

Including per tid and per acs stats.

Nice for those who like to peer deep into the guts of a system.

Signed-off-by: Ben Greear <[email protected]>
---
net/mac80211/debugfs_sta.c | 88 ++++++++++++++++++++++++++++++++++++++
net/mac80211/sta_info.c | 33 ++++++++++++++
net/mac80211/sta_info.h | 4 ++
3 files changed, 125 insertions(+)

diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 1deacce85177..374db61527a9 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -102,6 +102,93 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
}
STA_OPS(flags);

+static ssize_t sta_stats_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct sta_info *sta = file->private_data;
+ unsigned int len = 0;
+ const int buf_len = 8000;
+ char *buf = kzalloc(buf_len, GFP_KERNEL);
+ unsigned long sum;
+ char tmp[60];
+ int i;
+ struct ieee80211_sta_rx_stats rx_stats = {0};
+
+ if (!buf)
+ return -ENOMEM;
+
+ sta_accum_rx_stats(sta, &rx_stats);
+
+#define PRINT_MY_STATS(a, b) do { \
+ len += scnprintf(buf + len, buf_len - len, "%30s %18lu\n", a, (unsigned long)(b)); \
+ if (len >= buf_len) { \
+ goto done; \
+ } \
+ } while (0)
+
+#define PRINT_MY_STATS_S(a, b) do { \
+ len += scnprintf(buf + len, buf_len - len, "%30s %18ld\n", a, (long)(b)); \
+ if (len >= buf_len) { \
+ goto done; \
+ } \
+ } while (0)
+
+ PRINT_MY_STATS("rx-packets", rx_stats.packets);
+ PRINT_MY_STATS("rx-bytes", rx_stats.bytes);
+ PRINT_MY_STATS("rx-dup", rx_stats.num_duplicates);
+ PRINT_MY_STATS("rx-fragments", rx_stats.fragments);
+ PRINT_MY_STATS("rx-dropped", rx_stats.dropped);
+ PRINT_MY_STATS_S("rx-last-signal", rx_stats.last_signal);
+
+ for (i = 0; i<IEEE80211_MAX_CHAINS; i++) {
+ if (rx_stats.chains & (1<<i)) {
+ sprintf(tmp, "rx-last-signal-chain[%i]", i);
+ PRINT_MY_STATS_S(tmp, rx_stats.chain_signal_last[i]);
+ }
+ }
+ PRINT_MY_STATS("rx-last-rate-encoded", rx_stats.last_rate);
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+
+ sum = sta->tx_stats.packets[0] + sta->tx_stats.packets[1]
+ + sta->tx_stats.packets[2] + sta->tx_stats.packets[3];
+ PRINT_MY_STATS("tx-packets", sum);
+
+ sum = sta->tx_stats.bytes[0] + sta->tx_stats.bytes[1]
+ + sta->tx_stats.bytes[2] + sta->tx_stats.bytes[3];
+ PRINT_MY_STATS("tx-bytes", sum);
+
+ /* per txq stats */
+ PRINT_MY_STATS("tx-packets-acs[VO]", sta->tx_stats.packets[IEEE80211_AC_VO]);
+ PRINT_MY_STATS("tx-packets-acs[VI]", sta->tx_stats.packets[IEEE80211_AC_VI]);
+ PRINT_MY_STATS("tx-packets-acs[BE]", sta->tx_stats.packets[IEEE80211_AC_BE]);
+ PRINT_MY_STATS("tx-packets-acs[BK]", sta->tx_stats.packets[IEEE80211_AC_BK]);
+
+ PRINT_MY_STATS("tx-bytes-acs[VO]", sta->tx_stats.bytes[IEEE80211_AC_VO]);
+ PRINT_MY_STATS("tx-bytes-acs[VI]", sta->tx_stats.bytes[IEEE80211_AC_VI]);
+ PRINT_MY_STATS("tx-bytes-acs[BE]", sta->tx_stats.bytes[IEEE80211_AC_BE]);
+ PRINT_MY_STATS("tx-bytes-acs[BK]", sta->tx_stats.bytes[IEEE80211_AC_BK]);
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ for (i = 0; i<=IEEE80211_NUM_TIDS; i++) {
+ sprintf(tmp, "tx-msdu-tid[%2i]", i);
+ PRINT_MY_STATS(tmp, sta->tx_stats.msdu[i]);
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ for (i = 0; i<=IEEE80211_NUM_TIDS; i++) {
+ sprintf(tmp, "rx-msdu-tid[%2i]", i);
+ PRINT_MY_STATS(tmp, rx_stats.msdu[i]);
+ }
+
+#undef PRINT_MY_STATS
+done:
+ i = simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
+ kfree(buf);
+ return i;
+}
+STA_OPS(stats);
+
static ssize_t sta_num_ps_buf_frames_read(struct file *file,
char __user *userbuf,
size_t count, loff_t *ppos)
@@ -1073,6 +1160,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
sta->debugfs_dir = debugfs_create_dir(mac, stations_dir);

DEBUGFS_ADD(flags);
+ DEBUGFS_ADD(stats);
DEBUGFS_ADD(aid);
DEBUGFS_ADD(num_ps_buf_frames);
DEBUGFS_ADD(last_seq_ctrl);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index b096370b45b1..aa95db547465 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2650,6 +2650,39 @@ static void sta_update_codel_params(struct sta_info *sta, u32 thr)
}
}

+void sta_accum_rx_stats(struct sta_info *sta,
+ struct ieee80211_sta_rx_stats *rx_stats)
+{
+ int cpu;
+ int i;
+
+ memcpy(rx_stats, &sta->rx_stats, sizeof(*rx_stats));
+
+ if (!sta->pcpu_rx_stats)
+ return;
+
+ for_each_possible_cpu(cpu) {
+ struct ieee80211_sta_rx_stats *cpurxs;
+
+ cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
+ rx_stats->packets += cpurxs->packets;
+ if (time_after(cpurxs->last_rx, rx_stats->last_rx)) {
+ rx_stats->last_rx = cpurxs->last_rx;
+ rx_stats->last_signal = cpurxs->last_signal;
+ for (i = 0; i<IEEE80211_MAX_CHAINS; i++)
+ rx_stats->chain_signal_last[i] = cpurxs->chain_signal_last[i];
+ rx_stats->last_rate = cpurxs->last_rate;
+ }
+ rx_stats->num_duplicates += cpurxs->num_duplicates;
+ rx_stats->fragments += cpurxs->fragments;
+ rx_stats->dropped += cpurxs->dropped;
+ rx_stats->bytes += sta_get_stats_bytes(cpurxs);
+ for (i = 0; i<=IEEE80211_NUM_TIDS; i++) {
+ rx_stats->msdu[i] += sta_get_tidstats_msdu(cpurxs, i);
+ }
+ }
+}
+
void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta,
u32 thr)
{
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 897b4d12103e..a6b13d749ffa 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -422,6 +422,7 @@ struct mesh_sta {

DECLARE_EWMA(signal, 10, 8)

+/* Update sta_accum_rx_stats if you change this structure. */
struct ieee80211_sta_rx_stats {
unsigned long packets;
unsigned long last_rx;
@@ -907,4 +908,7 @@ static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s)
return r;
}

+void sta_accum_rx_stats(struct sta_info *sta,
+ struct ieee80211_sta_rx_stats *rx_stats);
+
#endif /* STA_INFO_H */
--
2.20.1

2021-04-01 04:28:29

by Ben Greear

[permalink] [raw]
Subject: Re: [PATCH-v2 1/6] mac80211: Fix station rx-packets counters.

On 3/24/21 11:14 AM, [email protected] wrote:
> From: Ben Greear <[email protected]>
>
> I noticed 'iw dev wlan6 station dump' showed almost no rx-packets
> one one of my radios. The rx-amsdu path did not appear to gather
> any stats, and after code inspection, neither did the rx-data
> handler.
>
> Add common method to deal with these stats. Verified in AX
> and /a mode, stats look at least generally correct now.
>
> Signed-off-by: Ben Greear <[email protected]>
> ---

> @@ -2706,6 +2727,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
> struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
> struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> __le16 fc = hdr->frame_control;
> + ieee80211_rx_result rv;
> + int orig_len = skb->len;
>
> if (!(status->rx_flags & IEEE80211_RX_AMSDU))
> return RX_CONTINUE;
> @@ -2734,7 +2757,12 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
> if (is_multicast_ether_addr(hdr->addr1))
> return RX_DROP_UNUSABLE;
>
> - return __ieee80211_rx_h_amsdu(rx, 0);
> + rv = __ieee80211_rx_h_amsdu(rx, 0);
> + if ((rv == RX_QUEUED) && (rx->sta)) {
> + struct ieee80211_sta_rx_stats *stats = &rx->sta->rx_stats;
> + ieee80211_update_data_rx_stats(rx, stats, status, orig_len);
> + }
> + return rv;
> }

I noticed this is buggy in several ways (potential use-after-free, bogus
status field).

I noticed too that upcoming changes changed some API that made later patches
in this series not apply cleanly..needed a bit of re-work.

Maybe best if I wait and rebase it against 5.13 when it is ready, unless
someone is actually interested enough in this to want to apply it earlier?

Thanks,
Ben

--
Ben Greear <[email protected]>
Candela Technologies Inc http://www.candelatech.com