P2P: Skip Listen phase when peer is expected to be waiting

In case we have replied to a peer's GO Negotiation Request frame with a
GO Negotiation Response frame using status code
info-currently-unavailable (1), the peer is likely going to wait for us
to initiate GO Negotiation on its Listen channel. We were previously
using alternativing send-GO-Neg-Req and Listen phase when providing that
response after the user had authorized the connection. However, the
Listen phase here is unnecessary in this case and will make the
connection take longer time to go through. Skip the Listen phase and
make the wait-for-GO-Neg-Resp timeout random between 100 and 200 ms to
avoid getting in sync with the peer. In practice, this will make us
retry GO Negotiation Request frames more frequently and remain on the
peer's Listen channel for most of the time when initiating GO
Negotiation after status=1 response.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2013-02-28 22:35:11 +02:00 committed by Jouni Malinen
parent 8e4839cefa
commit fb8984fd6f

View file

@ -198,8 +198,10 @@ void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
struct p2p_go_neg_results res; struct p2p_go_neg_results res;
p2p_clear_timeout(p2p); p2p_clear_timeout(p2p);
p2p_set_state(p2p, P2P_IDLE); p2p_set_state(p2p, P2P_IDLE);
if (p2p->go_neg_peer) if (p2p->go_neg_peer) {
p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
p2p->go_neg_peer->wps_method = WPS_NOT_READY; p2p->go_neg_peer->wps_method = WPS_NOT_READY;
}
p2p->go_neg_peer = NULL; p2p->go_neg_peer = NULL;
os_memset(&res, 0, sizeof(res)); os_memset(&res, 0, sizeof(res));
@ -1128,6 +1130,10 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
p2p_set_state(p2p, P2P_IDLE); p2p_set_state(p2p, P2P_IDLE);
p2p_free_req_dev_types(p2p); p2p_free_req_dev_types(p2p);
p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING; p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
if (p2p->go_neg_peer) {
p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
p2p->go_neg_peer->wps_method = WPS_NOT_READY;
}
p2p->go_neg_peer = NULL; p2p->go_neg_peer = NULL;
p2p->sd_peer = NULL; p2p->sd_peer = NULL;
p2p->invite_peer = NULL; p2p->invite_peer = NULL;
@ -2907,6 +2913,7 @@ int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success) static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
{ {
struct p2p_device *dev = p2p->go_neg_peer; struct p2p_device *dev = p2p->go_neg_peer;
int timeout;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: GO Negotiation Request TX callback: success=%d", "P2P: GO Negotiation Request TX callback: success=%d",
@ -2945,7 +2952,20 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success)
* channel. * channel.
*/ */
p2p_set_state(p2p, P2P_CONNECT); p2p_set_state(p2p, P2P_CONNECT);
p2p_set_timeout(p2p, 0, success ? 500000 : 100000); timeout = success ? 500000 : 100000;
if (!success && p2p->go_neg_peer &&
(p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE)) {
unsigned int r;
/*
* Peer is expected to wait our response and we will skip the
* listen phase. Add some randomness to the wait time here to
* make it less likely to hit cases where we could end up in
* sync with peer not listening.
*/
os_get_random((u8 *) &r, sizeof(r));
timeout += r % 100000;
}
p2p_set_timeout(p2p, 0, timeout);
} }
@ -3183,6 +3203,15 @@ static void p2p_timeout_connect(struct p2p_data *p2p)
p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1); p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
return; return;
} }
if (p2p->go_neg_peer &&
(p2p->go_neg_peer->flags & P2P_DEV_PEER_WAITING_RESPONSE) &&
p2p->go_neg_peer->connect_reqs < 120) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer expected to "
"wait our response - skip listen");
p2p_connect_send(p2p, p2p->go_neg_peer);
return;
}
p2p_set_state(p2p, P2P_CONNECT_LISTEN); p2p_set_state(p2p, P2P_CONNECT_LISTEN);
p2p_listen_in_find(p2p, 0); p2p_listen_in_find(p2p, 0);
} }