DPP: Retransmit DPP Authentication Response frame if it is not ACKed

This extends wpa_supplicant DPP implementation to retransmit DPP
Authentication Response frame every 10 seconds up to 5 times if the peer
does not reply with DPP Authentication Confirm frame.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2017-11-13 12:34:17 +02:00 committed by Jouni Malinen
parent c1d3773967
commit 95b0104a34
5 changed files with 84 additions and 1 deletions

View file

@ -1541,6 +1541,9 @@ static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
size_t len[2], siv_len, attr_len; size_t len[2], siv_len, attr_len;
u8 *attr_start, *attr_end, *pos; u8 *attr_start, *attr_end, *pos;
auth->waiting_auth_conf = 1;
auth->auth_resp_tries = 0;
/* Build DPP Authentication Response frame attributes */ /* Build DPP Authentication Response frame attributes */
attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) +
4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data); 4 + (pr ? wpabuf_len(pr) : 0) + 4 + sizeof(wrapped_data);
@ -1551,7 +1554,6 @@ static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len); msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len);
if (!msg) if (!msg)
return NULL; return NULL;
wpabuf_free(auth->resp_msg);
attr_start = wpabuf_put(msg, 0); attr_start = wpabuf_put(msg, 0);
@ -2497,6 +2499,7 @@ static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
auth->k2); auth->k2);
if (!msg) if (!msg)
goto fail; goto fail;
wpabuf_free(auth->resp_msg);
auth->resp_msg = msg; auth->resp_msg = msg;
ret = 0; ret = 0;
fail: fail:
@ -2542,6 +2545,7 @@ static int dpp_auth_build_resp_status(struct dpp_authentication *auth,
NULL, i_nonce, NULL, 0, auth->k1); NULL, i_nonce, NULL, 0, auth->k1);
if (!msg) if (!msg)
return -1; return -1;
wpabuf_free(auth->resp_msg);
auth->resp_msg = msg; auth->resp_msg = msg;
return 0; return 0;
} }
@ -3454,6 +3458,8 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
size_t unwrapped_len = 0; size_t unwrapped_len = 0;
u8 i_auth2[DPP_MAX_HASH_LEN]; u8 i_auth2[DPP_MAX_HASH_LEN];
auth->waiting_auth_conf = 0;
wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len); &wrapped_data_len);
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {

View file

@ -183,6 +183,8 @@ struct dpp_authentication {
u8 ke[DPP_MAX_HASH_LEN]; u8 ke[DPP_MAX_HASH_LEN];
int initiator; int initiator;
int waiting_auth_resp; int waiting_auth_resp;
int waiting_auth_conf;
unsigned int auth_resp_tries;
u8 allowed_roles; u8 allowed_roles;
int configurator; int configurator;
int remove_on_tx_status; int remove_on_tx_status;

View file

@ -611,6 +611,10 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->dpp_init_retry_time = atoi(value); wpa_s->dpp_init_retry_time = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) { } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) {
wpa_s->dpp_resp_wait_time = atoi(value); wpa_s->dpp_resp_wait_time = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) {
wpa_s->dpp_resp_max_tries = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) {
wpa_s->dpp_resp_retry_time = atoi(value);
#endif /* CONFIG_DPP */ #endif /* CONFIG_DPP */
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
@ -7755,6 +7759,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->dpp_init_max_tries = 0; wpa_s->dpp_init_max_tries = 0;
wpa_s->dpp_init_retry_time = 0; wpa_s->dpp_init_retry_time = 0;
wpa_s->dpp_resp_wait_time = 0; wpa_s->dpp_resp_wait_time = 0;
wpa_s->dpp_resp_max_tries = 0;
wpa_s->dpp_resp_retry_time = 0;
#endif /* CONFIG_DPP */ #endif /* CONFIG_DPP */
#ifdef CONFIG_TDLS #ifdef CONFIG_TDLS

View file

@ -300,6 +300,63 @@ int wpas_dpp_bootstrap_info(struct wpa_supplicant *wpa_s, int id,
} }
static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct dpp_authentication *auth = wpa_s->dpp_auth;
if (!auth || !auth->resp_msg)
return;
wpa_printf(MSG_DEBUG,
"DPP: Retry Authentication Response after timeout");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
" freq=%u type=%d",
MAC2STR(auth->peer_mac_addr), auth->curr_freq,
DPP_PA_AUTHENTICATION_RESP);
offchannel_send_action(wpa_s, auth->curr_freq, auth->peer_mac_addr,
wpa_s->own_addr, broadcast,
wpabuf_head(auth->resp_msg),
wpabuf_len(auth->resp_msg),
500, wpas_dpp_tx_status, 0);
}
static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
unsigned int wait_time, max_tries;
if (!auth || !auth->resp_msg)
return;
if (wpa_s->dpp_resp_max_tries)
max_tries = wpa_s->dpp_resp_max_tries;
else
max_tries = 5;
auth->auth_resp_tries++;
if (auth->auth_resp_tries >= max_tries) {
wpa_printf(MSG_INFO, "DPP: No confirm received from initiator - stopping exchange");
offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
return;
}
if (wpa_s->dpp_resp_retry_time)
wait_time = wpa_s->dpp_resp_retry_time;
else
wait_time = 10000;
wpa_printf(MSG_DEBUG,
"DPP: Schedule retransmission of Authentication Response frame in %u ms",
wait_time);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
eloop_register_timeout(wait_time / 1000,
(wait_time % 1000) * 1000,
wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
}
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *src, const u8 *bssid,
@ -328,6 +385,8 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
"DPP: Terminate authentication exchange due to an earlier error"); "DPP: Terminate authentication exchange due to an earlier error");
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
NULL);
offchannel_send_action_done(wpa_s); offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth); dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL; wpa_s->dpp_auth = NULL;
@ -348,6 +407,10 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
wpas_dpp_auth_init_next(wpa_s); wpas_dpp_auth_init_next(wpa_s);
return; return;
} }
if (auth->waiting_auth_conf) {
wpas_dpp_auth_resp_retry(wpa_s);
return;
}
} }
if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 && if (!wpa_s->dpp_auth_ok_on_ack && wpa_s->dpp_auth->neg_freq > 0 &&
@ -685,6 +748,8 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd)
if (wpa_s->dpp_auth) { if (wpa_s->dpp_auth) {
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s,
NULL);
offchannel_send_action_done(wpa_s); offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth); dpp_auth_deinit(wpa_s->dpp_auth);
} }
@ -1856,6 +1921,7 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok); ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
offchannel_send_action_done(wpa_s); offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s); wpas_dpp_listen_stop(wpa_s);
if (ok) if (ok)
@ -2244,6 +2310,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
return; return;
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
offchannel_send_action_done(wpa_s); offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s); wpas_dpp_listen_stop(wpa_s);
dpp_bootstrap_del(wpa_s, 0); dpp_bootstrap_del(wpa_s, 0);

View file

@ -1203,6 +1203,8 @@ struct wpa_supplicant {
unsigned int dpp_init_max_tries; unsigned int dpp_init_max_tries;
unsigned int dpp_init_retry_time; unsigned int dpp_init_retry_time;
unsigned int dpp_resp_wait_time; unsigned int dpp_resp_wait_time;
unsigned int dpp_resp_max_tries;
unsigned int dpp_resp_retry_time;
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
char *dpp_config_obj_override; char *dpp_config_obj_override;
char *dpp_discovery_override; char *dpp_discovery_override;