Date: Mon, 24 Feb 2025 20:27:18 GMT From: "Bjoern A. Zeeb" <bz@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: a960f6e71743 - stable/14 - LinuxKPI: 802.11: dump station_info using (*sta_statistics)() as sysctl Message-ID: <202502242027.51OKRIsJ027530@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/14 has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=a960f6e717438983da18a03786531c97a41253d3 commit a960f6e717438983da18a03786531c97a41253d3 Author: Bjoern A. Zeeb <bz@FreeBSD.org> AuthorDate: 2024-12-30 06:35:03 +0000 Commit: Bjoern A. Zeeb <bz@FreeBSD.org> CommitDate: 2025-02-24 20:26:49 +0000 LinuxKPI: 802.11: dump station_info using (*sta_statistics)() as sysctl Implement the mac80211 (*sta_statistics) to obtain station statistics. Fix up struct station_info for that. Add supporting funtions to decode station_info and rate_info_bw fields to make the output more usable to human beings. Add a per-VIF (VAP) sysctl to export that information. This is mostly used for now to see what the driver/fw thinks about its TX rate. We should later gather this information in different ways and pass it to net80211 to export it to user space so we can finally have nice station information (also for the non-AP side). Sponsored by: The FreeBSD Foundation (cherry picked from commit 408394185fe9be0c158189b7671bde316ac14ac9) --- sys/compat/linuxkpi/common/include/linux/nl80211.h | 1 + sys/compat/linuxkpi/common/include/net/cfg80211.h | 38 +++- sys/compat/linuxkpi/common/src/linux_80211.c | 221 ++++++++++++++++++++- sys/compat/linuxkpi/common/src/linux_80211.h | 5 +- .../linuxkpi/common/src/linux_80211_macops.c | 30 +++ 5 files changed, 283 insertions(+), 12 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/nl80211.h b/sys/compat/linuxkpi/common/include/linux/nl80211.h index 1babd23d65fe..80546e56f0c1 100644 --- a/sys/compat/linuxkpi/common/include/linux/nl80211.h +++ b/sys/compat/linuxkpi/common/include/linux/nl80211.h @@ -247,6 +247,7 @@ enum nl80211_ext_feature { NUM_NL80211_EXT_FEATURES }; +/* Keep in order with lkpi_nl80211_sta_info_to_str() */ enum nl80211_sta_info { /* XXX TODO */ NL80211_STA_INFO_BEACON_RX, diff --git a/sys/compat/linuxkpi/common/include/net/cfg80211.h b/sys/compat/linuxkpi/common/include/net/cfg80211.h index cf1e05dde7ea..338ffb82bd83 100644 --- a/sys/compat/linuxkpi/common/include/net/cfg80211.h +++ b/sys/compat/linuxkpi/common/include/net/cfg80211.h @@ -81,6 +81,9 @@ enum cfg80211_rate_info_flags { /* Max 8 bits as used in struct rate_info. */ }; +#define CFG80211_RATE_INFO_FLAGS_BITS \ + "\20\1MCS\2VHT_MCS\3SGI\5HE_MCS\10EHT_MCS" + extern const uint8_t rfc1042_header[6]; extern const uint8_t bridge_tunnel_header[6]; @@ -164,7 +167,7 @@ enum rate_info_bw { struct rate_info { uint8_t flags; /* enum cfg80211_rate_info_flags */ - uint8_t bw; + uint8_t bw; /* enum rate_info_bw */ uint16_t legacy; uint8_t mcs; uint8_t nss; @@ -546,18 +549,39 @@ struct station_del_parameters { }; struct station_info { - /* TODO FIXME */ - int assoc_req_ies_len, connected_time; - int generation, inactive_time, rx_bytes, rx_dropped_misc, rx_packets, signal, tx_bytes, tx_packets; - int filled, rx_beacon, rx_beacon_signal_avg, signal_avg; - int rx_duration, tx_duration, tx_failed, tx_retries; - int ack_signal, avg_ack_signal; + uint64_t filled; /* enum nl80211_sta_info */ + uint32_t connected_time; + uint32_t inactive_time; + + uint64_t rx_bytes; + uint32_t rx_packets; + uint32_t rx_dropped_misc; + + uint64_t rx_duration; + uint32_t rx_beacon; + uint8_t rx_beacon_signal_avg; + + int8_t signal; + int8_t signal_avg; + int8_t ack_signal; + int8_t avg_ack_signal; + + /* gap */ + int generation; + + uint64_t tx_bytes; + uint32_t tx_packets; + uint32_t tx_failed; + uint64_t tx_duration; + uint32_t tx_retries; int chains; uint8_t chain_signal[IEEE80211_MAX_CHAINS]; uint8_t chain_signal_avg[IEEE80211_MAX_CHAINS]; uint8_t *assoc_req_ies; + size_t assoc_req_ies_len; + struct rate_info rxrate; struct rate_info txrate; struct cfg80211_ibss_params bss_param; diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c index 853d77fd4a96..b276f502be76 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -47,6 +47,7 @@ #include <sys/malloc.h> #include <sys/module.h> #include <sys/mutex.h> +#include <sys/sbuf.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <sys/queue.h> @@ -88,14 +89,14 @@ static MALLOC_DEFINE(M_LKPI80211, "lkpi80211", "LinuxKPI 80211 compat"); /* -------------------------------------------------------------------------- */ -/* Keep public for as long as header files are using it too. */ -int linuxkpi_debug_80211; - -#ifdef LINUXKPI_DEBUG_80211 SYSCTL_DECL(_compat_linuxkpi); SYSCTL_NODE(_compat_linuxkpi, OID_AUTO, 80211, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "LinuxKPI 802.11 compatibility layer"); +/* Keep public for as long as header files are using it too. */ +int linuxkpi_debug_80211; + +#ifdef LINUXKPI_DEBUG_80211 SYSCTL_INT(_compat_linuxkpi_80211, OID_AUTO, debug, CTLFLAG_RWTUN, &linuxkpi_debug_80211, 0, "LinuxKPI 802.11 debug level"); @@ -154,6 +155,200 @@ static void lkpi_ieee80211_free_skb_mbuf(void *); static int lkpi_wme_update(struct lkpi_hw *, struct ieee80211vap *, bool); #endif +static const char * +lkpi_rate_info_bw_to_str(enum rate_info_bw bw) +{ + + switch (bw) { + + case RATE_INFO_BW_20: + return ("20"); + break; + case RATE_INFO_BW_5: + return ("5"); + break; + case RATE_INFO_BW_10: + return ("10"); + break; + case RATE_INFO_BW_40: + return ("40"); + break; + case RATE_INFO_BW_80: + return ("80"); + break; + case RATE_INFO_BW_160: + return ("160"); + break; + case RATE_INFO_BW_HE_RU: + IMPROVE("nl80211_he_ru_alloc"); + return ("HE_RU"); + break; + case RATE_INFO_BW_320: + return ("320"); + break; + case RATE_INFO_BW_EHT_RU: + IMPROVE("nl80211_eht_ru_alloc"); + return ("EHT_RU"); + break; + default: + return ("?"); + break; + } +} + +static void +lkpi_nl80211_sta_info_to_str(struct sbuf *s, const char *prefix, + const uint64_t flags) +{ + int bit, i; + + sbuf_printf(s, "%s %#010jx", prefix, flags); + + i = 0; + for (bit = 0; bit < BITS_PER_TYPE(flags); bit++) { + + if ((flags & BIT_ULL(bit)) == 0) + continue; + +#define EXPAND_CASE(_flag) \ + case NL80211_STA_INFO_ ## _flag: \ + sbuf_printf(s, "%c%s", (i == 0) ? '<' : ',', #_flag); \ + i++; \ + break; + + switch (bit) { + EXPAND_CASE(BEACON_RX) + EXPAND_CASE(BEACON_SIGNAL_AVG) + EXPAND_CASE(BSS_PARAM) + EXPAND_CASE(CHAIN_SIGNAL) + EXPAND_CASE(CHAIN_SIGNAL_AVG) + EXPAND_CASE(CONNECTED_TIME) + EXPAND_CASE(INACTIVE_TIME) + EXPAND_CASE(SIGNAL) + EXPAND_CASE(SIGNAL_AVG) + EXPAND_CASE(STA_FLAGS) + EXPAND_CASE(RX_BITRATE) + EXPAND_CASE(RX_PACKETS) + EXPAND_CASE(RX_BYTES) + EXPAND_CASE(RX_DROP_MISC) + EXPAND_CASE(TX_BITRATE) + EXPAND_CASE(TX_PACKETS) + EXPAND_CASE(TX_BYTES) + EXPAND_CASE(TX_BYTES64) + EXPAND_CASE(RX_BYTES64) + EXPAND_CASE(TX_FAILED) + EXPAND_CASE(TX_RETRIES) + EXPAND_CASE(RX_DURATION) + EXPAND_CASE(TX_DURATION) + EXPAND_CASE(ACK_SIGNAL) + EXPAND_CASE(ACK_SIGNAL_AVG) + default: + sbuf_printf(s, "%c?%d", (i == 0) ? '<' : ',', bit); + break; + } + } +#undef EXPAND_CASE + if (i > 0) + sbuf_printf(s, ">"); + sbuf_printf(s, "\n"); +} + +static int +lkpi_80211_dump_stas(SYSCTL_HANDLER_ARGS) +{ + struct lkpi_hw *lhw; + struct ieee80211_hw *hw; + struct ieee80211vap *vap; + struct lkpi_vif *lvif; + struct ieee80211_vif *vif; + struct lkpi_sta *lsta; + struct ieee80211_sta *sta; + struct station_info sinfo; + struct sbuf s; + int error; + + if (req->newptr) + return (EPERM); + + lvif = (struct lkpi_vif *)arg1; + vif = LVIF_TO_VIF(lvif); + vap = LVIF_TO_VAP(lvif); + lhw = vap->iv_ic->ic_softc; + hw = LHW_TO_HW(lhw); + + sbuf_new_for_sysctl(&s, NULL, 1024, req); + + wiphy_lock(hw->wiphy); + TAILQ_FOREACH(lsta, &lvif->lsta_head, lsta_entry) { + sta = LSTA_TO_STA(lsta); + + sbuf_putc(&s, '\n'); + sbuf_printf(&s, "lsta %p sta %p added_to_drv %d\n", lsta, sta, lsta->added_to_drv); + + memset(&sinfo, 0, sizeof(sinfo)); + error = lkpi_80211_mo_sta_statistics(hw, vif, sta, &sinfo); + if (error == EEXIST) /* Not added to driver. */ + continue; + if (error == ENOTSUPP) { + sbuf_printf(&s, " sta_statistics not supported\n"); + continue; + } + if (error != 0) { + sbuf_printf(&s, " sta_statistics failed: %d\n", error); + continue; + } + + lkpi_nl80211_sta_info_to_str(&s, " nl80211_sta_info (valid fields)", sinfo.filled); + sbuf_printf(&s, " connected_time %u inactive_time %u\n", + sinfo.connected_time, sinfo.inactive_time); + sbuf_printf(&s, " rx_bytes %ju rx_packets %u rx_dropped_misc %u\n", + (uintmax_t)sinfo.rx_bytes, sinfo.rx_packets, sinfo.rx_dropped_misc); + sbuf_printf(&s, " rx_duration %ju rx_beacon %u rx_beacon_signal_avg %d\n", + (uintmax_t)sinfo.rx_duration, sinfo.rx_beacon, (int8_t)sinfo.rx_beacon_signal_avg); + + sbuf_printf(&s, " tx_bytes %ju tx_packets %u tx_failed %u\n", + (uintmax_t)sinfo.tx_bytes, sinfo.tx_packets, sinfo.tx_failed); + sbuf_printf(&s, " tx_duration %ju tx_retries %u\n", + (uintmax_t)sinfo.tx_duration, sinfo.tx_retries); + + sbuf_printf(&s, " signal %d signal_avg %d ack_signal %d avg_ack_signal %d\n", + sinfo.signal, sinfo.signal_avg, sinfo.ack_signal, sinfo.avg_ack_signal); + + sbuf_printf(&s, " generation %d assoc_req_ies_len %zu chains %d\n", + sinfo.generation, sinfo.assoc_req_ies_len, sinfo.chains); + + for (int i = 0; i < sinfo.chains && i < IEEE80211_MAX_CHAINS; i++) { + sbuf_printf(&s, " chain[%d] signal %d signal_avg %d\n", + i, (int8_t)sinfo.chain_signal[i], (int8_t)sinfo.chain_signal_avg[i]); + } + + /* assoc_req_ies, bss_param, sta_flags */ + + sbuf_printf(&s, " rxrate: flags %b bw %u(%s) legacy %u kbit/s mcs %u nss %u\n", + sinfo.rxrate.flags, CFG80211_RATE_INFO_FLAGS_BITS, + sinfo.rxrate.bw, lkpi_rate_info_bw_to_str(sinfo.rxrate.bw), + sinfo.rxrate.legacy * 100, + sinfo.rxrate.mcs, sinfo.rxrate.nss); + sbuf_printf(&s, " he_dcm %u he_gi %u he_ru_alloc %u eht_gi %u\n", + sinfo.rxrate.he_dcm, sinfo.rxrate.he_gi, sinfo.rxrate.he_ru_alloc, + sinfo.rxrate.eht_gi); + sbuf_printf(&s, " txrate: flags %b bw %u(%s) legacy %u kbit/s mcs %u nss %u\n", + sinfo.txrate.flags, CFG80211_RATE_INFO_FLAGS_BITS, + sinfo.txrate.bw, lkpi_rate_info_bw_to_str(sinfo.txrate.bw), + sinfo.txrate.legacy * 100, + sinfo.txrate.mcs, sinfo.txrate.nss); + sbuf_printf(&s, " he_dcm %u he_gi %u he_ru_alloc %u eht_gi %u\n", + sinfo.txrate.he_dcm, sinfo.txrate.he_gi, sinfo.txrate.he_ru_alloc, + sinfo.txrate.eht_gi); + } + wiphy_unlock(hw->wiphy); + + sbuf_finish(&s); + sbuf_delete(&s); + + return (0); +} + #if defined(LKPI_80211_HT) static void lkpi_sta_sync_ht_from_ni(struct ieee80211_sta *sta, struct ieee80211_node *ni, int *ht_rx_nss) @@ -2803,6 +2998,7 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], struct ieee80211_vif *vif; struct ieee80211_tx_queue_params txqp; enum ieee80211_bss_changed changed; + struct sysctl_oid *node; size_t len; int error, i; uint16_t ac; @@ -2976,6 +3172,20 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], hw->wiphy->rts_threshold = vap->iv_rtsthreshold; lkpi_80211_mo_set_rts_threshold(hw, vap->iv_rtsthreshold); /* any others? */ + + /* Add per-VIF/VAP sysctls. */ + sysctl_ctx_init(&lvif->sysctl_ctx); + + node = SYSCTL_ADD_NODE(&lvif->sysctl_ctx, + SYSCTL_CHILDREN(&sysctl___compat_linuxkpi_80211), + OID_AUTO, if_name(vap->iv_ifp), + CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_MPSAFE, NULL, "VIF Information"); + + SYSCTL_ADD_PROC(&lvif->sysctl_ctx, + SYSCTL_CHILDREN(node), OID_AUTO, "dump_stas", + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, lvif, 0, + lkpi_80211_dump_stas, "A", "Dump sta statistics of this vif"); + IMPROVE(); return (vap); @@ -3015,6 +3225,9 @@ lkpi_ic_vap_delete(struct ieee80211vap *vap) EVENTHANDLER_DEREGISTER(iflladdr_event, lvif->lvif_ifllevent); + /* Clear up per-VIF/VAP sysctls. */ + sysctl_ctx_free(&lvif->sysctl_ctx); + LKPI_80211_LHW_LVIF_LOCK(lhw); TAILQ_REMOVE(&lhw->lvif_head, lvif, lvif_entry); LKPI_80211_LHW_LVIF_UNLOCK(lhw); diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h index 0c4c615d82e5..bb1ecb45636f 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.h +++ b/sys/compat/linuxkpi/common/src/linux_80211.h @@ -168,6 +168,8 @@ struct lkpi_vif { struct ieee80211vap iv_vap; eventhandler_tag lvif_ifllevent; + struct sysctl_ctx_list sysctl_ctx; + struct mtx mtx; struct wireless_dev wdev; @@ -442,6 +444,7 @@ int lkpi_80211_mo_set_key(struct ieee80211_hw *, enum set_key_cmd, struct ieee80211_key_conf *); int lkpi_80211_mo_ampdu_action(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_ampdu_params *); - +int lkpi_80211_mo_sta_statistics(struct ieee80211_hw *, struct ieee80211_vif *, + struct ieee80211_sta *, struct station_info *); #endif /* _LKPI_SRC_LINUX_80211_H */ diff --git a/sys/compat/linuxkpi/common/src/linux_80211_macops.c b/sys/compat/linuxkpi/common/src/linux_80211_macops.c index e60ccbdeb4ce..7440d1d3c26c 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211_macops.c +++ b/sys/compat/linuxkpi/common/src/linux_80211_macops.c @@ -718,3 +718,33 @@ lkpi_80211_mo_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, out: return (error); } + +int +lkpi_80211_mo_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct station_info *sinfo) +{ + struct lkpi_hw *lhw; + struct lkpi_sta *lsta; + int error; + + lhw = HW_TO_LHW(hw); + if (lhw->ops->sta_statistics == NULL) { + error = EOPNOTSUPP; + goto out; + } + + lsta = STA_TO_LSTA(sta); + if (!lsta->added_to_drv) { + error = EEXIST; + goto out; + } + + lockdep_assert_wiphy(hw->wiphy); + + LKPI_80211_TRACE_MO("hw %p vif %p sta %p sinfo %p", hw, vif, sta, sinfo); + lhw->ops->sta_statistics(hw, vif, sta, sinfo); + error = 0; + +out: + return (error); +}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502242027.51OKRIsJ027530>