[PATCH v2] P2P: Clear pending_listen_freq when radio work is cancelled
Benjamin Berg
benjamin at sipsolutions.net
Mon Aug 31 04:58:46 PDT 2026
Hi,
so, while this might fix the bug, I really do feel that bigger code
refactor is needed here. At least I find it hard to argue that the fix
is formally correct.
As I see it, we have multiple things driving the P2P search state here:
* p2p_state_timeout -> p2p_search
* p2p_search -> staring scan
* p2p_scan_res_handled -> p2p_continue_find
* p2p_continue_find
-> p2p_pre_find_operation -> SD discovery
-> p2p_listen_in_find
* p2p_listen_in_find -> starting listen
* p2p_listen_end
-> starting search iff timeout already happened
* various *_cb functions:
-> p2p_continue_find
- In the case of the provision discovery TX callback this happens
out of sync.
In the end, we have the odd situation that the P2P TX callback tries to
restart the find operation (p2p_continue_find), while the p2p-listen
work is already scheduled but has not yet started.
The patch does not really address that side of the issue. It "just"
avoids getting into a bad state at that point in the process.
So, in my view this needs some more refactoring. We should have a well
defined behaviour here whether we interrupt the usual listen/search
cycle and re-start it (e.g. going into listen state immediately), or if
we just continue the cycle normally.
There are also some things in the code that are obviously wrong (e.g.
p2p_listen_cb adding 20ms to the timer). Overall, having the logic
cleaned up should make it much easier to work with in the long run.
All that said, I am not really NACK'ing this patch either.
Benjamin
On Thu, 2026-08-27 at 17:13 +0000, Arowa Suliman wrote:
> When a P2P listen radio work is deinitialized before starting (e.g.,
> preempted by a scan or stopped during provision discovery),
> pending_listen_freq was not cleared in wpa_supplicant and the P2P
> core.
> This left the state machine with a pending listen state, causing
> subsequent listen operations to be rejected and stalling the event
> loop.
>
> Fix this by:
> 1. Clearing pending_listen_freq and notifying the P2P core in
> wpas_start_listen_cb() on deinit and in wpas_stop_listen().
> 2. Adding p2p_cancel_pending_listen() helper to clear
> pending_listen_freq
> and pending_listen_wait_drv in struct p2p_data.
>
> Signed-off-by: Arowa Suliman <arowa at chromium.org>
> ---
> src/p2p/p2p.c | 13 +++++++++++++
> src/p2p/p2p.h | 1 +
> wpa_supplicant/p2p_supplicant.c | 6 ++++++
> 3 files changed, 20 insertions(+)
>
> diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
> index 09ed2fe0f..ba1148a38 100644
> --- a/src/p2p/p2p.c
> +++ b/src/p2p/p2p.c
> @@ -1418,6 +1418,19 @@ void p2p_stop_listen(struct p2p_data *p2p)
> }
>
>
> +void p2p_cancel_pending_listen(struct p2p_data *p2p)
> +{
> + if (p2p) {
> + if (p2p->pending_listen_freq) {
> + p2p_dbg(p2p, "Clear pending_listen_freq (%u) for
> p2p_cancel_pending_listen",
> + p2p->pending_listen_freq);
> + p2p->pending_listen_freq = 0;
> + }
> + p2p->pending_listen_wait_drv = false;
> + }
> +}
> +
> +
> void p2p_stop_find(struct p2p_data *p2p)
> {
> p2p->pending_listen_freq = 0;
> diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
> index 7c89c8c35..0d1b81a18 100644
> --- a/src/p2p/p2p.h
> +++ b/src/p2p/p2p.h
> @@ -1606,6 +1606,7 @@ int p2p_listen(struct p2p_data *p2p, unsigned
> int timeout);
> * @p2p: P2P module context from p2p_init()
> */
> void p2p_stop_listen(struct p2p_data *p2p);
> +void p2p_cancel_pending_listen(struct p2p_data *p2p);
>
> /**
> * p2p_connect - Start P2P group formation (GO negotiation)
> diff --git a/wpa_supplicant/p2p_supplicant.c
> b/wpa_supplicant/p2p_supplicant.c
> index e5d4afe3c..f9d893528 100644
> --- a/wpa_supplicant/p2p_supplicant.c
> +++ b/wpa_supplicant/p2p_supplicant.c
> @@ -3235,6 +3235,9 @@ static void wpas_start_listen_cb(struct
> wpa_radio_work *work, int deinit)
> unsigned int duration;
>
> if (deinit) {
> + wpa_s->pending_listen_freq = 0;
> + if (wpa_s->global->p2p)
> + p2p_cancel_pending_listen(wpa_s->global->p2p);
> if (work->started && !wpa_s->p2p_removing_listen_work)
> wpas_stop_started_listen_work(work);
> wpas_p2p_listen_work_free(lwork);
> @@ -3341,6 +3344,9 @@ static void wpas_stop_listen(void *ctx)
> radio_remove_works(wpa_s, "p2p-listen", 0);
> wpa_s->p2p_removing_listen_work = false;
> }
> + wpa_s->pending_listen_freq = 0;
> + if (wpa_s->global->p2p)
> + p2p_cancel_pending_listen(wpa_s->global->p2p);
> }
>
>
More information about the Hostap
mailing list