Index | Thread | Search

From:
Mark Kettenis <mark.kettenis@xs4all.nl>
Subject:
Re: iwx: roaming fix for MA/Bz devices and PMF
To:
Stefan Sperling <stsp@stsp.name>
Cc:
tech@openbsd.org
Date:
Thu, 05 Feb 2026 23:24:39 +0100

Download raw body.

Thread
> Date: Tue, 3 Feb 2026 17:01:14 +0100
> From: Stefan Sperling <stsp@stsp.name>
> 
> Tests of this patch while using roaming on any iwx(4) device would be
> much appreciated.
> 
> Bz device firmware throws a fatal firmware error if we attempt to remove
> the firmware AP station before removing associated crypto keys. We currently
> rely on firmware to implicitly remove keys along with the station and this
> will no longer work on Bz.
> The same might be true for MA devices, not sure. I cannot test them.

Tested this diff on:

iwx0 at pci0 dev 20 function 3 "Intel Wi-Fi 6 AX210" rev 0x20, msix
iwx0: hw rev 0x440, fw 83.d24e06ed.0, pnvm 285b3568, address dc:45:46:e7:d5:33

This is FW version 83, so it must be MA ;).

Doesn't seem to make a difference here.  But I'm not roaming between
access points.

On the bright side, it seems this device works a lot better now.  But
I'm also using a different access point now.  Will do a bit more
testing before declaring that MA now work.


