From 661e661186af8891df801b53af24b25f21bd7319 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 30 May 2020 00:04:53 +0300 Subject: [PATCH] OCV: Allow OCI channel to be overridden for testing (AP) Add hostapd configuration parameters oci_freq_override_* to allow the OCI channel information to be overridden for various frames for testing purposes. This can be set in the configuration and also updated during the runtime of a BSS. Signed-off-by: Jouni Malinen --- hostapd/config_file.c | 14 +++++++++ hostapd/ctrl_iface.c | 16 +++++++++++ src/ap/ap_config.h | 7 +++++ src/ap/ieee802_11_shared.c | 20 +++++++++++++ src/ap/wnm_ap.c | 9 ++++++ src/ap/wpa_auth.c | 58 +++++++++++++++++++++++++++++++++----- src/ap/wpa_auth.h | 14 +++++++++ src/ap/wpa_auth_ft.c | 9 ++++++ src/ap/wpa_auth_glue.c | 5 ++++ 9 files changed, 145 insertions(+), 7 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index cc1855dcd..bc650e949 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4217,6 +4217,20 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->skip_prune_assoc = atoi(pos); } else if (os_strcmp(buf, "ft_rsnxe_used") == 0) { bss->ft_rsnxe_used = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_eapol_m3") == 0) { + bss->oci_freq_override_eapol_m3 = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_eapol_g1") == 0) { + bss->oci_freq_override_eapol_g1 = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_saquery_req") == 0) { + bss->oci_freq_override_saquery_req = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_saquery_resp") == 0) { + bss->oci_freq_override_saquery_resp = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_ft_assoc") == 0) { + bss->oci_freq_override_ft_assoc = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_fils_assoc") == 0) { + bss->oci_freq_override_fils_assoc = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_wnm_sleep") == 0) { + bss->oci_freq_override_wnm_sleep = atoi(pos); #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_SAE } else if (os_strcmp(buf, "sae_password") == 0) { diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index edc69f470..8a79ef783 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1484,6 +1484,22 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) if (os_strcmp(cmd, "ft_rsnxe_used") == 0) wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth, hapd->conf->ft_rsnxe_used); + else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0) + wpa_auth_set_ocv_override_freq( + hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3, + atoi(value)); + else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0) + wpa_auth_set_ocv_override_freq( + hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1, + atoi(value)); + else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0) + wpa_auth_set_ocv_override_freq( + hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC, + atoi(value)); + else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0) + wpa_auth_set_ocv_override_freq( + hapd->wpa_auth, + WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value)); #endif /* CONFIG_TESTING_OPTIONS */ } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index cffa636cc..c1b4b1bbb 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -687,6 +687,13 @@ struct hostapd_bss_config { int no_beacon_rsnxe; int skip_prune_assoc; int ft_rsnxe_used; + unsigned int oci_freq_override_eapol_m3; + unsigned int oci_freq_override_eapol_g1; + unsigned int oci_freq_override_saquery_req; + unsigned int oci_freq_override_saquery_resp; + unsigned int oci_freq_override_ft_assoc; + unsigned int oci_freq_override_fils_assoc; + unsigned int oci_freq_override_wnm_sleep; #endif /* CONFIG_TESTING_OPTIONS */ #define MESH_ENABLED BIT(0) diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c index 45a07085f..45683d76e 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -73,6 +73,16 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, "Failed to get channel info for OCI element in SA Query Request"); return; } +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->conf->oci_freq_override_saquery_req) { + wpa_printf(MSG_INFO, + "TEST: Override OCI frequency %d -> %u MHz", + ci.frequency, + hapd->conf->oci_freq_override_saquery_req); + ci.frequency = + hapd->conf->oci_freq_override_saquery_req; + } +#endif /* CONFIG_TESTING_OPTIONS */ oci_ie_len = OCV_OCI_EXTENDED_LEN; oci_ie = os_zalloc(oci_ie_len); @@ -152,6 +162,16 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd, "Failed to get channel info for OCI element in SA Query Response"); return; } +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->conf->oci_freq_override_saquery_resp) { + wpa_printf(MSG_INFO, + "TEST: Override OCI frequency %d -> %u MHz", + ci.frequency, + hapd->conf->oci_freq_override_saquery_resp); + ci.frequency = + hapd->conf->oci_freq_override_saquery_resp; + } +#endif /* CONFIG_TESTING_OPTIONS */ oci_ie_len = OCV_OCI_EXTENDED_LEN; oci_ie = os_zalloc(oci_ie_len); diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index 4a7da9513..248f5a1cf 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -103,6 +103,15 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, os_free(wnmtfs_ie); return -1; } +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->conf->oci_freq_override_wnm_sleep) { + wpa_printf(MSG_INFO, + "TEST: Override OCI frequency %d -> %u MHz", + ci.frequency, + hapd->conf->oci_freq_override_wnm_sleep); + ci.frequency = hapd->conf->oci_freq_override_wnm_sleep; + } +#endif /* CONFIG_TESTING_OPTIONS */ oci_ie_len = OCV_OCI_EXTENDED_LEN; oci_ie = os_zalloc(oci_ie_len); diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 50b42646e..0efa28797 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2772,6 +2772,15 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm, wpabuf_clear_free(plain); return NULL; } +#ifdef CONFIG_TESTING_OPTIONS + if (conf->oci_freq_override_fils_assoc) { + wpa_printf(MSG_INFO, + "TEST: Override OCI frequency %d -> %u MHz", + ci.frequency, + conf->oci_freq_override_fils_assoc); + ci.frequency = conf->oci_freq_override_fils_assoc; + } +#endif /* CONFIG_TESTING_OPTIONS */ pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN); if (ocv_insert_extended_oci(&ci, pos) < 0) { @@ -3237,7 +3246,9 @@ static int ocv_oci_len(struct wpa_state_machine *sm) return 0; } -static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos) + +static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos, + unsigned int freq) { #ifdef CONFIG_OCV struct wpa_channel_info ci; @@ -3250,6 +3261,14 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos) "Failed to get channel info for OCI element"); return -1; } +#ifdef CONFIG_TESTING_OPTIONS + if (freq) { + wpa_printf(MSG_INFO, + "TEST: Override OCI KDE frequency %d -> %u MHz", + ci.frequency, freq); + ci.frequency = freq; + } +#endif /* CONFIG_TESTING_OPTIONS */ return ocv_insert_oci_kde(&ci, argpos); #else /* CONFIG_OCV */ @@ -3466,7 +3485,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) gtk, gtk_len); } pos = ieee80211w_kde_add(sm, pos); - if (ocv_oci_add(sm, &pos) < 0) + if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0) goto done; #ifdef CONFIG_IEEE80211R_AP @@ -3816,7 +3835,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gsm->GTK_len); pos = ieee80211w_kde_add(sm, pos); - if (ocv_oci_add(sm, &pos) < 0) { + if (ocv_oci_add(sm, &pos, + conf->oci_freq_override_eapol_g1) < 0) { os_free(kde_buf); return; } @@ -5299,6 +5319,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos; u8 *opos; size_t gtk_len, kde_len; + struct wpa_auth_config *conf = &sm->wpa_auth->conf; struct wpa_group *gsm = sm->group; u8 *wpa_ie; int wpa_ie_len, secure, gtkidx, encr = 0; @@ -5409,7 +5430,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, opos += 2 + RSN_SELECTOR_LEN + 2; os_memset(opos, 0, 6); /* clear PN */ } - if (ocv_oci_add(sm, &pos) < 0) { + if (ocv_oci_add(sm, &pos, conf->oci_freq_override_eapol_m3) < 0) { os_free(kde); return -1; } @@ -5417,9 +5438,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, #ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { int res; - struct wpa_auth_config *conf; - conf = &sm->wpa_auth->conf; if (sm->assoc_resp_ftie && kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) { os_memcpy(pos, sm->assoc_resp_ftie, @@ -5476,6 +5495,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, void *ctx1, void *ctx2) { u8 rsc[WPA_KEY_RSC_LEN]; + struct wpa_auth_config *conf = &sm->wpa_auth->conf; struct wpa_group *gsm = sm->group; const u8 *kde; u8 *kde_buf = NULL, *pos, hdr[2]; @@ -5510,7 +5530,8 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, opos += 2 + RSN_SELECTOR_LEN + 2; os_memset(opos, 0, 6); /* clear PN */ } - if (ocv_oci_add(sm, &pos) < 0) { + if (ocv_oci_add(sm, &pos, + conf->oci_freq_override_eapol_g1) < 0) { os_free(kde_buf); return -1; } @@ -5552,4 +5573,27 @@ void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val) wpa_auth->conf.ft_rsnxe_used = val; } + +void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth, + enum wpa_auth_ocv_override_frame frame, + unsigned int freq) +{ + if (!wpa_auth) + return; + switch (frame) { + case WPA_AUTH_OCV_OVERRIDE_EAPOL_M3: + wpa_auth->conf.oci_freq_override_eapol_m3 = freq; + break; + case WPA_AUTH_OCV_OVERRIDE_EAPOL_G1: + wpa_auth->conf.oci_freq_override_eapol_g1 = freq; + break; + case WPA_AUTH_OCV_OVERRIDE_FT_ASSOC: + wpa_auth->conf.oci_freq_override_ft_assoc = freq; + break; + case WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC: + wpa_auth->conf.oci_freq_override_fils_assoc = freq; + break; + } +} + #endif /* CONFIG_TESTING_OPTIONS */ diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 90b188599..e059f3db3 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -241,6 +241,10 @@ struct wpa_auth_config { unsigned int igtk_rsc_override_set:1; int ft_rsnxe_used; #endif /* CONFIG_TESTING_OPTIONS */ + unsigned int oci_freq_override_eapol_m3; + unsigned int oci_freq_override_eapol_g1; + unsigned int oci_freq_override_ft_assoc; + unsigned int oci_freq_override_fils_assoc; #ifdef CONFIG_P2P u8 ip_addr_go[4]; u8 ip_addr_mask[4]; @@ -526,4 +530,14 @@ int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth); void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm); void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val); +enum wpa_auth_ocv_override_frame { + WPA_AUTH_OCV_OVERRIDE_EAPOL_M3, + WPA_AUTH_OCV_OVERRIDE_EAPOL_G1, + WPA_AUTH_OCV_OVERRIDE_FT_ASSOC, + WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, +}; +void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth, + enum wpa_auth_ocv_override_frame frame, + unsigned int freq); + #endif /* WPA_AUTH_H */ diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 570e2ee4a..db272d41e 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -2661,6 +2661,15 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, os_free(subelem); return NULL; } +#ifdef CONFIG_TESTING_OPTIONS + if (conf->oci_freq_override_ft_assoc) { + wpa_printf(MSG_INFO, + "TEST: Override OCI frequency %d -> %u MHz", + ci.frequency, + conf->oci_freq_override_ft_assoc); + ci.frequency = conf->oci_freq_override_ft_assoc; + } +#endif /* CONFIG_TESTING_OPTIONS */ subelem_len += 2 + OCV_OCI_LEN; nbuf = os_realloc(subelem, subelem_len); diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index e1da56da9..b90c9ef61 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -175,6 +175,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->igtk_rsc_override_set = 1; } wconf->ft_rsnxe_used = conf->ft_rsnxe_used; + wconf->oci_freq_override_eapol_m3 = conf->oci_freq_override_eapol_m3; + wconf->oci_freq_override_eapol_g1 = conf->oci_freq_override_eapol_g1; + wconf->oci_freq_override_ft_assoc = conf->oci_freq_override_ft_assoc; + wconf->oci_freq_override_fils_assoc = + conf->oci_freq_override_fils_assoc; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_P2P os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);