P2P: Retry provision discovery requests in IDLE state
Since the peer may not be in Listen state when the provision discovery request is sent, try to send the request again number of times when in IDLE state. This was already done when p2p_find is in progress, but this commit adds retries to the case where no other P2P operations are in progress. Signed-off-by: Jayant Sane <jayant.sane@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
6b98a33c86
commit
6b56cc2d97
3 changed files with 155 additions and 1 deletions
|
@ -2250,19 +2250,81 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success)
|
|||
p2p_set_timeout(p2p, 0, 200000);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* p2p_retry_pd - Retry any pending provision disc requests in IDLE state
|
||||
* @p2p: P2P module context from p2p_init()
|
||||
*/
|
||||
void p2p_retry_pd(struct p2p_data *p2p)
|
||||
{
|
||||
struct p2p_device *dev;
|
||||
|
||||
if (p2p->state != P2P_IDLE)
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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)
|
||||
continue;
|
||||
if (dev->flags & P2P_DEV_PD_FOR_JOIN)
|
||||
continue;
|
||||
|
||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
|
||||
"pending Provisioning 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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
|
||||
{
|
||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||
"P2P: Provision Discovery Request TX callback: success=%d",
|
||||
success);
|
||||
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
|
||||
|
||||
/*
|
||||
* Postpone resetting the pending action state till after we actually
|
||||
* time out. This allows us to take some action like notifying any
|
||||
* interested parties about no response to the request.
|
||||
*
|
||||
* When the timer (below) goes off we check in IDLE, SEARCH, or
|
||||
* LISTEN_ONLY state, which are the only allowed states to issue a PD
|
||||
* requests in, if this was still pending and then raise notification.
|
||||
*/
|
||||
|
||||
if (!success) {
|
||||
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
|
||||
|
||||
if (p2p->state != P2P_IDLE)
|
||||
p2p_continue_find(p2p);
|
||||
else if (p2p->user_initiated_pd) {
|
||||
p2p->pending_action_state = P2P_PENDING_PD;
|
||||
p2p_set_timeout(p2p, 0, 300000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This postponing, of resetting pending_action_state, needs to be
|
||||
* done only for user initiated PD requests and not internal ones.
|
||||
*/
|
||||
if (p2p->user_initiated_pd)
|
||||
p2p->pending_action_state = P2P_PENDING_PD;
|
||||
else
|
||||
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
|
||||
|
||||
/* Wait for response from the peer */
|
||||
if (p2p->state == P2P_SEARCH)
|
||||
p2p_set_state(p2p, P2P_PD_DURING_FIND);
|
||||
|
@ -2653,6 +2715,30 @@ static void p2p_timeout_prov_disc_during_find(struct p2p_data *p2p)
|
|||
}
|
||||
|
||||
|
||||
static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
|
||||
{
|
||||
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
|
||||
|
||||
/*
|
||||
* For user initiated PD requests that we have not gotten any responses
|
||||
* for while in IDLE state, we retry them a couple of times before
|
||||
* giving up.
|
||||
*/
|
||||
if (!p2p->user_initiated_pd)
|
||||
return;
|
||||
|
||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||
"P2P: User initiated Provision Discovery Request timeout");
|
||||
|
||||
if (p2p->pd_retries) {
|
||||
p2p->pd_retries--;
|
||||
p2p_retry_pd(p2p);
|
||||
} else {
|
||||
p2p_reset_pending_pd(p2p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void p2p_timeout_invite(struct p2p_data *p2p)
|
||||
{
|
||||
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
|
||||
|
@ -2701,8 +2787,14 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
|
|||
|
||||
switch (p2p->state) {
|
||||
case P2P_IDLE:
|
||||
/* Check if we timed out waiting for PD req */
|
||||
if (p2p->pending_action_state == P2P_PENDING_PD)
|
||||
p2p_timeout_prov_disc_req(p2p);
|
||||
break;
|
||||
case P2P_SEARCH:
|
||||
/* Check if we timed out waiting for PD req */
|
||||
if (p2p->pending_action_state == P2P_PENDING_PD)
|
||||
p2p_timeout_prov_disc_req(p2p);
|
||||
p2p_search(p2p);
|
||||
break;
|
||||
case P2P_CONNECT:
|
||||
|
@ -2714,6 +2806,10 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx)
|
|||
case P2P_GO_NEG:
|
||||
break;
|
||||
case P2P_LISTEN_ONLY:
|
||||
/* Check if we timed out waiting for PD req */
|
||||
if (p2p->pending_action_state == P2P_PENDING_PD)
|
||||
p2p_timeout_prov_disc_req(p2p);
|
||||
|
||||
if (p2p->ext_listen_only) {
|
||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||
"P2P: Extended Listen Timing - Listen State "
|
||||
|
|
|
@ -393,6 +393,23 @@ struct p2p_data {
|
|||
* wps_vendor_ext - WPS Vendor Extensions to add
|
||||
*/
|
||||
struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
|
||||
|
||||
/*
|
||||
* user_initiated_pd - Whether a PD request is user initiated or not.
|
||||
*/
|
||||
u8 user_initiated_pd;
|
||||
|
||||
/*
|
||||
* Keep track of which peer a given PD request was sent to.
|
||||
* Used to raise a timeout alert in case there is no response.
|
||||
*/
|
||||
u8 pending_pd_devaddr[ETH_ALEN];
|
||||
|
||||
/*
|
||||
* Retry counter for provision discovery requests when issued
|
||||
* in IDLE state.
|
||||
*/
|
||||
int pd_retries;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -586,6 +603,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
|
|||
const u8 *data, size_t len);
|
||||
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
|
||||
int join);
|
||||
void p2p_reset_pending_pd(struct p2p_data *p2p);
|
||||
|
||||
/* p2p_invitation.c */
|
||||
void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
|
||||
|
|
|
@ -21,6 +21,13 @@
|
|||
#include "p2p.h"
|
||||
|
||||
|
||||
/*
|
||||
* Number of retries to attempt for provision discovery requests during IDLE
|
||||
* state in case the peer is not listening.
|
||||
*/
|
||||
#define MAX_PROV_DISC_REQ_RETRIES 10
|
||||
|
||||
|
||||
static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
|
||||
u16 config_methods)
|
||||
{
|
||||
|
@ -215,6 +222,11 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
|
|||
return;
|
||||
}
|
||||
|
||||
if (p2p->pending_action_state == P2P_PENDING_PD) {
|
||||
os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
|
||||
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
|
||||
}
|
||||
|
||||
if (dev->dialog_token != msg.dialog_token) {
|
||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||
"P2P: Ignore Provisioning Discovery Response with "
|
||||
|
@ -224,6 +236,14 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the response is from the peer to whom a user initiated request
|
||||
* was sent earlier, we reset that state info here.
|
||||
*/
|
||||
if (p2p->user_initiated_pd &&
|
||||
os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
|
||||
p2p_reset_pending_pd(p2p);
|
||||
|
||||
if (msg.wps_config_methods != dev->req_config_methods) {
|
||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
|
||||
"our Provisioning Discovery Request");
|
||||
|
@ -301,6 +321,8 @@ int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
|
|||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
|
||||
|
||||
wpabuf_free(req);
|
||||
return 0;
|
||||
}
|
||||
|
@ -343,5 +365,23 @@ int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We use the join param as a cue to differentiate between user
|
||||
* initiated PD request and one issued during finds (internal).
|
||||
*/
|
||||
p2p->user_initiated_pd = !join;
|
||||
|
||||
/* Also set some retries to attempt in case of IDLE state */
|
||||
if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
|
||||
p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
|
||||
|
||||
return p2p_send_prov_disc_req(p2p, dev, join);
|
||||
}
|
||||
|
||||
|
||||
void p2p_reset_pending_pd(struct p2p_data *p2p)
|
||||
{
|
||||
p2p->user_initiated_pd = 0;
|
||||
os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
|
||||
p2p->pd_retries = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue