The branch main has been updated by bz:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=8f532c7b25d54906c307bfda6cb679632cc26313

commit 8f532c7b25d54906c307bfda6cb679632cc26313
Author:     Bjoern A. Zeeb <[email protected]>
AuthorDate: 2026-03-02 12:51:55 +0000
Commit:     Bjoern A. Zeeb <[email protected]>
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;
        }

Reply via email to