Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 27 Feb 2026 02:30:20 +0000
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: c201c9ff5f3d - stable/15 - LinuxKPI: 802.11: fold the sta state machine again
Message-ID:  <69a101bc.220af.2922828e@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by bz:

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

commit c201c9ff5f3d2dd5c7614c58b1afb9892d3d1cf5
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-02-25 00:13:22 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-02-26 23:09:49 +0000

    LinuxKPI: 802.11: fold the sta state machine again
    
    In and around d9f59799fc3e7 we adjusted the initial sta state machine
    implementation and unfolded some functions, duplicating code.
    This version tries to undo some of that as it seems that we can get
    away with doing it more cleanly these days.
    
    There are 5 main functions for the path from INIT to RUN (UP1,2,3.1,3.2,4)
    and 4 main functions for the path from RUN to INIT (DOWN1,2,3,4).
    The reason there is one more on the patch up is that we can go directly
    from AUTH to RUN without going through ASSOC first.
    In addition there are further functions relying only on these 9 base
    state change functions in order to implement the remaining possible
    state transitions net80211 can do (without CSA and SLEEP).
    
    Another change is that we no longer take a sta always through INIT/SCAN
    first and then back up to AUTH, that is, we are no longer deleting the
    sta from the firmware unless net80211 would also take us down to that
    state and in a follow-up back up.
    
    This is a preparation for another fix to come in order to import a
    newer version of iwlwifi (v6.19).
    
    I have run a few days of mlme_assoc (see tools) and some other basic
    regression tests.  The only thing I managed was to deadlock net80211
    for other reasons (ieee80211_waitfor_parent()).  But this will need
    excessive user testing as the various options which may have an
    effect on the subtle details are great as we learnt in the past years.
    
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit 48f55a49a1d142c616edbc7ee6745dd6b83393e4)
---
 sys/compat/linuxkpi/common/src/linux_80211.c | 834 +++++++++------------------
 1 file changed, 278 insertions(+), 556 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 9693e4eec268..48b87ae47751 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -2121,7 +2121,7 @@ lkpi_disassoc(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
 		 * The caller is responsible for removing the sta gong to
 		 * IEEE80211_STA_NOTEXIST and then executing the
 		 * bss_info_changed() update.
-		 * See lkpi_sta_run_to_init() for more detailed comment.
+		 * See DOWN4 for more detailed comment.
 		 */
 
 		lvif = VIF_TO_LVIF(vif);
@@ -2248,13 +2248,17 @@ lkpi_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 static int
 lkpi_sta_state_do_nada(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
-
 	return (0);
 }
 
-/* lkpi_iv_newstate() handles the stop scan case generally. */
-#define	lkpi_sta_scan_to_init(_v, _n, _a)	lkpi_sta_state_do_nada(_v, _n, _a)
+/* UP1 */
+static int
+lkpi_sta_init_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+	return (lkpi_sta_state_do_nada(vap, nstate, arg));
+}
 
+/* UP2 */
 static int
 lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
@@ -2579,136 +2583,7 @@ out_relocked:
 	return (error);
 }
 
