From 562f77144cd2f4f44969c844b3bf035530351d16 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 27 Mar 2020 12:42:00 +0200 Subject: [PATCH] DPP2: Chirping in wpa_supplicant Enrollee Add a new wpa_supplicant control interface command "DPP_CHIRP own= iter=" to request chirping, i.e., sending of Presence Announcement frames, to be started. Signed-off-by: Jouni Malinen --- src/common/dpp.c | 6 + src/common/dpp.h | 1 + src/common/wpa_ctrl.h | 1 + wpa_supplicant/ctrl_iface.c | 8 + wpa_supplicant/dpp_supplicant.c | 281 ++++++++++++++++++++++++++++++ wpa_supplicant/dpp_supplicant.h | 2 + wpa_supplicant/wpa_supplicant_i.h | 8 + 7 files changed, 307 insertions(+) diff --git a/src/common/dpp.c b/src/common/dpp.c index ea5d6df57..56abe507f 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -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); diff --git a/src/common/dpp.h b/src/common/dpp.h index d544fba66..513918bb5 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -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); diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 7471f0d15..0b0413068 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -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 " diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index ebcb60e5a..a2b4ee765 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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 { diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 89d86ca02..c6d555662 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -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 */ diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h index 5c3397a24..2ce378dc1 100644 --- a/wpa_supplicant/dpp_supplicant.h +++ b/wpa_supplicant/dpp_supplicant.h @@ -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 */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 775bce89e..b71e33583 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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;