DPP3: Add PKEX initiator retries and fallback from v2 to v1 for hostapd

This extends hostapd with the design used in wpa_supplicant for PKEX
initiator retries and automatic version fallback from v2 to v1 (the
latter is enabled only with CONFIG_DPP3=y).

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2022-01-24 20:57:19 +02:00 committed by Jouni Malinen
parent 3f67ab5871
commit 9d3f347a2b

View file

@ -216,6 +216,163 @@ static void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd)
}
static int hostapd_dpp_allow_ir(struct hostapd_data *hapd, unsigned int freq)
{
int i, j;
if (!hapd->iface->hw_features)
return -1;
for (i = 0; i < hapd->iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &hapd->iface->hw_features[i];
for (j = 0; j < mode->num_channels; j++) {
struct hostapd_channel_data *chan = &mode->channels[j];
if (chan->freq != (int) freq)
continue;
if (chan->flag & (HOSTAPD_CHAN_DISABLED |
HOSTAPD_CHAN_NO_IR |
HOSTAPD_CHAN_RADAR))
continue;
return 1;
}
}
wpa_printf(MSG_DEBUG,
"DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list",
freq);
return 0;
}
static int hostapd_dpp_pkex_next_channel(struct hostapd_data *hapd,
struct dpp_pkex *pkex)
{
if (pkex->freq == 2437)
pkex->freq = 5745;
else if (pkex->freq == 5745)
pkex->freq = 5220;
else if (pkex->freq == 5220)
pkex->freq = 60480;
else
return -1; /* no more channels to try */
if (hostapd_dpp_allow_ir(hapd, pkex->freq) == 1) {
wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz",
pkex->freq);
return 0;
}
/* Could not use this channel - try the next one */
return hostapd_dpp_pkex_next_channel(hapd, pkex);
}
static int hostapd_dpp_pkex_init(struct hostapd_data *hapd, bool v2)
{
struct dpp_pkex *pkex;
struct wpabuf *msg;
unsigned int wait_time;
wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1);
dpp_pkex_free(hapd->dpp_pkex);
hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi,
hapd->own_addr,
hapd->dpp_pkex_identifier,
hapd->dpp_pkex_code, v2);
pkex = hapd->dpp_pkex;
if (!pkex)
return -1;
msg = hapd->dpp_pkex->exchange_req;
wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */
pkex->freq = 2437;
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
" freq=%u type=%d", MAC2STR(broadcast), pkex->freq,
v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
DPP_PA_PKEX_V1_EXCHANGE_REQ);
hostapd_drv_send_action(hapd, pkex->freq, 0, broadcast,
wpabuf_head(msg), wpabuf_len(msg));
pkex->exch_req_wait_time = wait_time;
pkex->exch_req_tries = 1;
return 0;
}
static void hostapd_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct dpp_pkex *pkex = hapd->dpp_pkex;
if (!pkex || !pkex->exchange_req)
return;
if (pkex->exch_req_tries >= 5) {
if (hostapd_dpp_pkex_next_channel(hapd, pkex) < 0) {
#ifdef CONFIG_DPP3
if (pkex->v2) {
wpa_printf(MSG_DEBUG,
"DPP: Fall back to PKEXv1");
hostapd_dpp_pkex_init(hapd, false);
return;
}
#endif /* CONFIG_DPP3 */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"No response from PKEX peer");
dpp_pkex_free(pkex);
hapd->dpp_pkex = NULL;
return;
}
pkex->exch_req_tries = 0;
}
pkex->exch_req_tries++;
wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
pkex->exch_req_tries);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
" freq=%u type=%d",
MAC2STR(broadcast), pkex->freq,
pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
DPP_PA_PKEX_V1_EXCHANGE_REQ);
hostapd_drv_send_action(hapd, pkex->freq, pkex->exch_req_wait_time,
broadcast,
wpabuf_head(pkex->exchange_req),
wpabuf_len(pkex->exchange_req));
}
static void hostapd_dpp_pkex_tx_status(struct hostapd_data *hapd, const u8 *dst,
const u8 *data, size_t data_len, int ok)
{
struct dpp_pkex *pkex = hapd->dpp_pkex;
if (pkex->failed) {
wpa_printf(MSG_DEBUG,
"DPP: Terminate PKEX exchange due to an earlier error");
if (pkex->t > pkex->own_bi->pkex_t)
pkex->own_bi->pkex_t = pkex->t;
dpp_pkex_free(pkex);
hapd->dpp_pkex = NULL;
return;
}
if (pkex->exch_req_wait_time && pkex->exchange_req) {
/* Wait for PKEX Exchange Response frame and retry request if
* no response is seen. */
eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd,
NULL);
eloop_register_timeout(pkex->exch_req_wait_time / 1000,
(pkex->exch_req_wait_time % 1000) * 1000,
hostapd_dpp_pkex_retry_timeout, hapd,
NULL);
}
}
void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
const u8 *data, size_t data_len, int ok)
{
@ -227,6 +384,11 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
" result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED");
if (!hapd->dpp_auth) {
if (hapd->dpp_pkex) {
hostapd_dpp_pkex_tx_status(hapd, dst, data, data_len,
ok);
return;
}
wpa_printf(MSG_DEBUG,
"DPP: Ignore TX status since there is no ongoing authentication exchange");
return;
@ -1783,6 +1945,9 @@ hostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src,
return;
}
eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd, NULL);
hapd->dpp_pkex->exch_req_wait_time = 0;
msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len);
if (!msg) {
wpa_printf(MSG_DEBUG, "DPP: Failed to process the response");
@ -2172,26 +2337,14 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
return -1;
if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
struct wpabuf *msg;
#ifdef CONFIG_DPP3
bool v2 = true;
#else /* CONFIG_DPP3 */
bool v2 = os_strstr(cmd, " init=2") != NULL;
#endif /* CONFIG_DPP3 */
wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
dpp_pkex_free(hapd->dpp_pkex);
hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
hapd->own_addr,
hapd->dpp_pkex_identifier,
hapd->dpp_pkex_code, v2);
if (!hapd->dpp_pkex)
if (hostapd_dpp_pkex_init(hapd, v2) < 0)
return -1;
msg = hapd->dpp_pkex->exchange_req;
/* TODO: Which channel to use? */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
" freq=%u type=%d", MAC2STR(broadcast), 2437,
v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
DPP_PA_PKEX_V1_EXCHANGE_REQ);
hostapd_drv_send_action(hapd, 2437, 0, broadcast,
wpabuf_head(msg), wpabuf_len(msg));
}
/* TODO: Support multiple PKEX info entries */
@ -2319,6 +2472,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
#endif /* CONFIG_TESTING_OPTIONS */
if (!hapd->dpp_init_done)
return;
eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);