Use radio work for P2P scan requests

Avoid concurrent P2P scan requests with any other exclusive use of the
radio by using the radio work queuing mechanism. This removes some of
the earlier workarounds that postponed scans depending on other
operations.

Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2014-01-03 11:57:57 +02:00
parent d12a51b5d2
commit 1b5d4714dd
9 changed files with 102 additions and 195 deletions

View file

@ -127,10 +127,6 @@ static const char * p2p_state_txt(int state)
return "INVITE";
case P2P_INVITE_LISTEN:
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 "?";
}
@ -884,9 +880,6 @@ static void p2p_search(struct p2p_data *p2p)
if (res < 0) {
p2p_dbg(p2p, "Scan request failed");
p2p_continue_find(p2p);
} else if (res == 1) {
p2p_dbg(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 {
p2p_dbg(p2p, "Running p2p_scan");
p2p->p2p_scan_running = 1;
@ -1041,11 +1034,9 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
p2p, NULL);
} else if (res == 1) {
p2p_dbg(p2p, "Could not start p2p_scan at this point - will try again after previous scan completes");
res = 0;
p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
} else if (p2p->p2p_scan_running) {
p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
/* wait for the previous p2p_scan to complete */
} else {
p2p_dbg(p2p, "Failed to start p2p_scan");
p2p_set_state(p2p, P2P_IDLE);
@ -1056,34 +1047,12 @@ 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;
p2p_dbg(p2p, "Starting pending P2P find now that previous scan was completed");
if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
p2p->num_req_dev_types, p2p->req_dev_types,
p2p->find_dev_id, p2p->search_delay) < 0) {
p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
return 0;
}
return 1;
}
void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
{
p2p_dbg(p2p, "Stopping find");
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p_clear_timeout(p2p);
if (p2p->state == P2P_SEARCH ||
p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY ||
p2p->state == P2P_SEARCH_WHEN_READY)
if (p2p->state == P2P_SEARCH)
p2p->cfg->find_stopped(p2p->cfg->cb_ctx);
p2p_set_state(p2p, P2P_IDLE);
p2p_free_req_dev_types(p2p);
@ -3369,10 +3338,6 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
case P2P_INVITE_LISTEN:
p2p_timeout_invite_listen(p2p);
break;
case P2P_SEARCH_WHEN_READY:
break;
case P2P_CONTINUE_SEARCH_WHEN_READY:
break;
}
}
@ -4183,8 +4148,7 @@ 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)
if (p2p->state == P2P_SEARCH)
return 2;
return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
}
@ -4200,13 +4164,6 @@ void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
}
void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay)
{
if (p2p && p2p->search_delay < delay)
p2p->search_delay = delay;
}
#ifdef CONFIG_WIFI_DISPLAY
static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)

View file

@ -1826,13 +1826,6 @@ int p2p_set_no_go_freq(struct p2p_data *p2p,
*/
int p2p_in_progress(struct p2p_data *p2p);
/**
* p2p_other_scan_completed - Notify completion of non-P2P scan
* @p2p: P2P module context from p2p_init()
* Returns: 0 if P2P module is idle or 1 if an operation was started
*/
int p2p_other_scan_completed(struct p2p_data *p2p);
const char * p2p_wps_method_text(enum p2p_wps_method method);
/**
@ -1844,8 +1837,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);
int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie);
int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie);

View file

@ -205,16 +205,6 @@ struct p2p_data {
* P2P_INVITE_LISTEN - Listen during Invite
*/
P2P_INVITE_LISTEN,
/**
* 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;
/**

View file

@ -978,9 +978,6 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
wpa_dbg(wpa_s, MSG_DEBUG, "Short-circuit new scan request "
"since there are no enabled networks");
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
#ifdef CONFIG_P2P
wpa_s->sta_scan_pending = 0;
#endif /* CONFIG_P2P */
return;
}
@ -1195,25 +1192,6 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
wpa_supplicant_notify_scanning(wpa_s, 0);
#ifdef CONFIG_P2P
if (own_request && wpa_s->global->p2p_cb_on_scan_complete &&
!wpa_s->global->p2p_disabled &&
wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending &&
!wpa_s->scan_res_handler) {
wpa_s->global->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 "
"stopped scan processing");
wpa_s->scan_req = wpa_s->last_scan_req;
wpa_s->sta_scan_pending = 1;
wpa_supplicant_req_scan(wpa_s, 5, 0);
ret = -1;
goto scan_work_done;
}
}
wpa_s->sta_scan_pending = 0;
#endif /* CONFIG_P2P */
scan_res = wpa_supplicant_get_scan_results(wpa_s,
data ? &data->scan_info :
NULL, 1);
@ -2885,9 +2863,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
wpa_supplicant_event_scan_results(wpa_s, data);
wpa_s->own_scan_running = 0;
wpa_s->external_scan_running = 0;
if (wpa_s->wpa_state != WPA_AUTHENTICATING &&
wpa_s->wpa_state != WPA_ASSOCIATING)
wpas_p2p_continue_after_scan(wpa_s);
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
case EVENT_ASSOCINFO:

View file

@ -1,6 +1,7 @@
/*
* wpa_supplicant - P2P
* Copyright (c) 2009-2010, Atheros Communications
* Copyright (c) 2010-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -196,6 +197,12 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
{
size_t i;
if (wpa_s->p2p_scan_work) {
struct wpa_radio_work *work = wpa_s->p2p_scan_work;
wpa_s->p2p_scan_work = NULL;
radio_work_done(work);
}
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
@ -234,95 +241,125 @@ static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
}
static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
{
struct wpa_supplicant *wpa_s = work->wpa_s;
struct wpa_driver_scan_params *params = work->ctx;
int ret;
if (deinit) {
wpa_scan_free_params(params);
return;
}
ret = wpa_drv_scan(wpa_s, params);
wpa_scan_free_params(params);
work->ctx = NULL;
if (ret) {
radio_work_done(work);
return;
}
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
wpa_s->own_scan_requested = 1;
wpa_s->p2p_scan_work = work;
}
static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
unsigned int num_req_dev_types,
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 wpa_driver_scan_params *params = NULL;
struct wpabuf *wps_ie, *ies;
int social_channels[] = { 2412, 2437, 2462, 0, 0 };
size_t ielen;
u8 *n;
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_scan_scheduled(ifs) || ifs->scanning) &&
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->global->p2p_cb_on_scan_complete = 1;
wpa_supplicant_req_scan(ifs, 0, 0);
return 1;
}
if (wpa_s->p2p_scan_work) {
wpa_dbg(wpa_s, MSG_INFO, "P2P: Reject scan trigger since one is already pending");
return -1;
}
os_memset(&params, 0, sizeof(params));
params = os_zalloc(sizeof(*params));
if (params == NULL)
return -1;
/* P2P Wildcard SSID */
params.num_ssids = 1;
params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID;
params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
params->num_ssids = 1;
n = os_malloc(P2P_WILDCARD_SSID_LEN);
if (n == NULL)
goto fail;
os_memcpy(n, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN);
params->ssids[0].ssid = n;
params->ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN;
wpa_s->wps->dev.p2p = 1;
wps_ie = wps_build_probe_req_ie(pw_id, &wpa_s->wps->dev,
wpa_s->wps->uuid, WPS_REQ_ENROLLEE,
num_req_dev_types, req_dev_types);
if (wps_ie == NULL)
return -1;
goto fail;
ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
if (ies == NULL) {
wpabuf_free(wps_ie);
return -1;
goto fail;
}
wpabuf_put_buf(ies, wps_ie);
wpabuf_free(wps_ie);
p2p_scan_ie(wpa_s->global->p2p, ies, dev_id);
params.p2p_probe = 1;
params.extra_ies = wpabuf_head(ies);
params.extra_ies_len = wpabuf_len(ies);
params->p2p_probe = 1;
n = os_malloc(wpabuf_len(ies));
if (n == NULL) {
wpabuf_free(ies);
goto fail;
}
os_memcpy(n, wpabuf_head(ies), wpabuf_len(ies));
params->extra_ies = n;
params->extra_ies_len = wpabuf_len(ies);
wpabuf_free(ies);
switch (type) {
case P2P_SCAN_SOCIAL:
params.freqs = social_channels;
params->freqs = os_malloc(4 * sizeof(int));
if (params->freqs == NULL)
goto fail;
params->freqs[0] = 2412;
params->freqs[1] = 2437;
params->freqs[2] = 2462;
params->freqs[3] = 0;
break;
case P2P_SCAN_FULL:
break;
case P2P_SCAN_SOCIAL_PLUS_ONE:
social_channels[3] = freq;
params.freqs = social_channels;
params->freqs = os_malloc(5 * sizeof(int));
if (params->freqs == NULL)
goto fail;
params->freqs[0] = 2412;
params->freqs[1] = 2437;
params->freqs[2] = 2462;
params->freqs[3] = freq;
params->freqs[4] = 0;
break;
}
ret = wpa_drv_scan(wpa_s, &params);
radio_remove_unstarted_work(wpa_s, "p2p-scan");
if (radio_add_work(wpa_s, 0, "p2p-scan", 0, wpas_p2p_trigger_scan_cb,
params) < 0)
goto fail;
return 0;
wpabuf_free(ies);
if (ret) {
for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
if (ifs->scanning ||
ifs->scan_res_handler == wpas_p2p_scan_res_handler) {
wpa_s->global->p2p_cb_on_scan_complete = 1;
ret = 1;
break;
}
}
} else {
os_get_reltime(&wpa_s->scan_trigger_time);
wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
wpa_s->own_scan_requested = 1;
}
return ret;
fail:
wpa_scan_free_params(params);
return -1;
}
@ -513,7 +550,6 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
wpa_config_remove_network(wpa_s->conf, id);
wpa_supplicant_clear_status(wpa_s);
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_s->sta_scan_pending = 0;
} else {
wpa_printf(MSG_DEBUG, "P2P: Temporary group network not "
"found");
@ -5092,7 +5128,6 @@ static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
wpa_s->p2p_long_listen = 0;
eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
wpa_s->global->p2p_cb_on_scan_complete = 0;
if (wpa_s->global->p2p)
p2p_stop_find(wpa_s->global->p2p);
@ -5408,7 +5443,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
}
if (!wpa_s->show_group_started || !ssid)
goto done;
return;
wpa_s->show_group_started = 0;
@ -5450,9 +5485,6 @@ 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:
wpas_p2p_continue_after_scan(wpa_s);
}
@ -6250,30 +6282,6 @@ unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
}
void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
{
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Station mode scan operation not "
"pending anymore (sta_scan_pending=%d "
"p2p_cb_on_scan_complete=%d)", wpa_s->sta_scan_pending,
wpa_s->global->p2p_cb_on_scan_complete);
wpa_s->sta_scan_pending = 0;
if (!wpa_s->global->p2p_cb_on_scan_complete)
return;
wpa_s->global->p2p_cb_on_scan_complete = 0;
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
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));
}
}
static int wpas_p2p_remove_psk_entry(struct wpa_supplicant *wpa_s,
struct wpa_ssid *s, const u8 *addr,
int iface_addr)

