From: Peter Hessler Subject: Re: qwx background scan and roaming support To: tech@openbsd.org Date: Fri, 25 Jul 2025 09:10:51 +0200 tested on x13s. OK On 2025 Jul 24 (Thu) at 15:46:42 +0200 (+0200), Stefan Sperling wrote: :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. : -- Health nuts are going to feel stupid someday, lying in hospitals dying of nothing. -- Redd Foxx