The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=38075f7d5c87176f7b317c368712444a2f450a5e
commit 38075f7d5c87176f7b317c368712444a2f450a5e Author: Adrian Chadd <adr...@freebsd.org> AuthorDate: 2025-01-02 03:52:25 +0000 Commit: Adrian Chadd <adr...@freebsd.org> CommitDate: 2025-02-26 19:29:09 +0000 net80211: remove direct use of ni->ni_txrate, add indirection methods The summary: * Refactor ni_txrate access into ieee80211_node_get_txrate_dot11rate() and ieee80211_node_set_txrate_dot11rate(). These wrap the ni->ni_txrate access and will eventually be able to do runtime sanity checks and fallback where necessary. * Refactor ieee80211_node_get_txrate_kbit() from the ioctl code which sets isi_txmbps (which is in 0.5Mbit/s units.) This new routine returns the TX rate in kbit/s units. * Also use ieee80211_node_get_txrate_kbit() in various places in the code where the dot11rate was turned into a Mbit/sec value, which was very wrong for HT (but also only used for logging, so it didn't have an effect on normal runtime.) * Mb -> Mbit/s The long version: The current ni->ni_txrate value is what net80211's phy code calls a 'dot11rate'. Inside the ieee80211_phy.c tables you'll find a bunch of tables which represent: * for legacy rates its in 1/2 mbit units. * for turbo (Atheros 40MHz OFDM) it's the non-turbo rates, but the turbo rate speed in kbit/sec. * for 802.11n rates its the MCS, starting at 0x80. However there are a couple of catches with this: * Basic rates are represented in the pre-11n rates using the high bit (IEEE80211_RATE_BASIC) * 11n rates are also represented using the high bit (IEEE80211_RATE_MCS) Now, ni->ni_txrate will clear the IEEE80211_RATE_BASIC flag before storing it, so if the high bit exists it must be an 802.11n rate. However, there's still a bunch of code everywhere that purposefully filters that out. The goals of this commit: * Provide an easy API to migrate existing drivers and other consumers to - ieee80211_node_get_txrate_dot11rate() is defined as "will return the normal legacy or HT rate" so all the existing code can work. * Lay the ground work for extending ni_txrate (and a rate representation in general) that can represent legacy, HT, VHT, EHT, HE, etc rates. * Create a central place where ni_txrate is updated from rate control, drivers that will update ni_txrate itself, and consumers, so we can provide some basic runtime checks / logging as VHT, EHT, HE, etc rates are eventually added. For example, a VHT driver will eventually receive VHT rates, but an existing HT driver will not, so the API should log and return a sensible default when something like a VHT rate shows up on a HT only device. The rate control code currently returns a rix, and sets ni_txrate to the dot11rate. Drivers can choose either. However, choosing the rix is risky because you need to know if it's the ni_rates or ni_htrates, which requires a lot of duplicate work that lines up consistently at all layers (see the AMRR code for an example.) Differential Revision: https://reviews.freebsd.org/D48601 Reviewed by: bz, thj --- sys/net80211/ieee80211.c | 2 +- sys/net80211/ieee80211_adhoc.c | 5 ++- sys/net80211/ieee80211_amrr.c | 14 +++++--- sys/net80211/ieee80211_hostap.c | 7 ++-- sys/net80211/ieee80211_ioctl.c | 20 ++--------- sys/net80211/ieee80211_mesh.c | 2 +- sys/net80211/ieee80211_node.c | 65 +++++++++++++++++++++++++++++++++++ sys/net80211/ieee80211_node.h | 6 ++++ sys/net80211/ieee80211_ratectl_none.c | 6 ++-- sys/net80211/ieee80211_rssadapt.c | 16 +++++---- sys/net80211/ieee80211_scan_sta.c | 2 +- sys/net80211/ieee80211_sta.c | 7 ++-- sys/net80211/ieee80211_superg.c | 10 +++--- 13 files changed, 112 insertions(+), 50 deletions(-) diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index 49d313e5077d..eb796462d3d1 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -2306,7 +2306,7 @@ ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) * In station mode report the current transmit rate. */ imr->ifm_active |= ieee80211_rate2media(ic, - vap->iv_bss->ni_txrate, mode); + ieee80211_node_get_txrate_dot11rate(vap->iv_bss), mode); } else imr->ifm_active |= IFM_AUTO; if (imr->ifm_status & IFM_ACTIVE) diff --git a/sys/net80211/ieee80211_adhoc.c b/sys/net80211/ieee80211_adhoc.c index d252b75899a2..77e5a2d99904 100644 --- a/sys/net80211/ieee80211_adhoc.c +++ b/sys/net80211/ieee80211_adhoc.c @@ -235,10 +235,9 @@ adhoc_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ether_sprintf(ni->ni_bssid)); ieee80211_print_essid(vap->iv_bss->ni_essid, ni->ni_esslen); - /* XXX MCS/HT */ - printf(" channel %d start %uMb\n", + printf(" channel %d start %uMbit/s\n", ieee80211_chan2ieee(ic, ic->ic_curchan), - IEEE80211_RATE2MBS(ni->ni_txrate)); + ieee80211_node_get_txrate_kbit(ni) / 1000); } #endif break; diff --git a/sys/net80211/ieee80211_amrr.c b/sys/net80211/ieee80211_amrr.c index 386a3de92a74..d366bf71e367 100644 --- a/sys/net80211/ieee80211_amrr.c +++ b/sys/net80211/ieee80211_amrr.c @@ -207,7 +207,7 @@ amrr_node_init(struct ieee80211_node *ni) rate |= IEEE80211_RATE_MCS; /* Assign initial rate from the rateset */ - ni->ni_txrate = rate; + ieee80211_node_set_txrate_dot11rate(ni, rate); amn->amn_ticks = ticks; /* XXX TODO: we really need a rate-to-string method */ @@ -321,7 +321,8 @@ amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused) /* XXX should return -1 here, but drivers may not expect this... */ if (!amn) { - ni->ni_txrate = ni->ni_rates.rs_rates[0]; + ieee80211_node_set_txrate_dot11rate(ni, + ni->ni_rates.rs_rates[0]); return 0; } @@ -338,13 +339,16 @@ amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused) if (is_enough(amn) && (ticks - amn->amn_ticks) > amrr->amrr_interval) { rix = amrr_update(amrr, amn, ni); if (rix != amn->amn_rix) { + uint8_t dot11Rate; /* update public rate */ - ni->ni_txrate = rs->rs_rates[rix]; + dot11Rate = rs->rs_rates[rix]; /* XXX strip basic rate flag from txrate, if non-11n */ if (ieee80211_ht_check_tx_ht(ni)) - ni->ni_txrate |= IEEE80211_RATE_MCS; + dot11Rate |= IEEE80211_RATE_MCS; else - ni->ni_txrate &= IEEE80211_RATE_VAL; + dot11Rate &= IEEE80211_RATE_VAL; + ieee80211_node_set_txrate_dot11rate(ni, dot11Rate); + amn->amn_rix = rix; } amn->amn_ticks = ticks; diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c index 1dce9a6b5923..76c419f5bdf8 100644 --- a/sys/net80211/ieee80211_hostap.c +++ b/sys/net80211/ieee80211_hostap.c @@ -63,8 +63,6 @@ #include <net80211/ieee80211_vht.h> #include <net80211/ieee80211_sta.h> /* for parse_wmeie */ -#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) - static void hostap_vattach(struct ieee80211vap *); static int hostap_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int hostap_input(struct ieee80211_node *ni, struct mbuf *m, @@ -311,10 +309,9 @@ hostap_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ether_sprintf(ni->ni_bssid)); ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); - /* XXX MCS/HT */ - printf(" channel %d start %uMb\n", + printf(" channel %d start %uMbit/s\n", ieee80211_chan2ieee(ic, ic->ic_curchan), - IEEE80211_RATE2MBS(ni->ni_txrate)); + ieee80211_node_get_txrate_kbit(ni) / 1000); } #endif break; diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c index 3b57e7d8cd8e..24ec9659dc2d 100644 --- a/sys/net80211/ieee80211_ioctl.c +++ b/sys/net80211/ieee80211_ioctl.c @@ -406,23 +406,9 @@ get_sta_info(void *arg, struct ieee80211_node *ni) if (si->isi_nrates > 15) si->isi_nrates = 15; memcpy(si->isi_rates, ni->ni_rates.rs_rates, si->isi_nrates); - si->isi_txrate = ni->ni_txrate; - if (si->isi_txrate & IEEE80211_RATE_MCS) { - const struct ieee80211_mcs_rates *mcs = - &ieee80211_htrates[ni->ni_txrate &~ IEEE80211_RATE_MCS]; - if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { - if (ni->ni_flags & IEEE80211_NODE_SGI40) - si->isi_txmbps = mcs->ht40_rate_800ns; - else - si->isi_txmbps = mcs->ht40_rate_400ns; - } else { - if (ni->ni_flags & IEEE80211_NODE_SGI20) - si->isi_txmbps = mcs->ht20_rate_800ns; - else - si->isi_txmbps = mcs->ht20_rate_400ns; - } - } else - si->isi_txmbps = si->isi_txrate; + si->isi_txrate = ieee80211_node_get_txrate_dot11rate(ni); + /* Note: txmbps is in 1/2Mbit/s units */ + si->isi_txmbps = ieee80211_node_get_txrate_kbit(ni) / 500; si->isi_associd = ni->ni_associd; si->isi_txpower = ni->ni_txpower; si->isi_vlan = ni->ni_vlan; diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c index c52122ebeb13..9f81bc3643aa 100644 --- a/sys/net80211/ieee80211_mesh.c +++ b/sys/net80211/ieee80211_mesh.c @@ -3298,7 +3298,7 @@ mesh_airtime_calc(struct ieee80211_node *ni) uint64_t res; /* Time to transmit a frame */ - rate = ni->ni_txrate; + rate = ieee80211_node_get_txrate_dot11rate(ni); overhead = ieee80211_compute_duration(ic->ic_rt, ifp->if_mtu + IEEE80211_MESH_MAXOVERHEAD, rate, 0) << M_BITS; /* Error rate in percentage */ diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index f2fc3d21a361..f5b05ed769c9 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -3137,3 +3137,68 @@ ieee80211_getsignal(struct ieee80211vap *vap, int8_t *rssi, int8_t *noise) if (vap->iv_opmode != IEEE80211_M_STA) *rssi = ieee80211_getrssi(vap); } + +uint8_t +ieee80211_node_get_txrate_dot11rate(struct ieee80211_node *ni) +{ + return (ni->ni_txrate); +} + +void +ieee80211_node_set_txrate_dot11rate(struct ieee80211_node *ni, + uint8_t dot11Rate) +{ + ni->ni_txrate = dot11Rate; +} + +void +ieee80211_node_set_txrate_ht_mcsrate(struct ieee80211_node *ni, + uint8_t mcs) +{ + KASSERT(mcs <= 76, ("%s: MCS is not 0..76 (%d)", __func__, mcs)); + if (mcs > 76) { + ic_printf(ni->ni_ic, "%s: invalid MCS (%d)\n", __func__, mcs); + return; + } + ni->ni_txrate = IEEE80211_RATE_MCS | mcs; +} + + +/* + * @brief Fetch the transmit rate for the given node in kbit/s. + * + * This currently only works for CCK, OFDM and HT rates. + * + * @param ni struct ieee80211_node * to lookup + * @returns current transmit rate in kbit/s + */ +uint32_t +ieee80211_node_get_txrate_kbit(struct ieee80211_node *ni) +{ + uint32_t mbps; + + if (ni->ni_txrate & IEEE80211_RATE_MCS) { + const struct ieee80211_mcs_rates *mcs = + &ieee80211_htrates[ni->ni_txrate & ~IEEE80211_RATE_MCS]; + + if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { + /* Note: these are in 1/2Mbit/s units */ + if (ni->ni_flags & IEEE80211_NODE_SGI40) + mbps = mcs->ht40_rate_800ns; + else + mbps = mcs->ht40_rate_400ns; + } else { + if (ni->ni_flags & IEEE80211_NODE_SGI20) + mbps = mcs->ht20_rate_800ns; + else + mbps = mcs->ht20_rate_400ns; + } + } else + /* Note: CCK/OFDM dot11rate entries are in 1/2Mbit/s units */ + mbps = ni->ni_txrate; + + /* + * Note; 'mbps' in 1/2 Mbit/s units so *500 to make it in kbit/s units. + */ + return (mbps * 500); +} diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index 0039c743544c..722f3d54a00b 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -498,4 +498,10 @@ void ieee80211_node_join(struct ieee80211_node *,int); void ieee80211_node_leave(struct ieee80211_node *); int8_t ieee80211_getrssi(struct ieee80211vap *); void ieee80211_getsignal(struct ieee80211vap *, int8_t *, int8_t *); + +uint8_t ieee80211_node_get_txrate_dot11rate(struct ieee80211_node *); +void ieee80211_node_set_txrate_dot11rate(struct ieee80211_node *, uint8_t); +void ieee80211_node_set_txrate_ht_mcsrate(struct ieee80211_node *, uint8_t); +uint32_t ieee80211_node_get_txrate_kbit(struct ieee80211_node *); + #endif /* _NET80211_IEEE80211_NODE_H_ */ diff --git a/sys/net80211/ieee80211_ratectl_none.c b/sys/net80211/ieee80211_ratectl_none.c index 4ab122fbab92..47f88cbd3a79 100644 --- a/sys/net80211/ieee80211_ratectl_none.c +++ b/sys/net80211/ieee80211_ratectl_none.c @@ -62,7 +62,8 @@ none_deinit(struct ieee80211vap *vap) static void none_node_init(struct ieee80211_node *ni) { - ni->ni_txrate = ni->ni_rates.rs_rates[0] & IEEE80211_RATE_VAL; + ieee80211_node_set_txrate_dot11rate(ni, + ni->ni_rates.rs_rates[0] & IEEE80211_RATE_VAL); } static void @@ -75,7 +76,8 @@ none_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused) { int rix = 0; - ni->ni_txrate = ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL; + ieee80211_node_set_txrate_dot11rate(ni, + ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL); return rix; } diff --git a/sys/net80211/ieee80211_rssadapt.c b/sys/net80211/ieee80211_rssadapt.c index 6c77727d7526..43118aad53c3 100644 --- a/sys/net80211/ieee80211_rssadapt.c +++ b/sys/net80211/ieee80211_rssadapt.c @@ -203,11 +203,13 @@ rssadapt_node_init(struct ieee80211_node *ni) ra->ra_rix > 0 && (rs->rs_rates[ra->ra_rix] & IEEE80211_RATE_VAL) > 72; ra->ra_rix--) ; - ni->ni_txrate = rs->rs_rates[ra->ra_rix] & IEEE80211_RATE_VAL; + ieee80211_node_set_txrate_dot11rate(ni, + rs->rs_rates[ra->ra_rix] & IEEE80211_RATE_VAL); ra->ra_ticks = ticks; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, - "RSSADAPT initial rate %d", ni->ni_txrate); + "RSSADAPT initial rate %d Mbit/s", + ieee80211_node_get_txrate_kbit(ni) / 1000); } static void @@ -244,7 +246,8 @@ rssadapt_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg) /* XXX should return -1 here, but drivers may not expect this... */ if (!ra) { - ni->ni_txrate = ni->ni_rates.rs_rates[0]; + ieee80211_node_set_txrate_dot11rate(ni, + ni->ni_rates.rs_rates[0]); return 0; } @@ -263,12 +266,13 @@ rssadapt_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg) break; if (rix != ra->ra_rix) { /* update public rate */ - ni->ni_txrate = ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL; + ieee80211_node_set_txrate_dot11rate(ni, + ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL); ra->ra_rix = rix; IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, - "RSSADAPT new rate %d (pktlen %d rssi %d)", - ni->ni_txrate, pktlen, rssi); + "RSSADAPT new rate %d Mbit/s (pktlen %d rssi %d)", + ieee80211_node_get_txrate_kbit(ni) / 1000, pktlen, rssi); } return rix; } diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c index a8159fca6d80..69347a5d99cf 100644 --- a/sys/net80211/ieee80211_scan_sta.c +++ b/sys/net80211/ieee80211_scan_sta.c @@ -1365,7 +1365,7 @@ sta_roam_check(struct ieee80211_scan_state *ss, struct ieee80211vap *vap) /* NB: the most up to date rssi is in the node, not the scan cache */ curRssi = ic->ic_node_getrssi(ni); if (ucastRate == IEEE80211_FIXED_RATE_NONE) { - curRate = ni->ni_txrate; + curRate = ieee80211_node_get_txrate_dot11rate(ni); IEEE80211_DPRINTF(vap, IEEE80211_MSG_ROAM, "%s: currssi %d currate %u roamrssi %d roamrate %u\n", __func__, curRssi, curRate, roamRssi, roamRate); diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c index 9e4e1013fd2f..96603f339710 100644 --- a/sys/net80211/ieee80211_sta.c +++ b/sys/net80211/ieee80211_sta.c @@ -64,8 +64,6 @@ #include <net80211/ieee80211_sta.h> #include <net80211/ieee80211_vht.h> -#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) - static void sta_vattach(struct ieee80211vap *); static void sta_beacon_miss(struct ieee80211vap *); static int sta_newstate(struct ieee80211vap *, enum ieee80211_state, int); @@ -417,10 +415,9 @@ sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ether_sprintf(ni->ni_bssid)); ieee80211_print_essid(vap->iv_bss->ni_essid, ni->ni_esslen); - /* XXX MCS/HT */ - printf(" channel %d start %uMb\n", + printf(" channel %d start %uMbit/s\n", ieee80211_chan2ieee(ic, ic->ic_curchan), - IEEE80211_RATE2MBS(ni->ni_txrate)); + ieee80211_node_get_txrate_kbit(ni) / 1000); } #endif ieee80211_scan_assoc_success(vap, ni->ni_macaddr); diff --git a/sys/net80211/ieee80211_superg.c b/sys/net80211/ieee80211_superg.c index 815fb356891c..ee3b70d5ed9f 100644 --- a/sys/net80211/ieee80211_superg.c +++ b/sys/net80211/ieee80211_superg.c @@ -725,6 +725,7 @@ ff_approx_txtime(struct ieee80211_node *ni, struct ieee80211vap *vap = ni->ni_vap; uint32_t framelen; uint32_t frame_time; + uint8_t dot11rate; /* * Approximate the frame length to be transmitted. A swag to add @@ -746,15 +747,16 @@ ff_approx_txtime(struct ieee80211_node *ni, * For now, we assume non-shortgi, 20MHz, just because I want to * at least test 802.11n. */ - if (ni->ni_txrate & IEEE80211_RATE_MCS) + dot11rate = ieee80211_node_get_txrate_dot11rate(ni); + if (dot11rate & IEEE80211_RATE_MCS) frame_time = ieee80211_compute_duration_ht(framelen, - ni->ni_txrate, - IEEE80211_HT_RC_2_STREAMS(ni->ni_txrate), + dot11rate, + IEEE80211_HT_RC_2_STREAMS(dot11rate), 0, /* isht40 */ 0); /* isshortgi */ else frame_time = ieee80211_compute_duration(ic->ic_rt, framelen, - ni->ni_txrate, 0); + dot11rate, 0); return (frame_time); }