]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP2: Chirping in wpa_supplicant Enrollee
authorJouni Malinen <jouni@codeaurora.org>
Fri, 27 Mar 2020 10:42:00 +0000 (12:42 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 27 Mar 2020 18:05:25 +0000 (20:05 +0200)
Add a new wpa_supplicant control interface command "DPP_CHIRP own=<BI
ID> iter=<count>" to request chirping, i.e., sending of Presence
Announcement frames, to be started.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
src/common/dpp.c
src/common/dpp.h
src/common/wpa_ctrl.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dpp_supplicant.c
wpa_supplicant/dpp_supplicant.h
wpa_supplicant/wpa_supplicant_i.h

index ea5d6df57fe00edf0437ab7938c6270b48e39929..56abe507f2377e0ca07473440377ee0c62270ae4 100644 (file)
@@ -131,6 +131,7 @@ struct dpp_global {
        struct dl_list tcp_init; /* struct dpp_connection */
        void *cb_ctx;
        int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+       void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
 #endif /* CONFIG_DPP2 */
 };
 
@@ -10333,6 +10334,10 @@ static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id)
                if (id && bi->id != id)
                        continue;
                found = 1;
+#ifdef CONFIG_DPP2
+               if (dpp->remove_bi)
+                       dpp->remove_bi(dpp->cb_ctx, bi);
+#endif /* CONFIG_DPP2 */
                dl_list_del(&bi->list);
                dpp_bootstrap_info_free(bi);
        }
@@ -10903,6 +10908,7 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config)
 #ifdef CONFIG_DPP2
        dpp->cb_ctx = config->cb_ctx;
        dpp->process_conf_obj = config->process_conf_obj;
+       dpp->remove_bi = config->remove_bi;
 #endif /* CONFIG_DPP2 */
 
        dl_list_init(&dpp->bootstrap);
index d544fba6679532a03977ff4d3abada8b5a40c79b..513918bb5696beadca01f5fb5206721e28dd054c 100644 (file)
@@ -602,6 +602,7 @@ struct dpp_global_config {
        void *msg_ctx;
        void *cb_ctx;
        int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
+       void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi);
 };
 
 struct dpp_global * dpp_global_init(struct dpp_global_config *config);
index 7471f0d15384de5a7a00c76b516b365a69961290..0b04130685a63773cf6d3c774c93cfc1a1f69c35 100644 (file)
@@ -187,6 +187,7 @@ extern "C" {
 #define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
 #define DPP_EVENT_INTRO "DPP-INTRO "
 #define DPP_EVENT_CONF_REQ_RX "DPP-CONF-REQ-RX "
+#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
 
 /* MESH events */
 #define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
index ebcb60e5a742f92fd7cb53504b682a053aa48087..a2b4ee765b6841e86e6c0dcd331f497c7a66a88a 100644 (file)
@@ -8104,6 +8104,9 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
        wpa_s->dpp_resp_wait_time = 0;
        wpa_s->dpp_resp_max_tries = 0;
        wpa_s->dpp_resp_retry_time = 0;
+#ifdef CONFIG_DPP2
+       wpas_dpp_chirp_stop(wpa_s);
+#endif /* CONFIG_DPP2 */
 #ifdef CONFIG_TESTING_OPTIONS
        os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN);
        os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN);
@@ -10947,6 +10950,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                        reply_len = -1;
        } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) {
                dpp_controller_stop(wpa_s->dpp);
+       } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) {
+               if (wpas_dpp_chirp(wpa_s, buf + 9) < 0)
+                       reply_len = -1;
+       } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) {
+               wpas_dpp_chirp_stop(wpa_s);
 #endif /* CONFIG_DPP2 */
 #endif /* CONFIG_DPP */
        } else {
index 89d86ca02599d481396a3dea0d7f6397cb7cc8f9..c6d555662bb6b5fbf1fc71abbcddef47da673a1b 100644 (file)
@@ -975,6 +975,10 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src,
        wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR,
                   MAC2STR(src));
 
