[PATCH 03/16] PR: Fix pr_pasn_params leak by consolidating responder teardown
Peddolla Harshavardhan Reddy
peddolla.reddy at oss.qualcomm.com
Sun Jul 12 23:29:51 PDT 2026
Without central cleanup helpers, pr_pasn_params is left allocated in
several PASN responder failure paths, causing subsequent PR_PASN_START
requests to fail with "Already in progress".
Consolidate the scattered open-coded teardown sequences into two
helpers: wpas_pr_pasn_abort_responder(), which cancels the ROC budget
timer, clears pr_responder_mode, clears pr_responder_src_addr, and
clears pr_pasn_params via wpas_pr_clear_ranging_params(); and
wpas_pr_cancel_roc(), which cancels the driver ROC, resets freq
tracking fields, calls wpas_pr_pasn_roc_work_done(), and calls
radio_remove_works(). The helpers replace open-coded copies in
roc_start_cb, wpas_pr_schedule_responder_roc(), roc_total_timeout,
wpas_pr_pasn_auth_rx(), and wpas_pr_abort_ranging(). The
radio_remove_works() call in wpas_pr_cancel_roc() also fixes a gap
in wpas_pr_pasn_auth_rx() where pending pr-pasn-roc work chunks were
not flushed when M1 arrived between ROC windows.
Fixes: d5ae0328ae08 ("PR: Add remain-on-channel support for PASN responder role")
Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy at oss.qualcomm.com>
---
wpa_supplicant/pr_supplicant.c | 90 ++++++++++++++++++----------------
1 file changed, 48 insertions(+), 42 deletions(-)
diff --git a/wpa_supplicant/pr_supplicant.c b/wpa_supplicant/pr_supplicant.c
index 547428945..1b928448a 100644
--- a/wpa_supplicant/pr_supplicant.c
+++ b/wpa_supplicant/pr_supplicant.c
@@ -22,6 +22,7 @@
#ifdef CONFIG_PASN
static void wpas_pr_pasn_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpas_pr_pasn_roc_total_timeout(void *eloop_ctx, void *timeout_ctx);
/* Total listen window (ms) for the PASN responder ROC */
#define PR_PASN_RESPONDER_ROC_DURATION 5000
@@ -999,6 +1000,40 @@ static void wpas_pr_pasn_roc_work_done(struct wpa_supplicant *wpa_s)
}
+/**
+ * wpas_pr_cancel_roc - Stop all responder ROC activity, both active and queued
+ *
+ * Cancels any in-progress driver ROC, releases the active radio work item,
+ * and removes any pending pr-pasn-roc work items that have not yet started.
+ * Safe to call when no ROC is active; all sub-operations are idempotent.
+ * Must NOT be called from within a pr-pasn-roc radio work callback (deinit
+ * path) as that would cause re-entrant radio_remove_works() -> radio_work_free().
+ */
+static void wpas_pr_cancel_roc(struct wpa_supplicant *wpa_s)
+{
+ wpa_drv_cancel_remain_on_channel(wpa_s);
+ wpa_s->off_channel_freq = 0;
+ wpa_s->roc_waiting_drv_freq = 0;
+ wpas_pr_pasn_roc_work_done(wpa_s);
+ radio_remove_works(wpa_s, "pr-pasn-roc", 0);
+}
+
+
+/**
+ * wpas_pr_pasn_abort_responder - Cancel the responder PASN session and
+ * clean up all associated state. Safe to call from any responder error
+ * path; calling eloop_cancel_timeout() on an already-expired timer is a
+ * no-op.
+ */
+static void wpas_pr_pasn_abort_responder(struct wpa_supplicant *wpa_s)
+{
+ eloop_cancel_timeout(wpas_pr_pasn_roc_total_timeout, wpa_s, NULL);
+ wpa_s->pr_responder_mode = false;
+ os_memset(wpa_s->pr_responder_src_addr, 0, ETH_ALEN);
+ wpas_pr_clear_ranging_params(wpa_s->global->pr);
+}
+
+
/**
* wpas_pr_pasn_roc_total_timeout - Total ROC budget expiry; stop responder
*/
@@ -1008,15 +1043,9 @@ static void wpas_pr_pasn_roc_total_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG,
"PR PASN: Total ROC budget expired, stopping responder listen");
- wpa_s->pr_responder_mode = false;
- os_memset(wpa_s->pr_responder_src_addr, 0, ETH_ALEN);
- if (wpa_s->pr_roc_work) {
- wpa_drv_cancel_remain_on_channel(wpa_s);
- wpa_s->off_channel_freq = 0;
- wpa_s->roc_waiting_drv_freq = 0;
- wpas_pr_pasn_roc_work_done(wpa_s);
- }
+ wpas_pr_cancel_roc(wpa_s);
+ wpas_pr_pasn_abort_responder(wpa_s);
}
@@ -1046,10 +1075,7 @@ static void wpas_pr_pasn_roc_start_cb(struct wpa_radio_work *work, int deinit)
* regardless of whether the work was started or not - the
* ROC will never fire now.
*/
- eloop_cancel_timeout(wpas_pr_pasn_roc_total_timeout,
- wpa_s, NULL);
- wpa_s->pr_responder_mode = false;
- os_memset(wpa_s->pr_responder_src_addr, 0, ETH_ALEN);
+ wpas_pr_pasn_abort_responder(wpa_s);
os_free(rwork);
work->ctx = NULL;
return;
@@ -1071,14 +1097,8 @@ static void wpas_pr_pasn_roc_start_cb(struct wpa_radio_work *work, int deinit)
NULL : rwork->src_addr) < 0) {
wpa_printf(MSG_ERROR,
"PR PASN: Failed to start ROC for responder");
- eloop_cancel_timeout(wpas_pr_pasn_roc_total_timeout,
- wpa_s, NULL);
- wpa_s->pr_responder_mode = false;
- os_memset(wpa_s->pr_responder_src_addr, 0, ETH_ALEN);
- os_free(rwork);
- work->ctx = NULL;
- radio_work_done(work);
- wpa_s->pr_roc_work = NULL;
+ wpas_pr_pasn_roc_work_done(wpa_s);
+ wpas_pr_pasn_abort_responder(wpa_s);
return;
}
@@ -1111,9 +1131,7 @@ static void wpas_pr_schedule_responder_roc(struct wpa_supplicant *wpa_s,
return;
fail:
- wpa_s->pr_responder_mode = false;
- os_memset(wpa_s->pr_responder_src_addr, 0, ETH_ALEN);
- eloop_cancel_timeout(wpas_pr_pasn_roc_total_timeout, wpa_s, NULL);
+ wpas_pr_pasn_abort_responder(wpa_s);
}
@@ -1637,18 +1655,12 @@ int wpas_pr_pasn_auth_rx(struct wpa_supplicant *wpa_s,
/*
* Cancel ROC on the listening interface; the dedicated
* PR interface (if created) will handle all subsequent
- * frames. Then complete the radio work item so the
- * radio is released for other operations.
- *
- * wpas_pr_cancel_remain_on_channel_cb() may also fire
- * asynchronously when the driver processes the cancel
- * request, but wpas_pr_pasn_roc_work_done() is
- * idempotent (no-op if pr_roc_work is already NULL).
+ * frames. wpas_pr_cancel_roc() also flushes any pending
+ * pr-pasn-roc chunks that were queued but not yet started
+ * (M1 can arrive between two ROC chunks when pr_roc_work
+ * is already NULL but a next chunk is already queued).
*/
- wpa_drv_cancel_remain_on_channel(wpa_s);
- wpa_s->off_channel_freq = 0;
- wpa_s->roc_waiting_drv_freq = 0;
- wpas_pr_pasn_roc_work_done(wpa_s);
+ wpas_pr_cancel_roc(wpa_s);
/* Clear responder mode */
wpa_s->pr_responder_mode = false;
@@ -1688,14 +1700,8 @@ void wpas_pr_abort_ranging(struct wpa_supplicant *wpa_s)
wpas_pr_pasn_cancel_auth_work(wpa_s);
wpa_s->pr_pasn_auth_work = NULL;
if (wpa_s->pr_responder_mode) {
- eloop_cancel_timeout(wpas_pr_pasn_roc_total_timeout,
- wpa_s, NULL);
- wpa_drv_cancel_remain_on_channel(wpa_s);
- wpa_s->off_channel_freq = 0;
- wpa_s->roc_waiting_drv_freq = 0;
- wpas_pr_pasn_roc_work_done(wpa_s);
- wpa_s->pr_responder_mode = false;
- os_memset(wpa_s->pr_responder_src_addr, 0, ETH_ALEN);
+ wpas_pr_cancel_roc(wpa_s);
+ wpas_pr_pasn_abort_responder(wpa_s);
}
/* Stop PD wdev and cleanup all ranging resources */
--
2.34.1
More information about the Hostap
mailing list