git: f5b0b80a3d0e - stable/15 - LinuxKPI: 802.11: add function to update some rate related fields
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 29 Jun 2026 06:34:42 UTC
The branch stable/15 has been updated by bz:
URL: https://cgit.FreeBSD.org/src/commit/?id=f5b0b80a3d0eb7bf8b8cfa4092124d5a0e695df5
commit f5b0b80a3d0eb7bf8b8cfa4092124d5a0e695df5
Author: Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-06-22 00:41:38 +0000
Commit: Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-06-29 03:54:51 +0000
LinuxKPI: 802.11: add function to update some rate related fields
Add lkpi_sta_supp_rates() which serves multiple purposes:
(a) build (and update) the supp_rates field on a sta link (deflink only
in our case still),
(b) build and update basic_rates on the vif->bss_conf and print a
warning in case we end up without any basic rate (should not happen
anymore, not even on initial startup sync),
(c) if HT or VHT are supported, then update the relevant br_mask fields
for the current band.
Deal with the various flags which trigger different updates by returning
them so the caller can act upon.
Sponsored by: The FreeBSD Foundation
(cherry picked from commit 0d3cd54642f6695f9f82b82402f27e10bbee7cfc)
---
sys/compat/linuxkpi/common/src/linux_80211.c | 152 ++++++++++++++++++++++++++-
1 file changed, 150 insertions(+), 2 deletions(-)
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 777caa6d14e4..33ce55814b44 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -503,6 +503,144 @@ lkpi_rx_bw_to_cw(enum ieee80211_sta_rx_bandwidth rx_bw)
}
}
+static enum ieee80211_bss_changed
+lkpi_sta_supp_rates(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_node *ni,
+ enum ieee80211_rate_control_changed_flags *rc_changed)
+{
+ struct lkpi_vif *lvif;
+ struct lkpi_sta *lsta;
+ struct ieee80211_sta *sta;
+ enum ieee80211_bss_changed bss_changed;
+ struct ieee80211_supported_band *supband;
+ uint32_t supp_rates, basic_rates;
+ int band, i, n;
+
+ bss_changed = 0;
+
+ band = vif->bss_conf.chanreq.oper.chan->band;
+ supband = hw->wiphy->bands[band];
+ if (supband == NULL)
+ return (bss_changed);
+
+ lvif = VIF_TO_LVIF(vif);
+ lsta = ni->ni_drv_data;
+ sta = LSTA_TO_STA(lsta);
+
+ supp_rates = 0;
+ basic_rates = 0;
+
+ for (n = 0; n < ni->ni_rates.rs_nrates; n++) {
+ uint8_t supp_rate;
+ uint16_t bitr;
+ bool basic;
+
+ /* Note: net80211 rates are in 0.5Mbit/s, e.g., 108 is 54Mbit/s. */
+ supp_rate = ni->ni_rates.rs_rates[n] & (~IEEE80211_RATE_BASIC);
+ basic = (ni->ni_rates.rs_rates[n] & IEEE80211_RATE_BASIC) != 0;
+
+ for (i = 0; i < supband->n_bitrates; i++) {
+ /* Band bitrates are * 10 so, e.g., 55 is 5.5Mbit/s. */
+ /* To match net80211 rates we need to do a DIV5. */
+ bitr = howmany(supband->bitrates[i].bitrate, 5);
+ if (supp_rate == bitr) {
+ supp_rates |= BIT(i);
+ if (basic)
+ basic_rates |= BIT(i);
+ }
+ /*
+ * We are not checking if we are doing 11b or 11g and
+ * if the rate is fine for each.
+ */
+ }
+ TRACE_RATES("supp_rate %u basic %d supp_rates %#010x basic_rates %#010x",
+ supp_rate, basic, supp_rates, basic_rates);
+ }
+ if (basic_rates != 0 &&
+ vif->bss_conf.basic_rates != basic_rates) {
+ TRACE_RATES("vif bss_conf basic_rates %#010x update to %#010x",
+ vif->bss_conf.basic_rates, basic_rates);
+ vif->bss_conf.basic_rates = basic_rates;
+ bss_changed |= BSS_CHANGED_BASIC_RATES;
+ }
+ /* Guard against net80211 not having any rates set when we get here. */
+ if (supp_rates == 0)
+ supp_rates = vif->bss_conf.basic_rates;
+ if (sta->deflink.supp_rates[band] != supp_rates) {
+ TRACE_RATES("band %d supp_rates %#010x update to %#010x",
+ band, sta->deflink.supp_rates[band], supp_rates);
+ sta->deflink.supp_rates[band] = supp_rates;
+ if (rc_changed != NULL)
+ *rc_changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
+ }
+
+ /*
+ * br_mask got initialized in lkpi_ic_vap_create().
+ * Do a basic rates check against it for the current band if we are
+ * in a state to have all the above information.
+ */
+ TRACE_RATES("band %d br_mask legacy %#010x & basic_rates %#010x != 0?",
+ band, lvif->br_mask.control[band].legacy, vif->bss_conf.basic_rates);
+ if (band == vif->bss_conf.chanreq.oper.chan->band &&
+ (lvif->br_mask.control[band].legacy & vif->bss_conf.basic_rates) == 0) {
+ /* In our setup this should never happen. */
+ printf("%s: WARNING: no acceptable basic rate %#010x & %#010x\n",
+ __func__, lvif->br_mask.control[band].legacy, vif->bss_conf.basic_rates);
+ }
+
+ /*
+ * XXX-BZ we should track changes here as well and call or let the
+ * caller call lkpi_80211_mo_set_bitrate_mask() if needed.
+ * Note: the call in lkpi_sta_scan_to_auth() still have to
+ * happen unconditionally for the initial setting.
+ */
+#if defined(LKPI_80211_HT)
+ if (supband->ht_cap.ht_supported) {
+ memcpy(lvif->br_mask.control[band].ht_mcs,
+ supband->ht_cap.mcs.rx_mask,
+ sizeof(lvif->br_mask.control[band].ht_mcs));
+#if defined(LINUXKPI_DEBUG_80211)
+ for (int i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ TRACE_RATES("band %d ht_mcs[%d] %#010x",
+ band, i, lvif->br_mask.control[band].ht_mcs[i]);
+ }
+#endif
+ }
+#endif /* LKPI_80211_HT */
+#if defined(LKPI_80211_VHT)
+ if (supband->vht_cap.vht_supported) {
+ uint16_t mcs_map, val;
+ uint8_t nss;
+
+ mcs_map = supband->vht_cap.vht_mcs.tx_mcs_map;
+ for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
+ TRACE_RATES("band %d nss %d vht_mcs.tx_mcs_map %#06x mcs_map %#06x & 0x3 = %#06x",
+ band, nss, supband->vht_cap.vht_mcs.tx_mcs_map, mcs_map, mcs_map & 0x3);
+ switch (mcs_map & 0x3) {
+ case IEEE80211_VHT_MCS_SUPPORT_0_7:
+ val = 0x00ff;
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_8:
+ val = 0x01ff;
+ break;
+ case IEEE80211_VHT_MCS_SUPPORT_0_9:
+ val = 0x03ff;
+ break;
+ case IEEE80211_VHT_MCS_NOT_SUPPORTED:
+ val = 0;
+ break;
+ }
+ lvif->br_mask.control[band].vht_mcs[nss] = val;
+ TRACE_RATES("band %d nss %d vht_mcs %#06x",
+ band, nss, lvif->br_mask.control[band].vht_mcs[nss]);
+ mcs_map >>= 2;
+ }
+ }
+#endif /* LKPI_80211_VHT */
+
+ return (bss_changed);
+}
+
static void
lkpi_sync_chanctx_cw_from_rx_bw(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_sta *sta)
@@ -751,11 +889,13 @@ lkpi_sta_sync_from_ni(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_node *ni, bool updchnctx)
{
enum ieee80211_bss_changed bss_changed;
+ enum ieee80211_rate_control_changed_flags rc_changed;
if (updchnctx)
lockdep_assert_wiphy(hw->wiphy);
bss_changed = 0;
+ rc_changed = 0;
/*
* Ensure rx_nss is at least 1 as otherwise drivers run into
@@ -780,6 +920,11 @@ lkpi_sta_sync_from_ni(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (updchnctx)
lkpi_sync_chanctx_cw_from_rx_bw(hw, vif, sta);
+ bss_changed |= lkpi_sta_supp_rates(hw, vif, ni, &rc_changed);
+
+ if (rc_changed != 0)
+ lkpi_80211_mo_link_sta_rc_update(hw, vif, &sta->deflink, rc_changed);
+
return (bss_changed);
}
@@ -2689,8 +2834,6 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
vif->cfg.idle = false;
bss_changed |= BSS_CHANGED_IDLE;
- /* vif->bss_conf.basic_rates ? Where exactly? */
-
lvif->beacons = 0;
/* Should almost assert it is this. */
vif->cfg.assoc = false;
@@ -2706,6 +2849,11 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
/* RATES */
IMPROVE("bss info: not all needs to come now and rates are missing");
+ bss_changed |= lkpi_sta_supp_rates(hw, vif, ni, NULL);
+ if (ieee80211_hw_check(hw, HAS_RATE_CONTROL))
+ lkpi_80211_mo_set_bitrate_mask(hw, vif, &lvif->br_mask);
+ TODO("cfg80211_tid_config WHERE?");
+
lkpi_bss_info_change(hw, vif, bss_changed);
/*