+#ifdef CONFIG_DPP2
+       wpas_dpp_chirp_stop(wpa_s);
+#endif /* CONFIG_DPP2 */
+
        r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH,
                                   &r_bootstrap_len);
        if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) {
@@ -1681,6 +1685,15 @@ static int wpas_dpp_process_conf_obj(void *ctx,
        return res;
 }
 
+
+static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       if (bi == wpa_s->dpp_chirp_bi)
+               wpas_dpp_chirp_stop(wpa_s);
+}
+
 #endif /* CONFIG_DPP2 */
 
 
@@ -2651,6 +2664,7 @@ int wpas_dpp_init(struct wpa_supplicant *wpa_s)
        config.cb_ctx = wpa_s;
 #ifdef CONFIG_DPP2
        config.process_conf_obj = wpas_dpp_process_conf_obj;
+       config.remove_bi = wpas_dpp_remove_bi;
 #endif /* CONFIG_DPP2 */
        wpa_s->dpp = dpp_global_init(&config);
        return wpa_s->dpp ? 0 : -1;
@@ -2682,6 +2696,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
        eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL);
        dpp_pfs_free(wpa_s->dpp_pfs);
        wpa_s->dpp_pfs = NULL;
+       wpas_dpp_chirp_stop(wpa_s);
 #endif /* CONFIG_DPP2 */
        offchannel_send_action_done(wpa_s);
        wpas_dpp_listen_stop(wpa_s);
@@ -2694,6 +2709,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
 
 
 #ifdef CONFIG_DPP2
