]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP3: Add PKEX initiator retries and fallback from v2 to v1 for hostapd
authorJouni Malinen <quic_jouni@quicinc.com>
Mon, 24 Jan 2022 18:57:19 +0000 (20:57 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 24 Jan 2022 20:58:38 +0000 (22:58 +0200)
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>
src/ap/dpp_hostapd.c

index 13e1fc5bdd961a3662251ec32ed7cbac9db55802..6c30ba3020d8a4d8b0b6e27a33d859d6199649fb 100644 (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);