Download raw body.
iwx: roaming fix for MA/Bz devices and PMF
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.
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 **);
iwx: roaming fix for MA/Bz devices and PMF