+
 int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
 {
        struct dpp_controller_config config;
@@ -2710,4 +2726,269 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd)
        config.configurator_params = wpa_s->dpp_configurator_params;
        return dpp_controller_start(wpa_s->dpp, &config);
 }
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx);
+
+static void wpas_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+
+       wpa_printf(MSG_DEBUG, "DPP: No chirp response received");
+       offchannel_send_action_done(wpa_s);
+       wpas_dpp_chirp_next(wpa_s, NULL);
+}
+
+
+static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s,
+                                    unsigned int freq, const u8 *dst,
+                                    const u8 *src, const u8 *bssid,
+                                    const u8 *data, size_t data_len,
+                                    enum offchannel_send_action_result result)
+{
+       if (result == OFFCHANNEL_SEND_ACTION_FAILED) {
+               wpa_printf(MSG_DEBUG, "DPP: Failed to send chirp on %d MHz",
+                          wpa_s->dpp_chirp_freq);
+               if (eloop_register_timeout(0, 0, wpas_dpp_chirp_next,
+                                          wpa_s, NULL) < 0)
+                       wpas_dpp_chirp_stop(wpa_s);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "DPP: Chirp send completed - wait for response");
+       if (eloop_register_timeout(2, 0, wpas_dpp_chirp_timeout,
+                                  wpa_s, NULL) < 0)
+               wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s)
+{
+       wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq);
+       wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+               MAC2STR(broadcast), wpa_s->dpp_chirp_freq,
+               DPP_PA_PRESENCE_ANNOUNCEMENT);
+       if (offchannel_send_action(
+                   wpa_s, wpa_s->dpp_chirp_freq, broadcast,
+                   wpa_s->own_addr, broadcast,
+                   wpabuf_head(wpa_s->dpp_presence_announcement),
+                   wpabuf_len(wpa_s->dpp_presence_announcement),
+                   2000, wpas_dpp_chirp_tx_status, 0) < 0)
+               wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s,
+                                           struct wpa_scan_results *scan_res)
+{
+       struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi;
+       unsigned int i;
+       struct hostapd_hw_modes *mode;
+       int c;
+       struct wpa_bss *bss;
+
+       if (!bi)
+               return;
+
+       wpa_s->dpp_chirp_scan_done = 1;
+
+       os_free(wpa_s->dpp_chirp_freqs);
+       wpa_s->dpp_chirp_freqs = NULL;
+
+       /* Channels from own bootstrapping info */
+       for (i = 0; i < bi->num_freq; i++)
+               int_array_add_unique(&wpa_s->dpp_chirp_freqs, bi->freq[i]);
+
+       /* Preferred chirping channels */
+       int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437);
+
+       mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+                       HOSTAPD_MODE_IEEE80211A, 0);
+       if (mode) {
+               int chan44 = 0, chan149 = 0;
+
+               for (c = 0; c < mode->num_channels; c++) {
+                       struct hostapd_channel_data *chan = &mode->channels[c];
+
+                       if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+                                         HOSTAPD_CHAN_RADAR))
+                               continue;
+                       if (chan->freq == 5220)
+                               chan44 = 1;
+                       if (chan->freq == 5745)
+                               chan149 = 1;
+               }
+               if (chan149)
+                       int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745);
+               else if (chan44)
+                       int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220);
+       }
+
+       mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+                       HOSTAPD_MODE_IEEE80211AD, 0);
+       if (mode) {
+               for (c = 0; c < mode->num_channels; c++) {
+                       struct hostapd_channel_data *chan = &mode->channels[c];
+
+                       if ((chan->flag & (HOSTAPD_CHAN_DISABLED |
+                                          HOSTAPD_CHAN_RADAR)) ||
+                           chan->freq != 60480)
+                               continue;
+                       int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480);
+                       break;
+               }
+       }
+
+       /* Add channels from scan results for APs that advertise Configurator
+        * Connectivity element */
+       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+               if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE))
+                       int_array_add_unique(&wpa_s->dpp_chirp_freqs,
+                                            bss->freq);
+       }
+
+       if (!wpa_s->dpp_chirp_freqs ||
+           eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0)
+               wpas_dpp_chirp_stop(wpa_s);
+}
+
+
+static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_supplicant *wpa_s = eloop_ctx;
+       int i;
+
+       if (wpa_s->dpp_chirp_listen)
+               wpas_dpp_listen_stop(wpa_s);
+
+       if (wpa_s->dpp_chirp_freq == 0) {
+               if (wpa_s->dpp_chirp_round % 4 == 0 &&
+                   !wpa_s->dpp_chirp_scan_done) {
+                       wpa_printf(MSG_DEBUG,
+                                  "DPP: Update channel list for chirping");
+                       wpa_s->scan_req = MANUAL_SCAN_REQ;
+                       wpa_s->scan_res_handler =
+                               wpas_dpp_chirp_scan_res_handler;
+                       wpa_supplicant_req_scan(wpa_s, 0, 0);
+                       return;
+               }
+               wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[0];
+               wpa_s->dpp_chirp_round++;
+               wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d",
+                          wpa_s->dpp_chirp_round);
+       } else {
+               for (i = 0; wpa_s->dpp_chirp_freqs[i]; i++)
+                       if (wpa_s->dpp_chirp_freqs[i] == wpa_s->dpp_chirp_freq)
+                               break;
+               if (!wpa_s->dpp_chirp_freqs[i]) {
+                       wpa_printf(MSG_DEBUG,
+                                  "DPP: Previous chirp freq %d not found",
+                                  wpa_s->dpp_chirp_freq);
+                       return;
+               }
+               i++;
+               if (wpa_s->dpp_chirp_freqs[i]) {
+                       wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[i];
+               } else {
+                       wpa_s->dpp_chirp_iter--;
+                       if (wpa_s->dpp_chirp_iter <= 0) {
+                               wpa_printf(MSG_DEBUG,
+                                          "DPP: Chirping iterations completed");
+                               wpas_dpp_chirp_stop(wpa_s);
+                               return;
+                       }
+                       wpa_s->dpp_chirp_freq = 0;
+                       wpa_s->dpp_chirp_scan_done = 0;
+                       if (eloop_register_timeout(30, 0, wpas_dpp_chirp_next,
+                                                  wpa_s, NULL) < 0) {
+                               wpas_dpp_chirp_stop(wpa_s);
+                               return;
+                       }
+                       if (wpa_s->dpp_chirp_listen) {
+                               wpa_printf(MSG_DEBUG,
+                                          "DPP: Listen on %d MHz during chirp 30 second wait",
+                                       wpa_s->dpp_chirp_listen);
+                               wpas_dpp_listen_start(wpa_s,
+                                                     wpa_s->dpp_chirp_listen);
+                       } else {
+                               wpa_printf(MSG_DEBUG,
+                                          "DPP: Wait 30 seconds before starting the next chirping round");
+                       }
+                       return;
+               }
+       }
+
+       wpas_dpp_chirp_start(wpa_s);
+}
+
+
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd)
+{
+       const char *pos;
+       int iter = 1, listen_freq = 0;
+       struct dpp_bootstrap_info *bi;
+
+       pos = os_strstr(cmd, " own=");
+       if (!pos)
+               return -1;
+       pos += 5;
+       bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos));
+       if (!bi) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Identified bootstrap info not found");
+               return -1;
+       }
+
+       pos = os_strstr(cmd, " iter=");
+       if (pos) {
+               iter = atoi(pos + 6);
+               if (iter <= 0)
+                       return -1;
+       }
+
+       pos = os_strstr(cmd, " listen=");
+       if (pos) {
+               listen_freq = atoi(pos + 8);
+               if (iter <= 0)
+                       return -1;
+       }
+
+       wpas_dpp_chirp_stop(wpa_s);
+       wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+       wpa_s->dpp_chirp_bi = bi;
+       wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi);
+       if (!wpa_s->dpp_presence_announcement)
+               return -1;
+       wpa_s->dpp_chirp_iter = iter;
+       wpa_s->dpp_chirp_round = 0;
+       wpa_s->dpp_chirp_scan_done = 0;
+       wpa_s->dpp_chirp_listen = listen_freq;
+
+       return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL);
+}
+
+
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->dpp_presence_announcement) {
+               offchannel_send_action_done(wpa_s);
+               wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED);
+       }
+       wpa_s->dpp_chirp_bi = NULL;
+       wpabuf_free(wpa_s->dpp_presence_announcement);
+       wpa_s->dpp_presence_announcement = NULL;
+       if (wpa_s->dpp_chirp_listen)
+               wpas_dpp_listen_stop(wpa_s);
+       wpa_s->dpp_chirp_listen = 0;
+       wpa_s->dpp_chirp_freq = 0;
+       os_free(wpa_s->dpp_chirp_freqs);
+       wpa_s->dpp_chirp_freqs = NULL;
+       eloop_cancel_timeout(wpas_dpp_chirp_next, wpa_s, NULL);
+       eloop_cancel_timeout(wpas_dpp_chirp_timeout, wpa_s, NULL);
+       if (wpa_s->scan_res_handler == wpas_dpp_chirp_scan_res_handler) {
+               wpas_abort_ongoing_scan(wpa_s);
+               wpa_s->scan_res_handler = NULL;
+       }
+}
+
 #endif /* CONFIG_DPP2 */
