From: Kirill A. Korinsky Subject: The 4th batch of qwz fixes and backports To: Stefan Sperling Cc: OpenBSD tech Date: Wed, 30 Sep 2026 13:54:08 +0200 Stefan, 3rd batch without one commit was commited. So, I'd like to move on and here the 4th batch quite small batch. OK? From 72864d1ec94b2a5b20995fb207af9790adb865a3 Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Sun, 27 Sep 2026 12:55:13 +0200 Subject: [PATCH 1/8] sys/qwz: use the standard media callback Backport of sys/dev/ic/qwx.c,v 1.133 and sys/dev/pci/if_qwx_pci.c,v 1.37 --- sys/dev/ic/qwz.c | 19 +------------------ sys/dev/ic/qwzvar.h | 1 - sys/dev/pci/if_qwz_pci.c | 2 +- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c index 2e2eb80461c..0ea3e795d24 100644 --- a/sys/dev/ic/qwz.c +++ b/sys/dev/ic/qwz.c @@ -331,7 +331,7 @@ qwz_init(struct ifnet *ifp) sc->sc_dev.dv_xname, ether_sprintf(ic->ic_myaddr), error); - ieee80211_media_init(ifp, qwz_media_change, + ieee80211_media_init(ifp, ieee80211_media_change, ieee80211_media_status); } @@ -605,23 +605,6 @@ qwz_watchdog(struct ifnet *ifp) ieee80211_watchdog(ifp); } -int -qwz_media_change(struct ifnet *ifp) -{ - int err; - - err = ieee80211_media_change(ifp); - if (err != ENETRESET) - return err; - - if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == - (IFF_UP | IFF_RUNNING)) { - qwz_stop(ifp); - err = qwz_init(ifp); - } - - return err; -} int qwz_queue_setkey_cmd(struct ieee80211com *ic, struct ieee80211_node *ni, diff --git a/sys/dev/ic/qwzvar.h b/sys/dev/ic/qwzvar.h index 6f748f92b59..738bc29d247 100644 --- a/sys/dev/ic/qwzvar.h +++ b/sys/dev/ic/qwzvar.h @@ -2155,7 +2155,6 @@ int qwz_ioctl(struct ifnet *, u_long, caddr_t); void qwz_start(struct ifnet *); void qwz_stop(struct ifnet *); void qwz_watchdog(struct ifnet *); -int qwz_media_change(struct ifnet *); void qwz_init_task(void *); int qwz_newstate(struct ieee80211com *, enum ieee80211_state, int); void qwz_newstate_task(void *); diff --git a/sys/dev/pci/if_qwz_pci.c b/sys/dev/pci/if_qwz_pci.c index 4bd8819d41a..1c7c3895c72 100644 --- a/sys/dev/pci/if_qwz_pci.c +++ b/sys/dev/pci/if_qwz_pci.c @@ -995,7 +995,7 @@ qwz_pci_attach(struct device *parent, struct device *self, void *aux) memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); if_attach(ifp); ieee80211_ifattach(ifp); - ieee80211_media_init(ifp, qwz_media_change, ieee80211_media_status); + ieee80211_media_init(ifp, ieee80211_media_change, ieee80211_media_status); ic->ic_node_alloc = qwz_node_alloc; -- 2.55.0 From 6abc6bbdd521bc49436774807ec320b170f66245 Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Sun, 27 Sep 2026 12:56:05 +0200 Subject: [PATCH 2/8] sys/qwz: respect the configured scan PHY mode Backport of sys/dev/ic/qwx.c,v 1.68 --- sys/dev/ic/qwz.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c index 0ea3e795d24..d091fe175ee 100644 --- a/sys/dev/ic/qwz.c +++ b/sys/dev/ic/qwz.c @@ -23935,6 +23935,7 @@ qwz_scan(struct qwz_softc *sc) struct ieee80211_channel *chan, *lastc; int ret = 0, num_channels, i; uint32_t scan_timeout; + int scan_2ghz = 1, scan_5ghz = 1; /* * TODO Will we need separate scan iterations on devices with @@ -23997,11 +23998,22 @@ qwz_scan(struct qwz_softc *sc) } else arg->scan_flags |= WMI_SCAN_FLAG_PASSIVE; + if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) != IFM_AUTO) { + if (ic->ic_curmode == IEEE80211_MODE_11A) + scan_2ghz = 0; + if (ic->ic_curmode == IEEE80211_MODE_11B || + ic->ic_curmode == IEEE80211_MODE_11G) + scan_5ghz = 0; + } + lastc = &ic->ic_channels[IEEE80211_CHAN_MAX]; num_channels = 0; for (chan = &ic->ic_channels[1]; chan <= lastc; chan++) { if (chan->ic_flags == 0) continue; + if ((!scan_2ghz && IEEE80211_IS_CHAN_2GHZ(chan)) || + (!scan_5ghz && IEEE80211_IS_CHAN_5GHZ(chan))) + continue; num_channels++; } if (num_channels) { @@ -24018,6 +24030,9 @@ qwz_scan(struct qwz_softc *sc) for (chan = &ic->ic_channels[1]; chan <= lastc; chan++) { if (chan->ic_flags == 0) continue; + if ((!scan_2ghz && IEEE80211_IS_CHAN_2GHZ(chan)) || + (!scan_5ghz && IEEE80211_IS_CHAN_5GHZ(chan))) + continue; arg->chan_list[i++] = chan->ic_freq; } } @@ -24051,7 +24066,7 @@ qwz_scan(struct qwz_softc *sc) * The current mode might have been fixed during association. * Ensure all channels get scanned. */ - if (IFM_SUBTYPE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) + if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); } #if 0 -- 2.55.0 From 10f7f769b3b6f4acd7f744c80f531f7bf16d3850 Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Sun, 27 Sep 2026 12:55:59 +0200 Subject: [PATCH 3/8] sys/qwz: stop firmware scans on interface down Based on sys/dev/ic/qwx.c,v 1.72 Abort firmware scans during interface stop, including scans still starting; taer down started vdevs and remaining peers even when net80211 has not reached AUTH. --- sys/dev/ic/qwz.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c index d091fe175ee..8be9dd8bddd 100644 --- a/sys/dev/ic/qwz.c +++ b/sys/dev/ic/qwz.c @@ -410,11 +410,15 @@ qwz_stop(struct ifnet *ifp) clear_bit(ATH12K_FLAG_CRASH_FLUSH, sc->sc_flags); + if (sc->scan.state != ATH12K_SCAN_IDLE) + qwz_scan_abort(sc); + /* Tear down firmware-side association so we can re-associate. */ if (sc->num_created_vdevs != 0) { if (ic->ic_state == IEEE80211_S_RUN) qwz_run_stop(sc); - if (ic->ic_state >= IEEE80211_S_AUTH) + if (ic->ic_state >= IEEE80211_S_AUTH || + sc->num_started_vdevs > 0 || !TAILQ_EMPTY(&sc->peers)) qwz_deauth(sc); } @@ -24105,11 +24109,11 @@ qwz_scan_abort(struct qwz_softc *sc) * abortion while scan completion was being processed. */ break; - case ATH12K_SCAN_STARTING: case ATH12K_SCAN_ABORTING: printf("%s: refusing scan abortion due to invalid " "scan state: %d\n", sc->sc_dev.dv_xname, sc->scan.state); break; + case ATH12K_SCAN_STARTING: case ATH12K_SCAN_RUNNING: sc->scan.state = ATH12K_SCAN_ABORTING; #ifdef notyet -- 2.55.0 From 1a27403747cb1606e8b0404aad80110bdcd3dadb Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Sun, 27 Sep 2026 12:56:33 +0200 Subject: [PATCH 4/8] sys/qwz: handle scan events during cancellation Ignore late scan started events while cancellation is pending; finish an aborting scan when firmware reports that startup failed. --- sys/dev/ic/qwz.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c index 8be9dd8bddd..07fa50211c9 100644 --- a/sys/dev/ic/qwz.c +++ b/sys/dev/ic/qwz.c @@ -11329,11 +11329,12 @@ qwz_wmi_event_scan_started(struct qwz_softc *sc) switch (sc->scan.state) { case ATH12K_SCAN_IDLE: case ATH12K_SCAN_RUNNING: - case ATH12K_SCAN_ABORTING: printf("%s: received scan started event in an invalid " "scan state: %s (%d)\n", sc->sc_dev.dv_xname, qwz_scan_state_str(sc->scan.state), sc->scan.state); break; + case ATH12K_SCAN_ABORTING: + break; case ATH12K_SCAN_STARTING: sc->scan.state = ATH12K_SCAN_RUNNING; #if 0 @@ -11426,12 +11427,12 @@ qwz_wmi_event_scan_start_failed(struct qwz_softc *sc) switch (sc->scan.state) { case ATH12K_SCAN_IDLE: case ATH12K_SCAN_RUNNING: - case ATH12K_SCAN_ABORTING: printf("%s: received scan start failed event in an invalid " "scan state: %s (%d)\n", sc->sc_dev.dv_xname, qwz_scan_state_str(sc->scan.state), sc->scan.state); break; case ATH12K_SCAN_STARTING: + case ATH12K_SCAN_ABORTING: wakeup(&sc->scan.state); qwz_mac_scan_finish(sc); break; -- 2.55.0 From 5b011561d1736bf51931128ba3bebded90444c90 Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Sun, 27 Sep 2026 12:56:02 +0200 Subject: [PATCH 5/8] sys/qwz: discard stale foreground scan results Backport of sys/dev/ic/qwx.c,v 1.79 --- sys/dev/ic/qwz.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c index 07fa50211c9..9ed19d5fffa 100644 --- a/sys/dev/ic/qwz.c +++ b/sys/dev/ic/qwz.c @@ -1002,6 +1002,11 @@ qwz_newstate_task(void *arg) } /* FALLTHROUGH */ case IEEE80211_S_SCAN: + if (sc->scan.state == ATH12K_SCAN_RUNNING) + qwz_scan_abort(sc); + if (nstate == IEEE80211_S_SCAN) + ieee80211_free_allnodes(ic, 0); + break; case IEEE80211_S_INIT: break; } -- 2.55.0 From 90d8248eb00c8253ba4a0b6894ca067be1882db5 Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Sun, 27 Sep 2026 12:54:37 +0200 Subject: [PATCH 6/8] sys/qwz: report HT transmit rates Backport missed pieces from sys/dev/ic/qwx.c,v 1.85 --- sys/dev/ic/qwz.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c index 9ed19d5fffa..556ae29be6e 100644 --- a/sys/dev/ic/qwz.c +++ b/sys/dev/ic/qwz.c @@ -14448,9 +14448,13 @@ qwz_dp_tx_complete_msdu(struct qwz_softc *sc, struct dp_tx_ring *tx_ring, pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE, ts->rate_stats); mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS, ts->rate_stats); - if (qwz_mac_hw_ratecode_to_legacy_rate(tx_data->ni, mcs, pkt_type, - &rateidx, &rate) == 0) - tx_data->ni->ni_txrate = rateidx; + if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A || + pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) { + if (qwz_mac_hw_ratecode_to_legacy_rate(tx_data->ni, mcs, pkt_type, + &rateidx, &rate) == 0) + tx_data->ni->ni_txrate = rateidx; + } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) + tx_data->ni->ni_txmcs = mcs; ieee80211_release_node(ic, tx_data->ni); tx_data->ni = NULL; -- 2.55.0 From 9dbddcc99b345dd60b863fe6ef301835f2c6dd57 Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Sun, 27 Sep 2026 12:55:31 +0200 Subject: [PATCH 7/8] sys/qwz: track pairwise and group RX ciphers Backport of sys/dev/ic/qwx.c,v 1.88 and sys/dev/ic/qwxvar.h,v 1.30 fix qwx enctype setting for received group-encrypted frames --- sys/dev/ic/qwz.c | 60 +++++++++++++++++++++++++++++---------------- sys/dev/ic/qwzvar.h | 8 +++--- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c index 556ae29be6e..ea92efb0f67 100644 --- a/sys/dev/ic/qwz.c +++ b/sys/dev/ic/qwz.c @@ -752,6 +752,25 @@ qwz_wmi_install_key_cmd(struct qwz_softc *sc, struct qwz_vif *arvif, return sc->install_key_status; } +enum hal_encrypt_type +qwz_dp_tx_get_encrypt_type(enum ieee80211_cipher cipher) +{ + switch (cipher) { + case IEEE80211_CIPHER_NONE: + return HAL_ENCRYPT_TYPE_OPEN; + case IEEE80211_CIPHER_WEP40: + return HAL_ENCRYPT_TYPE_WEP_40; + case IEEE80211_CIPHER_WEP104: + return HAL_ENCRYPT_TYPE_WEP_104; + case IEEE80211_CIPHER_TKIP: + return HAL_ENCRYPT_TYPE_TKIP_MIC; + case IEEE80211_CIPHER_CCMP: + return HAL_ENCRYPT_TYPE_CCMP_128; + default: + panic("unknown cipher 0x%x", cipher); + } +} + int qwz_add_sta_key(struct qwz_softc *sc, struct ieee80211_node *ni, struct ieee80211_key *k) @@ -762,6 +781,7 @@ qwz_add_sta_key(struct qwz_softc *sc, struct ieee80211_node *ni, struct qwz_vif *arvif = &sc->sc_vif; int ret = 0; uint32_t flags = 0; + uint16_t *sec_type, old_sec_type; const int want_keymask = (QWZ_NODE_FLAG_HAVE_PAIRWISE_KEY | QWZ_NODE_FLAG_HAVE_GROUP_KEY); @@ -775,13 +795,19 @@ qwz_add_sta_key(struct qwz_softc *sc, struct ieee80211_node *ni, */ qwz_peer_frags_flush(sc, peer); - if (k->k_flags & IEEE80211_KEY_GROUP) + if (k->k_flags & IEEE80211_KEY_GROUP) { flags |= WMI_KEY_GROUP; - else + sec_type = &peer->sec_type_grp; + } else { flags |= WMI_KEY_PAIRWISE; + sec_type = &peer->sec_type; + } + old_sec_type = *sec_type; + *sec_type = qwz_dp_tx_get_encrypt_type(k->k_cipher); ret = qwz_wmi_install_key_cmd(sc, arvif, ni->ni_macaddr, k, flags, 0); if (ret) { + *sec_type = old_sec_type; printf("%s: installing crypto key failed (%d)\n", sc->sc_dev.dv_xname, ret); return ret; @@ -1776,8 +1802,8 @@ const struct hal_rx_ops hal_rx_wcn7850_ops = { #ifdef notyet .rx_desc_get_mesh_ctl = qwz_hw_wcn7850_rx_desc_get_mesh_ctl, .rx_desc_get_mpdu_seq_ctl_vld = qwz_hw_wcn7850_rx_desc_get_mpdu_seq_ctl_vld, - .rx_desc_get_mpdu_start_seq_no = qwz_hw_wcn7850_rx_desc_get_mpdu_start_seq_no, #endif + .rx_desc_get_mpdu_start_seq_no = qwz_hw_wcn7850_rx_desc_get_mpdu_start_seq_no, .rx_desc_get_mpdu_fc_valid = qwz_hw_wcn7850_rx_desc_get_mpdu_fc_valid, .rx_desc_get_msdu_len = qwz_hw_wcn7850_rx_desc_get_msdu_len, #ifdef notyet @@ -15435,38 +15461,28 @@ qwz_dp_rx_h_mpdu(struct qwz_softc *sc, struct qwz_rx_msdu *msdu, int fill_crypto_hdr = 0; enum hal_encrypt_type enctype; int is_decrypted = 0, ret; -#if 0 - struct ath12k_skb_rxcb *rxcb; -#endif struct ieee80211_frame *wh; -#if 0 struct ath12k_peer *peer; -#endif uint32_t err_bitmap; /* PN for multicast packets will be checked in net80211 */ fill_crypto_hdr = qwz_dp_rx_h_is_da_mcbc(sc, rx_desc); msdu->is_mcbc = fill_crypto_hdr; -#if 0 - if (rxcb->is_mcbc) { - rxcb->peer_id = ath12k_dp_rx_h_mpdu_start_peer_id(ar->ab, rx_desc); - rxcb->seq_no = ath12k_dp_rx_h_mpdu_start_seq_no(ar->ab, rx_desc); + if (msdu->is_mcbc) { + msdu->peer_id = sc->hal_rx_ops->rx_desc_get_mpdu_peer_id(rx_desc); + msdu->seq_no = sc->hal_rx_ops->rx_desc_get_mpdu_start_seq_no( + rx_desc); } - spin_lock_bh(&ar->ab->base_lock); - peer = ath12k_dp_rx_h_find_peer(ar->ab, msdu); + peer = qwz_peer_find_by_id(sc, msdu->peer_id); if (peer) { - if (rxcb->is_mcbc) + if (msdu->is_mcbc) enctype = peer->sec_type_grp; else enctype = peer->sec_type; - } else { -#endif + } else enctype = qwz_dp_rx_h_enctype(sc, rx_desc); -#if 0 - } - spin_unlock_bh(&ar->ab->base_lock); -#endif + err_bitmap = qwz_dp_rx_h_h_mpdu_err(sc, rx_desc); if (enctype != HAL_ENCRYPT_TYPE_OPEN && !err_bitmap) is_decrypted = qwz_dp_rx_h_is_decrypted(sc, rx_desc); @@ -22492,6 +22508,8 @@ qwz_peer_create(struct qwz_softc *sc, struct qwz_vif *arvif, uint8_t pdev_id, if (peer == NULL) return ENOMEM; peer->peer_id = HAL_INVALID_PEERID; + peer->sec_type = HAL_ENCRYPT_TYPE_OPEN; + peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN; peer->vdev_id = param->vdev_id; peer->pdev_id = pdev_id; IEEE80211_ADDR_COPY(peer->addr, param->peer_addr); diff --git a/sys/dev/ic/qwzvar.h b/sys/dev/ic/qwzvar.h index 738bc29d247..c21ad3ee860 100644 --- a/sys/dev/ic/qwzvar.h +++ b/sys/dev/ic/qwzvar.h @@ -283,8 +283,8 @@ struct hal_rx_ops { #ifdef notyet uint8_t (*rx_desc_get_mesh_ctl)(struct hal_rx_desc *desc); bool (*rx_desc_get_mpdu_seq_ctl_vld)(struct hal_rx_desc *desc); - uint16_t (*rx_desc_get_mpdu_start_seq_no)(struct hal_rx_desc *desc); #endif + uint16_t (*rx_desc_get_mpdu_start_seq_no)(struct hal_rx_desc *desc); bool (*rx_desc_get_mpdu_fc_valid)(struct hal_rx_desc *desc); uint16_t (*rx_desc_get_msdu_len)(struct hal_rx_desc *desc); #ifdef notyet @@ -1941,8 +1941,10 @@ struct ath12k_peer { struct crypto_shash *tfm_mmic; u8 mcast_keyidx; u8 ucast_keyidx; - u16 sec_type; - u16 sec_type_grp; +#endif + uint16_t sec_type; + uint16_t sec_type_grp; +#if 0 bool is_authorized; bool dp_setup_done; #endif -- 2.55.0 From b19572b6cefbd9aabec5812d6f7e5f3da98af853 Mon Sep 17 00:00:00 2001 From: "Kirill A. Korinsky" Date: Sun, 27 Sep 2026 12:56:48 +0200 Subject: [PATCH 8/8] sys/qwz: avoid peer access after key waits Do not retain a pointer into peer cipher state across key installation. Installation can sleep while the peer is removed; dropping the failure rollback avoids accessing freed peer memory. --- sys/dev/ic/qwz.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sys/dev/ic/qwz.c b/sys/dev/ic/qwz.c index ea92efb0f67..94d3c5d8e9f 100644 --- a/sys/dev/ic/qwz.c +++ b/sys/dev/ic/qwz.c @@ -781,7 +781,6 @@ qwz_add_sta_key(struct qwz_softc *sc, struct ieee80211_node *ni, struct qwz_vif *arvif = &sc->sc_vif; int ret = 0; uint32_t flags = 0; - uint16_t *sec_type, old_sec_type; const int want_keymask = (QWZ_NODE_FLAG_HAVE_PAIRWISE_KEY | QWZ_NODE_FLAG_HAVE_GROUP_KEY); @@ -797,17 +796,14 @@ qwz_add_sta_key(struct qwz_softc *sc, struct ieee80211_node *ni, if (k->k_flags & IEEE80211_KEY_GROUP) { flags |= WMI_KEY_GROUP; - sec_type = &peer->sec_type_grp; + peer->sec_type_grp = qwz_dp_tx_get_encrypt_type(k->k_cipher); } else { flags |= WMI_KEY_PAIRWISE; - sec_type = &peer->sec_type; + peer->sec_type = qwz_dp_tx_get_encrypt_type(k->k_cipher); } - old_sec_type = *sec_type; - *sec_type = qwz_dp_tx_get_encrypt_type(k->k_cipher); ret = qwz_wmi_install_key_cmd(sc, arvif, ni->ni_macaddr, k, flags, 0); if (ret) { - *sec_type = old_sec_type; printf("%s: installing crypto key failed (%d)\n", sc->sc_dev.dv_xname, ret); return ret; -- 2.55.0 -- wbr, Kirill