From 98e4b38403c8ae957359eaf98f065f463f50a683 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 13 May 2020 17:11:40 +0300 Subject: [PATCH] DPP2: Chirping in hostapd Enrollee Add a new hostapd control interface command "DPP_CHIRP own= iter=" to request chirping, i.e., sending of Presence Announcement frames, to be started. This follows the model of similar wpa_supplicant functionality from commit 562f77144cd2 ("DPP2: Chirping in wpa_supplicant Enrollee"). The hostapd case requires the AP to be started without beaconing, i.e., with start_disabled=1 in hostapd configuration, to allow iteration of channels needed for chirping. Signed-off-by: Jouni Malinen --- hostapd/ctrl_iface.c | 7 + hostapd/main.c | 4 + src/ap/dpp_hostapd.c | 322 +++++++++++++++++++++++++++++++++++++++++++ src/ap/dpp_hostapd.h | 6 + src/ap/hostapd.h | 10 ++ 5 files changed, 349 insertions(+) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 87f2cb17e..ed5100fbf 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -3708,6 +3708,13 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) { if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0) reply_len = -1; +#ifdef CONFIG_DPP2 + } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) { + if (hostapd_dpp_chirp(hapd, buf + 9) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) { + hostapd_dpp_chirp_stop(hapd); +#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ #ifdef RADIUS_SERVER } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) { diff --git a/hostapd/main.c b/hostapd/main.c index 09261d6be..353b20a80 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -674,7 +674,11 @@ int main(int argc, char *argv[]) #endif /* CONFIG_ETH_P_OUI */ #ifdef CONFIG_DPP os_memset(&dpp_conf, 0, sizeof(dpp_conf)); + dpp_conf.cb_ctx = &interfaces; /* TODO: dpp_conf.msg_ctx? */ +#ifdef CONFIG_DPP2 + dpp_conf.remove_bi = hostapd_dpp_remove_bi; +#endif /* CONFIG_DPP2 */ interfaces.dpp = dpp_global_init(&dpp_conf); if (!interfaces.dpp) return -1; diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 548e8856e..178fd126e 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -630,6 +630,10 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR, MAC2STR(src)); +#ifdef CONFIG_DPP2 + hostapd_dpp_chirp_stop(hapd); +#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) { @@ -2139,6 +2143,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) NULL); eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd, NULL); + hostapd_dpp_chirp_stop(hapd); #endif /* CONFIG_DPP2 */ dpp_auth_deinit(hapd->dpp_auth); hapd->dpp_auth = NULL; @@ -2147,3 +2152,320 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) os_free(hapd->dpp_configurator_params); hapd->dpp_configurator_params = NULL; } + + +#ifdef CONFIG_DPP2 + +static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx); + +static void hostapd_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + + wpa_printf(MSG_DEBUG, "DPP: No chirp response received"); + hostapd_drv_send_action_cancel_wait(hapd); + hostapd_dpp_chirp_next(hapd, NULL); +} + + +static void hostapd_dpp_chirp_start(struct hostapd_data *hapd) +{ + struct wpabuf *msg; + int type; + + msg = hapd->dpp_presence_announcement; + type = DPP_PA_PRESENCE_ANNOUNCEMENT; + wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", hapd->dpp_chirp_freq); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", + MAC2STR(broadcast), hapd->dpp_chirp_freq, type); + if (hostapd_drv_send_action( + hapd, hapd->dpp_chirp_freq, 2000, broadcast, + wpabuf_head(msg), wpabuf_len(msg)) < 0 || + eloop_register_timeout(2, 0, hostapd_dpp_chirp_timeout, + hapd, NULL) < 0) + hostapd_dpp_chirp_stop(hapd); +} + + +static struct hostapd_hw_modes * +dpp_get_mode(struct hostapd_data *hapd, + enum hostapd_hw_mode mode) +{ + struct hostapd_hw_modes *modes = hapd->iface->hw_features; + u16 num_modes = hapd->iface->num_hw_features; + u16 i; + + for (i = 0; i < num_modes; i++) { + if (modes[i].mode != mode || + !modes[i].num_channels || !modes[i].channels) + continue; + return &modes[i]; + } + + return NULL; +} + + +static void +hostapd_dpp_chirp_scan_res_handler(struct hostapd_iface *iface) +{ + struct hostapd_data *hapd = iface->bss[0]; + struct wpa_scan_results *scan_res; + struct dpp_bootstrap_info *bi = hapd->dpp_chirp_bi; + unsigned int i; + struct hostapd_hw_modes *mode; + int c; + + if (!bi) + return; + + hapd->dpp_chirp_scan_done = 1; + + scan_res = hostapd_driver_get_scan_results(hapd); + + os_free(hapd->dpp_chirp_freqs); + hapd->dpp_chirp_freqs = NULL; + + /* Channels from own bootstrapping info */ + if (bi) { + for (i = 0; i < bi->num_freq; i++) + int_array_add_unique(&hapd->dpp_chirp_freqs, + bi->freq[i]); + } + + /* Preferred chirping channels */ + int_array_add_unique(&hapd->dpp_chirp_freqs, 2437); + + mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211A); + 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(&hapd->dpp_chirp_freqs, 5745); + else if (chan44) + int_array_add_unique(&hapd->dpp_chirp_freqs, 5220); + } + + mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211AD); + 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(&hapd->dpp_chirp_freqs, 60480); + break; + } + } + + /* Add channels from scan results for APs that advertise Configurator + * Connectivity element */ + for (i = 0; scan_res && i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + size_t ie_len = bss->ie_len; + + if (!ie_len) + ie_len = bss->beacon_ie_len; + if (get_vendor_ie((const u8 *) (bss + 1), ie_len, + DPP_CC_IE_VENDOR_TYPE)) + int_array_add_unique(&hapd->dpp_chirp_freqs, + bss->freq); + } + + if (!hapd->dpp_chirp_freqs || + eloop_register_timeout(0, 0, hostapd_dpp_chirp_next, + hapd, NULL) < 0) + hostapd_dpp_chirp_stop(hapd); + + wpa_scan_results_free(scan_res); +} + + +static void hostapd_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + int i; + + if (hapd->dpp_chirp_listen) + hostapd_dpp_listen_stop(hapd); + + if (hapd->dpp_chirp_freq == 0) { + if (hapd->dpp_chirp_round % 4 == 0 && + !hapd->dpp_chirp_scan_done) { + struct wpa_driver_scan_params params; + int ret; + + wpa_printf(MSG_DEBUG, + "DPP: Update channel list for chirping"); + os_memset(¶ms, 0, sizeof(params)); + ret = hostapd_driver_scan(hapd, ¶ms); + if (ret < 0) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to request a scan ret=%d (%s)", + ret, strerror(-ret)); + hostapd_dpp_chirp_scan_res_handler(hapd->iface); + } else { + hapd->iface->scan_cb = + hostapd_dpp_chirp_scan_res_handler; + } + return; + } + hapd->dpp_chirp_freq = hapd->dpp_chirp_freqs[0]; + hapd->dpp_chirp_round++; + wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d", + hapd->dpp_chirp_round); + } else { + for (i = 0; hapd->dpp_chirp_freqs[i]; i++) + if (hapd->dpp_chirp_freqs[i] == hapd->dpp_chirp_freq) + break; + if (!hapd->dpp_chirp_freqs[i]) { + wpa_printf(MSG_DEBUG, + "DPP: Previous chirp freq %d not found", + hapd->dpp_chirp_freq); + return; + } + i++; + if (hapd->dpp_chirp_freqs[i]) { + hapd->dpp_chirp_freq = hapd->dpp_chirp_freqs[i]; + } else { + hapd->dpp_chirp_iter--; + if (hapd->dpp_chirp_iter <= 0) { + wpa_printf(MSG_DEBUG, + "DPP: Chirping iterations completed"); + hostapd_dpp_chirp_stop(hapd); + return; + } + hapd->dpp_chirp_freq = 0; + hapd->dpp_chirp_scan_done = 0; + if (eloop_register_timeout(30, 0, + hostapd_dpp_chirp_next, + hapd, NULL) < 0) { + hostapd_dpp_chirp_stop(hapd); + return; + } + if (hapd->dpp_chirp_listen) { + wpa_printf(MSG_DEBUG, + "DPP: Listen on %d MHz during chirp 30 second wait", + hapd->dpp_chirp_listen); + /* TODO: start listen on the channel */ + } else { + wpa_printf(MSG_DEBUG, + "DPP: Wait 30 seconds before starting the next chirping round"); + } + return; + } + } + + hostapd_dpp_chirp_start(hapd); +} + + +int hostapd_dpp_chirp(struct hostapd_data *hapd, 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(hapd->iface->interfaces->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 (listen_freq <= 0) + return -1; + } + + hostapd_dpp_chirp_stop(hapd); + hapd->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; + hapd->dpp_qr_mutual = 0; + hapd->dpp_chirp_bi = bi; + hapd->dpp_presence_announcement = dpp_build_presence_announcement(bi); + if (!hapd->dpp_presence_announcement) + return -1; + hapd->dpp_chirp_iter = iter; + hapd->dpp_chirp_round = 0; + hapd->dpp_chirp_scan_done = 0; + hapd->dpp_chirp_listen = listen_freq; + + return eloop_register_timeout(0, 0, hostapd_dpp_chirp_next, hapd, NULL); +} + + +void hostapd_dpp_chirp_stop(struct hostapd_data *hapd) +{ + if (hapd->dpp_presence_announcement) { + hostapd_drv_send_action_cancel_wait(hapd); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CHIRP_STOPPED); + } + hapd->dpp_chirp_bi = NULL; + wpabuf_free(hapd->dpp_presence_announcement); + hapd->dpp_presence_announcement = NULL; + if (hapd->dpp_chirp_listen) + hostapd_dpp_listen_stop(hapd); + hapd->dpp_chirp_listen = 0; + hapd->dpp_chirp_freq = 0; + os_free(hapd->dpp_chirp_freqs); + hapd->dpp_chirp_freqs = NULL; + eloop_cancel_timeout(hostapd_dpp_chirp_next, hapd, NULL); + eloop_cancel_timeout(hostapd_dpp_chirp_timeout, hapd, NULL); + if (hapd->iface->scan_cb == hostapd_dpp_chirp_scan_res_handler) { + /* TODO: abort ongoing scan */ + hapd->iface->scan_cb = NULL; + } +} + + +static int handle_dpp_remove_bi(struct hostapd_iface *iface, void *ctx) +{ + struct dpp_bootstrap_info *bi = ctx; + size_t i; + + for (i = 0; i < iface->num_bss; i++) { + struct hostapd_data *hapd = iface->bss[i]; + + if (bi == hapd->dpp_chirp_bi) + hostapd_dpp_chirp_stop(hapd); + } + + return 0; +} + + +void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi) +{ + struct hapd_interfaces *interfaces = ctx; + + hostapd_for_each_interface(interfaces, handle_dpp_remove_bi, bi); +} + +#endif /* CONFIG_DPP2 */ diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h index b1fa99ed0..7e74185ca 100644 --- a/src/ap/dpp_hostapd.h +++ b/src/ap/dpp_hostapd.h @@ -10,6 +10,8 @@ #ifndef DPP_HOSTAPD_H #define DPP_HOSTAPD_H +struct dpp_bootstrap_info; + int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd); @@ -39,4 +41,8 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd); void hostapd_dpp_init_global(struct hapd_interfaces *ifaces); void hostapd_dpp_deinit_global(struct hapd_interfaces *ifaces); +int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd); +void hostapd_dpp_chirp_stop(struct hostapd_data *hapd); +void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi); + #endif /* DPP_HOSTAPD_H */ diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index fff15f118..597bbb432 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -386,6 +386,16 @@ struct hostapd_data { unsigned int dpp_resp_wait_time; unsigned int dpp_resp_max_tries; unsigned int dpp_resp_retry_time; +#ifdef CONFIG_DPP2 + 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; char *dpp_discovery_override;