index 5c3397a241048dbf022b6b1c05bb1216789ed38e..2ce378dc18f3d72d5b79f99dd46d9d1811360af7 100644 (file)
@@ -35,5 +35,7 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd);
 void wpas_dpp_connected(struct wpa_supplicant *wpa_s);
 void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s,
                                      enum dpp_status_error result);
+int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd);
+void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s);
 
 #endif /* DPP_SUPPLICANT_H */
index 775bce89e6d1a1b1acf96dfee61a920833289cf4..b71e335831e58642116e0647ee2599ba41b396b4 100644 (file)
@@ -1273,6 +1273,14 @@ struct wpa_supplicant {
        size_t dpp_last_ssid_len;
 #ifdef CONFIG_DPP2
        struct dpp_pfs *dpp_pfs;
+       struct wpabuf *dpp_presence_announcement;
+       struct dpp_bootstrap_info *dpp_chirp_bi;
+       int dpp_chirp_freq;
+       int *dpp_chirp_freqs;
+       int dpp_chirp_iter;
+       int dpp_chirp_round;
+       int dpp_chirp_scan_done;
+       int dpp_chirp_listen;
 #endif /* CONFIG_DPP2 */
 #ifdef CONFIG_TESTING_OPTIONS
        char *dpp_config_obj_override;