-static int
-lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
-{
-	struct lkpi_hw *lhw;
-	struct ieee80211_hw *hw;
-	struct lkpi_vif *lvif;
-	struct ieee80211_vif *vif;
-	struct ieee80211_node *ni;
-	struct lkpi_sta *lsta;
-	struct ieee80211_sta *sta;
-	struct ieee80211_prep_tx_info prep_tx_info;
-	enum ieee80211_bss_changed bss_changed;
-	int error;
-
-	lhw = vap->iv_ic->ic_softc;
-	hw = LHW_TO_HW(lhw);
-	lvif = VAP_TO_LVIF(vap);
-	vif = LVIF_TO_VIF(lvif);
-
-	LKPI_80211_LVIF_LOCK(lvif);
-#ifdef LINUXKPI_DEBUG_80211
-	/* XXX-BZ KASSERT later; state going down so no action. */
-	if (lvif->lvif_bss == NULL)
-		ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
-		    "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
-		    lvif, vap, vap->iv_bss, lvif->lvif_bss,
-		    (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
-		    lvif->lvif_bss_synched);
-#endif
-
-	lsta = lvif->lvif_bss;
-	LKPI_80211_LVIF_UNLOCK(lvif);
-	KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
-	    "lvif %p vap %p\n", __func__,
-	    lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
-	ni = lsta->ni;			/* Reference held for lvif_bss. */
-	sta = LSTA_TO_STA(lsta);
-
-	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
-
-	IEEE80211_UNLOCK(vap->iv_ic);
-	wiphy_lock(hw->wiphy);
-
-	/* flush, drop. */
-	lkpi_80211_mo_flush(hw, vif,  nitems(sta->txq), true);
-
-	/* Wake tx queues to get packet(s) out. */
-	lkpi_wake_tx_queues(hw, sta, false, true);
-
-	/* flush, no drop */
-	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;
-		lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);
-		lsta->in_mgd = false;
-	}
-
-	/* sync_rx_queues */
-	lkpi_80211_mo_sync_rx_queues(hw);
-
-	/* sta_pre_rcu_remove */
-        lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);
-
-	/* Take the station down. */
-
-	/* Adjust sta and change state (from NONE) to NOTEXIST. */
-	KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
-	KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "
-	    "NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));
-	error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);
-	if (error != 0) {
-		IMPROVE("do we need to undo the chan ctx?");
-		ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "
-		    "failed: %d\n", __func__, __LINE__, error);
-		goto out;
-	}
-#if 0
-	lsta->added_to_drv = false;	/* mo manages. */
-#endif
-
-	bss_changed = 0;
-	vif->bss_conf.dtim_period = 0; /* go back to 0. */
-	bss_changed |= BSS_CHANGED_BEACON_INFO;
-	lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);
-
-	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
-
-	LKPI_80211_LVIF_LOCK(lvif);
-	/* Remove ni reference for this cache of lsta. */
-	lvif->lvif_bss = NULL;
-	lvif->lvif_bss_synched = false;
-	LKPI_80211_LVIF_UNLOCK(lvif);
-	lkpi_lsta_remove(lsta, lvif);
-
-	/* conf_tx */
-
-	lkpi_remove_chanctx(hw, vif);
-
-out:
-	wiphy_unlock(hw->wiphy);
-	IEEE80211_LOCK(vap->iv_ic);
-	if (error == 0) {
-		/*
-		 * We do this outside the wiphy lock as net80211::node_free() may call
-		 * into crypto code to delete keys and we have a recursed on
-		 * non-recursive sx panic.  Also only do this if we get here w/o error.
-		 *
-		 * The very last release the reference on the ni for the ni/lsta on
-		 * lvif->lvif_bss.  Upon return from this both ni and lsta are invalid
-		 * and potentially freed.
-		 */
-		ieee80211_free_node(ni);
-	}
-	return (error);
-}
-
-static int
-lkpi_sta_auth_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
-{
-	int error;
-
-	error = lkpi_sta_auth_to_scan(vap, nstate, arg);
-	if (error == 0)
-		error = lkpi_sta_scan_to_init(vap, nstate, arg);
-	return (error);
-}
-
+/* UP3.1 */
 static int
 lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
@@ -2768,18 +2643,21 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
 		lsta->in_mgd = false;
 	}
 
-	/* Now start assoc. */
+	/* Now start assoc. unless nstate=RUN (auth_to_run). */
 
 	/* Start mgd_prepare_tx. */
-	if (!lsta->in_mgd) {
+	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;
 		lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);
 		lsta->in_mgd = true;
 	}
 
+#if 0
+	/* We do not yet have a packet to go out. */
 	/* Wake tx queue to get packet out. */
 	lkpi_wake_tx_queues(hw, LSTA_TO_STA(lsta), false, true);
