@@ -272,9 +272,16 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc)
p2p_state_txt(p2p->state));
if (p2p->pending_listen_freq) {
- /* We have a pending p2p_listen request */
- p2p_dbg(p2p, "p2p_listen command pending already");
- return;
+ if (!p2p->drv_in_listen) {
+ p2p_dbg(p2p, "Clear stale pending_listen_freq (%u)",
+ p2p->pending_listen_freq);
+ p2p->pending_listen_freq = 0;
+ } else {
+ /* We have an active driver listen in flight - retry after short delay */
+ p2p_dbg(p2p, "p2p_listen command pending already - retry after short delay");
+ p2p_set_timeout(p2p, 0, 100000);
+ return;
+ }
}
freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
@@ -327,9 +334,14 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout)
p2p_dbg(p2p, "Going to listen(only) state");
if (p2p->pending_listen_freq) {
- /* We have a pending p2p_listen request */
- p2p_dbg(p2p, "p2p_listen command pending already");
- return -1;
+ if (!p2p->drv_in_listen) {
+ p2p_dbg(p2p, "Clear stale pending_listen_freq (%u) for p2p_listen",
+ p2p->pending_listen_freq);
+ p2p->pending_listen_freq = 0;
+ } else {
+ p2p_dbg(p2p, "p2p_listen command pending already - stop ongoing listen first");
+ p2p_stop_listen_for_freq(p2p, 0);
+ }
}
freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel);
@@ -1418,6 +1430,16 @@ void p2p_stop_listen(struct p2p_data *p2p)
}
+void p2p_cancel_pending_listen(struct p2p_data *p2p)
+{
+ if (p2p && 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;
+ }
+}
+
+
void p2p_stop_find(struct p2p_data *p2p)
{
p2p->pending_listen_freq = 0;
@@ -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)
@@ -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);
}
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 phantom 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. Clearing stale pending_listen_freq in p2p_listen_in_find() and p2p_listen() if the driver is not actively in listen mode, or scheduling a fallback timeout/stopping ongoing listen if busy. 3. Adding p2p_cancel_pending_listen() helper to clear pending_listen_freq in struct p2p_data. Signed-off-by: Arowa Suliman <arowa@chromium.org> --- src/p2p/p2p.c | 34 +++++++++++++++++++++++++++------ src/p2p/p2p.h | 1 + wpa_supplicant/p2p_supplicant.c | 6 ++++++ 3 files changed, 35 insertions(+), 6 deletions(-)