DPP2: Chirping in hostapd Enrollee

Add a new hostapd control interface command "DPP_CHIRP own=<BI ID>
iter=<count>" to request chirping, i.e., sending of Presence
Announcement frames, to be started. This follows the model of similar
wpa_supplicant functionality from commit 562f77144c ("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 <jouni@codeaurora.org>
This commit is contained in:
Jouni Malinen 2020-05-13 17:11:40 +03:00 committed by Jouni Malinen
parent 95471fc3e8
commit 98e4b38403
5 changed files with 349 additions and 0 deletions

View file

@ -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) {

View file

@ -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;

View file

@ -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(&params, 0, sizeof(params));
ret = hostapd_driver_scan(hapd, &params);
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 */

View file

@ -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 */

View file

@ -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;