git: 8f532c7b25d5 - main - LinuxKPI: 802.11: improve prep_tx_info
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 04 Mar 2026 11:13:26 UTC
The branch main has been updated by bz:
URL: https://cgit.FreeBSD.org/src/commit/?id=8f532c7b25d54906c307bfda6cb679632cc26313
commit 8f532c7b25d54906c307bfda6cb679632cc26313
Author: Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-03-02 12:51:55 +0000
Commit: Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-03-04 08:21:41 +0000
LinuxKPI: 802.11: improve prep_tx_info
Over time struct ieee80211_prep_tx_info has grown further fields.
One which is becoming mandatory is the subtype (of the mgmt frame).
iwlwifi(mld) has a WARN for it if it does not match, so we now have
to set this for proper operation. In addition we are tyring to improve
the situation of setting/unsetting (prepare_tx/complete_tx) in various
states and cleanup the use of other fields but link_id which we now
leave as a marker for the future everywhere.
The general problem we are facing is that our hook surface in this case
is the state machine but likely would have to be tx/rx mgmt frames but
we would alos have to driver the TX queues from there which is tricky.
The long-term answer is to change net80211.
Further the hardware flag DEAUTH_NEED_MGD_TX_PREP is dead and was
removed again in favour of leting drivers deal with it. iwlwifi(mvm)
likely being the only driver which ever used this.
Sponsored by: The FreeBSD Foundation
MFC after: 3 days
---
sys/compat/linuxkpi/common/include/net/mac80211.h | 1 -
sys/compat/linuxkpi/common/src/linux_80211.c | 93 ++++++++++++++++++-----
2 files changed, 72 insertions(+), 22 deletions(-)
diff --git a/sys/compat/linuxkpi/common/include/net/mac80211.h b/sys/compat/linuxkpi/common/include/net/mac80211.h
index 18891d035094..4f3aad532810 100644
--- a/sys/compat/linuxkpi/common/include/net/mac80211.h
+++ b/sys/compat/linuxkpi/common/include/net/mac80211.h
@@ -431,7 +431,6 @@ enum ieee80211_hw_flags {
IEEE80211_HW_BUFF_MMPDU_TXQ,
IEEE80211_HW_CHANCTX_STA_CSA,
IEEE80211_HW_CONNECTION_MONITOR,
- IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
IEEE80211_HW_HAS_RATE_CONTROL,
IEEE80211_HW_MFP_CAPABLE,
IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 7b61ff6603b7..bbda35cb2e38 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -2502,7 +2502,9 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
/* Start mgd_prepare_tx. */
memset(&prep_tx_info, 0, sizeof(prep_tx_info));
- prep_tx_info.duration = PREP_TX_INFO_DURATION;
+ prep_tx_info.duration = PREP_TX_INFO_DURATION; /* SAE */
+ prep_tx_info.subtype = IEEE80211_STYPE_AUTH;
+ prep_tx_info.link_id = 0;
lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);
lsta->in_mgd = true;
@@ -2638,6 +2640,7 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
/* End mgd_complete_tx. */
if (lsta->in_mgd) {
memset(&prep_tx_info, 0, sizeof(prep_tx_info));
+ prep_tx_info.subtype = IEEE80211_STYPE_AUTH;
prep_tx_info.success = true;
lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);
lsta->in_mgd = false;
@@ -2648,7 +2651,8 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
/* Start mgd_prepare_tx. */
if (nstate == IEEE80211_S_ASSOC && !lsta->in_mgd) {
memset(&prep_tx_info, 0, sizeof(prep_tx_info));
- prep_tx_info.duration = PREP_TX_INFO_DURATION;
+ prep_tx_info.subtype = IEEE80211_STYPE_ASSOC_REQ;
+ prep_tx_info.link_id = 0;
lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);
lsta->in_mgd = true;
}
@@ -2796,7 +2800,9 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int
/* End mgd_complete_tx. (we do not have to check ostate == IEEE80211_S_ASSOC). */
if (lsta->in_mgd) {
memset(&prep_tx_info, 0, sizeof(prep_tx_info));
- prep_tx_info.success = true;
+ prep_tx_info.subtype = IEEE80211_STYPE_ASSOC_REQ;
+ prep_tx_info.success = true; /* Needs vif->cfg.assoc set! */
+ prep_tx_info.link_id = 0;
lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);
lsta->in_mgd = false;
}
@@ -2860,6 +2866,9 @@ out:
* DOWN1
* "to assoc" means we are going back to State 2 from State 4[/3].
* This means ni still is authenticated, so we keep sta, chanctx, ..
+ * We will send a (Re)Assoc Request in case net80211 handles roadming.
+ * Note: this can be called as part of a DEAUTH going to State 1 as well,
+ * so for RoC prep_tx_info we need to check nstate (see run_to_{auth,scan,init}).
*/
static int
lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
@@ -2910,15 +2919,33 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
/* flush, drop. */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);
- IMPROVE("What are the proper conditions for DEAUTH_NEED_MGD_TX_PREP?");
- if (ieee80211_hw_check(hw, DEAUTH_NEED_MGD_TX_PREP) &&
- !lsta->in_mgd) {
- memset(&prep_tx_info, 0, sizeof(prep_tx_info));
- prep_tx_info.duration = PREP_TX_INFO_DURATION;
- prep_tx_info.was_assoc = true;
- lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);
- lsta->in_mgd = true;
+ /* We should make this a KASSERT. */
+ if (lsta->in_mgd) {
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p lsta %p in_mgd\n",
+ __func__, __LINE__, lvif, vap, lsta);
}
+ /*
+ * Problem is that we should hook into the tx/rx flow and not
+ * try to re-model the state machine parts. We may miss a SME
+ * triggered frame this way.
+ */
+ memset(&prep_tx_info, 0, sizeof(prep_tx_info));
+ if (nstate == IEEE80211_S_ASSOC) {
+ if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) {
+ if (arg)
+ prep_tx_info.subtype = IEEE80211_STYPE_REASSOC_REQ;
+ else
+ prep_tx_info.subtype = IEEE80211_STYPE_ASSOC_REQ;
+ } else {
+ /* wpa_supplicant upon RTM_IEEE80211_LEAVE. */
+ prep_tx_info.subtype = IEEE80211_STYPE_DISASSOC;
+ }
+ } else
+ prep_tx_info.subtype = IEEE80211_STYPE_DEAUTH;
+ prep_tx_info.was_assoc = true;
+ prep_tx_info.link_id = 0;
+ lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);
+ lsta->in_mgd = true;
wiphy_unlock(hw->wiphy);
IEEE80211_LOCK(vap->iv_ic);
@@ -2957,13 +2984,13 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), false);
/* End mgd_complete_tx. */
- if (lsta->in_mgd) {
- memset(&prep_tx_info, 0, sizeof(prep_tx_info));
- prep_tx_info.success = false;
- prep_tx_info.was_assoc = true;
- lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);
- lsta->in_mgd = false;
+ /* We should make this a KASSERT. */
+ if (!lsta->in_mgd) {
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p lsta %p !in_mgd\n",
+ __func__, __LINE__, lvif, vap, lsta);
}
+ lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);
+ lsta->in_mgd = false;
#if 0
/* sync_rx_queues */
@@ -3047,6 +3074,7 @@ lkpi_sta_assoc_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, in
struct ieee80211_vif *vif;
struct ieee80211_node *ni;
struct lkpi_sta *lsta;
+ struct ieee80211_prep_tx_info prep_tx_info;
int error;
lhw = vap->iv_ic->ic_softc;
@@ -3077,6 +3105,20 @@ lkpi_sta_assoc_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, in
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
+ /* End mgd_complete_tx. */
+ if (lsta->in_mgd && vap->iv_state == IEEE80211_S_ASSOC) {
+ memset(&prep_tx_info, 0, sizeof(prep_tx_info));
+ prep_tx_info.subtype = IEEE80211_STYPE_ASSOC_REQ;
+ prep_tx_info.link_id = 0;
+ lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);
+ lsta->in_mgd = false;
+ } else if (lsta->in_mgd) {
+ ic_printf(vap->iv_ic, "%s:%d: in_mgd %d (%s) -> %d (%s) %d\n",
+ __func__, __LINE__,
+ vap->iv_state, ieee80211_state_name[vap->iv_state],
+ nstate, ieee80211_state_name[nstate], arg);
+ }
+
/* Take the station down. */
/* Update sta_state (AUTH to NONE). */
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
@@ -3158,7 +3200,8 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int
/* End mgd_complete_tx. */
if (lsta->in_mgd) {
memset(&prep_tx_info, 0, sizeof(prep_tx_info));
- prep_tx_info.success = false;
+ prep_tx_info.subtype = IEEE80211_STYPE_AUTH;
+ prep_tx_info.link_id = 0;
lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);
lsta->in_mgd = false;
}
@@ -3342,17 +3385,25 @@ lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
/* End mgd_complete_tx. */
if (lsta->in_mgd) {
memset(&prep_tx_info, 0, sizeof(prep_tx_info));
- prep_tx_info.success = false;
+ if (vap->iv_state == IEEE80211_S_AUTH)
+ prep_tx_info.subtype = IEEE80211_STYPE_AUTH;
+ else
+ prep_tx_info.subtype = IEEE80211_STYPE_ASSOC_REQ;
+ prep_tx_info.link_id = 0;
lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);
lsta->in_mgd = false;
}
- /* Now start assoc. */
+ /* Now start auth/assoc. */
/* Start mgd_prepare_tx. */
if (!lsta->in_mgd) {
memset(&prep_tx_info, 0, sizeof(prep_tx_info));
- prep_tx_info.duration = PREP_TX_INFO_DURATION;
+ if (nstate == IEEE80211_S_AUTH)
+ prep_tx_info.subtype = IEEE80211_STYPE_AUTH;
+ else
+ prep_tx_info.subtype = IEEE80211_STYPE_ASSOC_REQ;
+ prep_tx_info.link_id = 0;
lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);
lsta->in_mgd = true;
}