+#endif
 
 	/*
 	 * <twiddle> .. we end up in "assoc_to_run"
@@ -2797,76 +2675,23 @@ out:
 	return (error);
 }
 
-/* auth_to_auth, assoc_to_assoc. */
+static int lkpi_sta_assoc_to_run(struct ieee80211vap *, enum ieee80211_state, int);
+
+/* UP3.2 */
 static int
-lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+lkpi_sta_auth_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
-	struct lkpi_hw *lhw;
-	struct ieee80211_hw *hw;
-	struct lkpi_vif *lvif;
-	struct ieee80211_vif *vif;
-	struct lkpi_sta *lsta;
-	struct ieee80211_prep_tx_info prep_tx_info;
 	int error;
 
-	lhw = vap->iv_ic->ic_softc;
-	hw = LHW_TO_HW(lhw);
-	lvif = VAP_TO_LVIF(vap);
-	vif = LVIF_TO_VIF(lvif);
-
-	IEEE80211_UNLOCK(vap->iv_ic);
-	wiphy_lock(hw->wiphy);
-
-	LKPI_80211_LVIF_LOCK(lvif);
-	/* XXX-BZ KASSERT later? */
-	if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {
-#ifdef LINUXKPI_DEBUG_80211
-		ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
-		    "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
-		    lvif, vap, vap->iv_bss, lvif->lvif_bss,
-		    (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
-		    lvif->lvif_bss_synched);
-#endif
-		LKPI_80211_LVIF_UNLOCK(lvif);
-		error = ENOTRECOVERABLE;
-		goto out;
-	}
-	lsta = lvif->lvif_bss;
-	LKPI_80211_LVIF_UNLOCK(lvif);
-
-	KASSERT(lsta != NULL, ("%s: lsta %p! lvif %p vap %p\n", __func__,
-	    lsta, lvif, vap));
-
-	IMPROVE("event callback?");
-
-	/* End mgd_complete_tx. */
-	if (lsta->in_mgd) {
-		memset(&prep_tx_info, 0, sizeof(prep_tx_info));
-		prep_tx_info.success = false;
-		lkpi_80211_mo_mgd_complete_tx(hw, vif, &prep_tx_info);
-		lsta->in_mgd = false;
-	}
-
-	/* Now start 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;
-		lkpi_80211_mo_mgd_prepare_tx(hw, vif, &prep_tx_info);
-		lsta->in_mgd = true;
-	}
-
-	error = 0;
-out:
-	wiphy_unlock(hw->wiphy);
-	IEEE80211_LOCK(vap->iv_ic);
-
+	error = lkpi_sta_auth_to_assoc(vap, nstate, arg);
+	if (error == 0)
+		error = lkpi_sta_assoc_to_run(vap, nstate, arg);
 	return (error);
 }
 
+/* UP4 */
 static int
-_lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
 	struct lkpi_hw *lhw;
 	struct ieee80211_hw *hw;
@@ -2888,15 +2713,19 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i
 	wiphy_lock(hw->wiphy);
 
 	LKPI_80211_LVIF_LOCK(lvif);
+	/* XXX-BZ KASSERT later? */
+	if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {
 #ifdef LINUXKPI_DEBUG_80211
-	/* XXX-BZ KASSERT later; state going down so no action. */
-	if (lvif->lvif_bss == NULL)
 		ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
 		    "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
 		    lvif, vap, vap->iv_bss, lvif->lvif_bss,
 		    (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
 		    lvif->lvif_bss_synched);
 #endif
+		LKPI_80211_LVIF_UNLOCK(lvif);
+		error = ENOTRECOVERABLE;
+		goto out;
+	}
 	lsta = lvif->lvif_bss;
 	LKPI_80211_LVIF_UNLOCK(lvif);
 	KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
@@ -2904,244 +2733,28 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i
 	    lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
 
 	ni = lsta->ni;		/* Reference held for lvif_bss. */
-	sta = LSTA_TO_STA(lsta);
-
-	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
-
-	/* 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;
-	}
 
-	wiphy_unlock(hw->wiphy);
-	IEEE80211_LOCK(vap->iv_ic);
+	IMPROVE("ponder some of this moved to ic_newassoc, scan_assoc_success, "
+	    "and to lesser extend ieee80211_notify_node_join");
 
-	/* Call iv_newstate first so we get potential DEAUTH packet out. */
-	error = lvif->iv_newstate(vap, nstate, arg);
+	/* Finish assoc. (even if this is auth_to_run!) */
+	/* Update sta_state (AUTH to ASSOC) and set aid. */
+	KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "
+	    "AUTH: %#x\n", __func__, lsta, lsta->state));
+	sta = LSTA_TO_STA(lsta);
+	sta->aid = IEEE80211_NODE_AID(ni);
+#ifdef LKPI_80211_WME
+	if (vap->iv_flags & IEEE80211_F_WME)
+		sta->wme = true;
+#endif
+	error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);
 	if (error != 0) {
-		ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "
-		    "failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);
-		goto outni;
+		ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "
+		    "failed: %d\n", __func__, __LINE__, error);
+		goto out;
 	}
 
-	IEEE80211_UNLOCK(vap->iv_ic);
-
-	/* Ensure the packets get out. */
-	lkpi_80211_flush_tx(lhw, lsta);
-
-	wiphy_lock(hw->wiphy);
-
-	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
-
-	/* Wake tx queues to get packet(s) out. */
-	lkpi_wake_tx_queues(hw, sta, false, true);
-
-	/* flush, no drop */
-	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;
-	}
-
-	/* sync_rx_queues */
-	lkpi_80211_mo_sync_rx_queues(hw);
-
-	/* sta_pre_rcu_remove */
-        lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);
-
-	/* Take the station down. */
-
-	/* Update sta and change state (from AUTH) to NONE. */
-	KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
-	KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "
-	    "AUTH: %#x\n", __func__, lsta, lsta->state));
-	error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);
-	if (error != 0) {
-		ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "
-		    "failed: %d\n", __func__, __LINE__, error);
-		goto out;
-	}
-
-	/* See comment in lkpi_sta_run_to_init(). */
-	bss_changed = 0;
-	bss_changed |= lkpi_disassoc(sta, vif, lhw);
-
-#ifdef LKPI_80211_HW_CRYPTO
-	/*
-	 * In theory we remove keys here but there must not exist any for this
-	 * state change until we clean them up again into small steps and no
-	 * code duplication.
-	 */
-#endif
-
-	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
-
-	/* Adjust sta and change state (from NONE) to NOTEXIST. */
-	KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
-	KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "
-	    "NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));
-	error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);
-	if (error != 0) {
-		IMPROVE("do we need to undo the chan ctx?");
-		ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "
-		    "failed: %d\n", __func__, __LINE__, error);
-		goto out;
-	}
-
-	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);	/* sta no longer save to use. */
-
-	IMPROVE("Any bss_info changes to announce?");
-	vif->bss_conf.qos = 0;
-	bss_changed |= BSS_CHANGED_QOS;
-	vif->cfg.ssid_len = 0;
-	memset(vif->cfg.ssid, '\0', sizeof(vif->cfg.ssid));
-	bss_changed |= BSS_CHANGED_BSSID;
-	vif->bss_conf.dtim_period = 0; /* go back to 0. */
-	bss_changed |= BSS_CHANGED_BEACON_INFO;
-	lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);
-
-	LKPI_80211_LVIF_LOCK(lvif);
-	/* Remove ni reference for this cache of lsta. */
-	lvif->lvif_bss = NULL;
-	lvif->lvif_bss_synched = false;
-	LKPI_80211_LVIF_UNLOCK(lvif);
-	lkpi_lsta_remove(lsta, lvif);
-
-	/* conf_tx */
-
-	lkpi_remove_chanctx(hw, vif);
-
-	error = EALREADY;
-out:
-	wiphy_unlock(hw->wiphy);
-	IEEE80211_LOCK(vap->iv_ic);
-	if (error == EALREADY) {
-		/*
-		 * We do this outside the wiphy lock as net80211::node_free() may call
-		 * into crypto code to delete keys and we have a recursed on
-		 * non-recursive sx panic.  Also only do this if we get here w/o error.
-		 *
-		 * The very last release the reference on the ni for the ni/lsta on
-		 * lvif->lvif_bss.  Upon return from this both ni and lsta are invalid
-		 * and potentially freed.
-		 */
-		ieee80211_free_node(ni);
-	}
-outni:
-	return (error);
-}
-
-static int
-lkpi_sta_assoc_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
-{
-	int error;
-
-	error = _lkpi_sta_assoc_to_down(vap, nstate, arg);
-	if (error != 0 && error != EALREADY)
-		return (error);
-
-	/* At this point iv_bss is long a new node! */
-
-	error |= lkpi_sta_scan_to_auth(vap, nstate, 0);
-	return (error);
-}
-
-static int
-lkpi_sta_assoc_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
-{
-	int error;
-
-	error = _lkpi_sta_assoc_to_down(vap, nstate, arg);
-	return (error);
-}
-
-static int
-lkpi_sta_assoc_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
-{
-	int error;
-
-	error = _lkpi_sta_assoc_to_down(vap, nstate, arg);
-	return (error);
-}
-
-static int
-lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
-{
-	struct lkpi_hw *lhw;
-	struct ieee80211_hw *hw;
-	struct lkpi_vif *lvif;
-	struct ieee80211_vif *vif;
-	struct ieee80211_node *ni;
-	struct lkpi_sta *lsta;
-	struct ieee80211_sta *sta;
-	struct ieee80211_prep_tx_info prep_tx_info;
-	enum ieee80211_bss_changed bss_changed;
-	int error;
-
-	lhw = vap->iv_ic->ic_softc;
-	hw = LHW_TO_HW(lhw);
-	lvif = VAP_TO_LVIF(vap);
-	vif = LVIF_TO_VIF(lvif);
-
-	IEEE80211_UNLOCK(vap->iv_ic);
-	wiphy_lock(hw->wiphy);
-
-	LKPI_80211_LVIF_LOCK(lvif);
-	/* XXX-BZ KASSERT later? */
-	if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {
-#ifdef LINUXKPI_DEBUG_80211
-		ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
-		    "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
-		    lvif, vap, vap->iv_bss, lvif->lvif_bss,
-		    (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
-		    lvif->lvif_bss_synched);
-#endif
-		LKPI_80211_LVIF_UNLOCK(lvif);
-		error = ENOTRECOVERABLE;
-		goto out;
-	}
-	lsta = lvif->lvif_bss;
-	LKPI_80211_LVIF_UNLOCK(lvif);
-	KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
-	    "lvif %p vap %p\n", __func__,
-	    lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
-
-	ni = lsta->ni;		/* Reference held for lvif_bss. */
-
-	IMPROVE("ponder some of this moved to ic_newassoc, scan_assoc_success, "
-	    "and to lesser extend ieee80211_notify_node_join");
-
-	/* Finish assoc. */
-	/* Update sta_state (AUTH to ASSOC) and set aid. */
-	KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "
-	    "AUTH: %#x\n", __func__, lsta, lsta->state));
-	sta = LSTA_TO_STA(lsta);
-	sta->aid = IEEE80211_NODE_AID(ni);
-#ifdef LKPI_80211_WME
-	if (vap->iv_flags & IEEE80211_F_WME)
-		sta->wme = true;
-#endif
-	error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);
-	if (error != 0) {
-		ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "
-		    "failed: %d\n", __func__, __LINE__, error);
-		goto out;
-	}
-
-	IMPROVE("wme / conf_tx [all]");
+	IMPROVE("wme / conf_tx [all]");
 
 	/* Update bss info (bss_info_changed) (assoc, aid, ..). */
 	bss_changed = 0;
