From 947b5a1532f95347d34f0dc79d602402975eca3d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 17 Feb 2019 16:53:03 +0200 Subject: [PATCH] P2P: Stop listen state if Action frame TX is needed on another channel This speeds up P2P responses to frames received on an operating channel in case there is an ongoing P2P listen operation on another channel. This is applicable to drivers that support multiple channels in concurrently. This addresses an issue showing up in the p2ps_channel_active_go_and_station_different_mcc test case where the Provision Discovery Request frame can be received on the operating channel of a group instead of the Listen channel. The response was delayed until the listen operation timed out and this took too long time for the peer to receive the response. Signed-off-by: Jouni Malinen --- src/p2p/p2p.c | 16 +++++++++++++--- src/p2p/p2p.h | 4 +++- src/p2p/p2p_group.c | 3 ++- wpa_supplicant/p2p_supplicant.c | 17 ++++++++++++----- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 4bbd1bcca..157bf891c 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1076,7 +1076,7 @@ static int p2p_run_after_scan(struct p2p_data *p2p) p2p->after_scan_tx->bssid, (u8 *) (p2p->after_scan_tx + 1), p2p->after_scan_tx->len, - p2p->after_scan_tx->wait_time); + p2p->after_scan_tx->wait_time, NULL); os_free(p2p->after_scan_tx); p2p->after_scan_tx = NULL; return 1; @@ -4973,6 +4973,8 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, size_t len, unsigned int wait_time) { + int res, scheduled; + if (p2p->p2p_scan_running) { p2p_dbg(p2p, "Delay Action frame TX until p2p_scan completes"); if (p2p->after_scan_tx) { @@ -4993,8 +4995,16 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst, return 0; } - return p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid, - buf, len, wait_time); + res = p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid, + buf, len, wait_time, &scheduled); + if (res == 0 && scheduled && p2p->in_listen && freq > 0 && + (unsigned int) p2p->drv_in_listen != freq) { + p2p_dbg(p2p, + "Stop listen on %d MHz to allow a frame to be sent immediately on %d MHz", + p2p->drv_in_listen, freq); + p2p_stop_listen_for_freq(p2p, freq); + } + return res; } diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index f2969ee13..425b037be 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -665,6 +665,8 @@ struct p2p_config { * @buf: Frame body (starting from Category field) * @len: Length of buf in octets * @wait_time: How many msec to wait for a response frame + * @scheduled: Return value indicating whether the transmissions was + * scheduled to happen once the radio is available * Returns: 0 on success, -1 on failure * * The Action frame may not be transmitted immediately and the status @@ -675,7 +677,7 @@ struct p2p_config { */ int (*send_action)(void *ctx, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, - size_t len, unsigned int wait_time); + size_t len, unsigned int wait_time, int *scheduled); /** * send_action_done - Notify that Action frame sequence was completed diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index 16c28a0d9..aa18af6c1 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -941,7 +941,8 @@ int p2p_group_go_discover(struct p2p_group *group, const u8 *dev_id, if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, m->addr, group->cfg->interface_addr, group->cfg->interface_addr, - wpabuf_head(req), wpabuf_len(req), 200) < 0) + wpabuf_head(req), wpabuf_len(req), 200, NULL) + < 0) { p2p_dbg(p2p, "Failed to send Action frame"); } diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index e265128b7..18fd02c3e 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -1584,20 +1584,27 @@ static int wpas_send_action_work(struct wpa_supplicant *wpa_s, static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, const u8 *buf, - size_t len, unsigned int wait_time) + size_t len, unsigned int wait_time, int *scheduled) { struct wpa_supplicant *wpa_s = ctx; int listen_freq = -1, send_freq = -1; + if (scheduled) + *scheduled = 0; if (wpa_s->p2p_listen_work) listen_freq = wpa_s->p2p_listen_work->freq; if (wpa_s->p2p_send_action_work) send_freq = wpa_s->p2p_send_action_work->freq; if (listen_freq != (int) freq && send_freq != (int) freq) { - wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d)", - listen_freq, send_freq); - return wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf, - len, wait_time); + int res; + + wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d freq=%u)", + listen_freq, send_freq, freq); + res = wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf, + len, wait_time); + if (res == 0 && scheduled) + *scheduled = 1; + return res; } wpa_printf(MSG_DEBUG, "P2P: Use ongoing radio work for Action frame TX");