diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 85d506252..311aad3b3 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -130,6 +130,8 @@ static const char * p2p_state_txt(int state) return "INVITE_LISTEN"; case P2P_SEARCH_WHEN_READY: return "SEARCH_WHEN_READY"; + case P2P_CONTINUE_SEARCH_WHEN_READY: + return "CONTINUE_SEARCH_WHEN_READY"; default: return "?"; } @@ -799,6 +801,7 @@ static void p2p_search(struct p2p_data *p2p) int freq = 0; enum p2p_scan_type type; u16 pw_id = DEV_PW_DEFAULT; + int res; if (p2p->drv_in_listen) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still " @@ -818,12 +821,18 @@ static void p2p_search(struct p2p_data *p2p) wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search"); } - if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq, - p2p->num_req_dev_types, p2p->req_dev_types, - p2p->find_dev_id, pw_id)) { + res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq, + p2p->num_req_dev_types, p2p->req_dev_types, + p2p->find_dev_id, pw_id); + if (res < 0) { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scan request failed"); p2p_continue_find(p2p); + } else if (res == 1) { + wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start " + "p2p_scan at this point - will try again after " + "previous scan completes"); + p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY); } else { wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan"); p2p->p2p_scan_running = 1; @@ -1005,6 +1014,11 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, int p2p_other_scan_completed(struct p2p_data *p2p) { + if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) { + p2p_set_state(p2p, P2P_SEARCH); + p2p_search(p2p); + return 1; + } if (p2p->state != P2P_SEARCH_WHEN_READY) return 0; wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find " @@ -3199,6 +3213,8 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx) break; case P2P_SEARCH_WHEN_READY: break; + case P2P_CONTINUE_SEARCH_WHEN_READY: + break; } } @@ -3980,6 +3996,9 @@ int p2p_in_progress(struct p2p_data *p2p) { if (p2p == NULL) return 0; + if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY || + p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) + return 2; return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING; } @@ -3992,3 +4011,10 @@ void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout, p2p->client_timeout = client_timeout; } } + + +void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay) +{ + if (p2p && p2p->search_delay < delay) + p2p->search_delay = delay; +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 138f3e760..2f35deb74 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1708,4 +1708,6 @@ const char * p2p_wps_method_text(enum p2p_wps_method method); void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout, u8 client_timeout); +void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay); + #endif /* P2P_H */ diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 3c505563a..7dbdf805e 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -207,6 +207,11 @@ struct p2p_data { * P2P_SEARCH_WHEN_READY - Waiting to start Search */ P2P_SEARCH_WHEN_READY, + + /** + * P2P_CONTINUE_SEARCH_WHEN_READY - Waiting to continue Search + */ + P2P_CONTINUE_SEARCH_WHEN_READY, } state; /** diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 0c5c07c9f..d70eae78d 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1027,7 +1027,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, #ifdef CONFIG_P2P if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && - wpa_s->global->p2p != NULL) { + wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending) { wpa_s->p2p_cb_on_scan_complete = 0; if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " @@ -1035,6 +1035,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return -1; } } + wpa_s->sta_scan_pending = 0; #endif /* CONFIG_P2P */ scan_res = wpa_supplicant_get_scan_results(wpa_s, @@ -2321,6 +2322,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #ifndef CONFIG_NO_SCAN_PROCESSING case EVENT_SCAN_RESULTS: wpa_supplicant_event_scan_results(wpa_s, data); +#ifdef CONFIG_P2P + if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && + wpa_s->global->p2p != NULL && + wpa_s->wpa_state != WPA_AUTHENTICATING && + wpa_s->wpa_state != WPA_ASSOCIATING) { + wpa_s->p2p_cb_on_scan_complete = 0; + if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " + "continued after scan result processing"); + } + } +#endif /* CONFIG_P2P */ break; #endif /* CONFIG_NO_SCAN_PROCESSING */ case EVENT_ASSOCINFO: diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index e9934ae14..b47cf66a4 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -121,6 +121,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, const u8 *req_dev_types, const u8 *dev_id, u16 pw_id) { struct wpa_supplicant *wpa_s = ctx; + struct wpa_supplicant *ifs; struct wpa_driver_scan_params params; int ret; struct wpabuf *wps_ie, *ies; @@ -130,6 +131,18 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; + for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { + if (ifs->sta_scan_pending && + wpas_p2p_in_progress(wpa_s) == 2) { + wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow " + "pending station mode scan to be " + "completed on interface %s", ifs->ifname); + wpa_s->p2p_cb_on_scan_complete = 1; + wpa_supplicant_req_scan(ifs, 0, 0); + return 1; + } + } + os_memset(¶ms, 0, sizeof(params)); /* P2P Wildcard SSID */ @@ -4263,7 +4276,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) } if (!wpa_s->show_group_started || !ssid) - return; + goto done; wpa_s->show_group_started = 0; @@ -4305,6 +4318,19 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) if (network_id < 0) network_id = ssid->id; wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1); + +done: + if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && + wpa_s->global->p2p != NULL) { + wpa_s->p2p_cb_on_scan_complete = 0; + if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " + "continued after successful connection"); + p2p_increase_search_delay( + wpa_s->global->p2p, + wpas_p2p_search_delay(wpa_s)); + } + } } diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index c608c3877..93d152ed9 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -468,15 +468,18 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) #ifdef CONFIG_P2P if (wpas_p2p_in_progress(wpa_s)) { - if (wpa_s->wpa_state == WPA_SCANNING) { + if (wpa_s->sta_scan_pending && + wpas_p2p_in_progress(wpa_s) == 2 && + wpa_s->p2p_cb_on_scan_complete) { + wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station " + "mode scan during P2P search"); + } else { wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan " "while P2P operation is in progress"); + wpa_s->sta_scan_pending = 1; wpa_supplicant_req_scan(wpa_s, 5, 0); - } else { - wpa_dbg(wpa_s, MSG_DEBUG, "Do not request scan while " - "P2P operation is in progress"); + return; } - return; } #endif /* CONFIG_P2P */ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index aa0e578f2..a0c2608c2 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -192,6 +192,20 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) * So, wait a second until scanning again. */ wpa_supplicant_req_scan(wpa_s, 1, 0); + +#ifdef CONFIG_P2P + if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && + wpa_s->global->p2p != NULL) { + wpa_s->p2p_cb_on_scan_complete = 0; + if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " + "continued after timed out authentication"); + p2p_increase_search_delay( + wpa_s->global->p2p, + wpas_p2p_search_delay(wpa_s)); + } + } +#endif /* CONFIG_P2P */ } @@ -3392,6 +3406,17 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) */ wpa_supplicant_req_scan(wpa_s, timeout / 1000, 1000 * (timeout % 1000)); + +#ifdef CONFIG_P2P + if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled && + wpa_s->global->p2p != NULL) { + wpa_s->p2p_cb_on_scan_complete = 0; + if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " + "continued after failed association"); + } + } +#endif /* CONFIG_P2P */ } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 1bd1f5a25..b2457c7bf 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -515,6 +515,7 @@ struct wpa_supplicant { char cross_connect_uplink[100]; unsigned int p2p_cb_on_scan_complete:1; + unsigned int sta_scan_pending:1; unsigned int p2p_auto_join:1; unsigned int p2p_auto_pd:1; unsigned int p2p_persistent_group:1;