@@ -3180,7 +2793,7 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	 * - event_callback
 	 */
 
-	/* End mgd_complete_tx. */
+	/* 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;
@@ -3243,17 +2856,11 @@ out:
 	return (error);
 }
 
-static int
-lkpi_sta_auth_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
-{
-	int error;
-
-	error = lkpi_sta_auth_to_assoc(vap, nstate, arg);
-	if (error == 0)
-		error = lkpi_sta_assoc_to_run(vap, nstate, arg);
-	return (error);
-}
-
+/*
+ * 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, ..
+ */
 static int
 lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
@@ -3276,6 +2883,9 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	lvif = VAP_TO_LVIF(vap);
 	vif = LVIF_TO_VIF(lvif);
 
+	IEEE80211_UNLOCK(vap->iv_ic);
+	wiphy_lock(hw->wiphy);
+
 	LKPI_80211_LVIF_LOCK(lvif);
 #ifdef LINUXKPI_DEBUG_80211
 	/* XXX-BZ KASSERT later; state going down so no action. */
@@ -3297,9 +2907,6 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 
 	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
 
-	IEEE80211_UNLOCK(vap->iv_ic);
-	wiphy_lock(hw->wiphy);
-
 	/* flush, drop. */
 	lkpi_80211_mo_flush(hw, vif,  nitems(sta->txq), true);
 
