Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
qwx background scan and roaming support
To:
tech@openbsd.org
Date:
Thu, 24 Jul 2025 15:46:42 +0200

Download raw body.

Thread
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.