Use radio work for P2P Listen requests
Avoid concurrent P2P Listen operations 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:
parent
1b5d4714dd
commit
e1d1c8e223
2 changed files with 90 additions and 14 deletions
|
@ -1529,32 +1529,104 @@ static void wpas_find_stopped(void *ctx)
|
|||
}
|
||||
|
||||
|
||||
struct wpas_p2p_listen_work {
|
||||
unsigned int freq;
|
||||
unsigned int duration;
|
||||
struct wpabuf *probe_resp_ie;
|
||||
};
|
||||
|
||||
|
||||
static void wpas_p2p_listen_work_free(struct wpas_p2p_listen_work *lwork)
|
||||
{
|
||||
if (lwork == NULL)
|
||||
return;
|
||||
wpabuf_free(lwork->probe_resp_ie);
|
||||
os_free(lwork);
|
||||
}
|
||||
|
||||
|
||||
static void wpas_p2p_listen_work_done(struct wpa_supplicant *wpa_s)
|
||||
{
|
||||
struct wpas_p2p_listen_work *lwork;
|
||||
|
||||
if (!wpa_s->p2p_listen_work)
|
||||
return;
|
||||
|
||||
lwork = wpa_s->p2p_listen_work->ctx;
|
||||
wpas_p2p_listen_work_free(lwork);
|
||||
radio_work_done(wpa_s->p2p_listen_work);
|
||||
wpa_s->p2p_listen_work = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void wpas_start_listen_cb(struct wpa_radio_work *work, int deinit)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = work->wpa_s;
|
||||
struct wpas_p2p_listen_work *lwork = work->ctx;
|
||||
|
||||
if (deinit) {
|
||||
wpas_p2p_listen_work_free(lwork);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_s->p2p_listen_work = work;
|
||||
|
||||
wpa_drv_set_ap_wps_ie(wpa_s, NULL, lwork->probe_resp_ie, NULL);
|
||||
|
||||
if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
|
||||
"report received Probe Request frames");
|
||||
wpas_p2p_listen_work_done(wpa_s);
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_s->pending_listen_freq = lwork->freq;
|
||||
wpa_s->pending_listen_duration = lwork->duration;
|
||||
|
||||
if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
|
||||
"to remain on channel (%u MHz) for Listen "
|
||||
"state", lwork->freq);
|
||||
wpas_p2p_listen_work_done(wpa_s);
|
||||
wpa_s->pending_listen_freq = 0;
|
||||
return;
|
||||
}
|
||||
wpa_s->off_channel_freq = 0;
|
||||
wpa_s->roc_waiting_drv_freq = lwork->freq;
|
||||
}
|
||||
|
||||
|
||||
static int wpas_start_listen(void *ctx, unsigned int freq,
|
||||
unsigned int duration,
|
||||
const struct wpabuf *probe_resp_ie)
|
||||
{
|
||||
struct wpa_supplicant *wpa_s = ctx;
|
||||
struct wpas_p2p_listen_work *lwork;
|
||||
|
||||
wpa_drv_set_ap_wps_ie(wpa_s, NULL, probe_resp_ie, NULL);
|
||||
|
||||
if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
|
||||
"report received Probe Request frames");
|
||||
if (wpa_s->p2p_listen_work) {
|
||||
wpa_printf(MSG_DEBUG, "P2P: Reject start_listen since p2p_listen_work already exists");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_s->pending_listen_freq = freq;
|
||||
wpa_s->pending_listen_duration = duration;
|
||||
|
||||
if (wpa_drv_remain_on_channel(wpa_s, freq, duration) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
|
||||
"to remain on channel (%u MHz) for Listen "
|
||||
"state", freq);
|
||||
wpa_s->pending_listen_freq = 0;
|
||||
lwork = os_zalloc(sizeof(*lwork));
|
||||
if (lwork == NULL)
|
||||
return -1;
|
||||
lwork->freq = freq;
|
||||
lwork->duration = duration;
|
||||
if (probe_resp_ie) {
|
||||
lwork->probe_resp_ie = wpabuf_dup(probe_resp_ie);
|
||||
if (lwork->probe_resp_ie == NULL) {
|
||||
wpas_p2p_listen_work_free(lwork);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (radio_add_work(wpa_s, freq, "p2p-listen", 0, wpas_start_listen_cb,
|
||||
lwork) < 0) {
|
||||
wpas_p2p_listen_work_free(lwork);
|
||||
return -1;
|
||||
}
|
||||
wpa_s->off_channel_freq = 0;
|
||||
wpa_s->roc_waiting_drv_freq = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1570,6 +1642,7 @@ static void wpas_stop_listen(void *ctx)
|
|||
}
|
||||
wpa_drv_set_ap_wps_ie(wpa_s, NULL, NULL, NULL);
|
||||
wpa_drv_probe_req_report(wpa_s, 0);
|
||||
wpas_p2p_listen_work_done(wpa_s);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3606,6 +3679,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s)
|
|||
eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
|
||||
wpas_p2p_remove_pending_group_interface(wpa_s);
|
||||
eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
|
||||
wpas_p2p_listen_work_done(wpa_s);
|
||||
|
||||
/* TODO: remove group interface from the driver if this wpa_s instance
|
||||
* is on top of a P2P group interface */
|
||||
|
@ -4437,6 +4511,7 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
|
|||
wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
|
||||
"(p2p_long_listen=%d ms pending_action_tx=%p)",
|
||||
wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s));
|
||||
wpas_p2p_listen_work_done(wpa_s);
|
||||
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
|
||||
return;
|
||||
if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
|
||||
|
|
|
@ -697,6 +697,7 @@ struct wpa_supplicant {
|
|||
struct os_reltime p2p_auto_started;
|
||||
struct wpa_ssid *p2p_last_4way_hs_fail;
|
||||
struct wpa_radio_work *p2p_scan_work;
|
||||
struct wpa_radio_work *p2p_listen_work;
|
||||
#endif /* CONFIG_P2P */
|
||||
|
||||
struct wpa_ssid *bgscan_ssid;
|
||||
|
|
Loading…
Reference in a new issue