@@ -3316,7 +2923,7 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	wiphy_unlock(hw->wiphy);
 	IEEE80211_LOCK(vap->iv_ic);
 
-	/* Call iv_newstate first so we get potential DISASSOC packet out. */
+	/* Call iv_newstate first so we get potential (RE-)ASSOC/DEAUTH? packet out. */
 	error = lvif->iv_newstate(vap, nstate, arg);
 	if (error != 0) {
 		ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "
@@ -3363,7 +2970,7 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	lkpi_80211_mo_sync_rx_queues(hw);
 
 	/* sta_pre_rcu_remove */
-        lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);
+	lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);
 #endif
 
 	/* Take the station down. */
@@ -3412,6 +3019,7 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 
 #if 0
 	/* Update bss info (bss_info_changed) (assoc, aid, ..). */
+	/* See comment in DOWN4. */
 	lkpi_disassoc(sta, vif, lhw);
 #endif
 
@@ -3423,8 +3031,15 @@ outni:
 	return (error);
 }
 
+/*
+ * DOWN2
+ * We are in state 2 and go back to state 1 and will try to auth again
+ * (to IEEE80211_S_AUTH in FreeBSD means "try to auth").  This should be
+ * like scan_to_auth but that we keep the "ni" and with that chanctx/bssid,
+ * which essentially makes this "a_to_a" in LinuxKPI.
+ */
 static int
-lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+lkpi_sta_assoc_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
 	struct lkpi_hw *lhw;
 	struct ieee80211_hw *hw;
@@ -3432,10 +3047,6 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	struct ieee80211_vif *vif;
 	struct ieee80211_node *ni;
 	struct lkpi_sta *lsta;
-	struct ieee80211_sta *sta;
-	struct ieee80211_prep_tx_info prep_tx_info;
-	enum ieee80211_bss_changed bss_changed;
-	struct ieee80211_rx_ampdu *rap;
 	int error;
 
 	lhw = vap->iv_ic->ic_softc;
@@ -3463,53 +3074,81 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	    lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
 
 	ni = lsta->ni;		/* Reference held for lvif_bss. */
-	sta = LSTA_TO_STA(lsta);
 
 	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
 
-	/* 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;
+	/* Take the station down. */
+	/* Update sta_state (AUTH to NONE). */
+	KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
+	KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "
+	    "AUTH: %#x\n", __func__, lsta, lsta->state));
+	error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);
+	if (error != 0) {
+		ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "
+		    "failed: %d\n", __func__, __LINE__, error);
+		goto out;
 	}
 
+	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
+
+out:
 	wiphy_unlock(hw->wiphy);
 	IEEE80211_LOCK(vap->iv_ic);
+	return (error);
+}
 
-	/* Call iv_newstate first so we get potential DISASSOC packet out. */
-	error = lvif->iv_newstate(vap, nstate, arg);
-	if (error != 0) {
-		ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "
-		    "failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);
-		goto outni;
-	}
-
-	/* Stop any BA sessions if still active. */
-	for (int rapn = 0; rapn < WME_NUM_TID; rapn++) {
-		rap = &ni->ni_rx_ampdu[rapn];
-
-		if ((rap->rxa_flags & IEEE80211_AGGR_RUNNING) == 0)
-			continue;
+/*
+ * DOWN3
+ * We are in state 1.  Either auth timed out (arg != 0) or we have an internal
+ * state change forcing us to give up trying to authenticate.
+ * Cleanup and remove chanctx, sta, ...
+ */
+static int
+lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+	struct lkpi_hw *lhw;
+	struct ieee80211_hw *hw;
+	struct lkpi_vif *lvif;
+	struct ieee80211_vif *vif;
+	struct ieee80211_node *ni;
+	struct lkpi_sta *lsta;
+	struct ieee80211_sta *sta;
+	struct ieee80211_prep_tx_info prep_tx_info;
+	enum ieee80211_bss_changed bss_changed;
+	int error;
 
-		vap->iv_ic->ic_ampdu_rx_stop(ni, rap);
-	}
+	lhw = vap->iv_ic->ic_softc;
+	hw = LHW_TO_HW(lhw);
+	lvif = VAP_TO_LVIF(vap);
+	vif = LVIF_TO_VIF(lvif);
 
 	IEEE80211_UNLOCK(vap->iv_ic);
+	wiphy_lock(hw->wiphy);
 
-	/* Ensure the packets get out. */
-	lkpi_80211_flush_tx(lhw, lsta);
+	LKPI_80211_LVIF_LOCK(lvif);
+#ifdef LINUXKPI_DEBUG_80211
+	/* XXX-BZ KASSERT later; state going down so no action. */
+	if (lvif->lvif_bss == NULL)
+		ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+		    "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+		    lvif, vap, vap->iv_bss, lvif->lvif_bss,
+		    (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+		    lvif->lvif_bss_synched);
+#endif
 
-	wiphy_lock(hw->wiphy);
+	lsta = lvif->lvif_bss;
+	LKPI_80211_LVIF_UNLOCK(lvif);
+	KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+	    "lvif %p vap %p\n", __func__,
+	    lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+	ni = lsta->ni;			/* Reference held for lvif_bss. */
+	sta = LSTA_TO_STA(lsta);
 
 	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
 
+	/* flush, drop. */
+	lkpi_80211_mo_flush(hw, vif,  nitems(sta->txq), true);
+
 	/* Wake tx queues to get packet(s) out. */
 	lkpi_wake_tx_queues(hw, sta, false, true);
 
@@ -3520,7 +3159,6 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	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;
 	}
@@ -3528,36 +3166,8 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	/* sync_rx_queues */
 	lkpi_80211_mo_sync_rx_queues(hw);
 
-	/* sta_pre_rcu_remove */
-        lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);
-
-	/* Take the station down. */
-
-	/* Adjust sta and change state (from AUTHORIZED) to ASSOC. */
-	KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
-	KASSERT(lsta->state == IEEE80211_STA_AUTHORIZED, ("%s: lsta %p state not "
-	    "AUTHORIZED: %#x\n", __func__, lsta, lsta->state));
-	error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);
-	if (error != 0) {
-		ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "
-		    "failed: %d\n", __func__, __LINE__, error);
-		goto out;
-	}
-
-	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
-
 #ifdef LKPI_80211_HW_CRYPTO
 	if (lkpi_hwcrypto) {
-		/*
-		 * In theory we only need to do this if we changed assoc.
-		 * If we were not assoc, there should be no keys and we
-		 * should not be here.
-		 */
-#ifdef notyet
-		KASSERT((bss_changed & BSS_CHANGED_ASSOC) != 0, ("%s: "
-		    "trying to remove keys but were not assoc: %#010jx, lvif %p\n",
-		    __func__, (uintmax_t)bss_changed, lvif));
-#endif
 		error = lkpi_sta_del_keys(hw, vif, lsta);
 		if (error != 0) {
 			ic_printf(vap->iv_ic, "%s:%d: lkpi_sta_del_keys "
@@ -3572,29 +3182,12 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 	}
 #endif
 
-	/* Update sta_state (ASSOC to AUTH). */
-	KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
-	KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "
-	    "ASSOC: %#x\n", __func__, lsta, lsta->state));
-	error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);
-	if (error != 0) {
-		ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "
-		    "failed: %d\n", __func__, __LINE__, error);
-		goto out;
-	}
+	/* sta_pre_rcu_remove */
+        lkpi_80211_mo_sta_pre_rcu_remove(hw, vif, sta);
 