> Also improve roaming behaviour when PMF is enabled. We must send the deauth
> frame to the old AP properly encrypted, so send it before keys get removed.
> 
> Thanks to Johannes Berg for deciphering firmware SYSASSERT code 0x0000251B.
> 
> M  sys/dev/pci/if_iwx.c           |  56+  3-
> M  sys/net80211/ieee80211_node.c  |   0+  1-
> M  sys/net80211/ieee80211_node.h  |   1+  0-
> 
> 3 files changed, 57 insertions(+), 4 deletions(-)
> 
> commit - d2b520ec61a7e83d4019845aa16dddcae54a25b4
> commit + d8efa19ebc99e3df6b75c7977d2708263746ca57
> blob - 5889c86b6502beae028604eb0d51cca7f59b6b07
> blob + b635a2b55989d3076d60629e301534c684262611
> --- sys/dev/pci/if_iwx.c
> +++ sys/dev/pci/if_iwx.c
> @@ -481,6 +481,7 @@ int	iwx_send_temp_report_ths_cmd(struct iwx_softc *);
>  int	iwx_init_hw(struct iwx_softc *);
>  int	iwx_init(struct ifnet *);
>  void	iwx_start(struct ifnet *);
> +void	iwx_mfp_leave(struct iwx_softc *);
>  void	iwx_stop(struct ifnet *);
>  void	iwx_watchdog(struct ifnet *);
>  int	iwx_ioctl(struct ifnet *, u_long, caddr_t);
> @@ -7982,6 +7983,43 @@ iwx_bgscan_done_task(void *arg)
>  	}
>  
>  	/*
> +	 * Remove installed crypto keys while we still have access to them.
> +	 * Once iwx_newstate() is entered ic_bss will already contain
> +	 * information about our next AP.
> +	 */
> +	if (ic->ic_flags & IEEE80211_F_RSNON) {
> +		struct ieee80211_key *k;
> +
> +		if (ic->ic_bss->ni_flags & IEEE80211_NODE_MFP)
> +			iwx_mfp_leave(sc);
> +	
> +		if (in->in_flags & IWX_NODE_FLAG_HAVE_PAIRWISE_KEY)
> +			(*ic->ic_delete_key)(ic, ni, &ni->ni_pairwise_key);
> +
> +		if ((in->in_flags & IWX_NODE_FLAG_HAVE_GROUP_KEY) &&
> +		    (ic->ic_def_txkey == 1 || ic->ic_def_txkey == 2)) {
> +			k = &ic->ic_nw_keys[ic->ic_def_txkey];
> +			if ((k->k_flags & IEEE80211_KEY_GROUP) &&
> +			    k->k_cipher == IEEE80211_CIPHER_CCMP)
> +				(*ic->ic_delete_key)(ic, ni, k);
> +		}
> +
> +		if ((in->in_flags & IWX_NODE_FLAG_HAVE_INTEGRITY_GROUP_KEY) &&
> +		    (ic->ic_igtk_kid == 4 || ic->ic_igtk_kid == 5)) {
> +
> +			k = &ic->ic_nw_keys[ic->ic_igtk_kid];
> +			if (k->k_flags & IEEE80211_KEY_IGTK)
> +				(*ic->ic_delete_key)(ic, ni, k);
> +		}
> +
> +		ni->ni_port_valid = 0;
> +		ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT;
> +		ni->ni_flags &= ~IEEE80211_NODE_TXMGMTPROT;
> +		ni->ni_flags &= ~IEEE80211_NODE_RXMGMTPROT;
> +		ni->ni_rsn_supp_state = RSNA_SUPP_INITIALIZE;
> +	}
> +
> +	/*
>  	 * Tx queues have been flushed and Tx agg has been stopped.
>  	 * Allow roaming to proceed.
>  	 */
> @@ -7989,7 +8027,11 @@ iwx_bgscan_done_task(void *arg)
>  	ni->ni_unref_arg_size = sc->bgscan_unref_arg_size;
>  	sc->bgscan_unref_arg = NULL;
>  	sc->bgscan_unref_arg_size = 0;
> -	ieee80211_node_tx_stopped(ic, &in->in_ni);
> +	if (ni->ni_flags & IEEE80211_NODE_MFP) {
> +		/* Deauth frame already sent. */
> +		ieee80211_node_switch_bss(ic, &in->in_ni);
> +	} else
> +		ieee80211_node_tx_stopped(ic, &in->in_ni);
>  done:
>  	if (err) {
>  		free(sc->bgscan_unref_arg, M_DEVBUF, sc->bgscan_unref_arg_size);
> @@ -8844,6 +8886,13 @@ iwx_mld_set_sta_key_cmd(struct iwx_softc *sc, int sta_
>  		return err;
>  	}
>  
> +	if (!remove_key) {
> +		if (k->k_flags & IEEE80211_KEY_GROUP)
> +			ic->ic_def_txkey = k->k_id;
> +		if (k->k_flags & IEEE80211_KEY_IGTK)
> +			ic->ic_igtk_kid = k->k_id;
> +	}
> +
>  	return 0;
>  }
>  
> @@ -8890,6 +8939,9 @@ iwx_add_sta_key_cmd(struct iwx_softc *sc, int sta_id,
>  		return err;
>  	}
>  
> +	if (k->k_flags & IEEE80211_KEY_GROUP)
> +		ic->ic_def_txkey = k->k_id;
> +
>  	return 0;
>  }
>  
> @@ -8990,9 +9042,10 @@ iwx_add_sta_key(struct iwx_softc *sc, int sta_id, stru
>  	if (k->k_flags & IEEE80211_KEY_IGTK) {
>  		in->in_flags |= IWX_NODE_FLAG_HAVE_INTEGRITY_GROUP_KEY;
>  		ic->ic_igtk_kid = k->k_id;
> -	} else if (k->k_flags & IEEE80211_KEY_GROUP)
> +	} else if (k->k_flags & IEEE80211_KEY_GROUP) {
>  		in->in_flags |= IWX_NODE_FLAG_HAVE_GROUP_KEY;
> -	else
> +		ic->ic_def_txkey = k->k_id;
> +	} else
>  		in->in_flags |= IWX_NODE_FLAG_HAVE_PAIRWISE_KEY;
>  
>  	if ((in->in_flags & want_keymask) == want_keymask) {
> blob - 6a6d141a064a5746eb967c37b1543069ce238048
> blob + 7ea1edd5828a9f48fe870dd191c6f24ae9a0e199
> --- sys/net80211/ieee80211_node.c
> +++ sys/net80211/ieee80211_node.c
> @@ -75,7 +75,6 @@ void ieee80211_setup_node(struct ieee80211com *, struc
>  struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *);
>  void ieee80211_node_free_unref_cb(struct ieee80211_node *);
>  void ieee80211_node_tx_flushed(struct ieee80211com *, struct ieee80211_node *);
> -void ieee80211_node_switch_bss(struct ieee80211com *, struct ieee80211_node *);
>  void ieee80211_node_addba_request(struct ieee80211_node *, int);
>  void ieee80211_node_addba_request_ac_be_to(void *);
>  void ieee80211_node_addba_request_ac_bk_to(void *);
> blob - 8a6a267cf1c06fc0ba5e14a9b30e50052a22e48b
> blob + db4d49ac605aa07d08bc78700a82d59215f91e81
> --- sys/net80211/ieee80211_node.h
> +++ sys/net80211/ieee80211_node.h
> @@ -656,6 +656,7 @@ void ieee80211_node_join(struct ieee80211com *,
>  void ieee80211_node_leave(struct ieee80211com *,
>  		struct ieee80211_node *);
>  int ieee80211_match_bss(struct ieee80211com *, struct ieee80211_node *, int);
> +void ieee80211_node_switch_bss(struct ieee80211com *, struct ieee80211_node *);
>  void ieee80211_node_tx_stopped(struct ieee80211com *, struct ieee80211_node *);
>  struct ieee80211_node *ieee80211_node_choose_bss(struct ieee80211com *, int,
>  		struct ieee80211_node **);
> 
>