View file

@ -149,14 +149,9 @@ void wpas_p2p_remove_client(struct wpa_supplicant *wpa_s, const u8 *peer,
int iface_addr);
#ifdef CONFIG_P2P
void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s);
int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s);
void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s);
#else /* CONFIG_P2P */
static inline void wpas_p2p_continue_after_scan(struct wpa_supplicant *wpa_s)
{
}
static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
{
return 0;

View file

@ -524,14 +524,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
wpas_p2p_continue_after_scan(wpa_s);
return;
}
if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
wpas_p2p_continue_after_scan(wpa_s);
return;
}
@ -560,7 +558,6 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
wpa_s->scan_req == NORMAL_SCAN_REQ) {
wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
wpas_p2p_continue_after_scan(wpa_s);
return;
}
@ -579,18 +576,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
#ifdef CONFIG_P2P
if (wpas_p2p_in_progress(wpa_s) || wpas_wpa_is_in_progress(wpa_s, 0)) {
if (wpa_s->sta_scan_pending &&
wpas_p2p_in_progress(wpa_s) == 2 &&
wpa_s->global->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);
return;
}
wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
wpa_supplicant_req_scan(wpa_s, 5, 0);
return;
}
#endif /* CONFIG_P2P */
@ -1202,7 +1190,6 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
{
wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
wpas_p2p_continue_after_scan(wpa_s);
}

View file

@ -195,8 +195,6 @@ 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);
wpas_p2p_continue_after_scan(wpa_s);
}
@ -2910,6 +2908,15 @@ static void radio_work_free(struct wpa_radio_work *work)
work->wpa_s->scan_work = NULL;
}
#ifdef CONFIG_P2P
if (work->wpa_s->p2p_scan_work == work) {
/* This should not really happen. */
wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work",
work->type, work, work->started);
work->wpa_s->p2p_scan_work = NULL;
}
#endif /* CONFIG_P2P */
dl_list_del(&work->list);
os_free(work);
}
@ -3966,8 +3973,6 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
*/
wpa_supplicant_req_scan(wpa_s, timeout / 1000,
1000 * (timeout % 1000));
wpas_p2p_continue_after_scan(wpa_s);
}

View file

@ -257,7 +257,6 @@ struct wpa_global {
WPA_CONC_PREF_STA,
WPA_CONC_PREF_P2P
} conc_pref;
unsigned int p2p_cb_on_scan_complete:1;
unsigned int p2p_per_sta_psk:1;
#ifdef CONFIG_WIFI_DISPLAY
@ -680,7 +679,6 @@ struct wpa_supplicant {
*/
char cross_connect_uplink[100];
unsigned int sta_scan_pending:1;
unsigned int p2p_auto_join:1;
unsigned int p2p_auto_pd:1;
unsigned int p2p_persistent_group:1;
@ -698,6 +696,7 @@ struct wpa_supplicant {
int p2p_connect_freq;
struct os_reltime p2p_auto_started;
struct wpa_ssid *p2p_last_4way_hs_fail;
struct wpa_radio_work *p2p_scan_work;
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;