-	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
+	synchronize_net();
 
-	/* Update sta and change state (from AUTH) to NONE. */
-	KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
-	KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "
-	    "AUTH: %#x\n", __func__, lsta, lsta->state));
-	error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);
-	if (error != 0) {
-		ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "
-		    "failed: %d\n", __func__, __LINE__, error);
-		goto out;
-	}
+	/* Take the station down. */
 
 	bss_changed = 0;
 	/*
@@ -3641,16 +3234,15 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 
 	lkpi_lsta_remove(lsta, lvif);
 
-	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);	/* sta no longer save to use. */
+	lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
 
 	IMPROVE("Any bss_info changes to announce?");
-	vif->bss_conf.qos = 0;
+	vif->bss_conf.qos = false;
 	bss_changed |= BSS_CHANGED_QOS;
 	vif->cfg.ssid_len = 0;
 	memset(vif->cfg.ssid, '\0', sizeof(vif->cfg.ssid));
 	bss_changed |= BSS_CHANGED_BSSID;
 	vif->bss_conf.use_short_preamble = false;
-	vif->bss_conf.qos = false;
 	/* XXX BSS_CHANGED_???? */
 	vif->bss_conf.dtim_period = 0; /* go back to 0. */
 	bss_changed |= BSS_CHANGED_BEACON_INFO;
@@ -3666,11 +3258,10 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 
 	lkpi_remove_chanctx(hw, vif);
 
-	error = EALREADY;
 out:
 	wiphy_unlock(hw->wiphy);
 	IEEE80211_LOCK(vap->iv_ic);
-	if (error == EALREADY) {
+	if (error == 0) {
 		/*
 		 * We do this outside the wiphy lock as net80211::node_free() may call
 		 * into crypto code to delete keys and we have a recursed on
@@ -3682,15 +3273,148 @@ out:
 		 */
 		ieee80211_free_node(ni);
 	}
-outni:
+	return (error);
+}
+
+/* DOWN4 */
+static int
+lkpi_sta_scan_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+	/* lkpi_iv_newstate() handles the stop scan case in common code. */
+	return (lkpi_sta_state_do_nada(vap, nstate, arg));
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+static int
+lkpi_sta_auth_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+	int error;
+
+	error = lkpi_sta_auth_to_scan(vap, nstate, arg);
+	if (error == 0)
+		error = lkpi_sta_scan_to_init(vap, nstate, arg);
+	return (error);
+}
+
+/* auth_to_auth, assoc_to_assoc. */
+static int
+lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+	struct lkpi_hw *lhw;
+	struct ieee80211_hw *hw;
+	struct lkpi_vif *lvif;
+	struct ieee80211_vif *vif;
+	struct lkpi_sta *lsta;
+	struct ieee80211_prep_tx_info prep_tx_info;
+	int error;
+
+	lhw = vap->iv_ic->ic_softc;
+	hw = LHW_TO_HW(lhw);
+	lvif = VAP_TO_LVIF(vap);
+	vif = LVIF_TO_VIF(lvif);
*** 161 LINES SKIPPED ***


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69a101bc.220af.2922828e>