P2P: Try SD Query with each non-ACK peer only once per search iteration

The previous behavior of bursting out all retry attempts of an SD Query
frame during a single search/listen iteration does not look very helpful
in the case where the peer does not ACK the query frame. Since the peer
was found in the search, but is not ACKing frames anymore, it is likely
that it left its listen state and we might as well do something more
useful to burst out a significant number of frames in hopes of seeing
the peer.

Modify the SD Query design during P2P Search to send out only a single
attempt (with likely multiple link-layer retries, if needed) per
search/listen iteration to each peer that has pending SD queries. Once
no more peers with pending queries remain, force another Listen and
Search phase to go through before continuing with the pending SD
queries.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2016-01-05 01:03:28 +02:00 committed by Jouni Malinen
parent e9ccfc38fd
commit cba9ebfdc2
3 changed files with 48 additions and 5 deletions

View file

@ -1228,6 +1228,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout,
p2p->cfg->stop_listen(p2p->cfg->cb_ctx); p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
p2p->find_type = type; p2p->find_type = type;
p2p_device_clear_reported(p2p); p2p_device_clear_reported(p2p);
os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
p2p_set_state(p2p, P2P_SEARCH); p2p_set_state(p2p, P2P_SEARCH);
p2p->search_delay = search_delay; p2p->search_delay = search_delay;
p2p->in_search_delay = 0; p2p->in_search_delay = 0;
@ -3163,13 +3164,18 @@ int p2p_set_country(struct p2p_data *p2p, const char *country)
static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev) static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
{ {
int res;
if (dev->sd_pending_bcast_queries == 0) { if (dev->sd_pending_bcast_queries == 0) {
/* Initialize with total number of registered broadcast /* Initialize with total number of registered broadcast
* SD queries. */ * SD queries. */
dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries; dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
} }
if (p2p_start_sd(p2p, dev) == 0) res = p2p_start_sd(p2p, dev);
if (res == -2)
return -2;
if (res == 0)
return 1; return 1;
if (dev->req_config_methods && if (dev->req_config_methods &&
@ -3189,7 +3195,7 @@ static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
void p2p_continue_find(struct p2p_data *p2p) void p2p_continue_find(struct p2p_data *p2p)
{ {
struct p2p_device *dev; struct p2p_device *dev;
int found; int found, res;
p2p_set_state(p2p, P2P_SEARCH); p2p_set_state(p2p, P2P_SEARCH);
@ -3202,10 +3208,13 @@ void p2p_continue_find(struct p2p_data *p2p)
} }
if (!found) if (!found)
continue; continue;
if (p2p_pre_find_operation(p2p, dev) > 0) { res = p2p_pre_find_operation(p2p, dev);
if (res > 0) {
p2p->last_p2p_find_oper = dev; p2p->last_p2p_find_oper = dev;
return; return;
} }
if (res == -2)
goto skip_sd;
} }
/* /*
@ -3213,14 +3222,19 @@ void p2p_continue_find(struct p2p_data *p2p)
* iteration device. * iteration device.
*/ */
dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
if (p2p_pre_find_operation(p2p, dev) > 0) { res = p2p_pre_find_operation(p2p, dev);
if (res > 0) {
p2p->last_p2p_find_oper = dev; p2p->last_p2p_find_oper = dev;
return; return;
} }
if (res == -2)
goto skip_sd;
if (dev == p2p->last_p2p_find_oper) if (dev == p2p->last_p2p_find_oper)
break; break;
} }
skip_sd:
os_memset(p2p->sd_query_no_ack, 0, ETH_ALEN);
p2p_listen_in_find(p2p, 1); p2p_listen_in_find(p2p, 1);
} }
@ -3232,8 +3246,17 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success)
p2p->pending_action_state = P2P_NO_PENDING_ACTION; p2p->pending_action_state = P2P_NO_PENDING_ACTION;
if (!success) { if (!success) {
if (p2p->sd_peer) if (p2p->sd_peer) {
if (is_zero_ether_addr(p2p->sd_query_no_ack)) {
os_memcpy(p2p->sd_query_no_ack,
p2p->sd_peer->info.p2p_device_addr,
ETH_ALEN);
p2p_dbg(p2p,
"First SD Query no-ACK in this search iteration: "
MACSTR, MAC2STR(p2p->sd_query_no_ack));
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx); p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
}
p2p->sd_peer = NULL; p2p->sd_peer = NULL;
if (p2p->state != P2P_IDLE) if (p2p->state != P2P_IDLE)
p2p_continue_find(p2p); p2p_continue_find(p2p);

View file

@ -308,6 +308,18 @@ struct p2p_data {
*/ */
int num_p2p_sd_queries; int num_p2p_sd_queries;
/**
* sd_query_no_ack - The first peer (Dev Addr) that did not ACK SD Query
*
* This is used to track the first peer that did not ACK an SD Query
* within a single P2P Search iteration. All zeros address means no such
* peer was yet seen. This information is used to allow a new Listen and
* Search phases to be once every pending SD Query has been sent once to
* each peer instead of looping all pending attempts continuously until
* running out of retry maximums.
*/
u8 sd_query_no_ack[ETH_ALEN];
/* GO Negotiation data */ /* GO Negotiation data */
/** /**

View file

@ -288,6 +288,14 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev)
query = p2p_pending_sd_req(p2p, dev); query = p2p_pending_sd_req(p2p, dev);
if (query == NULL) if (query == NULL)
return -1; return -1;
if (p2p->state == P2P_SEARCH &&
os_memcmp(p2p->sd_query_no_ack, dev->info.p2p_device_addr,
ETH_ALEN) == 0) {
p2p_dbg(p2p, "Do not start Service Discovery with " MACSTR
" due to it being the first no-ACK peer in this search iteration",
MAC2STR(dev->info.p2p_device_addr));
return -2;
}
p2p_dbg(p2p, "Start Service Discovery with " MACSTR, p2p_dbg(p2p, "Start Service Discovery with " MACSTR,
MAC2STR(dev->info.p2p_device_addr)); MAC2STR(dev->info.p2p_device_addr));