P2P: Retry PD Request in join-a-running-group case

The GO may be in sleep when we send a PD Request frame to indicate that
we are about to join a running group. Previously, this frame was not
retried more than normal low level retries. This can result in the GO
not getting the frame especially in cases where concurrent multi-channel
operations or aggressive sleep schedule is used since most drivers do
not yet synchronize with the GO's NoA before association.

Increase the likelihood of the GO receiving the PD Request frame by
retransmitting it similarly to the PD-for-GO-Negotiation case. Start
the actual join operation only after these retries have failed to get
an acknowledgment from the GO to give the connection attempt a chance
to succeed if the driver implements better NoA synchronization for it.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2012-11-23 00:53:42 +02:00 committed by Jouni Malinen
parent 6752716663
commit 175171ac6c
3 changed files with 33 additions and 17 deletions

View file

@ -2650,8 +2650,7 @@ static void p2p_retry_pd(struct p2p_data *p2p)
/*
* Retry the prov disc req attempt only for the peer that the user had
* requested for and provided a join has not been initiated on it
* in the meantime.
* requested.
*/
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
@ -2660,15 +2659,14 @@ static void p2p_retry_pd(struct p2p_data *p2p)
continue;
if (!dev->req_config_methods)
continue;
if (dev->flags & P2P_DEV_PD_FOR_JOIN)
continue;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
"pending Provision Discovery Request to "
MACSTR " (config methods 0x%x)",
MAC2STR(dev->info.p2p_device_addr),
dev->req_config_methods);
p2p_send_prov_disc_req(p2p, dev, 0, 0);
p2p_send_prov_disc_req(p2p, dev,
dev->flags & P2P_DEV_PD_FOR_JOIN, 0);
return;
}
}
@ -3183,9 +3181,23 @@ static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
p2p->pd_retries--;
p2p_retry_pd(p2p);
} else {
struct p2p_device *dev;
int for_join = 0;
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
if (os_memcmp(p2p->pending_pd_devaddr,
dev->info.p2p_device_addr, ETH_ALEN) != 0)
continue;
if (dev->req_config_methods &&
(dev->flags & P2P_DEV_PD_FOR_JOIN))
for_join = 1;
}
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
p2p->pending_pd_devaddr,
for_join ?
P2P_PROV_DISC_TIMEOUT_JOIN :
P2P_PROV_DISC_TIMEOUT);
p2p_reset_pending_pd(p2p);
}

View file

@ -232,6 +232,7 @@ enum p2p_prov_disc_status {
P2P_PROV_DISC_SUCCESS,
P2P_PROV_DISC_TIMEOUT,
P2P_PROV_DISC_REJECTED,
P2P_PROV_DISC_TIMEOUT_JOIN,
};
struct p2p_channel {

View file

@ -723,20 +723,14 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
if (result != OFFCHANNEL_SEND_ACTION_SUCCESS &&
wpa_s->pending_pd_before_join &&
(os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) &&
wpa_s->p2p_fallback_to_go_neg) {
wpa_s->pending_pd_before_join = 0;
if (wpa_s->p2p_fallback_to_go_neg) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req "
"during p2p_connect-auto");
wpas_p2p_fallback_to_go_neg(wpa_s, 0);
return;
}
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
"join-existing-group operation (no ACK for PD "
"Req)");
wpas_p2p_join_start(wpa_s);
}
}
@ -2290,6 +2284,15 @@ static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
return;
}
if (status == P2P_PROV_DISC_TIMEOUT_JOIN) {
wpa_s->pending_pd_before_join = 0;
wpa_printf(MSG_DEBUG, "P2P: Starting pending "
"join-existing-group operation (no ACK for PD "
"Req attempts)");
wpas_p2p_join_start(wpa_s);
return;
}
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
" p2p_dev_addr=" MACSTR " status=%d",
MAC2STR(peer), status);