P2P: Add retry mechanism for GO Negotiation Confirmation
wpa_supplicant now retries for P2P_GO_NEG_CNF_MAX_RETRY_COUNT times if it doesn't receive acknowledgement for GO Negotiation Confirmation frame. Currently, P2P_GO_NEG_CNF_MAX_RETRY_COUNT is set to 1. While this is not strictly speaking following the P2P specification, this can improve robustness of GO Negotiation in environments with interference and also with peer devices that do not behave properly (e.g., by not remaining awake on the negotiation channel through the full GO Negotiation). Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
8235f89f3f
commit
0e0e1e564f
3 changed files with 71 additions and 9 deletions
|
@ -218,6 +218,8 @@ void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
|
||||||
os_memset(&res, 0, sizeof(res));
|
os_memset(&res, 0, sizeof(res));
|
||||||
res.status = status;
|
res.status = status;
|
||||||
if (peer) {
|
if (peer) {
|
||||||
|
wpabuf_free(peer->go_neg_conf);
|
||||||
|
peer->go_neg_conf = NULL;
|
||||||
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr,
|
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr,
|
||||||
ETH_ALEN);
|
ETH_ALEN);
|
||||||
os_memcpy(res.peer_interface_addr, peer->intended_addr,
|
os_memcpy(res.peer_interface_addr, peer->intended_addr,
|
||||||
|
@ -802,6 +804,7 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
wpabuf_free(dev->info.wfd_subelems);
|
wpabuf_free(dev->info.wfd_subelems);
|
||||||
|
wpabuf_free(dev->go_neg_conf);
|
||||||
|
|
||||||
os_free(dev);
|
os_free(dev);
|
||||||
}
|
}
|
||||||
|
@ -1611,6 +1614,8 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
|
||||||
peer->go_neg_req_sent = 0;
|
peer->go_neg_req_sent = 0;
|
||||||
peer->wps_method = WPS_NOT_READY;
|
peer->wps_method = WPS_NOT_READY;
|
||||||
peer->oob_pw_id = 0;
|
peer->oob_pw_id = 0;
|
||||||
|
wpabuf_free(peer->go_neg_conf);
|
||||||
|
peer->go_neg_conf = NULL;
|
||||||
|
|
||||||
p2p_set_state(p2p, P2P_PROVISIONING);
|
p2p_set_state(p2p, P2P_PROVISIONING);
|
||||||
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
|
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
|
||||||
|
@ -2952,12 +2957,43 @@ static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
|
||||||
struct p2p_device *dev;
|
struct p2p_device *dev;
|
||||||
|
|
||||||
p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
|
p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
|
||||||
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
|
|
||||||
if (result == P2P_SEND_ACTION_FAILED) {
|
if (result == P2P_SEND_ACTION_FAILED) {
|
||||||
|
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
|
||||||
p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
|
p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev = p2p->go_neg_peer;
|
||||||
|
|
||||||
if (result == P2P_SEND_ACTION_NO_ACK) {
|
if (result == P2P_SEND_ACTION_NO_ACK) {
|
||||||
|
/*
|
||||||
|
* Retry GO Negotiation Confirmation
|
||||||
|
* P2P_GO_NEG_CNF_MAX_RETRY_COUNT times if we did not receive
|
||||||
|
* ACK for confirmation.
|
||||||
|
*/
|
||||||
|
if (dev && dev->go_neg_conf &&
|
||||||
|
dev->go_neg_conf_sent <= P2P_GO_NEG_CNF_MAX_RETRY_COUNT) {
|
||||||
|
p2p_dbg(p2p, "GO Negotiation Confirm retry %d",
|
||||||
|
dev->go_neg_conf_sent);
|
||||||
|
p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
|
||||||
|
if (p2p_send_action(p2p, dev->go_neg_conf_freq,
|
||||||
|
dev->info.p2p_device_addr,
|
||||||
|
p2p->cfg->dev_addr,
|
||||||
|
dev->info.p2p_device_addr,
|
||||||
|
wpabuf_head(dev->go_neg_conf),
|
||||||
|
wpabuf_len(dev->go_neg_conf), 0) >=
|
||||||
|
0) {
|
||||||
|
dev->go_neg_conf_sent++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p2p_dbg(p2p, "Failed to re-send Action frame");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Continue with the assumption that the first attempt
|
||||||
|
* went through and just the ACK frame was lost.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It looks like the TX status for GO Negotiation Confirm is
|
* It looks like the TX status for GO Negotiation Confirm is
|
||||||
* often showing failure even when the peer has actually
|
* often showing failure even when the peer has actually
|
||||||
|
@ -2971,7 +3007,8 @@ static void p2p_go_neg_conf_cb(struct p2p_data *p2p,
|
||||||
p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported");
|
p2p_dbg(p2p, "Assume GO Negotiation Confirm TX was actually received by the peer even though Ack was not reported");
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = p2p->go_neg_peer;
|
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
|
||||||
|
|
||||||
if (dev == NULL)
|
if (dev == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -896,7 +896,6 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
|
||||||
const u8 *data, size_t len, int rx_freq)
|
const u8 *data, size_t len, int rx_freq)
|
||||||
{
|
{
|
||||||
struct p2p_device *dev;
|
struct p2p_device *dev;
|
||||||
struct wpabuf *conf;
|
|
||||||
int go = -1;
|
int go = -1;
|
||||||
struct p2p_message msg;
|
struct p2p_message msg;
|
||||||
u8 status = P2P_SC_SUCCESS;
|
u8 status = P2P_SC_SUCCESS;
|
||||||
|
@ -1101,10 +1100,13 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
|
||||||
os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
|
os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token, status,
|
/* Store GO Negotiation Confirmation to allow retransmission */
|
||||||
msg.operating_channel, go);
|
wpabuf_free(dev->go_neg_conf);
|
||||||
|
dev->go_neg_conf = p2p_build_go_neg_conf(p2p, dev, msg.dialog_token,
|
||||||
|
status, msg.operating_channel,
|
||||||
|
go);
|
||||||
p2p_parse_free(&msg);
|
p2p_parse_free(&msg);
|
||||||
if (conf == NULL)
|
if (dev->go_neg_conf == NULL)
|
||||||
return;
|
return;
|
||||||
p2p_dbg(p2p, "Sending GO Negotiation Confirm");
|
p2p_dbg(p2p, "Sending GO Negotiation Confirm");
|
||||||
if (status == P2P_SC_SUCCESS) {
|
if (status == P2P_SC_SUCCESS) {
|
||||||
|
@ -1116,13 +1118,18 @@ fail:
|
||||||
freq = rx_freq;
|
freq = rx_freq;
|
||||||
else
|
else
|
||||||
freq = dev->listen_freq;
|
freq = dev->listen_freq;
|
||||||
|
|
||||||
|
dev->go_neg_conf_freq = freq;
|
||||||
|
dev->go_neg_conf_sent = 0;
|
||||||
|
|
||||||
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
|
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
|
||||||
wpabuf_head(conf), wpabuf_len(conf), 200) < 0) {
|
wpabuf_head(dev->go_neg_conf),
|
||||||
|
wpabuf_len(dev->go_neg_conf), 200) < 0) {
|
||||||
p2p_dbg(p2p, "Failed to send Action frame");
|
p2p_dbg(p2p, "Failed to send Action frame");
|
||||||
p2p_go_neg_failed(p2p, dev, -1);
|
p2p_go_neg_failed(p2p, dev, -1);
|
||||||
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
|
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
|
||||||
}
|
} else
|
||||||
wpabuf_free(conf);
|
dev->go_neg_conf_sent++;
|
||||||
if (status != P2P_SC_SUCCESS) {
|
if (status != P2P_SC_SUCCESS) {
|
||||||
p2p_dbg(p2p, "GO Negotiation failed");
|
p2p_dbg(p2p, "GO Negotiation failed");
|
||||||
p2p_go_neg_failed(p2p, dev, status);
|
p2p_go_neg_failed(p2p, dev, status);
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include "utils/list.h"
|
#include "utils/list.h"
|
||||||
#include "p2p.h"
|
#include "p2p.h"
|
||||||
|
|
||||||
|
#define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1
|
||||||
|
|
||||||
enum p2p_role_indication;
|
enum p2p_role_indication;
|
||||||
|
|
||||||
enum p2p_go_state {
|
enum p2p_go_state {
|
||||||
|
@ -108,6 +110,22 @@ struct p2p_device {
|
||||||
|
|
||||||
u8 go_timeout;
|
u8 go_timeout;
|
||||||
u8 client_timeout;
|
u8 client_timeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* go_neg_conf_sent - Number of GO Negotiation Confirmation retries
|
||||||
|
*/
|
||||||
|
u8 go_neg_conf_sent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* freq - Frquency on which the GO Negotiation Confirmation is sent
|
||||||
|
*/
|
||||||
|
int go_neg_conf_freq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* go_neg_conf - GO Negotiation Confirmation frame
|
||||||
|
*/
|
||||||
|
struct wpabuf *go_neg_conf;
|
||||||
|
|
||||||
int sd_pending_bcast_queries;
|
int sd_pending_bcast_queries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue