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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2019-02-17 16:53:03 +02:00
parent b3e8ca65a6
commit 947b5a1532
4 changed files with 30 additions and 10 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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");
}

View file

@ -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,
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");