From: Stefan Sperling Subject: qwx background scan and roaming support To: tech@openbsd.org Date: Thu, 24 Jul 2025 15:46:42 +0200 Add background scan and roaming support to qwx. This patch sits on top of the previous diffs I sent today, which have been now committed. M sys/dev/ic/qwx.c | 107+ 4- M sys/dev/ic/qwxvar.h | 2+ 0- M sys/dev/pci/if_qwx_pci.c | 2+ 0- 3 files changed, 111 insertions(+), 4 deletions(-) commit - 25fdf95e122e33891e7ad3898002cfe29d094cc1 commit + 3c01a782bb3d337863a438d785bb8fdfb8751d1c blob - f9996b63e8d39f993fea116ca38ca8179b471f61 blob + 83c3f17a6a14062c7b61e273e5eabb7a12fc3943 --- sys/dev/ic/qwx.c +++ sys/dev/ic/qwx.c @@ -163,7 +163,7 @@ void qwx_vif_free_all(struct qwx_softc *); void qwx_dp_stop_shadow_timers(struct qwx_softc *); void qwx_ce_stop_shadow_timers(struct qwx_softc *); -int qwx_scan(struct qwx_softc *); +int qwx_scan(struct qwx_softc *, int); void qwx_scan_abort(struct qwx_softc *); int qwx_auth(struct qwx_softc *); int qwx_deauth(struct qwx_softc *); @@ -373,6 +373,7 @@ qwx_stop(struct ifnet *ifp) task_del(systq, &sc->init_task); qwx_del_task(sc, sc->sc_nswq, &sc->newstate_task); qwx_del_task(sc, systq, &sc->setkey_task); + qwx_del_task(sc, systq, &sc->bgscan_task); refcnt_finalize(&sc->task_refs, "qwxstop"); qwx_setkey_clear(sc); @@ -868,6 +869,76 @@ qwx_setkey_task(void *arg) } void +qwx_clear_hwkeys(struct qwx_softc *sc, struct ath11k_peer *peer) +{ + struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); /* XXX */ + uint8_t pdev_id = 0; /* TODO: derive pdev ID somehow? */ + struct wmi_vdev_install_key_arg arg = { + .vdev_id = arvif->vdev_id, + .key_len = 0, + .key_data = NULL, + .key_cipher = WMI_CIPHER_NONE, + .key_flags = 0, + }; + int k_id = 0, ret; + + arg.macaddr = peer->addr; + + for (k_id = 0; k_id <= WMI_MAX_KEY_INDEX; k_id++) { + arg.key_idx = k_id; + + sc->install_key_done = 0; + ret = qwx_wmi_vdev_install_key(sc, &arg, pdev_id); + if (ret) { + printf("%s: delete key %d failed: error %d\n", + sc->sc_dev.dv_xname, k_id, ret); + continue; + } + + while (!sc->install_key_done) { + ret = tsleep_nsec(&sc->install_key_done, 0, + "qwxinstkey", SEC_TO_NSEC(1)); + if (ret) { + printf("%s: delete key %d timeout\n", + sc->sc_dev.dv_xname, k_id); + } + } + } +} + +void +qwx_clear_pn_replay_config(struct qwx_softc *sc, struct ath11k_peer *peer) +{ + struct ath11k_hal_reo_cmd cmd = {0}; + struct dp_rx_tid *rx_tid; + uint8_t tid; + int ret = 0; + + cmd.flag |= HAL_REO_CMD_FLG_NEED_STATUS; + cmd.upd0 |= HAL_REO_CMD_UPD0_PN | + HAL_REO_CMD_UPD0_PN_SIZE | + HAL_REO_CMD_UPD0_PN_VALID | + HAL_REO_CMD_UPD0_PN_CHECK | + HAL_REO_CMD_UPD0_SVLD; + + for (tid = 0; tid < IEEE80211_NUM_TID; tid++) { + rx_tid = &peer->rx_tid[tid]; + if (!rx_tid->active) + continue; + cmd.addr_lo = rx_tid->paddr & 0xffffffff; + cmd.addr_hi = (rx_tid->paddr >> 32); + ret = qwx_dp_tx_send_reo_cmd(sc, rx_tid, + HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, NULL); + if (ret) { + printf("%s: failed to configure rx tid %d queue " + "for pn replay detection %d\n", + sc->sc_dev.dv_xname, tid, ret); + break; + } + } +} + +void qwx_setkey_clear(struct qwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; @@ -910,6 +981,8 @@ qwx_newstate(struct ieee80211com *ic, enum ieee80211_s #endif qwx_del_task(sc, systq, &sc->setkey_task); qwx_setkey_clear(sc); + + qwx_del_task(sc, systq, &sc->bgscan_task); #if 0 qwx_del_task(sc, systq, &sc->bgscan_done_task); #endif @@ -991,7 +1064,7 @@ qwx_newstate_task(void *arg) case IEEE80211_S_SCAN: next_scan: - err = qwx_scan(sc); + err = qwx_scan(sc, 0); if (err) break; if (ifp->if_flags & IFF_DEBUG) @@ -25242,7 +25315,7 @@ qwx_start_scan(struct qwx_softc *sc, struct scan_req_p #define ATH11K_MAC_SCAN_CMD_EVT_OVERHEAD 200 /* in msecs */ int -qwx_scan(struct qwx_softc *sc) +qwx_scan(struct qwx_softc *sc, int bgscan) { struct ieee80211com *ic = &sc->sc_ic; struct qwx_vif *arvif = TAILQ_FIRST(&sc->vif_list); @@ -25406,7 +25479,7 @@ qwx_scan(struct qwx_softc *sc) #ifdef notyet spin_unlock_bh(&ar->data_lock); #endif - } else { + } else if (!bgscan) { /* * The current mode might have been fixed during association. * Ensure all channels get scanned. @@ -25474,6 +25547,31 @@ qwx_scan_abort(struct qwx_softc *sc) #endif } +void +qwx_bgscan_task(void *arg) +{ + struct qwx_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_state == IEEE80211_S_RUN && + sc->scan.state == ATH11K_SCAN_IDLE && + !test_bit(ATH11K_FLAG_CRASH_FLUSH, sc->sc_flags)) + qwx_scan(sc, 1); + + refcnt_rele_wake(&sc->task_refs); +} + +int +qwx_bgscan(struct ieee80211com *ic) +{ + struct ifnet *ifp = &ic->ic_if; + struct qwx_softc *sc = ifp->if_softc; + + qwx_add_task(sc, systq, &sc->bgscan_task); + + return 0; +} + /* * Find a pdev which corresponds to a given channel. * This doesn't exactly match the semantics of the Linux driver @@ -25627,6 +25725,9 @@ qwx_deauth(struct qwx_softc *sc) return ret; } + qwx_clear_pn_replay_config(sc, peer); + qwx_clear_hwkeys(sc, peer); + ret = qwx_mac_station_remove(sc, arvif, pdev_id, peer); if (ret) return ret; @@ -25839,6 +25940,7 @@ qwx_run(struct qwx_softc *sc) return ret; } + sc->ops.irq_enable(sc); return 0; } @@ -25896,6 +25998,7 @@ qwx_attach(struct qwx_softc *sc) task_set(&sc->init_task, qwx_init_task, sc); task_set(&sc->newstate_task, qwx_newstate_task, sc); task_set(&sc->setkey_task, qwx_setkey_task, sc); + task_set(&sc->bgscan_task, qwx_bgscan_task, sc); timeout_set_proc(&sc->scan.timeout, qwx_scan_timeout, sc); #if NBPFILTER > 0 qwx_radiotap_attach(sc); blob - 1c1bb17d9afd88820f08059e05be0a0f75a1435e blob + 54f93cf120d314f92ed89b11c2dd917c7b7f7f64 --- sys/dev/ic/qwxvar.h +++ sys/dev/ic/qwxvar.h @@ -1841,6 +1841,7 @@ struct qwx_softc { } scan; u_int scan_channel; struct qwx_survey_info survey[IEEE80211_CHAN_MAX]; + struct task bgscan_task; int attached; struct { @@ -1986,6 +1987,7 @@ int qwx_media_change(struct ifnet *); void qwx_init_task(void *); int qwx_newstate(struct ieee80211com *, enum ieee80211_state, int); void qwx_newstate_task(void *); +int qwx_bgscan(struct ieee80211com *); struct qwx_node { struct ieee80211_node ni; blob - fa91ce71bb49994fb8f625b56c9cf1d5487c2524 blob + 017b9c18bde30549eaa3cda9de590652da021227 --- sys/dev/pci/if_qwx_pci.c +++ sys/dev/pci/if_qwx_pci.c @@ -1119,6 +1119,8 @@ unsupported_wcn6855_soc: ic->ic_updateedca = qwx_updateedca; ic->ic_updatedtim = qwx_updatedtim; #endif + ic->ic_bgscan_start = qwx_bgscan; + /* * We cannot read the MAC address without loading the * firmware from disk. Postpone until mountroot is done.