Merge Android 13 QPR1
Bug: 261731544
Merged-In: Ibb8fe0afa3013bce9a313b24b9788b08a9bc1c10
Change-Id: Ib892a540be0eb2c6536fa63ad20a7806dde774a9
diff --git a/Android.mk b/Android.mk
index bd7a409..bb8326c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,10 +1,15 @@
-LOCAL_PATH:= $(call my-dir)
+S_LOCAL_PATH := $(call my-dir)
ifneq ($(filter VER_0_8_X VER_2_1_DEVEL,$(WPA_SUPPLICANT_VERSION)),)
# The order of the 2 Android.mks does matter!
# TODO: Clean up the Android.mks, reset all the temporary variables at the
# end of each Android.mk, so that one Android.mk doesn't depend on variables
# set up in the other Android.mk.
-include $(LOCAL_PATH)/hostapd/Android.mk \
- $(LOCAL_PATH)/wpa_supplicant/Android.mk
+include $(S_LOCAL_PATH)/hostapd/Android.mk \
+ $(S_LOCAL_PATH)/wpa_supplicant/Android.mk
+ifneq ($(TARGET_BUILD_VARIANT), user)
+ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
+include $(S_LOCAL_PATH)/hs20/client/Android.mk
+endif #End of Check for platform version
+endif #End of Check for target build variant
endif
diff --git a/hostapd/Android.bp b/hostapd/Android.bp
index 2cc2f91..020396d 100644
--- a/hostapd/Android.bp
+++ b/hostapd/Android.bp
@@ -316,7 +316,6 @@
"src/crypto/fips_prf_openssl.c",
"src/crypto/aes-siv.c",
"src/crypto/aes-ctr.c",
- "src/crypto/aes-omac1.c",
"src/crypto/sha1-prf.c",
"src/crypto/sha1-tlsprf.c",
"src/crypto/sha256-prf.c",
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 4c37b77..adb4c08 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -314,6 +314,12 @@
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BE
+CONFIG_IEEE80211AX=y
+L_CFLAGS += -DCONFIG_IEEE80211BE
+OBJS += src/ap/ieee802_11_eht.c
+endif
+
ifdef CONFIG_IEEE80211AX
L_CFLAGS += -DCONFIG_IEEE80211AX
endif
@@ -673,6 +679,7 @@
endif
ifeq ($(CONFIG_TLS), openssl)
+L_CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
ifdef TLS_FUNCS
OBJS += src/crypto/tls_openssl.c
OBJS += src/crypto/tls_openssl_ocsp.c
@@ -845,7 +852,9 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += src/crypto/aes-encblock.c
endif
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += src/crypto/aes-omac1.c
+endif
ifdef NEED_AES_UNWRAP
ifneq ($(CONFIG_TLS), openssl)
NEED_AES_DEC=y
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 98a0102..5f06378 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -343,6 +343,12 @@
CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BE
+CONFIG_IEEE80211AX=y
+CFLAGS += -DCONFIG_IEEE80211BE
+OBJS += ../src/ap/ieee802_11_eht.o
+endif
+
ifdef CONFIG_IEEE80211AX
CFLAGS += -DCONFIG_IEEE80211AX
OBJS += ../src/ap/ieee802_11_he.o
@@ -712,6 +718,7 @@
endif
ifeq ($(CONFIG_TLS), openssl)
+CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
CONFIG_CRYPTO=openssl
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_openssl.o
@@ -936,11 +943,13 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += ../src/crypto/aes-encblock.o
endif
+ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-omac1.o
endif
endif
+endif
ifdef NEED_AES_UNWRAP
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
diff --git a/hostapd/android.config b/hostapd/android.config
index 6ed6f6a..eaeda89 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -28,6 +28,9 @@
# Broadcom vendor extensions to nl80211
ifeq ($(BOARD_WLAN_DEVICE),bcmdhd)
CONFIG_DRIVER_NL80211_BRCM=y
+# Synaptics vendor extensions to nl80211
+else ifeq ($(BOARD_WLAN_DEVICE),synadhd)
+CONFIG_DRIVER_NL80211_SYNA=y
else
# QCA vendor extensions to nl80211
CONFIG_DRIVER_NL80211_QCA=y
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 7e605ff..2d5a510 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -118,52 +118,6 @@
#endif /* CONFIG_NO_VLAN */
-int hostapd_acl_comp(const void *a, const void *b)
-{
- const struct mac_acl_entry *aa = a;
- const struct mac_acl_entry *bb = b;
- return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
-}
-
-
-int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
- int vlan_id, const u8 *addr)
-{
- struct mac_acl_entry *newacl;
-
- newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
- if (!newacl) {
- wpa_printf(MSG_ERROR, "MAC list reallocation failed");
- return -1;
- }
-
- *acl = newacl;
- os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
- os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
- (*acl)[*num].vlan_id.untagged = vlan_id;
- (*acl)[*num].vlan_id.notempty = !!vlan_id;
- (*num)++;
-
- return 0;
-}
-
-
-void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
- const u8 *addr)
-{
- int i = 0;
-
- while (i < *num) {
- if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) {
- os_remove_in_array(*acl, *num, sizeof(**acl), i);
- (*num)--;
- } else {
- i++;
- }
- }
-}
-
-
static int hostapd_config_read_maclist(const char *fname,
struct mac_acl_entry **acl, int *num)
{
@@ -2635,6 +2589,9 @@
bss->eap_sim_aka_result_ind = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_id") == 0) {
bss->eap_sim_id = atoi(pos);
+ } else if (os_strcmp(buf, "imsi_privacy_key") == 0) {
+ os_free(bss->imsi_privacy_key);
+ bss->imsi_privacy_key = os_strdup(pos);
#endif /* EAP_SERVER_SIM */
#ifdef EAP_SERVER_TNC
} else if (os_strcmp(buf, "tnc") == 0) {
@@ -2975,7 +2932,8 @@
bss->wpa_psk_radius = atoi(pos);
if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
- bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
+ bss->wpa_psk_radius != PSK_RADIUS_REQUIRED &&
+ bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS) {
wpa_printf(MSG_ERROR,
"Line %d: unknown wpa_psk_radius %d",
line, bss->wpa_psk_radius);
@@ -3139,6 +3097,7 @@
line, pos);
return 1;
}
+ conf->hw_mode_set = true;
} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
if (os_strcmp(pos, "ad") == 0)
bss->wps_rf_bands = WPS_RF_60GHZ;
@@ -3193,6 +3152,8 @@
conf->acs_freq_list_present = 1;
} else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) {
conf->acs_exclude_6ghz_non_psc = atoi(pos);
+ } else if (os_strcmp(buf, "enable_background_radar") == 0) {
+ conf->enable_background_radar = atoi(pos);
} else if (os_strcmp(buf, "min_tx_power") == 0) {
int val = atoi(pos);
@@ -3642,6 +3603,8 @@
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "he_6ghz_reg_pwr_type") == 0) {
+ conf->he_6ghz_reg_pwr_type = atoi(pos);
} else if (os_strcmp(buf, "he_oper_chwidth") == 0) {
conf->he_oper_chwidth = atoi(pos);
} else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) {
@@ -4301,6 +4264,8 @@
conf->skip_send_eapol = atoi(pos);
} else if (os_strcmp(buf, "enable_eapol_large_timeout") == 0) {
conf->enable_eapol_large_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "eap_skip_prot_success") == 0) {
+ bss->eap_skip_prot_success = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_SAE
} else if (os_strcmp(buf, "sae_password") == 0) {
@@ -4665,6 +4630,16 @@
return 1;
}
bss->mka_priority = mka_priority;
+ } else if (os_strcmp(buf, "macsec_csindex") == 0) {
+ int macsec_csindex = atoi(pos);
+
+ if (macsec_csindex < 0 || macsec_csindex > 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid macsec_csindex (%d): '%s'.",
+ line, macsec_csindex, pos);
+ return 1;
+ }
+ bss->macsec_csindex = macsec_csindex;
} else if (os_strcmp(buf, "mka_cak") == 0) {
size_t len = os_strlen(pos);
@@ -4701,6 +4676,8 @@
bss->disable_11ac = !!atoi(pos);
} else if (os_strcmp(buf, "disable_11ax") == 0) {
bss->disable_11ax = !!atoi(pos);
+ } else if (os_strcmp(buf, "disable_11be") == 0) {
+ bss->disable_11be = !!atoi(pos);
#ifdef CONFIG_PASN
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcmp(buf, "force_kdk_derivation") == 0) {
@@ -4728,6 +4705,20 @@
return 1;
} else if (os_strcmp(buf, "rnr") == 0) {
bss->rnr = atoi(pos);
+#ifdef CONFIG_IEEE80211BE
+ } else if (os_strcmp(buf, "ieee80211be") == 0) {
+ conf->ieee80211be = atoi(pos);
+ } else if (os_strcmp(buf, "eht_oper_chwidth") == 0) {
+ conf->eht_oper_chwidth = atoi(pos);
+ } else if (os_strcmp(buf, "eht_oper_centr_freq_seg0_idx") == 0) {
+ conf->eht_oper_centr_freq_seg0_idx = atoi(pos);
+ } else if (os_strcmp(buf, "eht_su_beamformer") == 0) {
+ conf->eht_phy_capab.su_beamformer = atoi(pos);
+ } else if (os_strcmp(buf, "eht_su_beamformee") == 0) {
+ conf->eht_phy_capab.su_beamformee = atoi(pos);
+ } else if (os_strcmp(buf, "eht_mu_beamformer") == 0) {
+ conf->eht_phy_capab.mu_beamformer = atoi(pos);
+#endif /* CONFIG_IEEE80211BE */
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/hostapd/config_file.h b/hostapd/config_file.h
index 9830f5a..c98bdb6 100644
--- a/hostapd/config_file.h
+++ b/hostapd/config_file.h
@@ -13,10 +13,5 @@
int hostapd_set_iface(struct hostapd_config *conf,
struct hostapd_bss_config *bss, const char *field,
char *value);
-int hostapd_acl_comp(const void *a, const void *b);
-int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
- int vlan_id, const u8 *addr);
-void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
- const u8 *addr);
#endif /* CONFIG_FILE_H */
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index a62f3c7..ad994d4 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -772,235 +772,6 @@
#ifdef CONFIG_WNM_AP
-static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
- const char *cmd)
-{
- u8 addr[ETH_ALEN];
- int disassoc_timer;
- struct sta_info *sta;
-
- if (hwaddr_aton(cmd, addr))
- return -1;
- if (cmd[17] != ' ')
- return -1;
- disassoc_timer = atoi(cmd + 17);
-
- sta = ap_get_sta(hapd, addr);
- if (sta == NULL) {
- wpa_printf(MSG_DEBUG, "Station " MACSTR
- " not found for disassociation imminent message",
- MAC2STR(addr));
- return -1;
- }
-
- return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
-}
-
-
-static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
- const char *cmd)
-{
- u8 addr[ETH_ALEN];
- const char *url, *timerstr;
- int disassoc_timer;
- struct sta_info *sta;
-
- if (hwaddr_aton(cmd, addr))
- return -1;
-
- sta = ap_get_sta(hapd, addr);
- if (sta == NULL) {
- wpa_printf(MSG_DEBUG, "Station " MACSTR
- " not found for ESS disassociation imminent message",
- MAC2STR(addr));
- return -1;
- }
-
- timerstr = cmd + 17;
- if (*timerstr != ' ')
- return -1;
- timerstr++;
- disassoc_timer = atoi(timerstr);
- if (disassoc_timer < 0 || disassoc_timer > 65535)
- return -1;
-
- url = os_strchr(timerstr, ' ');
- if (url == NULL)
- return -1;
- url++;
-
- return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
-}
-
-
-static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
- const char *cmd)
-{
- u8 addr[ETH_ALEN];
- const char *pos, *end;
- int disassoc_timer = 0;
- struct sta_info *sta;
- u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
- u8 bss_term_dur[12];
- char *url = NULL;
- int ret;
- u8 nei_rep[1000];
- int nei_len;
- u8 mbo[10];
- size_t mbo_len = 0;
-
- if (hwaddr_aton(cmd, addr)) {
- wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
- return -1;
- }
-
- sta = ap_get_sta(hapd, addr);
- if (sta == NULL) {
- wpa_printf(MSG_DEBUG, "Station " MACSTR
- " not found for BSS TM Request message",
- MAC2STR(addr));
- return -1;
- }
-
- pos = os_strstr(cmd, " disassoc_timer=");
- if (pos) {
- pos += 16;
- disassoc_timer = atoi(pos);
- if (disassoc_timer < 0 || disassoc_timer > 65535) {
- wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
- return -1;
- }
- }
-
- pos = os_strstr(cmd, " valid_int=");
- if (pos) {
- pos += 11;
- valid_int = atoi(pos);
- }
-
- pos = os_strstr(cmd, " dialog_token=");
- if (pos) {
- pos += 14;
- dialog_token = atoi(pos);
- }
-
- pos = os_strstr(cmd, " bss_term=");
- if (pos) {
- pos += 10;
- req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
- /* TODO: TSF configurable/learnable */
- bss_term_dur[0] = 4; /* Subelement ID */
- bss_term_dur[1] = 10; /* Length */
- os_memset(&bss_term_dur[2], 0, 8);
- end = os_strchr(pos, ',');
- if (end == NULL) {
- wpa_printf(MSG_DEBUG, "Invalid bss_term data");
- return -1;
- }
- end++;
- WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
- }
-
- nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
- sizeof(nei_rep));
- if (nei_len < 0)
- return -1;
-
- pos = os_strstr(cmd, " url=");
- if (pos) {
- size_t len;
- pos += 5;
- end = os_strchr(pos, ' ');
- if (end)
- len = end - pos;
- else
- len = os_strlen(pos);
- url = os_malloc(len + 1);
- if (url == NULL)
- return -1;
- os_memcpy(url, pos, len);
- url[len] = '\0';
- req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
- }
-
- if (os_strstr(cmd, " pref=1"))
- req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
- if (os_strstr(cmd, " abridged=1"))
- req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
- if (os_strstr(cmd, " disassoc_imminent=1"))
- req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
-
-#ifdef CONFIG_MBO
- pos = os_strstr(cmd, "mbo=");
- if (pos) {
- unsigned int mbo_reason, cell_pref, reassoc_delay;
- u8 *mbo_pos = mbo;
-
- ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
- &reassoc_delay, &cell_pref);
- if (ret != 3) {
- wpa_printf(MSG_DEBUG,
- "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
- ret = -1;
- goto fail;
- }
-
- if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
- wpa_printf(MSG_DEBUG,
- "Invalid MBO transition reason code %u",
- mbo_reason);
- ret = -1;
- goto fail;
- }
-
- /* Valid values for Cellular preference are: 0, 1, 255 */
- if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
- wpa_printf(MSG_DEBUG,
- "Invalid MBO cellular capability %u",
- cell_pref);
- ret = -1;
- goto fail;
- }
-
- if (reassoc_delay > 65535 ||
- (reassoc_delay &&
- !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
- wpa_printf(MSG_DEBUG,
- "MBO: Assoc retry delay is only valid in disassoc imminent mode");
- ret = -1;
- goto fail;
- }
-
- *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
- *mbo_pos++ = 1;
- *mbo_pos++ = mbo_reason;
- *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
- *mbo_pos++ = 1;
- *mbo_pos++ = cell_pref;
-
- if (reassoc_delay) {
- *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
- *mbo_pos++ = 2;
- WPA_PUT_LE16(mbo_pos, reassoc_delay);
- mbo_pos += 2;
- }
-
- mbo_len = mbo_pos - mbo;
- }
-#endif /* CONFIG_MBO */
-
- ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
- valid_int, bss_term_dur, dialog_token, url,
- nei_len ? nei_rep : NULL, nei_len,
- mbo_len ? mbo : NULL, mbo_len);
-#ifdef CONFIG_MBO
-fail:
-#endif /* CONFIG_MBO */
- os_free(url);
- return ret;
-}
-
-
static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
const char *cmd)
{
@@ -1362,43 +1133,6 @@
}
-static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
-{
- struct sta_info *sta;
- struct vlan_description vlan_id;
-
- if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
- return;
-
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (!hostapd_maclist_found(hapd->conf->accept_mac,
- hapd->conf->num_accept_mac,
- sta->addr, &vlan_id) ||
- (vlan_id.notempty &&
- vlan_compare(&vlan_id, sta->vlan_desc)))
- ap_sta_disconnect(hapd, sta, sta->addr,
- WLAN_REASON_UNSPECIFIED);
- }
-}
-
-
-static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
-{
- struct sta_info *sta;
- struct vlan_description vlan_id;
-
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (hostapd_maclist_found(hapd->conf->deny_mac,
- hapd->conf->num_deny_mac, sta->addr,
- &vlan_id) &&
- (!vlan_id.notempty ||
- !vlan_compare(&vlan_id, sta->vlan_desc)))
- ap_sta_disconnect(hapd, sta, sta->addr,
- WLAN_REASON_UNSPECIFIED);
- }
-}
-
-
static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
const char *bands)
{
@@ -1519,6 +1253,9 @@
} else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
os_free(hapd->dpp_configurator_params);
hapd->dpp_configurator_params = os_strdup(value);
+#ifdef CONFIG_DPP2
+ dpp_controller_set_params(hapd->iface->interfaces->dpp, value);
+#endif /* CONFIG_DPP2 */
} else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
hapd->dpp_init_max_tries = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
@@ -2838,7 +2575,7 @@
for (i = 0; i < iface->num_bss; i++) {
- /* Save CHAN_SWITCH VHT and HE config */
+ /* Save CHAN_SWITCH VHT, HE, and EHT config */
hostapd_chan_switch_config(iface->bss[i],
&settings.freq_params);
@@ -3383,80 +3120,6 @@
}
-static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
- const char *txtaddr)
-{
- u8 addr[ETH_ALEN];
- struct vlan_description vlan_id;
-
- if (!(*num))
- return 0;
-
- if (hwaddr_aton(txtaddr, addr))
- return -1;
-
- if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
- hostapd_remove_acl_mac(acl, num, addr);
-
- return 0;
-}
-
-
-static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
- int *num)
-{
- while (*num)
- hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
-}
-
-
-static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
- char *buf, size_t buflen)
-{
- int i = 0, len = 0, ret = 0;
-
- if (!acl)
- return 0;
-
- while (i < num) {
- ret = os_snprintf(buf + len, buflen - len,
- MACSTR " VLAN_ID=%d\n",
- MAC2STR(acl[i].addr),
- acl[i].vlan_id.untagged);
- if (ret < 0 || (size_t) ret >= buflen - len)
- return len;
- i++;
- len += ret;
- }
- return len;
-}
-
-
-static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
- const char *cmd)
-{
- u8 addr[ETH_ALEN];
- struct vlan_description vlan_id;
- int ret = 0, vlanid = 0;
- const char *pos;
-
- if (hwaddr_aton(cmd, addr))
- return -1;
-
- pos = os_strstr(cmd, "VLAN_ID=");
- if (pos)
- vlanid = atoi(pos + 8);
-
- if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
- ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
- if (ret != -1 && *acl)
- qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
- }
-
- return ret < 0 ? -1 : 0;
-}
-
-
static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
const char *field, char *buf,
size_t buflen)
@@ -3832,14 +3495,15 @@
if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
if (hostapd_ctrl_iface_acl_add_mac(
&hapd->conf->accept_mac,
- &hapd->conf->num_accept_mac, buf + 19))
+ &hapd->conf->num_accept_mac, buf + 19) ||
+ hostapd_set_acl(hapd))
reply_len = -1;
} else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
- if (!hostapd_ctrl_iface_acl_del_mac(
+ if (hostapd_ctrl_iface_acl_del_mac(
&hapd->conf->accept_mac,
- &hapd->conf->num_accept_mac, buf + 19))
- hostapd_disassoc_accept_mac(hapd);
- else
+ &hapd->conf->num_accept_mac, buf + 19) ||
+ hostapd_set_acl(hapd) ||
+ hostapd_disassoc_accept_mac(hapd))
reply_len = -1;
} else if (os_strcmp(buf + 11, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
@@ -3849,20 +3513,23 @@
hostapd_ctrl_iface_acl_clear_list(
&hapd->conf->accept_mac,
&hapd->conf->num_accept_mac);
- hostapd_disassoc_accept_mac(hapd);
+ if (hostapd_set_acl(hapd) ||
+ hostapd_disassoc_accept_mac(hapd))
+ reply_len = -1;
}
} else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
- if (!hostapd_ctrl_iface_acl_add_mac(
+ if (hostapd_ctrl_iface_acl_add_mac(
&hapd->conf->deny_mac,
- &hapd->conf->num_deny_mac, buf + 17))
- hostapd_disassoc_deny_mac(hapd);
- else
+ &hapd->conf->num_deny_mac, buf + 17) ||
+ hostapd_set_acl(hapd) ||
+ hostapd_disassoc_deny_mac(hapd))
reply_len = -1;
} else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
if (hostapd_ctrl_iface_acl_del_mac(
&hapd->conf->deny_mac,
- &hapd->conf->num_deny_mac, buf + 17))
+ &hapd->conf->num_deny_mac, buf + 17) ||
+ hostapd_set_acl(hapd))
reply_len = -1;
} else if (os_strcmp(buf + 9, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
@@ -3872,6 +3539,8 @@
hostapd_ctrl_iface_acl_clear_list(
&hapd->conf->deny_mac,
&hapd->conf->num_deny_mac);
+ if (hostapd_set_acl(hapd))
+ reply_len = -1;
}
#ifdef CONFIG_DPP
} else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
@@ -3963,6 +3632,10 @@
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) {
+ if (dpp_configurator_set(hapd->iface->interfaces->dpp,
+ buf + 20) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
if (dpp_configurator_remove(hapd->iface->interfaces->dpp,
buf + 24) < 0)
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 2855acd..6a41dcf 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -156,10 +156,20 @@
#CONFIG_IEEE80211AC=y
# IEEE 802.11ax HE support
+#CONFIG_IEEE80211AX=y
+
+# IEEE 802.11be EHT support
+# CONFIG_IEEE80211AX is mandatory for setting CONFIG_IEEE80211BE.
# Note: This is experimental and work in progress. The definitions are still
# subject to change and this should not be expected to interoperate with the
-# final IEEE 802.11ax version.
-#CONFIG_IEEE80211AX=y
+# final IEEE 802.11be version.
+#CONFIG_IEEE80211BE=y
+
+# Simultaneous Authentication of Equals (SAE), WPA3-Personal
+#CONFIG_SAE=y
+
+# SAE Public Key, WPA3-Personal
+#CONFIG_SAE_PK=y
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 3c2019f..f37d563 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -225,6 +225,16 @@
# Default behavior is to include all PSC and non-PSC channels.
#acs_exclude_6ghz_non_psc=1
+# Enable background radar feature
+# This feature allows CAC to be run on dedicated radio RF chains while the
+# radio(s) are otherwise running normal AP activities on other channels.
+# This requires that the driver and the radio support it before feature will
+# actually be enabled, i.e., this parameter value is ignored with drivers that
+# do not advertise support for the capability.
+# 0: Leave disabled (default)
+# 1: Enable it.
+#enable_background_radar=1
+
# Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection.
# (default 0, i.e., not constraint)
#min_tx_power=20
@@ -965,6 +975,13 @@
# (default)
#he_6ghz_tx_ant_pat=1
+# 6 GHz Access Point type
+# This config is to set the 6 GHz Access Point type. Possible options are:
+# 0 = Indoor AP (default)
+# 1 = Standard Power AP
+# This has no impact for operation on other bands.
+#he_6ghz_reg_pwr_type=0
+
# Unsolicited broadcast Probe Response transmission settings
# This is for the 6 GHz band only. If the interval is set to a non-zero value,
# the AP schedules unsolicited broadcast Probe Response frames to be
@@ -973,6 +990,40 @@
# Valid range: 0..20 TUs; default is 0 (disabled)
#unsol_bcast_probe_resp_interval=0
+##### IEEE 802.11be related configuration #####################################
+
+#ieee80211be: Whether IEEE 802.11be (EHT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+#ieee80211be=1
+
+#disable_11be: Boolean (0/1) to disable EHT for a specific BSS
+#disable_11be=0
+
+#eht_su_beamformer: EHT single user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#eht_su_beamformer=1
+
+#eht_su_beamformee: EHT single user beamformee support
+# 0 = not supported (default)
+# 1 = supported
+#eht_su_beamformee=1
+
+#eht_mu_beamformer: EHT multiple user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#eht_mu_beamformer=1
+
+# EHT operating channel information; see matching he_* parameters for details.
+# The field eht_oper_centr_freq_seg0_idx field is used to indicate center
+# frequency of 40, 80, and 160 MHz bandwidth operation.
+# In the 6 GHz band, eht_oper_chwidth is ignored and the channel width is
+# derived from the configured operating class (IEEE P802.11be/D1.5,
+# Annex E.1 - Country information and operating classes).
+#eht_oper_chwidth
+#eht_oper_centr_freq_seg0_idx
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -1070,6 +1121,10 @@
# mka_priority (Priority of MKA Actor)
# Range: 0..255 (default: 255)
#
+# macsec_csindex: IEEE 802.1X/MACsec cipher suite
+# 0 = GCM-AES-128 (default)
+# 1 = GCM-AES-256 (default)
+#
# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
# In this mode, instances of hostapd can act as MACsec peers. The peer
@@ -1243,12 +1298,11 @@
# dh_file: File path to DH/DSA parameters file (in PEM format)
# This is an optional configuration file for setting parameters for an
-# ephemeral DH key exchange. In most cases, the default RSA authentication does
-# not use this configuration. However, it is possible setup RSA to use
-# ephemeral DH key exchange. In addition, ciphers with DSA keys always use
-# ephemeral DH keys. This can be used to achieve forward secrecy. If the file
-# is in DSA parameters format, it will be automatically converted into DH
-# params. This parameter is required if anonymous EAP-FAST is used.
+# ephemeral DH key exchange. If the file is in DSA parameters format, it will
+# be automatically converted into DH params. If the used TLS library supports
+# automatic DH parameter selection, that functionality will be used if this
+# parameter is not set. DH parameters are required if anonymous EAP-FAST is
+# used.
# You can generate DH parameters file with OpenSSL, e.g.,
# "openssl dhparam -out /etc/hostapd.dh.pem 2048"
#dh_file=/etc/hostapd.dh.pem
@@ -1369,6 +1423,10 @@
# 3 = use pseudonyms and use fast reauthentication (default)
#eap_sim_id=3
+# IMSI privacy key (PEM encoded RSA 2048-bit private key) for decrypting
+# permanent identity when using EAP-SIM/AKA/AKA'.
+#imsi_privacy_key=imsi-privacy-key.pem
+
# Trusted Network Connect (TNC)
# If enabled, TNC validation will be required before the peer is allowed to
# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
@@ -1651,12 +1709,15 @@
#wpa_psk_file=/etc/hostapd.wpa_psk
# Optionally, WPA passphrase can be received from RADIUS authentication server
-# This requires macaddr_acl to be set to 2 (RADIUS)
+# This requires macaddr_acl to be set to 2 (RADIUS) for wpa_psk_radius values
+# 1 and 2.
# 0 = disabled (default)
# 1 = optional; use default passphrase/psk if RADIUS server does not include
# Tunnel-Password
# 2 = required; reject authentication if RADIUS server does not include
# Tunnel-Password
+# 3 = ask RADIUS server during 4-way handshake if there is no locally
+# configured PSK/passphrase for the STA
#wpa_psk_radius=0
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 2609121..60396f3 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1169,7 +1169,7 @@
"arguments (count and freq)\n"
"usage: <cs_count> <freq> [sec_channel_offset=] "
"[center_freq1=] [center_freq2=] [bandwidth=] "
- "[blocktx] [ht|vht]\n");
+ "[blocktx] [ht|vht|he|eht]\n");
return -1;
}
diff --git a/hostapd/main.c b/hostapd/main.c
index d028fb5..eab57b6 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -15,6 +15,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
+#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/tls.h"
#include "common/version.h"
@@ -725,7 +726,6 @@
case 'v':
show_version();
exit(1);
- break;
case 'g':
if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
return -1;
@@ -947,6 +947,7 @@
fst_global_deinit();
+ crypto_unload();
os_program_deinit();
return ret;
diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk
index c42d53c..bb77341 100644
--- a/hs20/client/Android.mk
+++ b/hs20/client/Android.mk
@@ -60,6 +60,10 @@
L_CFLAGS += -Wno-unused-parameter
+ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+L_CFLAGS += -DANDROID_LOG_NAME='"hs20-osu-client"'
+endif
########################
include $(CLEAR_VARS)
@@ -71,9 +75,15 @@
LOCAL_SHARED_LIBRARIES := libc libcutils
LOCAL_SHARED_LIBRARIES += libcrypto libssl
+ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
+LOCAL_VENDOR_MODULE := true
+LOCAL_SHARED_LIBRARIES += libxml2
+LOCAL_SHARED_LIBRARIES += liblog
+else
#LOCAL_SHARED_LIBRARIES += libxml2
LOCAL_STATIC_LIBRARIES += libxml2
LOCAL_SHARED_LIBRARIES += libicuuc
+endif # End of check for platform version
LOCAL_SHARED_LIBRARIES += libcurl
LOCAL_CFLAGS := $(L_CFLAGS)
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 11bf0db..7b274da 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2911,20 +2911,27 @@
int found;
char *host = NULL;
- wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)",
- !ctx->no_osu_cert_validation, ctx->server_url);
+ wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s server_url=%s)",
+ !ctx->no_osu_cert_validation, cert->url ? cert->url : "N/A",
+ ctx->server_url);
- host = get_hostname(ctx->server_url);
+ if (ctx->no_osu_cert_validation && cert->url)
+ host = get_hostname(cert->url);
+ else
+ host = get_hostname(ctx->server_url);
- for (i = 0; i < ctx->server_dnsname_count; i++)
- os_free(ctx->server_dnsname[i]);
- os_free(ctx->server_dnsname);
- ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *));
- ctx->server_dnsname_count = 0;
+ if (!ctx->no_osu_cert_validation) {
+ for (i = 0; i < ctx->server_dnsname_count; i++)
+ os_free(ctx->server_dnsname[i]);
+ os_free(ctx->server_dnsname);
+ ctx->server_dnsname = os_calloc(cert->num_dnsname,
+ sizeof(char *));
+ ctx->server_dnsname_count = 0;
+ }
found = 0;
for (i = 0; i < cert->num_dnsname; i++) {
- if (ctx->server_dnsname) {
+ if (!ctx->no_osu_cert_validation && ctx->server_dnsname) {
ctx->server_dnsname[ctx->server_dnsname_count] =
os_strdup(cert->dnsname[i]);
if (ctx->server_dnsname[ctx->server_dnsname_count])
@@ -3249,7 +3256,6 @@
default:
usage();
exit(0);
- break;
}
}
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
index 39d10e0..194518e 100644
--- a/hs20/client/spp_client.c
+++ b/hs20/client/spp_client.c
@@ -564,7 +564,6 @@
free(id);
return -1;
}
- return 0;
}
if (strcasecmp(name, "uploadMO") == 0) {
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
index a50e907..72694be 100644
--- a/hs20/server/spp_server.c
+++ b/hs20/server/spp_server.c
@@ -1385,8 +1385,11 @@
SUBSCRIPTION_REGISTRATION, mac_addr) < 0)
return NULL;
val = db_get_osu_config_val(ctx, realm, "signup_url");
- if (val == NULL)
+ if (!val) {
+ hs20_eventlog(ctx, NULL, realm, session_id,
+ "signup_url not configured in osu_config", NULL);
return NULL;
+ }
spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
NULL);
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 0030edc..faaedbf 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -540,6 +540,10 @@
if (!acs_usable_chan(chan))
continue;
+ if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+ iface->conf->acs_exclude_dfs)
+ continue;
+
if (!is_in_chanlist(iface, chan))
continue;
@@ -670,6 +674,10 @@
if (!chan_pri_allowed(chan))
continue;
+ if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+ iface->conf->acs_exclude_dfs)
+ continue;
+
if (!is_in_chanlist(iface, chan))
continue;
@@ -1044,7 +1052,9 @@
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+ iface->conf->acs_exclude_dfs))
continue;
if (!is_in_chanlist(iface, chan))
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 33c68d4..db86a76 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration helper functions
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -463,9 +463,12 @@
wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
(u8 *) ssid->wpa_passphrase,
os_strlen(ssid->wpa_passphrase));
- pbkdf2_sha1(ssid->wpa_passphrase,
- ssid->ssid, ssid->ssid_len,
- 4096, ssid->wpa_psk->psk, PMK_LEN);
+ if (pbkdf2_sha1(ssid->wpa_passphrase,
+ ssid->ssid, ssid->ssid_len,
+ 4096, ssid->wpa_psk->psk, PMK_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()");
+ return -1;
+ }
wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
ssid->wpa_psk->psk, PMK_LEN);
return 0;
@@ -811,6 +814,7 @@
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
os_free(conf->eap_sim_db);
+ os_free(conf->imsi_privacy_key);
os_free(conf->radius_server_clients);
os_free(conf->radius);
os_free(conf->radius_das_shared_secret);
@@ -1245,15 +1249,18 @@
if (full_config && bss->wpa &&
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+ bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
"RADIUS checking (macaddr_acl=2) enabled.");
return -1;
}
- if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+ if (full_config && bss->wpa &&
+ wpa_key_mgmt_wpa_psk_no_sae(bss->wpa_key_mgmt) &&
bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
bss->ssid.wpa_psk_file == NULL &&
+ bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
(bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
@@ -1426,7 +1433,7 @@
#endif /* CONFIG_SAE_PK */
#ifdef CONFIG_FILS
- if (full_config && bss->fils_discovery_min_int &&
+ if (full_config && bss->fils_discovery_max_int &&
bss->unsol_bcast_probe_resp_interval) {
wpa_printf(MSG_ERROR,
"Cannot enable both FILS discovery and unsolicited broadcast Probe Response at the same time");
@@ -1434,6 +1441,14 @@
}
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211BE
+ if (full_config && !bss->disable_11be && bss->disable_11ax) {
+ bss->disable_11be = true;
+ wpa_printf(MSG_INFO,
+ "Disabling IEEE 802.11be as IEEE 802.11ax is disabled for this BSS");
+ }
+#endif /* CONFIG_IEEE80211BE */
+
return 0;
}
@@ -1465,6 +1480,13 @@
{
size_t i;
+ if (full_config && is_6ghz_op_class(conf->op_class) &&
+ !conf->hw_mode_set) {
+ /* Use the appropriate hw_mode value automatically when the
+ * op_class parameter has been set, but hw_mode was not. */
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+ }
+
if (full_config && conf->ieee80211d &&
(!conf->country[0] || !conf->country[1])) {
wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
@@ -1502,6 +1524,14 @@
return -1;
}
+#ifdef CONFIG_IEEE80211BE
+ if (full_config && conf->ieee80211be && !conf->ieee80211ax) {
+ wpa_printf(MSG_ERROR,
+ "Cannot set ieee80211be without ieee80211ax");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
for (i = 0; i < conf->num_bss; i++) {
if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
return -1;
@@ -1648,3 +1678,49 @@
return with_pk;
}
#endif /* CONFIG_SAE_PK */
+
+
+int hostapd_acl_comp(const void *a, const void *b)
+{
+ const struct mac_acl_entry *aa = a;
+ const struct mac_acl_entry *bb = b;
+ return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
+}
+
+
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+ int vlan_id, const u8 *addr)
+{
+ struct mac_acl_entry *newacl;
+
+ newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
+ if (!newacl) {
+ wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+ return -1;
+ }
+
+ *acl = newacl;
+ os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+ os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
+ (*acl)[*num].vlan_id.untagged = vlan_id;
+ (*acl)[*num].vlan_id.notempty = !!vlan_id;
+ (*num)++;
+
+ return 0;
+}
+
+
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+ const u8 *addr)
+{
+ int i = 0;
+
+ while (i < *num) {
+ if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) {
+ os_remove_in_array(*acl, *num, sizeof(**acl), i);
+ (*num)--;
+ } else {
+ i++;
+ }
+ }
+}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index c1a0f71..b97d49c 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,12 @@
#include "fst/fst.h"
#include "vlan.h"
+enum macaddr_acl {
+ ACCEPT_UNLESS_DENIED = 0,
+ DENY_UNLESS_ACCEPTED = 1,
+ USE_EXTERNAL_RADIUS_AUTH = 2
+};
+
/**
* mesh_conf - local MBSS state and settings
*/
@@ -331,12 +337,11 @@
int eap_reauth_period;
int erp_send_reauth_start;
char *erp_domain;
+#ifdef CONFIG_TESTING_OPTIONS
+ bool eap_skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
- enum macaddr_acl {
- ACCEPT_UNLESS_DENIED = 0,
- DENY_UNLESS_ACCEPTED = 1,
- USE_EXTERNAL_RADIUS_AUTH = 2
- } macaddr_acl;
+ enum macaddr_acl macaddr_acl;
struct mac_acl_entry *accept_mac;
int num_accept_mac;
struct mac_acl_entry *deny_mac;
@@ -364,7 +369,8 @@
enum {
PSK_RADIUS_IGNORED = 0,
PSK_RADIUS_ACCEPTED = 1,
- PSK_RADIUS_REQUIRED = 2
+ PSK_RADIUS_REQUIRED = 2,
+ PSK_RADIUS_DURING_4WAY_HS = 3,
} wpa_psk_radius;
int wpa_pairwise;
int group_cipher; /* wpa_group value override from configuation */
@@ -439,6 +445,7 @@
int eap_teap_id;
int eap_sim_aka_result_ind;
int eap_sim_id;
+ char *imsi_privacy_key;
int tnc;
int fragment_size;
u16 pwd_group;
@@ -537,6 +544,7 @@
bool disable_11n;
bool disable_11ac;
bool disable_11ax;
+ bool disable_11be;
/* IEEE 802.11v */
int time_advertisement;
@@ -849,6 +857,13 @@
int mka_priority;
/**
+ * macsec_csindex - Cipher suite index for MACsec
+ *
+ * Range: 0-1 (default: 0)
+ */
+ int macsec_csindex;
+
+ /**
* mka_ckn - MKA pre-shared CKN
*/
#define MACSEC_CKN_MAX_LEN 32
@@ -937,6 +952,15 @@
};
/**
+ * struct eht_phy_capabilities_info - EHT PHY capabilities
+ */
+struct eht_phy_capabilities_info {
+ bool su_beamformer;
+ bool su_beamformee;
+ bool mu_beamformer;
+};
+
+/**
* struct hostapd_config - Per-radio interface configuration
*/
struct hostapd_config {
@@ -957,7 +981,9 @@
int acs_exclude_dfs;
u8 min_tx_power;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+ bool hw_mode_set;
int acs_exclude_6ghz_non_psc;
+ int enable_background_radar;
enum {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
@@ -1075,6 +1101,7 @@
u8 he_6ghz_max_ampdu_len_exp;
u8 he_6ghz_rx_ant_pat;
u8 he_6ghz_tx_ant_pat;
+ u8 he_6ghz_reg_pwr_type;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@@ -1102,11 +1129,27 @@
unsigned int airtime_update_interval;
#define AIRTIME_MODE_MAX (__AIRTIME_MODE_MAX - 1)
#endif /* CONFIG_AIRTIME_POLICY */
+
+ int ieee80211be;
+#ifdef CONFIG_IEEE80211BE
+ u8 eht_oper_chwidth;
+ u8 eht_oper_centr_freq_seg0_idx;
+ struct eht_phy_capabilities_info eht_phy_capab;
+#endif /* CONFIG_IEEE80211BE */
+
+ /* EHT enable/disable config from CHAN_SWITCH */
+#define CH_SWITCH_EHT_ENABLED BIT(0)
+#define CH_SWITCH_EHT_DISABLED BIT(1)
+ unsigned int ch_switch_eht_config;
};
static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
{
+#ifdef CONFIG_IEEE80211BE
+ if (conf->ieee80211be)
+ return conf->eht_oper_chwidth;
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
return conf->he_oper_chwidth;
@@ -1117,6 +1160,10 @@
static inline void
hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
{
+#ifdef CONFIG_IEEE80211BE
+ if (conf->ieee80211be)
+ conf->eht_oper_chwidth = oper_chwidth;
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
conf->he_oper_chwidth = oper_chwidth;
@@ -1127,6 +1174,10 @@
static inline u8
hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf)
{
+#ifdef CONFIG_IEEE80211BE
+ if (conf->ieee80211be)
+ return conf->eht_oper_centr_freq_seg0_idx;
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
return conf->he_oper_centr_freq_seg0_idx;
@@ -1138,6 +1189,10 @@
hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
u8 oper_centr_freq_seg0_idx)
{
+#ifdef CONFIG_IEEE80211BE
+ if (conf->ieee80211be)
+ conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
@@ -1197,5 +1252,10 @@
bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
+int hostapd_acl_comp(const void *a, const void *b);
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+ int vlan_id, const u8 *addr);
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+ const u8 *addr);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index e917736..8af7a0e 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -418,6 +418,8 @@
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_eht_capabilities *eht_capab,
+ size_t eht_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set)
@@ -440,6 +442,8 @@
params.vht_capabilities = vht_capab;
params.he_capab = he_capab;
params.he_capab_len = he_capab_len;
+ params.eht_capab = eht_capab;
+ params.eht_capab_len = eht_capab_len;
params.he_6ghz_capab = he_6ghz_capab;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
@@ -547,7 +551,7 @@
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int edmg, u8 edmg_channel,
int ht_enabled, int vht_enabled,
- int he_enabled,
+ int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
{
@@ -556,12 +560,15 @@
if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
edmg_channel, ht_enabled,
- vht_enabled, he_enabled, sec_channel_offset,
- oper_chwidth,
+ vht_enabled, he_enabled, eht_enabled,
+ sec_channel_offset, oper_chwidth,
center_segment0, center_segment1,
cmode ? cmode->vht_capab : 0,
cmode ?
- &cmode->he_capab[IEEE80211_MODE_AP] : NULL))
+ &cmode->he_capab[IEEE80211_MODE_AP] : NULL,
+ cmode ?
+ &cmode->eht_capab[IEEE80211_MODE_AP] :
+ NULL))
return -1;
if (hapd->driver == NULL)
@@ -810,9 +817,10 @@
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
- int he_enabled,
+ int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
- int center_segment0, int center_segment1)
+ int center_segment0, int center_segment1,
+ bool radar_background)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_freq_params data;
@@ -830,18 +838,24 @@
if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
ht_enabled,
- vht_enabled, he_enabled, sec_channel_offset,
+ vht_enabled, he_enabled, eht_enabled,
+ sec_channel_offset,
oper_chwidth, center_segment0,
center_segment1,
cmode->vht_capab,
- &cmode->he_capab[IEEE80211_MODE_AP])) {
+ &cmode->he_capab[IEEE80211_MODE_AP],
+ &cmode->eht_capab[IEEE80211_MODE_AP])) {
wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
}
+ data.radar_background = radar_background;
res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
if (!res) {
- iface->cac_started = 1;
+ if (radar_background)
+ iface->radar_background.cac_started = 1;
+ else
+ iface->cac_started = 1;
os_get_reltime(&iface->dfs_cac_start);
}
@@ -953,13 +967,15 @@
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
+ params.eht_enabled = !!(hapd->iface->conf->ieee80211be);
params.ch_width = 20;
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
params.ch_width = 40;
/* Note: VHT20 is defined by combination of ht_capab & oper_chwidth
*/
- if ((hapd->iface->conf->ieee80211ax ||
+ if ((hapd->iface->conf->ieee80211be ||
+ hapd->iface->conf->ieee80211ax ||
hapd->iface->conf->ieee80211ac) &&
params.ht40_enabled) {
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 61c8f64..b4fb766 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -43,6 +43,8 @@
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_eht_capabilities *eht_capab,
+ size_t eht_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set);
@@ -64,8 +66,8 @@
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int edmg, u8 edmg_channel,
- int ht_enabled, int vht_enabled,
- int he_enabled, int sec_channel_offset, int oper_chwidth,
+ int ht_enabled, int vht_enabled, int he_enabled,
+ bool eht_enabled, int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
@@ -128,9 +130,10 @@
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
- int he_enabled,
+ int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
- int center_segment0, int center_segment1);
+ int center_segment0, int center_segment1,
+ bool radar_background);
int hostapd_drv_do_acs(struct hostapd_data *hapd);
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen);
@@ -299,6 +302,17 @@
return hapd->driver->switch_channel(hapd->drv_priv, settings);
}
+#ifdef CONFIG_IEEE80211AX
+static inline int hostapd_drv_switch_color(struct hostapd_data *hapd,
+ struct cca_settings *settings)
+{
+ if (!hapd->driver || !hapd->driver->switch_color || !hapd->drv_priv)
+ return -1;
+
+ return hapd->driver->switch_color(hapd->drv_priv, settings);
+}
+#endif /* CONFIG_IEEE80211AX */
+
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 8e12daf..fd9c96f 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "crypto/crypto.h"
#include "crypto/tls.h"
#include "eap_server/eap.h"
#include "eap_server/eap_sim_db.h"
@@ -168,6 +169,9 @@
wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
data->alert.description);
break;
+ case TLS_UNSAFE_RENEGOTIATION_DISABLED:
+ /* Not applicable to TLS server */
+ break;
}
}
#endif /* EAP_TLS_FUNCS */
@@ -209,6 +213,7 @@
cfg->eap_teap_id = hapd->conf->eap_teap_id;
cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
cfg->eap_sim_id = hapd->conf->eap_sim_id;
+ cfg->imsi_privacy_key = hapd->imsi_privacy_key;
cfg->tnc = hapd->conf->tnc;
cfg->wps = hapd->wps;
cfg->fragment_size = hapd->conf->fragment_size;
@@ -222,6 +227,9 @@
cfg->server_id_len = 7;
}
cfg->erp = hapd->conf->eap_server_erp;
+#ifdef CONFIG_TESTING_OPTIONS
+ cfg->skip_prot_success = hapd->conf->eap_skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
return cfg;
}
@@ -292,6 +300,22 @@
}
#endif /* EAP_TLS_FUNCS */
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(hapd->imsi_privacy_key);
+ hapd->imsi_privacy_key = NULL;
+ if (hapd->conf->imsi_privacy_key) {
+ hapd->imsi_privacy_key = crypto_rsa_key_read(
+ hapd->conf->imsi_privacy_key, true);
+ if (!hapd->imsi_privacy_key) {
+ wpa_printf(MSG_ERROR,
+ "Failed to read/parse IMSI privacy key %s",
+ hapd->conf->imsi_privacy_key);
+ authsrv_deinit(hapd);
+ return -1;
+ }
+ }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
#ifdef EAP_SIM_DB
if (hapd->conf->eap_sim_db) {
hapd->eap_sim_db_priv =
@@ -332,6 +356,11 @@
hapd->radius_srv = NULL;
#endif /* RADIUS_SERVER */
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(hapd->imsi_privacy_key);
+ hapd->imsi_privacy_key = NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
#ifdef EAP_TLS_FUNCS
if (hapd->ssl_ctx) {
tls_deinit(hapd->ssl_ctx);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 8cd1c41..eaa4033 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -186,7 +186,8 @@
}
-static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing,
+static u8 * hostapd_eid_country_add(struct hostapd_data *hapd, u8 *pos,
+ u8 *end, int chan_spacing,
struct hostapd_channel_data *start,
struct hostapd_channel_data *prev)
{
@@ -198,31 +199,23 @@
/* number of channels */
*pos++ = (prev->chan - start->chan) / chan_spacing + 1;
/* maximum transmit power level */
- *pos++ = start->max_tx_power;
+ if (!is_6ghz_op_class(hapd->iconf->op_class))
+ *pos++ = start->max_tx_power;
+ else
+ *pos++ = 0; /* Reserved when operating on the 6 GHz band */
return pos;
}
-static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
- int max_len)
+static u8 * hostapd_fill_subband_triplets(struct hostapd_data *hapd, u8 *pos,
+ u8 *end)
{
- u8 *pos = eid;
- u8 *end = eid + max_len;
int i;
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *start, *prev;
int chan_spacing = 1;
- if (!hapd->iconf->ieee80211d || max_len < 6 ||
- hapd->iface->current_mode == NULL)
- return eid;
-
- *pos++ = WLAN_EID_COUNTRY;
- pos++; /* length will be set later */
- os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
- pos += 3;
-
mode = hapd->iface->current_mode;
if (mode->mode == HOSTAPD_MODE_IEEE80211A)
chan_spacing = 4;
@@ -240,7 +233,8 @@
}
if (start && prev) {
- pos = hostapd_eid_country_add(pos, end, chan_spacing,
+ pos = hostapd_eid_country_add(hapd, pos, end,
+ chan_spacing,
start, prev);
start = NULL;
}
@@ -250,10 +244,50 @@
}
if (start) {
- pos = hostapd_eid_country_add(pos, end, chan_spacing,
+ pos = hostapd_eid_country_add(hapd, pos, end, chan_spacing,
start, prev);
}
+ return pos;
+}
+
+
+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
+ int max_len)
+{
+ u8 *pos = eid;
+ u8 *end = eid + max_len;
+
+ if (!hapd->iconf->ieee80211d || max_len < 6 ||
+ hapd->iface->current_mode == NULL)
+ return eid;
+
+ *pos++ = WLAN_EID_COUNTRY;
+ pos++; /* length will be set later */
+ os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
+ pos += 3;
+
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ /* Force the third octet of the country string to indicate
+ * Global Operating Class (Table E-4) */
+ eid[4] = 0x04;
+
+ /* Operating Triplet field */
+ /* Operating Extension Identifier (>= 201 to indicate this is
+ * not a Subband Triplet field) */
+ *pos++ = 201;
+ /* Operating Class */
+ *pos++ = hapd->iconf->op_class;
+ /* Coverage Class */
+ *pos++ = 0;
+ /* Subband Triplets are required only for the 20 MHz case */
+ if (hapd->iconf->op_class == 131 ||
+ hapd->iconf->op_class == 136)
+ pos = hostapd_fill_subband_triplets(hapd, pos, end);
+ } else {
+ pos = hostapd_fill_subband_triplets(hapd, pos, end);
+ }
+
if ((pos - eid) & 1) {
if (end - pos < 1)
return eid;
@@ -463,12 +497,25 @@
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
- if (is_6ghz_op_class(hapd->iconf->op_class))
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
buflen += sizeof(struct ieee80211_he_6ghz_oper_info) +
3 + sizeof(struct ieee80211_he_6ghz_band_cap);
+ /* An additional Transmit Power Envelope element for
+ * subordinate client */
+ if (hapd->iconf->he_6ghz_reg_pwr_type ==
+ HE_6GHZ_INDOOR_AP)
+ buflen += 4;
+ }
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
+ buflen += 3 + sizeof(struct ieee80211_eht_operation);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP);
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
@@ -578,14 +625,30 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
+ u8 *cca_pos;
+
pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_he_operation(hapd, pos);
+
+ /* BSS Color Change Announcement element */
+ cca_pos = hostapd_eid_cca(hapd, pos);
+ if (cca_pos != pos)
+ hapd->cca_c_off_proberesp = cca_pos - (u8 *) resp - 2;
+ pos = cca_pos;
+
pos = hostapd_eid_spatial_reuse(hapd, pos);
pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
pos = hostapd_eid_he_6ghz_band_cap(hapd, pos);
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP);
+ pos = hostapd_eid_eht_operation(hapd, pos);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
pos = hostapd_eid_vendor_vht(hapd, pos);
@@ -1319,6 +1382,15 @@
buf_len = pos - buf;
total_len += buf_len;
+#ifdef CONFIG_IEEE80211AX
+ /* Transmit Power Envelope element(s) */
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ total_len += 4;
+ if (hapd->iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP)
+ total_len += 4;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
head = os_zalloc(total_len);
if (!head)
return NULL;
@@ -1391,6 +1463,9 @@
pos += buf_len;
}
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ pos = hostapd_eid_txpower_envelope(hapd, pos);
+
*len = pos - (u8 *) head;
wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
head, pos - (u8 *) head);
@@ -1465,12 +1540,25 @@
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
- if (is_6ghz_op_class(hapd->iconf->op_class))
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
tail_len += sizeof(struct ieee80211_he_6ghz_oper_info) +
3 + sizeof(struct ieee80211_he_6ghz_band_cap);
+ /* An additional Transmit Power Envelope element for
+ * subordinate client */
+ if (hapd->iconf->he_6ghz_reg_pwr_type ==
+ HE_6GHZ_INDOOR_AP)
+ tail_len += 4;
+ }
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ tail_len += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
+ tail_len += 3 + sizeof(struct ieee80211_eht_operation);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON);
tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
@@ -1600,15 +1688,32 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
+ u8 *cca_pos;
+
tailpos = hostapd_eid_he_capab(hapd, tailpos,
IEEE80211_MODE_AP);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
+
+ /* BSS Color Change Announcement element */
+ cca_pos = hostapd_eid_cca(hapd, tailpos);
+ if (cca_pos != tailpos)
+ hapd->cca_c_off_beacon = cca_pos - tail - 2;
+ tailpos = cca_pos;
+
tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ tailpos = hostapd_eid_eht_capab(hapd, tailpos,
+ IEEE80211_MODE_AP);
+ tailpos = hostapd_eid_eht_operation(hapd, tailpos);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
@@ -1845,12 +1950,14 @@
iconf->channel, iconf->enable_edmg,
iconf->edmg_channel, iconf->ieee80211n,
iconf->ieee80211ac, iconf->ieee80211ax,
+ iconf->ieee80211be,
iconf->secondary_channel,
hostapd_get_oper_chwidth(iconf),
hostapd_get_oper_centr_freq_seg0_idx(iconf),
hostapd_get_oper_centr_freq_seg1_idx(iconf),
cmode->vht_capab,
- &cmode->he_capab[IEEE80211_MODE_AP]) == 0)
+ &cmode->he_capab[IEEE80211_MODE_AP],
+ &cmode->eht_capab[IEEE80211_MODE_AP]) == 0)
params.freq = &freq;
res = hostapd_drv_set_ap(hapd, ¶ms);
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 1d8fb82..29b41f5 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -24,6 +24,7 @@
#include "ap_drv_ops.h"
#include "mbo_ap.h"
#include "taxonomy.h"
+#include "wnm_ap.h"
static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
@@ -724,15 +725,15 @@
} else {
/* CAC started and CAC time set - calculate remaining time */
struct os_reltime now;
- unsigned int left_time;
+ long left_time;
os_reltime_age(&iface->dfs_cac_start, &now);
- left_time = iface->dfs_cac_ms / 1000 - now.sec;
+ left_time = (long) iface->dfs_cac_ms / 1000 - now.sec;
ret = os_snprintf(buf + len, buflen - len,
"cac_time_seconds=%u\n"
- "cac_time_left_seconds=%u\n",
+ "cac_time_left_seconds=%lu\n",
iface->dfs_cac_ms / 1000,
- left_time);
+ left_time > 0 ? left_time : 0);
}
if (os_snprintf_error(buflen - len, ret))
return len;
@@ -746,6 +747,7 @@
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
"ieee80211ax=%d\n"
+ "ieee80211be=%d\n"
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
@@ -758,12 +760,27 @@
!hapd->conf->disable_11ac,
iface->conf->ieee80211ax &&
!hapd->conf->disable_11ax,
+ iface->conf->ieee80211be &&
+ !hapd->conf->disable_11be,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+#ifdef CONFIG_IEEE80211BE
+ if (iface->conf->ieee80211be && !hapd->conf->disable_11be) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "eht_oper_chwidth=%d\n"
+ "eht_oper_centr_freq_seg0_idx=%d\n",
+ iface->conf->eht_oper_chwidth,
+ iface->conf->eht_oper_centr_freq_seg0_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_IEEE80211AX
if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
ret = os_snprintf(buf + len, buflen - len,
@@ -918,6 +935,7 @@
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
settings->freq_params.he_enabled = !!os_strstr(pos, " he");
+ settings->freq_params.eht_enabled = !!os_strstr(pos, " eht");
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
@@ -1047,3 +1065,351 @@
#endif /* CONFIG_MESH */
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
+#ifdef CONFIG_WNM_AP
+
+int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ int disassoc_timer;
+ struct sta_info *sta;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+ if (cmd[17] != ' ')
+ return -1;
+ disassoc_timer = atoi(cmd + 17);
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for disassociation imminent message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
+}
+
+
+int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ const char *url, *timerstr;
+ int disassoc_timer;
+ struct sta_info *sta;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for ESS disassociation imminent message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ timerstr = cmd + 17;
+ if (*timerstr != ' ')
+ return -1;
+ timerstr++;
+ disassoc_timer = atoi(timerstr);
+ if (disassoc_timer < 0 || disassoc_timer > 65535)
+ return -1;
+
+ url = os_strchr(timerstr, ' ');
+ if (url == NULL)
+ return -1;
+ url++;
+
+ return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
+}
+
+
+int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ const char *pos, *end;
+ int disassoc_timer = 0;
+ struct sta_info *sta;
+ u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
+ u8 bss_term_dur[12];
+ char *url = NULL;
+ int ret;
+ u8 nei_rep[1000];
+ int nei_len;
+ u8 mbo[10];
+ size_t mbo_len = 0;
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
+ return -1;
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for BSS TM Request message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " disassoc_timer=");
+ if (pos) {
+ pos += 16;
+ disassoc_timer = atoi(pos);
+ if (disassoc_timer < 0 || disassoc_timer > 65535) {
+ wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
+ return -1;
+ }
+ }
+
+ pos = os_strstr(cmd, " valid_int=");
+ if (pos) {
+ pos += 11;
+ valid_int = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " dialog_token=");
+ if (pos) {
+ pos += 14;
+ dialog_token = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " bss_term=");
+ if (pos) {
+ pos += 10;
+ req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
+ /* TODO: TSF configurable/learnable */
+ bss_term_dur[0] = 4; /* Subelement ID */
+ bss_term_dur[1] = 10; /* Length */
+ os_memset(&bss_term_dur[2], 0, 8);
+ end = os_strchr(pos, ',');
+ if (end == NULL) {
+ wpa_printf(MSG_DEBUG, "Invalid bss_term data");
+ return -1;
+ }
+ end++;
+ WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
+ }
+
+ nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
+ sizeof(nei_rep));
+ if (nei_len < 0)
+ return -1;
+
+ pos = os_strstr(cmd, " url=");
+ if (pos) {
+ size_t len;
+ pos += 5;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ url = os_malloc(len + 1);
+ if (url == NULL)
+ return -1;
+ os_memcpy(url, pos, len);
+ url[len] = '\0';
+ req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+ }
+
+ if (os_strstr(cmd, " pref=1"))
+ req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
+ if (os_strstr(cmd, " abridged=1"))
+ req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+ if (os_strstr(cmd, " disassoc_imminent=1"))
+ req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+
+#ifdef CONFIG_MBO
+ pos = os_strstr(cmd, "mbo=");
+ if (pos) {
+ unsigned int mbo_reason, cell_pref, reassoc_delay;
+ u8 *mbo_pos = mbo;
+
+ ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
+ &reassoc_delay, &cell_pref);
+ if (ret != 3) {
+ wpa_printf(MSG_DEBUG,
+ "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
+ ret = -1;
+ goto fail;
+ }
+
+ if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO transition reason code %u",
+ mbo_reason);
+ ret = -1;
+ goto fail;
+ }
+
+ /* Valid values for Cellular preference are: 0, 1, 255 */
+ if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO cellular capability %u",
+ cell_pref);
+ ret = -1;
+ goto fail;
+ }
+
+ if (reassoc_delay > 65535 ||
+ (reassoc_delay &&
+ !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Assoc retry delay is only valid in disassoc imminent mode");
+ ret = -1;
+ goto fail;
+ }
+
+ *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = mbo_reason;
+ *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = cell_pref;
+
+ if (reassoc_delay) {
+ *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+ *mbo_pos++ = 2;
+ WPA_PUT_LE16(mbo_pos, reassoc_delay);
+ mbo_pos += 2;
+ }
+
+ mbo_len = mbo_pos - mbo;
+ }
+#endif /* CONFIG_MBO */
+
+ ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
+ valid_int, bss_term_dur, dialog_token, url,
+ nei_len ? nei_rep : NULL, nei_len,
+ mbo_len ? mbo : NULL, mbo_len);
+#ifdef CONFIG_MBO
+fail:
+#endif /* CONFIG_MBO */
+ os_free(url);
+ return ret;
+}
+
+#endif /* CONFIG_WNM_AP */
+
+
+int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct vlan_description vlan_id;
+
+ if (!(*num))
+ return 0;
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
+ hostapd_remove_acl_mac(acl, num, addr);
+
+ return 0;
+}
+
+
+void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
+ int *num)
+{
+ while (*num)
+ hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
+}
+
+
+int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
+ char *buf, size_t buflen)
+{
+ int i = 0, len = 0, ret = 0;
+
+ if (!acl)
+ return 0;
+
+ while (i < num) {
+ ret = os_snprintf(buf + len, buflen - len,
+ MACSTR " VLAN_ID=%d\n",
+ MAC2STR(acl[i].addr),
+ acl[i].vlan_id.untagged);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ i++;
+ len += ret;
+ }
+ return len;
+}
+
+
+int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct vlan_description vlan_id;
+ int ret = 0, vlanid = 0;
+ const char *pos;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = os_strstr(cmd, "VLAN_ID=");
+ if (pos)
+ vlanid = atoi(pos + 8);
+
+ if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
+ ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
+ if (ret != -1 && *acl)
+ qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+ }
+
+ return ret < 0 ? -1 : 0;
+}
+
+
+int hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct vlan_description vlan_id;
+
+ if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
+ return 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!hostapd_maclist_found(hapd->conf->accept_mac,
+ hapd->conf->num_accept_mac,
+ sta->addr, &vlan_id) ||
+ (vlan_id.notempty &&
+ vlan_compare(&vlan_id, sta->vlan_desc)))
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ }
+
+ return 0;
+}
+
+
+int hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct vlan_description vlan_id;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (hostapd_maclist_found(hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac, sta->addr,
+ &vlan_id) &&
+ (!vlan_id.notempty ||
+ !vlan_compare(&vlan_id, sta->vlan_desc)))
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ }
+
+ return 0;
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index d1dcebf..614f042 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -37,4 +37,21 @@
const u8 *addr, char *buf, size_t len);
void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd);
+int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
+ const char *cmd);
+int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
+ const char *cmd);
+int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ const char *cmd);
+int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
+ const char *cmd);
+int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
+ const char *txtaddr);
+void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
+ int *num);
+int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
+ char *buf, size_t buflen);
+int hostapd_disassoc_accept_mac(struct hostapd_data *hapd);
+int hostapd_disassoc_deny_mac(struct hostapd_data *hapd);
+
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 5c99ecf..e46dd7e 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -19,6 +19,26 @@
#include "dfs.h"
+enum dfs_channel_type {
+ DFS_ANY_CHANNEL,
+ DFS_AVAILABLE, /* non-radar or radar-available */
+ DFS_NO_CAC_YET, /* radar-not-yet-available */
+};
+
+static struct hostapd_channel_data *
+dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx,
+ enum dfs_channel_type *channel_type);
+
+
+static bool dfs_use_radar_background(struct hostapd_iface *iface)
+{
+ return (iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) &&
+ iface->conf->enable_background_radar;
+}
+
+
static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
{
int n_chans = 1;
@@ -51,15 +71,27 @@
}
+/* dfs_channel_available: select new channel according to type parameter */
static int dfs_channel_available(struct hostapd_channel_data *chan,
- int skip_radar)
+ enum dfs_channel_type type)
{
+ if (type == DFS_NO_CAC_YET) {
+ /* Select only radar channel where CAC has not been
+ * performed yet
+ */
+ if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+ (chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
+ HOSTAPD_CHAN_DFS_USABLE)
+ return 1;
+ return 0;
+ }
+
/*
* When radar detection happens, CSA is performed. However, there's no
* time for CAC, so radar channels must be skipped when finding a new
* channel for CSA, unless they are available for immediate use.
*/
- if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
+ if (type == DFS_AVAILABLE && (chan->flag & HOSTAPD_CHAN_RADAR) &&
((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
HOSTAPD_CHAN_DFS_AVAILABLE))
return 0;
@@ -138,7 +170,7 @@
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int first_chan_idx, int num_chans,
- int skip_radar)
+ enum dfs_channel_type type)
{
struct hostapd_channel_data *first_chan, *chan;
int i;
@@ -177,7 +209,7 @@
return 0;
}
- if (!dfs_channel_available(chan, skip_radar)) {
+ if (!dfs_channel_available(chan, type)) {
wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
first_chan->freq + i * 20);
return 0;
@@ -207,7 +239,7 @@
*/
static int dfs_find_channel(struct hostapd_iface *iface,
struct hostapd_channel_data **ret_chan,
- int idx, int skip_radar)
+ int idx, enum dfs_channel_type type)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
@@ -232,7 +264,7 @@
}
/* Skip incompatible chandefs */
- if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
+ if (!dfs_chan_range_available(mode, i, n_chans, type)) {
wpa_printf(MSG_DEBUG,
"DFS: range not available for %d (%d)",
chan->freq, chan->chan);
@@ -475,7 +507,7 @@
int *secondary_channel,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx,
- int skip_radar)
+ enum dfs_channel_type type)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
@@ -499,7 +531,7 @@
return NULL;
/* Get the count first */
- num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
+ num_available_chandefs = dfs_find_channel(iface, NULL, 0, type);
wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
num_available_chandefs);
if (num_available_chandefs == 0)
@@ -508,7 +540,7 @@
if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
return NULL;
chan_idx = _rand % num_available_chandefs;
- dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+ dfs_find_channel(iface, &chan, chan_idx, type);
if (!chan) {
wpa_printf(MSG_DEBUG, "DFS: no random channel found");
return NULL;
@@ -537,7 +569,7 @@
for (i = 0; i < num_available_chandefs - 1; i++) {
/* start from chan_idx + 1, end when chan_idx - 1 */
chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
- dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
+ dfs_find_channel(iface, &chan2, chan_idx2, type);
if (chan2 && abs(chan2->chan - chan->chan) > 12) {
/* two channels are not adjacent */
sec_chan_idx_80p80 = chan2->chan;
@@ -568,6 +600,30 @@
}
+static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar)
+{
+ struct hostapd_channel_data *channel;
+ u8 cf1 = 0, cf2 = 0;
+ int sec = 0;
+
+ channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
+ skip_radar ? DFS_AVAILABLE :
+ DFS_ANY_CHANNEL);
+ if (!channel) {
+ wpa_printf(MSG_ERROR, "could not get valid channel");
+ return -1;
+ }
+
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = sec;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
+
+ return 0;
+}
+
+
static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
{
struct hostapd_hw_modes *mode;
@@ -755,7 +811,6 @@
*/
int hostapd_handle_dfs(struct hostapd_iface *iface)
{
- struct hostapd_channel_data *channel;
int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
int skip_radar = 0;
@@ -810,28 +865,17 @@
wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
res, res ? "yes": "no");
if (res) {
- int sec = 0;
- u8 cf1 = 0, cf2 = 0;
-
- channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
- skip_radar);
- if (!channel) {
- wpa_printf(MSG_ERROR, "could not get valid channel");
+ if (dfs_set_valid_channel(iface, skip_radar) < 0) {
hostapd_set_state(iface, HAPD_IFACE_DFS);
return 0;
}
-
- iface->freq = channel->freq;
- iface->conf->channel = channel->chan;
- iface->conf->secondary_channel = sec;
- hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
- hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
}
} while (res);
/* Finally start CAC */
hostapd_set_state(iface, HAPD_IFACE_DFS);
- wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
+ wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq,
+ dfs_use_radar_background(iface) ? " (background)" : "");
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
iface->freq,
@@ -844,17 +888,41 @@
res = hostapd_start_dfs_cac(
iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
iface->conf->ieee80211n, iface->conf->ieee80211ac,
- iface->conf->ieee80211ax,
+ iface->conf->ieee80211ax, iface->conf->ieee80211be,
iface->conf->secondary_channel,
hostapd_get_oper_chwidth(iface->conf),
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
- hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
+ dfs_use_radar_background(iface));
if (res) {
wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
return -1;
}
+ if (dfs_use_radar_background(iface)) {
+ /* Cache background radar parameters. */
+ iface->radar_background.channel = iface->conf->channel;
+ iface->radar_background.secondary_channel =
+ iface->conf->secondary_channel;
+ iface->radar_background.freq = iface->freq;
+ iface->radar_background.centr_freq_seg0_idx =
+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
+ iface->radar_background.centr_freq_seg1_idx =
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
+
+ /*
+ * Let's select a random channel according to the
+ * regulations and perform CAC on dedicated radar chain.
+ */
+ res = dfs_set_valid_channel(iface, 1);
+ if (res < 0)
+ return res;
+
+ iface->radar_background.temp_ch = 1;
+ return 1;
+ }
+
return 0;
}
@@ -876,6 +944,177 @@
}
+static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
+ int channel, int freq,
+ int secondary_channel,
+ u8 current_vht_oper_chwidth,
+ u8 oper_centr_freq_seg0_idx,
+ u8 oper_centr_freq_seg1_idx)
+{
+ struct hostapd_hw_modes *cmode = iface->current_mode;
+ int ieee80211_mode = IEEE80211_MODE_AP, err;
+ struct csa_settings csa_settings;
+ u8 new_vht_oper_chwidth;
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+ "freq=%d chan=%d sec_chan=%d", freq, channel,
+ secondary_channel);
+
+ new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
+
+ /* Setup CSA request */
+ os_memset(&csa_settings, 0, sizeof(csa_settings));
+ csa_settings.cs_count = 5;
+ csa_settings.block_tx = 1;
+#ifdef CONFIG_MESH
+ if (iface->mconf)
+ ieee80211_mode = IEEE80211_MODE_MESH;
+#endif /* CONFIG_MESH */
+ err = hostapd_set_freq_params(&csa_settings.freq_params,
+ iface->conf->hw_mode,
+ freq, channel,
+ iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
+ iface->conf->ieee80211be,
+ secondary_channel,
+ new_vht_oper_chwidth,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx,
+ cmode->vht_capab,
+ &cmode->he_capab[ieee80211_mode],
+ &cmode->eht_capab[ieee80211_mode]);
+
+ if (err) {
+ wpa_printf(MSG_ERROR,
+ "DFS failed to calculate CSA freq params");
+ hostapd_disable_iface(iface);
+ return err;
+ }
+
+ for (i = 0; i < iface->num_bss; i++) {
+ err = hostapd_switch_channel(iface->bss[i], &csa_settings);
+ if (err)
+ break;
+ }
+
+ if (err) {
+ wpa_printf(MSG_WARNING,
+ "DFS failed to schedule CSA (%d) - trying fallback",
+ err);
+ iface->freq = freq;
+ iface->conf->channel = channel;
+ iface->conf->secondary_channel = secondary_channel;
+ hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ oper_centr_freq_seg1_idx);
+
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+
+ return 0;
+ }
+
+ /* Channel configuration will be updated once CSA completes and
+ * ch_switch_notify event is received */
+ wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
+
+ return 0;
+}
+
+
+static void hostpad_dfs_update_background_chain(struct hostapd_iface *iface)
+{
+ int sec = 0;
+ enum dfs_channel_type channel_type = DFS_NO_CAC_YET;
+ struct hostapd_channel_data *channel;
+ u8 oper_centr_freq_seg0_idx = 0;
+ u8 oper_centr_freq_seg1_idx = 0;
+
+ /*
+ * Allow selection of DFS channel in ETSI to comply with
+ * uniform spreading.
+ */
+ if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
+ channel_type = DFS_ANY_CHANNEL;
+
+ channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ channel_type);
+ if (!channel ||
+ channel->chan == iface->conf->channel ||
+ channel->chan == iface->radar_background.channel)
+ channel = dfs_downgrade_bandwidth(iface, &sec,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &channel_type);
+ if (!channel ||
+ hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ channel->freq, channel->chan,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
+ iface->conf->ieee80211be,
+ sec, hostapd_get_oper_chwidth(iface->conf),
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx, true)) {
+ wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
+ iface->radar_background.channel = -1;
+ return;
+ }
+
+ iface->radar_background.channel = channel->chan;
+ iface->radar_background.freq = channel->freq;
+ iface->radar_background.secondary_channel = sec;
+ iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+ iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
+
+ wpa_printf(MSG_DEBUG,
+ "%s: setting background chain to chan %d (%d MHz)",
+ __func__, channel->chan, channel->freq);
+}
+
+
+static bool
+hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq)
+{
+ return dfs_use_radar_background(iface) &&
+ iface->radar_background.channel != -1 &&
+ iface->radar_background.freq == freq;
+}
+
+
+static int
+hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
+{
+ u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+
+ iface->conf->channel = iface->radar_background.channel;
+ iface->freq = iface->radar_background.freq;
+ iface->conf->secondary_channel =
+ iface->radar_background.secondary_channel;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ iface->conf, iface->radar_background.centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(
+ iface->conf, iface->radar_background.centr_freq_seg1_idx);
+
+ hostpad_dfs_update_background_chain(iface);
+
+ return hostapd_dfs_request_channel_switch(
+ iface, iface->conf->channel, iface->freq,
+ iface->conf->secondary_channel, current_vht_oper_chwidth,
+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
+}
+
+
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
@@ -896,6 +1135,22 @@
set_dfs_state(iface, freq, ht_enabled, chan_offset,
chan_width, cf1, cf2,
HOSTAPD_CHAN_DFS_AVAILABLE);
+
+ /*
+ * Radar event from background chain for the selected
+ * channel. Perform CSA, move the main chain to the
+ * selected channel and configure the background chain
+ * to a new DFS channel.
+ */
+ if (hostapd_dfs_is_background_event(iface, freq)) {
+ iface->radar_background.cac_started = 0;
+ if (!iface->radar_background.temp_ch)
+ return 0;
+
+ iface->radar_background.temp_ch = 0;
+ return hostapd_dfs_start_channel_switch_background(iface);
+ }
+
/*
* Just mark the channel available when CAC completion
* event is received in enabled state. CAC result could
@@ -912,6 +1167,9 @@
iface->cac_started = 0;
}
}
+ } else if (hostapd_dfs_is_background_event(iface, freq)) {
+ iface->radar_background.cac_started = 0;
+ hostpad_dfs_update_background_chain(iface);
}
return 0;
@@ -940,7 +1198,8 @@
static struct hostapd_channel_data *
dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
u8 *oper_centr_freq_seg0_idx,
- u8 *oper_centr_freq_seg1_idx, int *skip_radar)
+ u8 *oper_centr_freq_seg1_idx,
+ enum dfs_channel_type *channel_type)
{
struct hostapd_channel_data *channel;
@@ -948,22 +1207,22 @@
channel = dfs_get_valid_channel(iface, secondary_channel,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
- *skip_radar);
+ *channel_type);
if (channel) {
wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
channel->chan);
return channel;
}
- if (*skip_radar) {
- *skip_radar = 0;
+ if (*channel_type != DFS_ANY_CHANNEL) {
+ *channel_type = DFS_ANY_CHANNEL;
} else {
int oper_chwidth;
oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
if (oper_chwidth == CHANWIDTH_USE_HT)
break;
- *skip_radar = 1;
+ *channel_type = DFS_AVAILABLE;
hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
}
}
@@ -981,7 +1240,7 @@
int secondary_channel;
u8 oper_centr_freq_seg0_idx = 0;
u8 oper_centr_freq_seg1_idx = 0;
- int skip_radar = 0;
+ enum dfs_channel_type channel_type = DFS_ANY_CHANNEL;
int err = 1;
/* Radar detected during active CAC */
@@ -989,13 +1248,13 @@
channel = dfs_get_valid_channel(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
- skip_radar);
+ channel_type);
if (!channel) {
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
- &skip_radar);
+ &channel_type);
if (!channel) {
wpa_printf(MSG_ERROR, "No valid channel available");
return err;
@@ -1022,20 +1281,61 @@
}
+static int
+hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface,
+ int freq)
+{
+ if (!dfs_use_radar_background(iface))
+ return -1; /* Background radar chain not supported. */
+
+ wpa_printf(MSG_DEBUG,
+ "%s called (background CAC active: %s, CSA active: %s)",
+ __func__, iface->radar_background.cac_started ? "yes" : "no",
+ hostapd_csa_in_progress(iface) ? "yes" : "no");
+
+ /* Check if CSA in progress */
+ if (hostapd_csa_in_progress(iface))
+ return 0;
+
+ if (hostapd_dfs_is_background_event(iface, freq)) {
+ /*
+ * Radar pattern is reported on the background chain.
+ * Just select a new random channel according to the
+ * regulations for monitoring.
+ */
+ hostpad_dfs_update_background_chain(iface);
+ return 0;
+ }
+
+ /*
+ * If background radar detection is supported and the radar channel
+ * monitored by the background chain is available switch to it without
+ * waiting for the CAC.
+ */
+ if (iface->radar_background.channel == -1)
+ return -1; /* Background radar chain not available. */
+
+ if (iface->radar_background.cac_started) {
+ /*
+ * Background channel not available yet. Perform CAC on the
+ * main chain.
+ */
+ iface->radar_background.temp_ch = 1;
+ return -1;
+ }
+
+ return hostapd_dfs_start_channel_switch_background(iface);
+}
+
+
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
int secondary_channel;
u8 oper_centr_freq_seg0_idx;
u8 oper_centr_freq_seg1_idx;
- u8 new_vht_oper_chwidth;
- int skip_radar = 1;
- struct csa_settings csa_settings;
- unsigned int i;
- int err = 1;
- struct hostapd_hw_modes *cmode = iface->current_mode;
+ enum dfs_channel_type channel_type = DFS_AVAILABLE;
u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
- int ieee80211_mode = IEEE80211_MODE_AP;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -1054,13 +1354,13 @@
* uniform spreading.
*/
if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
- skip_radar = 0;
+ channel_type = DFS_ANY_CHANNEL;
/* Perform channel switch/CSA */
channel = dfs_get_valid_channel(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
- skip_radar);
+ channel_type);
if (!channel) {
/*
@@ -1068,11 +1368,11 @@
* there is another channel where we can switch even if it
* requires to perform a CAC first.
*/
- skip_radar = 0;
+ channel_type = DFS_ANY_CHANNEL;
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
- &skip_radar);
+ &channel_type);
if (!channel) {
/*
* Toggle interface state to enter DFS state
@@ -1083,7 +1383,7 @@
return 0;
}
- if (!skip_radar) {
+ if (channel_type == DFS_ANY_CHANNEL) {
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
@@ -1098,73 +1398,12 @@
}
}
- wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
- channel->chan);
- wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
- "freq=%d chan=%d sec_chan=%d", channel->freq,
- channel->chan, secondary_channel);
-
- new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
- hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
-
- /* Setup CSA request */
- os_memset(&csa_settings, 0, sizeof(csa_settings));
- csa_settings.cs_count = 5;
- csa_settings.block_tx = 1;
-#ifdef CONFIG_MESH
- if (iface->mconf)
- ieee80211_mode = IEEE80211_MODE_MESH;
-#endif /* CONFIG_MESH */
- err = hostapd_set_freq_params(&csa_settings.freq_params,
- iface->conf->hw_mode,
- channel->freq,
- channel->chan,
- iface->conf->enable_edmg,
- iface->conf->edmg_channel,
- iface->conf->ieee80211n,
- iface->conf->ieee80211ac,
- iface->conf->ieee80211ax,
- secondary_channel,
- new_vht_oper_chwidth,
- oper_centr_freq_seg0_idx,
- oper_centr_freq_seg1_idx,
- cmode->vht_capab,
- &cmode->he_capab[ieee80211_mode]);
-
- if (err) {
- wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
- hostapd_disable_iface(iface);
- return err;
- }
-
- for (i = 0; i < iface->num_bss; i++) {
- err = hostapd_switch_channel(iface->bss[i], &csa_settings);
- if (err)
- break;
- }
-
- if (err) {
- wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
- err);
- iface->freq = channel->freq;
- iface->conf->channel = channel->chan;
- iface->conf->secondary_channel = secondary_channel;
- hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
- hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
- oper_centr_freq_seg0_idx);
- hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
- oper_centr_freq_seg1_idx);
-
- hostapd_disable_iface(iface);
- hostapd_enable_iface(iface);
- return 0;
- }
-
- /* Channel configuration will be updated once CSA completes and
- * ch_switch_notify event is received */
-
- wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
- return 0;
+ return hostapd_dfs_request_channel_switch(iface, channel->chan,
+ channel->freq,
+ secondary_channel,
+ current_vht_oper_chwidth,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx);
}
@@ -1172,8 +1411,6 @@
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
- int res;
-
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
@@ -1186,20 +1423,23 @@
return 0;
/* mark radar frequency as invalid */
- res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
- cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
- if (!res)
+ if (!set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE))
return 0;
- /* Skip if reported radar event not overlapped our channels */
- res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
- if (!res)
- return 0;
+ if (!hostapd_dfs_is_background_event(iface, freq)) {
+ /* Skip if reported radar event not overlapped our channels */
+ if (!dfs_are_channels_overlapped(iface, freq, chan_width,
+ cf1, cf2))
+ return 0;
+ }
- /* radar detected while operating, switch the channel. */
- res = hostapd_dfs_start_channel_switch(iface);
+ if (hostapd_dfs_background_start_channel_switch(iface, freq)) {
+ /* Radar detected while operating, switch the channel. */
+ return hostapd_dfs_start_channel_switch(iface);
+ }
- return res;
+ return 0;
}
@@ -1219,9 +1459,14 @@
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
- /* Handle cases where all channels were initially unavailable */
- if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
+ if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) {
+ /* Handle cases where all channels were initially unavailable */
hostapd_handle_dfs(iface);
+ } else if (dfs_use_radar_background(iface) &&
+ iface->radar_background.channel == -1) {
+ /* Reset radar background chain if disabled */
+ hostpad_dfs_update_background_chain(iface);
+ }
return 0;
}
@@ -1259,17 +1504,24 @@
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
- /* This is called when the driver indicates that an offloaded DFS has
- * started CAC. */
- hostapd_set_state(iface, HAPD_IFACE_DFS);
+ if (hostapd_dfs_is_background_event(iface, freq)) {
+ iface->radar_background.cac_started = 1;
+ } else {
+ /* This is called when the driver indicates that an offloaded
+ * DFS has started CAC. */
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ iface->cac_started = 1;
+ }
/* TODO: How to check CAC time for ETSI weather channels? */
iface->dfs_cac_ms = 60000;
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
- "seg1=%d cac_time=%ds",
+ "seg1=%d cac_time=%ds%s",
freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
- iface->dfs_cac_ms / 1000);
- iface->cac_started = 1;
+ iface->dfs_cac_ms / 1000,
+ hostapd_dfs_is_background_event(iface, freq) ?
+ " (background)" : "");
+
os_get_reltime(&iface->dfs_cac_start);
return 0;
}
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 96a13fb..d4cbed8 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -31,6 +31,7 @@
static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
struct dpp_authentication *auth);
+static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd);
#ifdef CONFIG_DPP2
static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
void *timeout_ctx);
@@ -346,14 +347,8 @@
#endif /* CONFIG_DPP2 */
-enum hostapd_dpp_pkex_ver {
- PKEX_VER_AUTO,
- PKEX_VER_ONLY_1,
- PKEX_VER_ONLY_2,
-};
-
static int hostapd_dpp_pkex_init(struct hostapd_data *hapd,
- enum hostapd_dpp_pkex_ver ver,
+ enum dpp_pkex_ver ver,
const struct hostapd_ip_addr *ipaddr,
int tcp_port)
{
@@ -1160,6 +1155,21 @@
}
+#ifdef CONFIG_DPP3
+static void hostapd_dpp_build_new_key(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_new_key)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key");
+ hostapd_dpp_start_gas_client(hapd);
+}
+#endif /* CONFIG_DPP3 */
+
+
static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_ap_result result,
const struct wpabuf *adv_proto,
@@ -1169,6 +1179,7 @@
const u8 *pos;
struct dpp_authentication *auth = hapd->dpp_auth;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+ int res;
if (!auth || !auth->auth_success) {
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
@@ -1199,7 +1210,16 @@
goto fail;
}
- if (dpp_conf_resp_rx(auth, resp) < 0) {
+ res = dpp_conf_resp_rx(auth, resp);
+#ifdef CONFIG_DPP3
+ if (res == -3) {
+ wpa_printf(MSG_DEBUG, "DPP: New protocol key needed");
+ eloop_register_timeout(0, 0, hostapd_dpp_build_new_key, hapd,
+ NULL);
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+ if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
goto fail;
}
@@ -1986,6 +2006,17 @@
wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
MAC2STR(src));
+ if (hapd->dpp_pkex_ver == PKEX_VER_ONLY_1 && v2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore PKEXv2 Exchange Request when configured to be PKEX v1 only");
+ return;
+ }
+ if (hapd->dpp_pkex_ver == PKEX_VER_ONLY_2 && !v2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore PKEXv1 Exchange Request when configured to be PKEX v2 only");
+ return;
+ }
+
/* TODO: Support multiple PKEX codes by iterating over all the enabled
* values here */
@@ -2349,6 +2380,13 @@
if (!auth)
return;
+#ifdef CONFIG_DPP3
+ if (auth->waiting_new_key && ok) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key");
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
@@ -2409,6 +2447,11 @@
{
struct dpp_bootstrap_info *own_bi;
const char *pos, *end;
+#ifdef CONFIG_DPP3
+ enum dpp_pkex_ver ver = PKEX_VER_AUTO;
+#else /* CONFIG_DPP3 */
+ enum dpp_pkex_ver ver = PKEX_VER_ONLY_1;
+#endif /* CONFIG_DPP3 */
int tcp_port = DPP_TCP_PORT;
struct hostapd_ip_addr *ipaddr = NULL;
#ifdef CONFIG_DPP2
@@ -2474,27 +2517,22 @@
if (!hapd->dpp_pkex_code)
return -1;
+ pos = os_strstr(cmd, " ver=");
+ if (pos) {
+ int v;
+
+ pos += 5;
+ v = atoi(pos);
+ if (v == 1)
+ ver = PKEX_VER_ONLY_1;
+ else if (v == 2)
+ ver = PKEX_VER_ONLY_2;
+ else
+ return -1;
+ }
+ hapd->dpp_pkex_ver = ver;
+
if (os_strstr(cmd, " init=1")) {
-#ifdef CONFIG_DPP3
- enum hostapd_dpp_pkex_ver ver = PKEX_VER_AUTO;
-#else /* CONFIG_DPP3 */
- enum hostapd_dpp_pkex_ver ver = PKEX_VER_ONLY_1;
-#endif /* CONFIG_DPP3 */
-
- pos = os_strstr(cmd, " ver=");
- if (pos) {
- int v;
-
- pos += 5;
- v = atoi(pos);
- if (v == 1)
- ver = PKEX_VER_ONLY_1;
- else if (v == 2)
- ver = PKEX_VER_ONLY_2;
- else
- return -1;
- }
-
if (hostapd_dpp_pkex_init(hapd, ver, ipaddr, tcp_port) < 0)
return -1;
} else {
@@ -2646,6 +2684,9 @@
if (hapd->iface->interfaces)
dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd);
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ eloop_cancel_timeout(hostapd_dpp_build_new_key, hapd, NULL);
+#endif /* CONFIG_DPP3 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
hostapd_dpp_pkex_remove(hapd, "*");
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index f353a0e..643a273 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -261,12 +261,7 @@
}
#endif /* NEED_AP_MLME */
-#ifdef CONFIG_INTERWORKING
- if (elems.ext_capab && elems.ext_capab_len > 4) {
- if (elems.ext_capab[4] & 0x01)
- sta->qos_map_enabled = 1;
- }
-#endif /* CONFIG_INTERWORKING */
+ check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
@@ -870,10 +865,11 @@
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
finished ? "had" : "starting",
freq, ht, hapd->iconf->ch_switch_vht_config,
- hapd->iconf->ch_switch_he_config, offset,
+ hapd->iconf->ch_switch_he_config,
+ hapd->iconf->ch_switch_eht_config, offset,
width, channel_width_to_string(width), cf1, cf2);
if (!hapd->iface->current_mode) {
@@ -953,9 +949,23 @@
else if (hapd->iconf->ch_switch_he_config &
CH_SWITCH_HE_DISABLED)
hapd->iconf->ieee80211ax = 0;
+#ifdef CONFIG_IEEE80211BE
+ } else if (hapd->iconf->ch_switch_eht_config) {
+ /* CHAN_SWITCH EHT config */
+ if (hapd->iconf->ch_switch_eht_config &
+ CH_SWITCH_EHT_ENABLED) {
+ hapd->iconf->ieee80211be = 1;
+ hapd->iconf->ieee80211ax = 1;
+ if (!is_6ghz_freq(hapd->iface->freq))
+ hapd->iconf->ieee80211ac = 1;
+ } else if (hapd->iconf->ch_switch_eht_config &
+ CH_SWITCH_EHT_DISABLED)
+ hapd->iconf->ieee80211be = 0;
+#endif /* CONFIG_IEEE80211BE */
}
hapd->iconf->ch_switch_vht_config = 0;
hapd->iconf->ch_switch_he_config = 0;
+ hapd->iconf->ch_switch_eht_config = 0;
if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 ||
width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160)
@@ -1011,7 +1021,9 @@
hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
#ifdef CONFIG_OCV
- if (hapd->conf->ocv) {
+ if (hapd->conf->ocv &&
+ !(hapd->iface->drv_flags2 &
+ WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP)) {
struct sta_info *sta;
bool check_sa_query = false;
@@ -2084,6 +2096,32 @@
data->wds_sta_interface.ifname,
data->wds_sta_interface.sta_addr);
break;
+#ifdef CONFIG_IEEE80211AX
+ case EVENT_BSS_COLOR_COLLISION:
+ /* The BSS color is shared amongst all BBSs on a specific phy.
+ * Therefore we always start the color change on the primary
+ * BSS. */
+ wpa_printf(MSG_DEBUG, "BSS color collision on %s",
+ hapd->conf->iface);
+ hostapd_switch_color(hapd->iface->bss[0],
+ data->bss_color_collision.bitmap);
+ break;
+ case EVENT_CCA_STARTED_NOTIFY:
+ wpa_printf(MSG_DEBUG, "CCA started on on %s",
+ hapd->conf->iface);
+ break;
+ case EVENT_CCA_ABORTED_NOTIFY:
+ wpa_printf(MSG_DEBUG, "CCA aborted on on %s",
+ hapd->conf->iface);
+ hostapd_cleanup_cca_params(hapd);
+ break;
+ case EVENT_CCA_NOTIFY:
+ wpa_printf(MSG_DEBUG, "CCA finished on on %s",
+ hapd->conf->iface);
+ hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
+ hostapd_cleanup_cca_params(hapd);
+ break;
+#endif /* CONFIG_IEEE80211AX */
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 4b88641..ef53c41 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -66,6 +66,10 @@
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
void *timeout_ctx);
+#ifdef CONFIG_IEEE80211AX
+static void hostapd_switch_color_timeout_handler(void *eloop_data,
+ void *user_ctx);
+#endif /* CONFIG_IEEE80211AX */
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
@@ -462,6 +466,10 @@
}
eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_IEEE80211AX
+ eloop_cancel_timeout(hostapd_switch_color_timeout_handler, hapd, NULL);
+#endif /* CONFIG_IEEE80211AX */
}
@@ -1458,14 +1466,14 @@
}
-static void hostapd_set_acl(struct hostapd_data *hapd)
+int hostapd_set_acl(struct hostapd_data *hapd)
{
struct hostapd_config *conf = hapd->iconf;
- int err;
+ int err = 0;
u8 accept_acl;
if (hapd->iface->drv_max_acl_mac_addrs == 0)
- return;
+ return 0;
if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
accept_acl = 1;
@@ -1474,7 +1482,7 @@
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set accept acl");
- return;
+ return -1;
}
} else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
accept_acl = 0;
@@ -1483,9 +1491,10 @@
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set deny acl");
- return;
+ return -1;
}
}
+ return err;
}
@@ -2067,6 +2076,7 @@
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
hapd->iconf->ieee80211ax,
+ hapd->iconf->ieee80211be,
hapd->iconf->secondary_channel,
hostapd_get_oper_chwidth(hapd->iconf),
hostapd_get_oper_centr_freq_seg0_idx(
@@ -3452,12 +3462,14 @@
conf->channel, conf->enable_edmg,
conf->edmg_channel, conf->ieee80211n,
conf->ieee80211ac, conf->ieee80211ax,
- conf->secondary_channel,
+ conf->ieee80211be, conf->secondary_channel,
hostapd_get_oper_chwidth(conf),
hostapd_get_oper_centr_freq_seg0_idx(conf),
hostapd_get_oper_centr_freq_seg1_idx(conf),
conf->vht_capab,
mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+ NULL,
+ mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
NULL))
return -1;
@@ -3545,11 +3557,12 @@
&hapd->iface->cs_oper_class,
&chan) == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_DEBUG,
- "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)",
+ "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d)",
settings->freq_params.freq,
settings->freq_params.sec_channel_offset,
settings->freq_params.vht_enabled,
- settings->freq_params.he_enabled);
+ settings->freq_params.he_enabled,
+ settings->freq_params.eht_enabled);
return -1;
}
@@ -3606,6 +3619,11 @@
void hostapd_chan_switch_config(struct hostapd_data *hapd,
struct hostapd_freq_params *freq_params)
{
+ if (freq_params->eht_enabled)
+ hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_ENABLED;
+ else
+ hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_DISABLED;
+
if (freq_params->he_enabled)
hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED;
else
@@ -3618,7 +3636,8 @@
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "CHAN_SWITCH HE config 0x%x VHT config 0x%x",
+ "CHAN_SWITCH EHT config 0x%x HE config 0x%x VHT config 0x%x",
+ hapd->iconf->ch_switch_eht_config,
hapd->iconf->ch_switch_he_config,
hapd->iconf->ch_switch_vht_config);
}
@@ -3696,6 +3715,7 @@
iface->conf->ieee80211n = freq_params->ht_enabled;
iface->conf->ieee80211ac = freq_params->vht_enabled;
iface->conf->ieee80211ax = freq_params->he_enabled;
+ iface->conf->ieee80211be = freq_params->eht_enabled;
/*
* cs_params must not be cleared earlier because the freq_params
@@ -3706,6 +3726,139 @@
hostapd_enable_iface(iface);
}
+
+#ifdef CONFIG_IEEE80211AX
+
+void hostapd_cleanup_cca_params(struct hostapd_data *hapd)
+{
+ hapd->cca_count = 0;
+ hapd->cca_color = 0;
+ hapd->cca_c_off_beacon = 0;
+ hapd->cca_c_off_proberesp = 0;
+ hapd->cca_in_progress = false;
+}
+
+
+static int hostapd_fill_cca_settings(struct hostapd_data *hapd,
+ struct cca_settings *settings)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ u8 old_color;
+ int ret;
+
+ if (!iface || iface->conf->he_op.he_bss_color_disabled)
+ return -1;
+
+ old_color = iface->conf->he_op.he_bss_color;
+ iface->conf->he_op.he_bss_color = hapd->cca_color;
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
+ if (ret)
+ return ret;
+
+ iface->conf->he_op.he_bss_color = old_color;
+
+ settings->cca_count = hapd->cca_count;
+ settings->cca_color = hapd->cca_color,
+ hapd->cca_in_progress = true;
+
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_cca);
+ if (ret) {
+ free_beacon_data(&settings->beacon_after);
+ return ret;
+ }
+
+ settings->counter_offset_beacon = hapd->cca_c_off_beacon;
+ settings->counter_offset_presp = hapd->cca_c_off_proberesp;
+
+ return 0;
+}
+
+
+static void hostapd_switch_color_timeout_handler(void *eloop_data,
+ void *user_ctx)
+{
+ struct hostapd_data *hapd = (struct hostapd_data *) eloop_data;
+ os_time_t delta_t;
+ unsigned int b;
+ int i, r;
+
+ /* CCA can be triggered once the handler constantly receives
+ * color collision events to for at least
+ * DOT11BSS_COLOR_COLLISION_AP_PERIOD (50 s by default). */
+ delta_t = hapd->last_color_collision.sec -
+ hapd->first_color_collision.sec;
+ if (delta_t < DOT11BSS_COLOR_COLLISION_AP_PERIOD)
+ return;
+
+ r = os_random() % HE_OPERATION_BSS_COLOR_MAX;
+ for (i = 0; i < HE_OPERATION_BSS_COLOR_MAX; i++) {
+ if (r && !(hapd->color_collision_bitmap & BIT(r)))
+ break;
+
+ r = (r + 1) % HE_OPERATION_BSS_COLOR_MAX;
+ }
+
+ if (i == HE_OPERATION_BSS_COLOR_MAX) {
+ /* There are no free colors so turn BSS coloring off */
+ wpa_printf(MSG_INFO,
+ "No free colors left, turning off BSS coloring");
+ hapd->iface->conf->he_op.he_bss_color_disabled = 1;
+ hapd->iface->conf->he_op.he_bss_color = os_random() % 63 + 1;
+ for (b = 0; b < hapd->iface->num_bss; b++)
+ ieee802_11_set_beacon(hapd->iface->bss[b]);
+ return;
+ }
+
+ for (b = 0; b < hapd->iface->num_bss; b++) {
+ struct hostapd_data *bss = hapd->iface->bss[b];
+ struct cca_settings settings;
+ int ret;
+
+ hostapd_cleanup_cca_params(bss);
+ bss->cca_color = r;
+ bss->cca_count = 10;
+
+ if (hostapd_fill_cca_settings(bss, &settings)) {
+ hostapd_cleanup_cca_params(bss);
+ continue;
+ }
+
+ ret = hostapd_drv_switch_color(bss, &settings);
+ if (ret)
+ hostapd_cleanup_cca_params(bss);
+
+ free_beacon_data(&settings.beacon_cca);
+ free_beacon_data(&settings.beacon_after);
+ }
+}
+
+
+void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap)
+{
+ struct os_reltime now;
+
+ if (hapd->cca_in_progress)
+ return;
+
+ if (os_get_reltime(&now))
+ return;
+
+ hapd->color_collision_bitmap = bitmap;
+ hapd->last_color_collision = now;
+
+ if (eloop_is_timeout_registered(hostapd_switch_color_timeout_handler,
+ hapd, NULL))
+ return;
+
+ hapd->first_color_collision = now;
+ /* 10 s window as margin for persistent color collision reporting */
+ eloop_register_timeout(DOT11BSS_COLOR_COLLISION_AP_PERIOD + 10, 0,
+ hostapd_switch_color_timeout_handler,
+ hapd, NULL);
+}
+
+#endif /* CONFIG_IEEE80211AX */
+
#endif /* NEED_AP_MLME */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 7f7877b..6b9b65f 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -14,6 +14,7 @@
#endif /* CONFIG_SQLITE */
#include "common/defs.h"
+#include "common/dpp.h"
#include "utils/list.h"
#include "ap_config.h"
#include "drivers/driver.h"
@@ -207,6 +208,7 @@
void *ssl_ctx;
void *eap_sim_db_priv;
+ struct crypto_rsa_key *imsi_privacy_key;
struct radius_server_data *radius_srv;
struct dl_list erp_keys; /* struct eap_server_erp_key */
@@ -294,6 +296,17 @@
unsigned int cs_c_off_ecsa_beacon;
unsigned int cs_c_off_ecsa_proberesp;
+#ifdef CONFIG_IEEE80211AX
+ bool cca_in_progress;
+ u8 cca_count;
+ u8 cca_color;
+ unsigned int cca_c_off_beacon;
+ unsigned int cca_c_off_proberesp;
+ struct os_reltime first_color_collision;
+ struct os_reltime last_color_collision;
+ u64 color_collision_bitmap;
+#endif /* CONFIG_IEEE80211AX */
+
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@@ -388,6 +401,7 @@
struct dpp_bootstrap_info *dpp_pkex_bi;
char *dpp_pkex_code;
char *dpp_pkex_identifier;
+ enum dpp_pkex_ver dpp_pkex_ver;
char *dpp_pkex_auth_cmd;
char *dpp_configurator_params;
struct os_reltime dpp_last_init;
@@ -521,6 +535,21 @@
int *basic_rates;
int freq;
+ /* Background radar configuration */
+ struct {
+ int channel;
+ int secondary_channel;
+ int freq;
+ int centr_freq_seg0_idx;
+ int centr_freq_seg1_idx;
+ /* Main chain is on temporary channel during
+ * CAC detection on radar offchain.
+ */
+ unsigned int temp_ch:1;
+ /* CAC started on radar offchain */
+ unsigned int cac_started:1;
+ } radar_background;
+
u16 hw_flags;
/* Number of associated Non-ERP stations (i.e., stations using 802.11b
@@ -648,6 +677,9 @@
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
+void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap);
+void hostapd_cleanup_cca_params(struct hostapd_data *hapd);
+
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
@@ -693,4 +725,6 @@
struct fst_wpa_obj *iface_obj);
#endif /* CONFIG_FST */
+int hostapd_set_acl(struct hostapd_data *hapd);
+
#endif /* HOSTAPD_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 6140a49..394e292 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -498,6 +498,7 @@
struct sae_password_entry *pw;
struct sae_pt *pt = NULL;
const struct sae_pk *pk = NULL;
+ struct hostapd_sta_wpa_psk_short *psk = NULL;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
@@ -519,6 +520,15 @@
pt = hapd->conf->ssid.pt;
}
+ if (!password) {
+ for (psk = sta->psk; psk; psk = psk->next) {
+ if (psk->is_passphrase) {
+ password = psk->passphrase;
+ break;
+ }
+ }
+ }
+
if (pw_entry)
*pw_entry = pw;
if (s_pt)
@@ -2315,9 +2325,8 @@
}
-static int
-ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
- int res, struct radius_sta *info)
+int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+ int res, struct radius_sta *info)
{
u32 session_timeout = info->session_timeout;
u32 acct_interim_interval = info->acct_interim_interval;
@@ -3112,6 +3121,7 @@
int ret, inc_y;
bool derive_keys;
u32 i;
+ bool derive_kdk;
if (!groups)
groups = default_groups;
@@ -3151,10 +3161,14 @@
sta->pasn->akmp = rsn_data.key_mgmt;
sta->pasn->cipher = rsn_data.pairwise_cipher;
- if (hapd->conf->force_kdk_derivation ||
- ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
- ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
- WLAN_RSNX_CAPAB_SECURE_LTF)))
+ derive_kdk = (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
+ ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_SECURE_LTF);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!derive_kdk)
+ derive_kdk = hapd->conf->force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (derive_kdk)
sta->pasn->kdk_len = WPA_KDK_MAX_LEN;
else
sta->pasn->kdk_len = 0;
@@ -4123,32 +4137,6 @@
}
-static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *ext_capab_ie, size_t ext_capab_ie_len)
-{
-#ifdef CONFIG_INTERWORKING
- /* check for QoS Map support */
- if (ext_capab_ie_len >= 5) {
- if (ext_capab_ie[4] & 0x01)
- sta->qos_map_enabled = 1;
- }
-#endif /* CONFIG_INTERWORKING */
-
- if (ext_capab_ie_len > 0) {
- sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
- os_free(sta->ext_capability);
- sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
- if (sta->ext_capability) {
- sta->ext_capability[0] = ext_capab_ie_len;
- os_memcpy(sta->ext_capability + 1, ext_capab_ie,
- ext_capab_ie_len);
- }
- }
-
- return WLAN_STATUS_SUCCESS;
-}
-
-
#ifdef CONFIG_OWE
static int owe_group_supported(struct hostapd_data *hapd, u16 group)
@@ -4203,8 +4191,21 @@
else
return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
- crypto_ecdh_deinit(sta->owe_ecdh);
- sta->owe_ecdh = crypto_ecdh_init(group);
+ if (sta->owe_group == group && sta->owe_ecdh) {
+ /* This is a workaround for mac80211 behavior of retransmitting
+ * the Association Request frames multiple times if the link
+ * layer retries (i.e., seq# remains same) fail. The mac80211
+ * initiated retransmission will use a different seq# and as
+ * such, will go through duplicate detection. If we were to
+ * change our DH key for that attempt, there would be two
+ * different DH shared secrets and the STA would likely select
+ * the wrong one. */
+ wpa_printf(MSG_DEBUG,
+ "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
+ } else {
+ crypto_ecdh_deinit(sta->owe_ecdh);
+ sta->owe_ecdh = crypto_ecdh_init(group);
+ }
if (!sta->owe_ecdh)
return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
sta->owe_group = group;
@@ -4553,6 +4554,17 @@
}
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
+ elems.he_capabilities,
+ elems.he_capabilities_len,
+ elems.eht_capabilities,
+ elems.eht_capabilities_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_P2P
if (elems.p2p) {
@@ -4924,6 +4936,7 @@
struct ieee80211_ht_capabilities ht_cap;
struct ieee80211_vht_capabilities vht_cap;
struct ieee80211_he_capabilities he_cap;
+ struct ieee80211_eht_capabilities eht_cap;
int set = 1;
/*
@@ -4980,6 +4993,11 @@
sta->he_capab_len);
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (sta->flags & WLAN_STA_EHT)
+ hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
+ sta->eht_capab_len);
+#endif /* CONFIG_IEEE80211BE */
/*
* Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
@@ -4993,6 +5011,8 @@
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
sta->flags & WLAN_STA_HE ? &he_cap : NULL,
sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
+ sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
+ sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
sta->he_6ghz_capab,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
@@ -5043,6 +5063,13 @@
if (sta && sta->dpp_pfs)
buflen += 5 + sta->dpp_pfs->curve->prime_len;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
+ buflen += 3 + sizeof(struct ieee80211_eht_operation);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
buf = os_zalloc(buflen);
if (!buf) {
res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -5151,6 +5178,7 @@
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
p = hostapd_eid_he_operation(hapd, p);
+ p = hostapd_eid_cca(hapd, p);
p = hostapd_eid_spatial_reuse(hapd, p);
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
p = hostapd_eid_he_6ghz_band_cap(hapd, p);
@@ -5188,6 +5216,13 @@
rsnxe_done:
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
+ p = hostapd_eid_eht_operation(hapd, p);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
@@ -6903,6 +6938,38 @@
}
+static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count,
+ enum max_tx_pwr_interpretation tx_pwr_intrpn,
+ u8 tx_pwr_cat, u8 tx_pwr)
+{
+ int i;
+
+ *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */
+ *eid++ = 2 + tx_pwr_count; /* Length */
+
+ /*
+ * Transmit Power Information field
+ * bits 0-2 : Maximum Transmit Power Count
+ * bits 3-5 : Maximum Transmit Power Interpretation
+ * bits 6-7 : Maximum Transmit Power Category
+ */
+ *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6);
+
+ /* Maximum Transmit Power field */
+ for (i = 0; i <= tx_pwr_count; i++)
+ *eid++ = tx_pwr;
+
+ return eid;
+}
+
+
+/*
+ * TODO: Extract power limits from channel data after 6G regulatory
+ * support.
+ */
+#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */
+#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */
+
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
{
struct hostapd_iface *iface = hapd->iface;
@@ -6927,6 +6994,43 @@
if (i == mode->num_channels)
return eid;
+#ifdef CONFIG_IEEE80211AX
+ /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United
+ * States): An AP that is an Indoor Access Point per regulatory rules
+ * shall send at least two Transmit Power Envelope elements in Beacon
+ * and Probe Response frames as follows:
+ * - Maximum Transmit Power Category subfield = Default;
+ * Unit interpretation = Regulatory client EIRP PSD
+ * - Maximum Transmit Power Category subfield = Subordinate Device;
+ * Unit interpretation = Regulatory client EIRP PSD
+ */
+ if (is_6ghz_op_class(iconf->op_class)) {
+ enum max_tx_pwr_interpretation tx_pwr_intrpn;
+
+ /* Same Maximum Transmit Power for all 20 MHz bands */
+ tx_pwr_count = 0;
+ tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD;
+
+ /* Default Transmit Power Envelope for Global Operating Class */
+ tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2;
+ eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
+ REG_DEFAULT_CLIENT, tx_pwr);
+
+ /* Indoor Access Point must include an additional TPE for
+ * subordinate devices */
+ if (iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP) {
+ /* TODO: Extract PSD limits from channel data */
+ tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2;
+ eid = hostapd_add_tpe_info(eid, tx_pwr_count,
+ tx_pwr_intrpn,
+ REG_SUBORDINATE_CLIENT,
+ tx_pwr);
+ }
+
+ return eid;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
switch (hostapd_get_oper_chwidth(iconf)) {
case CHANWIDTH_USE_HT:
if (iconf->secondary_channel == 0) {
@@ -6999,19 +7103,9 @@
else
tx_pwr = max_tx_power;
- *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE;
- *eid++ = 2 + tx_pwr_count;
-
- /*
- * Max Transmit Power count and
- * Max Transmit Power units = 0 (EIRP)
- */
- *eid++ = tx_pwr_count;
-
- for (i = 0; i <= tx_pwr_count; i++)
- *eid++ = tx_pwr;
-
- return eid;
+ return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP,
+ 0 /* Reserved for bands other than 6 GHz */,
+ tx_pwr);
}
@@ -7022,7 +7116,8 @@
if (!hapd->cs_freq_params.channel ||
(!hapd->cs_freq_params.vht_enabled &&
- !hapd->cs_freq_params.he_enabled))
+ !hapd->cs_freq_params.he_enabled &&
+ !hapd->cs_freq_params.eht_enabled))
return eid;
/* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index c59ad5e..fa1f47b 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -78,6 +78,10 @@
const struct ieee80211_he_capabilities *he_cap,
struct ieee80211_he_capabilities *neg_he_cap,
size_t he_capab_len);
+void hostapd_get_eht_capab(struct hostapd_data *hapd,
+ const struct ieee80211_eht_capabilities *src,
+ struct ieee80211_eht_capabilities *dest,
+ size_t len);
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab);
@@ -100,6 +104,7 @@
const u8 *he_6ghz_capab);
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
enum ieee80211_op_mode mode);
+u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -194,7 +199,20 @@
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
+u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ext_capab_ie, size_t ext_capab_ie_len);
size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type);
u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type);
+int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+ int res, struct radius_sta *info);
+size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd,
+ enum ieee80211_op_mode opmode);
+u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode);
+u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid);
+u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode,
+ const u8 *he_capab, size_t he_capab_len,
+ const u8 *eht_capab, size_t eht_capab_len);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 783ee6d..4277d82 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,8 @@
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "wpa_auth.h"
#include "ieee802_11.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
@@ -43,6 +45,11 @@
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
size_t auth_msg_len;
struct hostapd_acl_query_data *next;
+ bool radius_psk;
+ int akm;
+ u8 *anonce;
+ u8 *eapol;
+ size_t eapol_len;
};
@@ -95,9 +102,11 @@
static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
{
- if (query == NULL)
+ if (!query)
return;
os_free(query->auth_msg);
+ os_free(query->anonce);
+ os_free(query->eapol);
os_free(query);
}
@@ -111,7 +120,7 @@
query->radius_id = radius_client_get_id(hapd->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
- if (msg == NULL)
+ if (!msg)
return -1;
if (radius_msg_make_authenticator(msg) < 0) {
@@ -153,6 +162,31 @@
goto fail;
}
+ if (query->akm &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
+ wpa_akm_to_suite(query->akm))) {
+ wpa_printf(MSG_DEBUG, "Could not add WLAN-AKM-Suite");
+ goto fail;
+ }
+
+ if (query->anonce &&
+ !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
+ RADIUS_VENDOR_ID_FREERADIUS,
+ RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE,
+ query->anonce, WPA_NONCE_LEN)) {
+ wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-Anonce");
+ goto fail;
+ }
+
+ if (query->eapol &&
+ !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
+ RADIUS_VENDOR_ID_FREERADIUS,
+ RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG,
+ query->eapol, query->eapol_len)) {
+ wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-EAPoL-Key-Msg");
+ goto fail;
+ }
+
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
goto fail;
return 0;
@@ -260,23 +294,23 @@
/* No entry in the cache - query external RADIUS server */
query = os_zalloc(sizeof(*query));
- if (query == NULL) {
+ if (!query) {
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
os_get_reltime(&query->timestamp);
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
- wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
- "for ACL query.");
+ wpa_printf(MSG_DEBUG,
+ "Failed to send Access-Request for ACL query.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
query->auth_msg = os_memdup(msg, len);
- if (query->auth_msg == NULL) {
- wpa_printf(MSG_ERROR, "Failed to allocate memory for "
- "auth frame.");
+ if (!query->auth_msg) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate memory for auth frame.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
@@ -392,7 +426,7 @@
* Passphrase is NULL iff there is no i-th Tunnel-Password
* attribute in msg.
*/
- if (passphrase == NULL)
+ if (!passphrase)
break;
/*
@@ -464,28 +498,30 @@
prev = query;
query = query->next;
}
- if (query == NULL)
+ if (!query)
return RADIUS_RX_UNKNOWN;
- wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
- "message (id=%d)", query->radius_id);
+ wpa_printf(MSG_DEBUG,
+ "Found matching Access-Request for RADIUS message (id=%d)",
+ query->radius_id);
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
- wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
- "correct authenticator - dropped\n");
+ wpa_printf(MSG_INFO,
+ "Incoming RADIUS packet did not have correct authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
hdr->code != RADIUS_CODE_ACCESS_REJECT) {
- wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
- "query", hdr->code);
+ wpa_printf(MSG_DEBUG,
+ "Unknown RADIUS message code %d to ACL query",
+ hdr->code);
return RADIUS_RX_UNKNOWN;
}
/* Insert Accept/Reject info into ACL cache */
cache = os_zalloc(sizeof(*cache));
- if (cache == NULL) {
+ if (!cache) {
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
@@ -506,8 +542,9 @@
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
&info->acct_interim_interval) == 0 &&
info->acct_interim_interval < 60) {
- wpa_printf(MSG_DEBUG, "Ignored too small "
- "Acct-Interim-Interval %d for STA " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "Ignored too small Acct-Interim-Interval %d for STA "
+ MACSTR,
info->acct_interim_interval,
MAC2STR(query->addr));
info->acct_interim_interval = 0;
@@ -557,20 +594,43 @@
cache->next = hapd->acl_cache;
hapd->acl_cache = cache;
+ if (query->radius_psk) {
+ struct sta_info *sta;
+ bool success = cache->accepted == HOSTAPD_ACL_ACCEPT;
+
+ sta = ap_get_sta(hapd, query->addr);
+ if (!sta || !sta->wpa_sm) {
+ wpa_printf(MSG_DEBUG,
+ "No STA/SM entry found for the RADIUS PSK response");
+ goto done;
+ }
+#ifdef NEED_AP_MLME
+ if (success &&
+ (ieee802_11_set_radius_info(hapd, sta, cache->accepted,
+ info) < 0 ||
+ ap_sta_bind_vlan(hapd, sta) < 0))
+ success = false;
+#endif /* NEED_AP_MLME */
+ wpa_auth_sta_radius_psk_resp(sta->wpa_sm, success);
+ } else {
#ifdef CONFIG_DRIVER_RADIUS_ACL
- hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
- info->session_timeout);
+ hostapd_drv_set_radius_acl_auth(hapd, query->addr,
+ cache->accepted,
+ info->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
- /* Re-send original authentication frame for 802.11 processing */
- wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
- "successful RADIUS ACL query");
- ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
+ /* Re-send original authentication frame for 802.11 processing
+ */
+ wpa_printf(MSG_DEBUG,
+ "Re-sending authentication frame after successful RADIUS ACL query");
+ ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
+ NULL);
#endif /* NEED_AP_MLME */
#endif /* CONFIG_DRIVER_RADIUS_ACL */
+ }
done:
- if (prev == NULL)
+ if (!prev)
hapd->acl_queries = query->next;
else
prev->next = query->next;
@@ -646,6 +706,40 @@
while (psk) {
struct hostapd_sta_wpa_psk_short *prev = psk;
psk = psk->next;
- os_free(prev);
+ bin_clear_free(prev, sizeof(*prev));
}
}
+
+
+#ifndef CONFIG_NO_RADIUS
+void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
+ int key_mgmt, const u8 *anonce,
+ const u8 *eapol, size_t eapol_len)
+{
+ struct hostapd_acl_query_data *query;
+
+ query = os_zalloc(sizeof(*query));
+ if (!query)
+ return;
+
+ query->radius_psk = true;
+ query->akm = key_mgmt;
+ os_get_reltime(&query->timestamp);
+ os_memcpy(query->addr, addr, ETH_ALEN);
+ if (anonce)
+ query->anonce = os_memdup(anonce, WPA_NONCE_LEN);
+ if (eapol) {
+ query->eapol = os_memdup(eapol, eapol_len);
+ query->eapol_len = eapol_len;
+ }
+ if (hostapd_radius_acl_query(hapd, addr, query)) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to send Access-Request for RADIUS PSK/ACL query");
+ hostapd_acl_query_free(query);
+ return;
+ }
+
+ query->next = hapd->acl_queries;
+ hapd->acl_queries = query;
+}
+#endif /* CONFIG_NO_RADIUS */
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 9410f55..22ae1a9 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -36,5 +36,8 @@
void hostapd_acl_expire(struct hostapd_data *hapd);
void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
struct hostapd_sta_wpa_psk_short *src);
+void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
+ int key_mgmt, const u8 *anonce,
+ const u8 *eapol, size_t eapol_len);
#endif /* IEEE802_11_AUTH_H */
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
new file mode 100644
index 0000000..dbbf9a6
--- /dev/null
+++ b/src/ap/ieee802_11_eht.c
@@ -0,0 +1,353 @@
+/*
+ * hostapd / IEEE 802.11be EHT
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ieee802_11.h"
+
+
+static u16 ieee80211_eht_ppet_size(u16 ppe_thres_hdr, const u8 *phy_cap_info)
+{
+ u8 ru;
+ u16 sz = 0;
+
+ if ((phy_cap_info[EHT_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] &
+ EHT_PHYCAP_PPE_THRESHOLD_PRESENT) == 0)
+ return 0;
+
+ ru = (ppe_thres_hdr &
+ EHT_PPE_THRES_RU_INDEX_MASK) >> EHT_PPE_THRES_RU_INDEX_SHIFT;
+ while (ru) {
+ if (ru & 0x1)
+ sz++;
+ ru >>= 1;
+ }
+
+ sz = sz * (1 + ((ppe_thres_hdr & EHT_PPE_THRES_NSS_MASK) >>
+ EHT_PPE_THRES_NSS_SHIFT));
+ sz = (sz * 6) + 9;
+ if (sz % 8)
+ sz += 8;
+ sz /= 8;
+
+ return sz;
+}
+
+
+static u8 ieee80211_eht_mcs_set_size(const u8 *he_phy_cap,
+ const u8 *eht_phy_cap)
+{
+ u8 sz = EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+
+ if ((he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0)
+ return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY;
+
+ if (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))
+ sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+
+ if (eht_phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)
+ sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+
+ return sz;
+}
+
+
+size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd,
+ enum ieee80211_op_mode opmode)
+{
+ struct hostapd_hw_modes *mode;
+ struct eht_capabilities *eht_cap;
+ size_t len = 3 + 2 + EHT_PHY_CAPAB_LEN;
+
+ mode = hapd->iface->current_mode;
+ if (!mode)
+ return 0;
+
+ eht_cap = &mode->eht_capab[opmode];
+ if (!eht_cap->eht_supported)
+ return 0;
+
+ len += ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+ eht_cap->phy_cap);
+ len += ieee80211_eht_ppet_size(WPA_GET_LE16(&eht_cap->ppet[0]),
+ eht_cap->phy_cap);
+
+ return len;
+}
+
+
+u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode)
+{
+ struct hostapd_hw_modes *mode;
+ struct eht_capabilities *eht_cap;
+ struct ieee80211_eht_capabilities *cap;
+ size_t mcs_nss_len, ppe_thresh_len;
+ u8 *pos = eid, *length_pos;
+
+ mode = hapd->iface->current_mode;
+ if (!mode)
+ return eid;
+
+ eht_cap = &mode->eht_capab[opmode];
+ if (!eht_cap->eht_supported)
+ return eid;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ length_pos = pos++;
+ *pos++ = WLAN_EID_EXT_EHT_CAPABILITIES;
+
+ cap = (struct ieee80211_eht_capabilities *) pos;
+ os_memset(cap, 0, sizeof(*cap));
+ cap->mac_cap = host_to_le16(eht_cap->mac_cap);
+ os_memcpy(cap->phy_cap, eht_cap->phy_cap, EHT_PHY_CAPAB_LEN);
+
+ if (!is_6ghz_op_class(hapd->iconf->op_class))
+ cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &=
+ ~EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK;
+ if (!hapd->iface->conf->eht_phy_capab.su_beamformer)
+ cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMER_IDX] &=
+ ~EHT_PHYCAP_SU_BEAMFORMER;
+
+ if (!hapd->iface->conf->eht_phy_capab.su_beamformee)
+ cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMEE_IDX] &=
+ ~EHT_PHYCAP_SU_BEAMFORMEE;
+
+ if (!hapd->iface->conf->eht_phy_capab.mu_beamformer)
+ cap->phy_cap[EHT_PHYCAP_MU_BEAMFORMER_IDX] &=
+ ~EHT_PHYCAP_MU_BEAMFORMER_MASK;
+
+ pos = cap->optional;
+
+ mcs_nss_len = ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+ eht_cap->phy_cap);
+ if (mcs_nss_len) {
+ os_memcpy(pos, eht_cap->mcs, mcs_nss_len);
+ pos += mcs_nss_len;
+ }
+
+ ppe_thresh_len = ieee80211_eht_ppet_size(
+ WPA_GET_LE16(&eht_cap->ppet[0]),
+ eht_cap->phy_cap);
+ if (ppe_thresh_len) {
+ os_memcpy(pos, eht_cap->ppet, ppe_thresh_len);
+ pos += ppe_thresh_len;
+ }
+
+ *length_pos = pos - (eid + 2);
+ return pos;
+}
+
+
+u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+ struct hostapd_config *conf = hapd->iconf;
+ struct ieee80211_eht_operation *oper;
+ u8 *pos = eid, chwidth, seg0 = 0, seg1 = 0;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 5;
+ *pos++ = WLAN_EID_EXT_EHT_OPERATION;
+
+ oper = (struct ieee80211_eht_operation *) pos;
+ oper->oper_params = EHT_OPER_INFO_PRESENT;
+
+ if (is_6ghz_op_class(conf->op_class))
+ chwidth = op_class_to_ch_width(conf->op_class);
+ else
+ chwidth = conf->eht_oper_chwidth;
+
+ seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf);
+
+ switch (chwidth) {
+#if 0 /* FIX: Need to clean up CHANWIDTH_* use for protocol vs. internal
+ * needs to be able to define this. */
+ case CHANWIDTH_320MHZ:
+ oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_320MHZ;
+ seg1 = seg0;
+ if (hapd->iconf->channel < seg0)
+ seg0 -= 16;
+ else
+ seg0 += 16;
+ break;
+#endif
+ case CHANWIDTH_160MHZ:
+ oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ;
+ seg1 = seg0;
+ if (hapd->iconf->channel < seg0)
+ seg0 -= 8;
+ else
+ seg0 += 8;
+ break;
+ case CHANWIDTH_80MHZ:
+ oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_80MHZ;
+ break;
+ case CHANWIDTH_USE_HT:
+ if (seg0)
+ oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_40MHZ;
+ break;
+ default:
+ return eid;
+ }
+
+ oper->oper_info.ccfs0 = seg0 ? seg0 : hapd->iconf->channel;
+ oper->oper_info.ccfs1 = seg1;
+
+ return pos + 4;
+}
+
+
+static bool check_valid_eht_mcs_nss(struct hostapd_data *hapd, const u8 *ap_mcs,
+ const u8 *sta_mcs, u8 mcs_count, u8 map_len)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < mcs_count; i++) {
+ ap_mcs += i * 3;
+ sta_mcs += i * 3;
+
+ for (j = 0; j < map_len; j++) {
+ if (((ap_mcs[j] >> 4) & 0xFF) == 0)
+ continue;
+
+ if ((sta_mcs[j] & 0xFF) == 0)
+ continue;
+
+ return true;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "No matching EHT MCS found between AP TX and STA RX");
+ return false;
+}
+
+
+static bool check_valid_eht_mcs(struct hostapd_data *hapd,
+ const u8 *sta_eht_capab,
+ enum ieee80211_op_mode opmode)
+{
+ struct hostapd_hw_modes *mode;
+ const struct ieee80211_eht_capabilities *capab;
+ const u8 *ap_mcs, *sta_mcs;
+ u8 mcs_count = 1;
+
+ mode = hapd->iface->current_mode;
+ if (!mode)
+ return true;
+
+ ap_mcs = mode->eht_capab[opmode].mcs;
+ capab = (const struct ieee80211_eht_capabilities *) sta_eht_capab;
+ sta_mcs = capab->optional;
+
+ if (ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+ mode->eht_capab[opmode].phy_cap) ==
+ EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY)
+ return check_valid_eht_mcs_nss(
+ hapd, ap_mcs, sta_mcs, 1,
+ EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY);
+
+ switch (hapd->iface->conf->eht_oper_chwidth) {
+ /* TODO: CHANWIDTH_320MHZ */
+ case CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_160MHZ:
+ mcs_count = 2;
+ break;
+ }
+
+ return check_valid_eht_mcs_nss(hapd, ap_mcs, sta_mcs, mcs_count,
+ EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS);
+}
+
+
+static bool ieee80211_invalid_eht_cap_size(const u8 *he_cap, const u8 *eht_cap,
+ size_t len)
+{
+ const struct ieee80211_he_capabilities *he_capab;
+ struct ieee80211_eht_capabilities *cap;
+ const u8 *he_phy_cap;
+ size_t cap_len;
+ u16 ppe_thres_hdr;
+
+ he_capab = (const struct ieee80211_he_capabilities *) he_cap;
+ he_phy_cap = he_capab->he_phy_capab_info;
+ cap = (struct ieee80211_eht_capabilities *) eht_cap;
+ cap_len = sizeof(*cap) - sizeof(cap->optional);
+ if (len < cap_len)
+ return true;
+
+ cap_len += ieee80211_eht_mcs_set_size(he_phy_cap, cap->phy_cap);
+ if (len < cap_len)
+ return true;
+
+ ppe_thres_hdr = len > cap_len + 1 ?
+ WPA_GET_LE16(&eht_cap[cap_len]) : 0x01ff;
+ cap_len += ieee80211_eht_ppet_size(ppe_thres_hdr, cap->phy_cap);
+
+ return len < cap_len;
+}
+
+
+u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode,
+ const u8 *he_capab, size_t he_capab_len,
+ const u8 *eht_capab, size_t eht_capab_len)
+{
+ if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be ||
+ !he_capab || he_capab_len < IEEE80211_HE_CAPAB_MIN_LEN ||
+ !eht_capab ||
+ ieee80211_invalid_eht_cap_size(he_capab, eht_capab,
+ eht_capab_len) ||
+ !check_valid_eht_mcs(hapd, eht_capab, opmode)) {
+ sta->flags &= ~WLAN_STA_EHT;
+ os_free(sta->eht_capab);
+ sta->eht_capab = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ os_free(sta->eht_capab);
+ sta->eht_capab = os_memdup(eht_capab, eht_capab_len);
+ if (!sta->eht_capab) {
+ sta->eht_capab_len = 0;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_EHT;
+ sta->eht_capab_len = eht_capab_len;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+void hostapd_get_eht_capab(struct hostapd_data *hapd,
+ const struct ieee80211_eht_capabilities *src,
+ struct ieee80211_eht_capabilities *dest,
+ size_t len)
+{
+ if (!src || !dest)
+ return;
+
+ if (len > sizeof(*dest))
+ len = sizeof(*dest);
+ /* TODO: mask out unsupported features */
+
+ os_memset(dest, 0, sizeof(*dest));
+ os_memcpy(dest, src, len);
+}
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 6cd6c90..1e74c58 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -29,17 +29,19 @@
ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) &
HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
+ /* Count the number of 1 bits in RU Index Bitmask */
while (ru) {
if (ru & 0x1)
sz++;
ru >>= 1;
}
+ /* fixed header of 3 (NSTS) + 4 (RU Index Bitmask) = 7 bits */
+ /* 6 * (NSTS + 1) bits for bit 1 in RU Index Bitmask */
sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
sz = (sz * 6) + 7;
- if (sz % 8)
- sz += 8;
- sz /= 8;
+ /* PPE Pad to count the number of needed full octets */
+ sz = (sz + 7) / 8;
return sz;
}
@@ -64,6 +66,7 @@
{
struct ieee80211_he_capabilities *cap;
size_t cap_len;
+ u8 ppe_thres_hdr;
cap = (struct ieee80211_he_capabilities *) buf;
cap_len = sizeof(*cap) - sizeof(cap->optional);
@@ -74,9 +77,11 @@
if (len < cap_len)
return 1;
- cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
+ ppe_thres_hdr = len > cap_len ? buf[cap_len] : 0xff;
+ cap_len += ieee80211_he_ppet_size(ppe_thres_hdr,
+ cap->he_phy_capab_info);
- return len != cap_len;
+ return len < cap_len;
}
@@ -195,7 +200,8 @@
if (hapd->iface->conf->he_op.he_er_su_disable)
params |= HE_OPERATION_ER_SU_DISABLE;
- if (hapd->iface->conf->he_op.he_bss_color_disabled)
+ if (hapd->iface->conf->he_op.he_bss_color_disabled ||
+ hapd->cca_in_progress)
params |= HE_OPERATION_BSS_COLOR_DISABLED;
if (hapd->iface->conf->he_op.he_bss_color_partial)
params |= HE_OPERATION_BSS_COLOR_PARTIAL;
@@ -213,6 +219,7 @@
if (is_6ghz_op_class(hapd->iconf->op_class)) {
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
+ u8 control;
if (!seg0)
seg0 = hapd->iconf->channel;
@@ -220,16 +227,28 @@
params |= HE_OPERATION_6GHZ_OPER_INFO;
/* 6 GHz Operation Information field
- * IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element,
+ * IEEE Std 802.11ax-2021, 9.4.2.249 HE Operation element,
* Figure 9-788k
*/
*pos++ = hapd->iconf->channel; /* Primary Channel */
- /* Control: Channel Width */
+ /* Control:
+ * bits 0-1: Channel Width
+ * bit 2: Duplicate Beacon
+ * bits 3-5: Regulatory Info
+ */
+ /* Channel Width */
if (seg1)
- *pos++ = 3;
+ control = 3;
else
- *pos++ = center_idx_to_bw_6ghz(seg0);
+ control = center_idx_to_bw_6ghz(seg0);
+ if (hapd->iconf->he_6ghz_reg_pwr_type == 1)
+ control |= HE_6GHZ_STANDARD_POWER_AP <<
+ HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT;
+ else
+ control |= HE_6GHZ_INDOOR_AP <<
+ HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT;
+ *pos++ = control;
/* Channel Center Freq Seg0/Seg1 */
if (hapd->iconf->he_oper_chwidth == 2) {
@@ -520,3 +539,19 @@
return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) &&
hapd->iface->conf->he_op.he_twt_responder;
}
+
+
+u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid)
+{
+ if (!hapd->cca_in_progress)
+ return eid;
+
+ /* BSS Color Change Announcement element */
+ *eid++ = WLAN_EID_EXTENSION;
+ *eid++ = 3;
+ *eid++ = WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT;
+ *eid++ = hapd->cca_count; /* Color Switch Countdown */
+ *eid++ = hapd->cca_color; /* New BSS Color Information */
+
+ return eid;
+}
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 4bff9e5..6154895 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -1093,3 +1093,29 @@
return pos;
}
+
+
+u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ext_capab_ie, size_t ext_capab_ie_len)
+{
+#ifdef CONFIG_INTERWORKING
+ /* check for QoS Map support */
+ if (ext_capab_ie_len >= 5) {
+ if (ext_capab_ie[4] & 0x01)
+ sta->qos_map_enabled = 1;
+ }
+#endif /* CONFIG_INTERWORKING */
+
+ if (ext_capab_ie_len > 0) {
+ sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
+ os_free(sta->ext_capability);
+ sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
+ if (sta->ext_capability) {
+ sta->ext_capability[0] = ext_capab_ie_len;
+ os_memcpy(sta->ext_capability + 1, ext_capab_ie,
+ ext_capab_ie_len);
+ }
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 753c883..fb5e920 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -2448,6 +2448,9 @@
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
conf.erp_domain = hapd->conf->erp_domain;
+#ifdef CONFIG_TESTING_OPTIONS
+ conf.eap_skip_prot_success = hapd->conf->eap_skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
os_memset(&cb, 0, sizeof(cb));
cb.eapol_send = ieee802_1x_eapol_send;
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 229edd2..e37324f 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -225,6 +225,7 @@
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
+ bool eht = he && hapd->iconf->ieee80211be && !hapd->conf->disable_11be;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
@@ -260,10 +261,12 @@
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
if (vht)
bssid_info |= NEI_REP_BSSID_INFO_VHT;
- if (he)
- bssid_info |= NEI_REP_BSSID_INFO_HE;
}
+ if (he)
+ bssid_info |= NEI_REP_BSSID_INFO_HE;
+ if (eht)
+ bssid_info |= NEI_REP_BSSID_INFO_EHT;
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index ccd1ed9..c541926 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -358,6 +358,7 @@
os_free(sta->vht_operation);
os_free(sta->he_capab);
os_free(sta->he_6ghz_capab);
+ os_free(sta->eht_capab);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@@ -410,6 +411,7 @@
#ifdef CONFIG_TESTING_OPTIONS
os_free(sta->sae_postponed_commit);
+ forced_memzero(sta->last_tk, WPA_TK_MAX_LEN);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(sta);
@@ -1251,8 +1253,6 @@
for (psk = ssid->wpa_psk; psk; psk = psk->next)
if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
break;
- if (!psk)
- return NULL;
if (!psk || !psk->keyid[0])
return NULL;
@@ -1461,7 +1461,7 @@
buf[0] = '\0';
res = os_snprintf(buf, buflen,
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1481,6 +1481,7 @@
(flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
(flags & WLAN_STA_HE ? "[HE]" : ""),
+ (flags & WLAN_STA_EHT ? "[EHT]" : ""),
(flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
@@ -1553,7 +1554,7 @@
if (hostapd_sta_add(hapd, sta->addr, 0, 0,
sta->supported_rates,
sta->supported_rates_len,
- 0, NULL, NULL, NULL, 0, NULL,
+ 0, NULL, NULL, NULL, 0, NULL, 0, NULL,
sta->flags, 0, 0, 0, 0)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 27e72f9..af8f171 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -42,6 +42,7 @@
#define WLAN_STA_HE BIT(24)
#define WLAN_STA_6GHZ BIT(25)
#define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
+#define WLAN_STA_EHT BIT(27)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -213,6 +214,8 @@
struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
+ struct ieee80211_eht_capabilities *eht_capab;
+ size_t eht_capab_len;
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 0042ed6..23a352c 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -409,6 +409,8 @@
u8 dialog_token, reason;
const u8 *pos, *end;
int enabled = hapd->conf->bss_transition;
+ char *hex = NULL;
+ size_t hex_len;
#ifdef CONFIG_MBO
if (hapd->conf->mbo_enabled)
@@ -441,6 +443,17 @@
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
+ hex_len = 2 * (end - pos) + 1;
+ if (hex_len > 1) {
+ hex = os_malloc(hex_len);
+ if (hex)
+ wpa_snprintf_hex(hex, hex_len, pos, end - pos);
+ }
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ BSS_TM_QUERY MACSTR " reason=%u%s%s",
+ MAC2STR(addr), reason, hex ? " neighbor=" : "", hex);
+ os_free(hex);
+
ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
}
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index bb7ee25..ad91883 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -607,7 +607,7 @@
while (group) {
prev = group;
group = group->next;
- os_free(prev);
+ bin_clear_free(prev, sizeof(*prev));
}
os_free(wpa_auth);
@@ -1485,6 +1485,12 @@
struct wpa_authenticator *wpa_auth = eloop_ctx;
struct wpa_state_machine *sm = timeout_ctx;
+ if (sm->waiting_radius_psk) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "Ignore EAPOL-Key timeout while waiting for RADIUS PSK");
+ return;
+ }
+
sm->pending_1_of_4_timeout = 0;
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
sm->TimeoutEvt = true;
@@ -1646,7 +1652,7 @@
if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
(key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
- os_free(buf);
+ bin_clear_free(buf, key_data_len);
return;
}
WPA_PUT_BE16(key_mic + mic_len, key_data_len);
@@ -1667,10 +1673,10 @@
#endif /* CONFIG_NO_RC4 */
} else {
os_free(hdr);
- os_free(buf);
+ bin_clear_free(buf, key_data_len);
return;
}
- os_free(buf);
+ bin_clear_free(buf, key_data_len);
}
if (key_info & WPA_KEY_INFO_MIC) {
@@ -1823,9 +1829,9 @@
case WPA_DEAUTH:
case WPA_DISASSOC:
sm->DeauthenticationRequest = true;
-#ifdef CONFIG_IEEE80211R_AP
os_memset(sm->PMK, 0, sizeof(sm->PMK));
sm->pmk_len = 0;
+#ifdef CONFIG_IEEE80211R_AP
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
sm->xxkey_len = 0;
os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
@@ -1853,6 +1859,14 @@
break;
}
+ if (sm->ptkstart_without_success > 3) {
+ wpa_printf(MSG_INFO,
+ "WPA: Multiple EAP reauth attempts without 4-way handshake completion, disconnect "
+ MACSTR, MAC2STR(sm->addr));
+ sm->Disconnect = true;
+ break;
+ }
+
if (!sm->use_ext_key_id &&
sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
wpa_printf(MSG_INFO,
@@ -2195,6 +2209,7 @@
sm->PTKRequest = false;
sm->TimeoutEvt = false;
sm->alt_snonce_valid = false;
+ sm->ptkstart_without_success++;
sm->TimeoutCtr++;
if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
@@ -3026,6 +3041,19 @@
break;
}
+ if (!ok && wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
+ wpa_auth->conf.radius_psk && wpa_auth->cb->request_radius_psk &&
+ !sm->waiting_radius_psk) {
+ wpa_printf(MSG_DEBUG, "No PSK available - ask RADIUS server");
+ wpa_auth->cb->request_radius_psk(wpa_auth->cb_ctx, sm->addr,
+ sm->wpa_key_mgmt,
+ sm->ANonce,
+ sm->last_rx_eapol_key,
+ sm->last_rx_eapol_key_len);
+ sm->waiting_radius_psk = 1;
+ return;
+ }
+
if (!ok) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"invalid MIC in msg 2/4 of 4-Way Handshake");
@@ -3279,6 +3307,7 @@
pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
(const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
NULL, 0);
+ forced_memzero(&igtk, sizeof(igtk));
if (!conf->beacon_prot)
return pos;
@@ -3302,6 +3331,7 @@
pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
(const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
NULL, 0);
+ forced_memzero(&bigtk, sizeof(bigtk));
return pos;
}
@@ -3382,7 +3412,7 @@
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, stub_gtk[32];
- size_t gtk_len, kde_len, wpa_ie_len;
+ size_t gtk_len, kde_len = 0, wpa_ie_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
int secure, gtkidx, encr = 0;
@@ -3640,7 +3670,7 @@
WPA_KEY_INFO_KEY_TYPE,
_rsc, sm->ANonce, kde, pos - kde, 0, encr);
done:
- os_free(kde);
+ bin_clear_free(kde, kde_len);
os_free(wpa_ie_buf);
os_free(wpa_ie_buf2);
}
@@ -3709,6 +3739,8 @@
#ifdef CONFIG_IEEE80211R_AP
wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
#endif /* CONFIG_IEEE80211R_AP */
+
+ sm->ptkstart_without_success = 0;
}
@@ -3783,6 +3815,11 @@
} else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
SM_ENTER(WPA_PTK, PTKSTART);
#endif /* CONFIG_SAE */
+ } else if (wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
+ wpa_auth->conf.radius_psk) {
+ wpa_printf(MSG_DEBUG,
+ "INITPSK: No PSK yet available for STA - use RADIUS later");
+ SM_ENTER(WPA_PTK, PTKSTART);
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"no PSK configured for the STA");
@@ -3861,7 +3898,7 @@
struct wpa_group *gsm = sm->group;
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
- size_t kde_len;
+ size_t kde_len = 0;
u8 *gtk, stub_gtk[32];
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
@@ -3930,7 +3967,7 @@
(!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
rsc, NULL, kde, kde_len, gsm->GN, 1);
- os_free(kde_buf);
+ bin_clear_free(kde_buf, kde_len);
}
@@ -5572,7 +5609,7 @@
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
_rsc, sm->ANonce, kde, pos - kde, 0, encr);
- os_free(kde);
+ bin_clear_free(kde, kde_len);
return 0;
}
@@ -5640,7 +5677,7 @@
(!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
rsc, NULL, kde, kde_len, gsm->GN, 1);
- os_free(kde_buf);
+ bin_clear_free(kde_buf, kde_len);
return 0;
}
@@ -5711,3 +5748,28 @@
#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success)
+{
+ if (!sm->waiting_radius_psk) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore RADIUS PSK response for " MACSTR
+ " that did not wait one",
+ MAC2STR(sm->addr));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RADIUS PSK response for " MACSTR " (%s)",
+ MAC2STR(sm->addr), success ? "success" : "fail");
+ sm->waiting_radius_psk = 0;
+
+ if (success) {
+ /* Try to process the EAPOL-Key msg 2/4 again */
+ sm->EAPOLKeyReceived = true;
+ } else {
+ sm->Disconnect = true;
+ }
+
+ eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 8f0b5a7..348a1de 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -275,6 +275,8 @@
* PTK derivation regardless of advertised capabilities.
*/
bool force_kdk_derivation;
+
+ bool radius_psk;
};
typedef enum {
@@ -322,6 +324,9 @@
void (*store_ptksa)(void *ctx, const u8 *addr, int cipher,
u32 life_time, const struct wpa_ptk *ptk);
void (*clear_ptksa)(void *ctx, const u8 *addr, int cipher);
+ void (*request_radius_psk)(void *ctx, const u8 *addr, int key_mgmt,
+ const u8 *anonce,
+ const u8 *eapol, size_t eapol_len);
#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
@@ -578,4 +583,6 @@
void wpa_auth_set_enable_eapol_large_timeout(struct wpa_authenticator *wpa_auth,
u8 val);
+void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success);
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index fef1104..7a97613 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2240,6 +2240,7 @@
wpa_printf(MSG_DEBUG,
"FT: GTK subelem encryption failed: kek_len=%d",
(int) kek_len);
+ forced_memzero(keybuf, sizeof(keybuf));
os_free(subelem);
return NULL;
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 9e88ea3..9e8dae1 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1,6 +1,6 @@
/*
* hostapd / WPA authenticator glue code
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,6 +29,7 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "ieee802_11.h"
+#include "ieee802_11_auth.h"
#include "pmksa_cache_auth.h"
#include "wpa_auth.h"
#include "wpa_auth_glue.h"
@@ -216,6 +217,8 @@
wconf->force_kdk_derivation = conf->force_kdk_derivation;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_PASN */
+
+ wconf->radius_psk = conf->wpa_psk_radius == PSK_RADIUS_DURING_4WAY_HS;
}
@@ -390,10 +393,14 @@
psk = sta->psk->psk;
for (pos = sta->psk; pos; pos = pos->next) {
if (pos->is_passphrase) {
- pbkdf2_sha1(pos->passphrase,
- hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len, 4096,
- pos->psk, PMK_LEN);
+ if (pbkdf2_sha1(pos->passphrase,
+ hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len, 4096,
+ pos->psk, PMK_LEN) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Error in pbkdf2_sha1()");
+ continue;
+ }
pos->is_passphrase = 0;
}
if (pos->psk == prev_psk) {
@@ -1445,6 +1452,23 @@
#endif /* CONFIG_IEEE80211R_AP */
+#ifndef CONFIG_NO_RADIUS
+static void hostapd_request_radius_psk(void *ctx, const u8 *addr, int key_mgmt,
+ const u8 *anonce,
+ const u8 *eapol, size_t eapol_len)
+{
+ struct hostapd_data *hapd = ctx;
+
+ wpa_printf(MSG_DEBUG, "RADIUS PSK request for " MACSTR " key_mgmt=0x%x",
+ MAC2STR(addr), key_mgmt);
+ wpa_hexdump(MSG_DEBUG, "ANonce", anonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAPOL", eapol, eapol_len);
+ hostapd_acl_req_radius_psk(hapd, addr, key_mgmt, anonce, eapol,
+ eapol_len);
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
int hostapd_setup_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config _conf;
@@ -1488,6 +1512,9 @@
.set_session_timeout = hostapd_wpa_auth_set_session_timeout,
.get_session_timeout = hostapd_wpa_auth_get_session_timeout,
#endif /* CONFIG_IEEE80211R_AP */
+#ifndef CONFIG_NO_RADIUS
+ .request_radius_psk = hostapd_request_radius_psk,
+#endif /* CONFIG_NO_RADIUS */
};
const u8 *wpa_ie;
size_t wpa_ie_len;
@@ -1633,4 +1660,10 @@
hapd->l2 = NULL;
hostapd_wpa_unregister_ft_oui(hapd);
#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ forced_memzero(hapd->last_gtk, WPA_GTK_MAX_LEN);
+ forced_memzero(hapd->last_igtk, WPA_IGTK_MAX_LEN);
+ forced_memzero(hapd->last_bigtk, WPA_BIGTK_MAX_LEN);
+#endif /* CONFIG_TESTING_OPTIONS */
}
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index a6dc1a5..17cb5a2 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -89,6 +89,7 @@
unsigned int rx_eapol_key_secure:1;
unsigned int update_snonce:1;
unsigned int alt_snonce_valid:1;
+ unsigned int waiting_radius_psk:1;
#ifdef CONFIG_IEEE80211R_AP
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
@@ -96,6 +97,8 @@
unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1;
+ unsigned int ptkstart_without_success;
+
#ifdef CONFIG_OCV
int ocv_enabled;
#endif /* CONFIG_OCV */
diff --git a/src/ap/wpa_auth_kay.c b/src/ap/wpa_auth_kay.c
index 46d94b4..e2c4e10 100644
--- a/src/ap/wpa_auth_kay.c
+++ b/src/ap/wpa_auth_kay.c
@@ -138,7 +138,6 @@
switch (co) {
case CONFIDENTIALITY_OFFSET_30:
return 30;
- break;
case CONFIDENTIALITY_OFFSET_50:
return 50;
default:
@@ -329,7 +328,9 @@
hapd->conf->macsec_replay_protect,
hapd->conf->macsec_replay_window,
hapd->conf->macsec_port,
- hapd->conf->mka_priority, hapd->conf->iface,
+ hapd->conf->mka_priority,
+ hapd->conf->macsec_csindex,
+ hapd->conf->iface,
hapd->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
if (!res)
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 4f1c76b..aacfa33 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1069,10 +1069,11 @@
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
wpabuf_free(wps->dev.vendor_ext[i]);
wps_device_data_free(&wps->dev);
- os_free(wps->network_key);
+ bin_clear_free(wps->network_key, wps->network_key_len);
hostapd_wps_nfc_clear(wps);
wpabuf_free(wps->dh_pubkey);
wpabuf_free(wps->dh_privkey);
+ forced_memzero(wps->psk, sizeof(wps->psk));
os_free(wps);
}
diff --git a/src/common/brcm_vendor.h b/src/common/brcm_vendor.h
index d77b007..c1f5807 100644
--- a/src/common/brcm_vendor.h
+++ b/src/common/brcm_vendor.h
@@ -40,15 +40,15 @@
* @BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS: Set some connect parameters.
* Used for the case that FW handle SAE.
*
- * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP paramters.
+ * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP parameters.
* Used for the case that FW handle SAE.
*
* @BRCM_VENDOR_SCMD_ACS: ACS command/event which is used to
* invoke the ACS function in device and pass selected channels to
* hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
*
- * @BRCM_VENDOR_SCMD_MAX: This acts as a the tail of cmds list.
- * Make sure it located at the end of the list.
+ * @BRCM_VENDOR_SCMD_MAX: This acts as a tail of cmds list.
+ * Make sure it is located at the end of the list.
*
*/
enum brcm_nl80211_vendor_subcmds {
@@ -67,7 +67,7 @@
};
/**
- * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers
+ * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchronous event identifiers
*
* @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0
*
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 42a9302..cc26b80 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -345,12 +345,36 @@
}
+static int dpp_parse_uri_supported_curves(struct dpp_bootstrap_info *bi,
+ const char *txt)
+{
+ int val;
+
+ if (!txt)
+ return 0;
+
+ val = hex2num(txt[0]);
+ if (val < 0)
+ return -1;
+ bi->supported_curves = val;
+
+ val = hex2num(txt[1]);
+ if (val > 0)
+ bi->supported_curves |= val << 4;
+
+ wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
+ bi->supported_curves);
+
+ return 0;
+}
+
+
static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
{
const char *pos = uri;
const char *end;
const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
- const char *version = NULL;
+ const char *version = NULL, *supported_curves = NULL;
struct dpp_bootstrap_info *bi;
wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
@@ -383,6 +407,8 @@
pk = pos + 2;
else if (pos[0] == 'V' && pos[1] == ':' && !version)
version = pos + 2;
+ else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves)
+ supported_curves = pos + 2;
else
wpa_hexdump_ascii(MSG_DEBUG,
"DPP: Ignore unrecognized URI parameter",
@@ -404,6 +430,7 @@
dpp_parse_uri_mac(bi, mac) < 0 ||
dpp_parse_uri_info(bi, info) < 0 ||
dpp_parse_uri_version(bi, version) < 0 ||
+ dpp_parse_uri_supported_curves(bi, supported_curves) < 0 ||
dpp_parse_uri_pk(bi, pk) < 0) {
dpp_bootstrap_info_free(bi);
bi = NULL;
@@ -604,6 +631,7 @@
{
char macstr[ETH_ALEN * 2 + 10];
size_t len;
+ char supp_curves[10];
len = 4; /* "DPP:" */
if (bi->chan)
@@ -621,11 +649,26 @@
#endif /* CONFIG_DPP2 */
len += 4 + os_strlen(bi->pk); /* K:...;; */
+ if (bi->supported_curves) {
+ u8 val = bi->supported_curves;
+
+ if (val & 0xf0) {
+ val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
+ len += os_snprintf(supp_curves, sizeof(supp_curves),
+ "B:%02x;", val);
+ } else {
+ len += os_snprintf(supp_curves, sizeof(supp_curves),
+ "B:%x;", val);
+ }
+ } else {
+ supp_curves[0] = '\0';
+ }
+
os_free(bi->uri);
bi->uri = os_malloc(len + 1);
if (!bi->uri)
return -1;
- os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%sK:%s;;",
+ os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
bi->chan ? ";" : "",
macstr,
@@ -633,6 +676,7 @@
bi->info ? ";" : "",
DPP_VERSION == 3 ? "V:3;" :
(DPP_VERSION == 2 ? "V:2;" : ""),
+ supp_curves,
bi->pk);
return 0;
}
@@ -658,9 +702,12 @@
{
size_t nonce_len;
size_t json_len, clear_len;
- struct wpabuf *clear = NULL, *msg = NULL;
+ struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL;
u8 *wrapped;
size_t attr_len;
+#ifdef CONFIG_DPP3
+ u8 auth_i[DPP_MAX_HASH_LEN];
+#endif /* CONFIG_DPP3 */
wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
@@ -675,6 +722,18 @@
/* { E-nonce, configAttrib }ke */
clear_len = 4 + nonce_len + 4 + json_len;
+#ifdef CONFIG_DPP3
+ if (auth->waiting_new_key) {
+ pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
+ if (!pe)
+ goto fail;
+ clear_len += 4 + wpabuf_len(pe);
+
+ if (dpp_derive_auth_i(auth, auth_i) < 0)
+ goto fail;
+ clear_len += 4 + auth->curve->hash_len;
+ }
+#endif /* CONFIG_DPP3 */
clear = wpabuf_alloc(clear_len);
attr_len = 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -716,6 +775,21 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DPP3
+ if (pe) {
+ wpa_printf(MSG_DEBUG, "DPP: Pe");
+ wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(pe));
+ wpabuf_put_buf(clear, pe);
+ }
+ if (auth->waiting_new_key) {
+ wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag");
+ wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+ wpabuf_put_le16(clear, auth->curve->hash_len);
+ wpabuf_put_data(clear, auth_i, auth->curve->hash_len);
+ }
+#endif /* CONFIG_DPP3 */
+
/* configAttrib */
wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
wpabuf_put_le16(clear, json_len);
@@ -748,13 +822,15 @@
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Configuration Request frame attributes", msg);
+out:
wpabuf_free(clear);
+ wpabuf_free(pe);
return msg;
fail:
- wpabuf_free(clear);
wpabuf_free(msg);
- return NULL;
+ msg = NULL;
+ goto out;
}
@@ -815,7 +891,7 @@
size_t len, name_len;
const char *tech = "infra";
const char *dpp_name;
- struct wpabuf *buf, *json;
+ struct wpabuf *buf = NULL, *json = NULL;
char *csr = NULL;
#ifdef CONFIG_TESTING_OPTIONS
@@ -840,19 +916,17 @@
csr = base64_encode_no_lf(wpabuf_head(auth->csr),
wpabuf_len(auth->csr), &csr_len);
if (!csr)
- return NULL;
+ goto fail;
len += 30 + csr_len;
}
#endif /* CONFIG_DPP2 */
json = wpabuf_alloc(len);
if (!json)
- return NULL;
+ goto fail;
json_start_object(json, NULL);
- if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) {
- wpabuf_free(json);
- return NULL;
- }
+ if (json_add_string_escape(json, "name", dpp_name, name_len) < 0)
+ goto fail;
json_value_sep(json);
json_add_string(json, "wi-fi_tech", tech);
json_value_sep(json);
@@ -877,6 +951,7 @@
json_end_object(json);
buf = dpp_build_conf_req(auth, wpabuf_head(json));
+fail:
wpabuf_free(json);
os_free(csr);
@@ -1431,7 +1506,8 @@
struct wpabuf *buf = NULL;
char *signed_conn = NULL;
size_t tailroom;
- const struct dpp_curve_params *curve;
+ const struct dpp_curve_params *curve; /* C-sign-key curve */
+ const struct dpp_curve_params *nak_curve; /* netAccessKey curve */
struct wpabuf *dppcon = NULL;
size_t extra_len = 1000;
int incl_legacy;
@@ -1444,6 +1520,10 @@
goto fail;
}
curve = auth->conf->curve;
+ if (auth->new_curve && auth->new_key_received)
+ nak_curve = auth->new_curve;
+ else
+ nak_curve = auth->curve;
akm = conf->akm;
if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
@@ -1461,7 +1541,7 @@
extra_len += os_strlen(conf->group_id);
/* Connector (JSON dppCon object) */
- dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
+ dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3);
if (!dppcon)
goto fail;
#ifdef CONFIG_TESTING_OPTIONS
@@ -1491,9 +1571,31 @@
#ifdef CONFIG_TESTING_OPTIONS
skip_groups:
#endif /* CONFIG_TESTING_OPTIONS */
- if (!auth->peer_protocol_key ||
- dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
- auth->curve) < 0) {
+ if (!auth->peer_protocol_key) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No peer protocol key available to build netAccessKey JWK");
+ goto fail;
+ }
+#ifdef CONFIG_DPP3
+ if (auth->conf->net_access_key_curve &&
+ auth->curve != auth->conf->net_access_key_curve &&
+ !auth->new_key_received) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
+ auth->curve->name,
+ auth->conf->net_access_key_curve->name,
+ auth->waiting_new_key ?
+ "the required key not received" :
+ "request a new key");
+ if (auth->waiting_new_key)
+ auth->waiting_new_key = false; /* failed */
+ else
+ auth->waiting_new_key = true;
+ goto fail;
+ }
+#endif /* CONFIG_DPP3 */
+ if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
+ nak_curve) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
goto fail;
}
@@ -1605,6 +1707,20 @@
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
wpabuf_head(buf), wpabuf_len(buf));
+#ifdef CONFIG_DPP3
+ if (!auth->conf->net_access_key_curve) {
+ /* All netAccessKey values used in the network will have to be
+ * from the same curve for network introduction to work, so
+ * hardcode the first used netAccessKey curve for consecutive
+ * operations if there was no explicit configuration of which
+ * curve to use. */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning",
+ nak_curve->name);
+ auth->conf->net_access_key_curve = nak_curve;
+ }
+#endif /* CONFIG_DPP3 */
+
out:
os_free(signed_conn);
wpabuf_free(dppcon);
@@ -1732,7 +1848,7 @@
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
{
- struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
+ struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL;
size_t clear_len, attr_len;
struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped;
@@ -1766,6 +1882,10 @@
else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
status = DPP_STATUS_CSR_NEEDED;
+#ifdef CONFIG_DPP3
+ else if (auth->waiting_new_key)
+ status = DPP_STATUS_NEW_KEY_NEEDED;
+#endif /* CONFIG_DPP3 */
else
status = DPP_STATUS_CONFIGURE_FAILURE;
forced_status:
@@ -1785,6 +1905,31 @@
if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
auth->conf_sta->csrattrs)
clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
+#ifdef CONFIG_DPP3
+ if (status == DPP_STATUS_NEW_KEY_NEEDED) {
+ struct crypto_ec_key *new_pc;
+
+ clear_len += 6; /* Finite Cyclic Group attribute */
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Generate a new own protocol key for the curve %s",
+ auth->conf->net_access_key_curve->name);
+ new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve);
+ if (!new_pc) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc");
+ return NULL;
+ }
+ pc = crypto_ec_key_get_pubkey_point(new_pc, 0);
+ if (!pc) {
+ crypto_ec_key_deinit(new_pc);
+ return NULL;
+ }
+ crypto_ec_key_deinit(auth->own_protocol_key);
+ auth->own_protocol_key = new_pc;
+ auth->new_curve = auth->conf->net_access_key_curve;
+ clear_len += 4 + wpabuf_len(pc);
+ }
+#endif /* CONFIG_DPP3 */
clear = wpabuf_alloc(clear_len);
attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -1862,6 +2007,27 @@
wpabuf_put_str(clear, auth->conf_sta->csrattrs);
}
+#ifdef CONFIG_DPP3
+ if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf &&
+ auth->conf->net_access_key_curve) {
+ u16 ike_group = auth->conf->net_access_key_curve->ike_group;
+
+ /* Finite Cyclic Group attribute */
+ wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
+ ike_group);
+ wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(clear, 2);
+ wpabuf_put_le16(clear, ike_group);
+
+ if (pc) {
+ wpa_printf(MSG_DEBUG, "DPP: Pc");
+ wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(pc));
+ wpabuf_put_buf(clear, pc);
+ }
+ }
+#endif /* CONFIG_DPP3 */
+
#ifdef CONFIG_TESTING_OPTIONS
skip_config_obj:
if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
@@ -1912,6 +2078,7 @@
wpabuf_clear_free(conf2);
wpabuf_clear_free(env_data);
wpabuf_clear_free(clear);
+ wpabuf_free(pc);
return msg;
fail:
@@ -1933,6 +2100,10 @@
struct json_token *root = NULL, *token;
enum dpp_netrole netrole;
struct wpabuf *cert_req = NULL;
+#ifdef CONFIG_DPP3
+ const u8 *i_proto;
+ u16 i_proto_len;
+#endif /* CONFIG_DPP3 */
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
@@ -1986,6 +2157,59 @@
wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
+#ifdef CONFIG_DPP3
+ i_proto = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len);
+ if (i_proto && !auth->waiting_new_key) {
+ dpp_auth_fail(auth,
+ "Enrollee included a new protocol key even though one was not expected");
+ goto fail;
+ }
+ if (i_proto) {
+ struct crypto_ec_key *pe;
+ u8 auth_i[DPP_MAX_HASH_LEN];
+ const u8 *rx_auth_i;
+ u16 rx_auth_i_len;
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)",
+ i_proto, i_proto_len);
+
+ pe = dpp_set_pubkey_point(auth->own_protocol_key,
+ i_proto, i_proto_len);
+ if (!pe) {
+ dpp_auth_fail(auth,
+ "Invalid Initiator Protocol Key (Pe)");
+ goto fail;
+ }
+ dpp_debug_print_key("New Peer Protocol Key (Pe)", pe);
+ crypto_ec_key_deinit(auth->peer_protocol_key);
+ auth->peer_protocol_key = pe;
+ auth->new_key_received = true;
+ auth->waiting_new_key = false;
+
+ if (dpp_derive_auth_i(auth, auth_i) < 0)
+ goto fail;
+
+ rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len);
+ if (!rx_auth_i) {
+ dpp_auth_fail(auth,
+ "Missing Initiator Authentication Tag");
+ goto fail;
+ }
+ if (rx_auth_i_len != auth->curve->hash_len ||
+ os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) {
+ dpp_auth_fail(auth,
+ "Mismatch in Initiator Authenticating Tag");
+ wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I",
+ rx_auth_i, rx_auth_i_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'",
+ auth_i, auth->curve->hash_len);
+ goto fail;
+ }
+ }
+#endif /* CONFIG_DPP3 */
+
config_attr = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONFIG_ATTR_OBJ,
&config_attr_len);
@@ -2989,6 +3213,72 @@
goto fail;
}
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) {
+ const u8 *fcgroup, *r_proto;
+ u16 fcgroup_len, r_proto_len;
+ u16 group;
+ const struct dpp_curve_params *curve;
+ struct crypto_ec_key *new_pe;
+ struct crypto_ec_key *pc;
+
+ fcgroup = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Finite Cyclic Group attribute");
+ goto fail;
+ }
+ group = WPA_GET_LE16(fcgroup);
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator requested a new protocol key from group %u",
+ group);
+ curve = dpp_get_curve_ike_group(group);
+ if (!curve) {
+ dpp_auth_fail(auth,
+ "Unsupported group for new protocol key");
+ goto fail;
+ }
+
+ new_pe = dpp_gen_keypair(curve);
+ if (!new_pe) {
+ dpp_auth_fail(auth,
+ "Failed to generate a new protocol key");
+ goto fail;
+ }
+
+ crypto_ec_key_deinit(auth->own_protocol_key);
+ auth->own_protocol_key = new_pe;
+ auth->new_curve = curve;
+
+ r_proto = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_R_PROTOCOL_KEY,
+ &r_proto_len);
+ if (!r_proto) {
+ dpp_auth_fail(auth,
+ "Missing required Responder Protocol Key attribute (Pc)");
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)",
+ r_proto, r_proto_len);
+
+ pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len);
+ if (!pc) {
+ dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)");
+ goto fail;
+ }
+ dpp_debug_print_key("New Peer Protocol Key (Pc)", pc);
+
+ crypto_ec_key_deinit(auth->peer_protocol_key);
+ auth->peer_protocol_key = pc;
+
+ auth->waiting_new_key = true;
+ ret = -3;
+ goto fail;
+ }
+#endif /* CONFIG_DPP3 */
if (status[0] != DPP_STATUS_OK) {
dpp_auth_fail(auth, "Configurator rejected configuration");
goto fail;
@@ -3903,10 +4193,47 @@
}
+static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi,
+ char *txt)
+{
+ char *token, *context = NULL;
+ u8 curves = 0;
+
+ if (!txt)
+ return 0;
+
+ while ((token = str_token(txt, ":", &context))) {
+ if (os_strcmp(token, "P-256") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256);
+ } else if (os_strcmp(token, "P-384") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384);
+ } else if (os_strcmp(token, "P-521") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521);
+ } else if (os_strcmp(token, "BP-256") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256);
+ } else if (os_strcmp(token, "BP-384") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384);
+ } else if (os_strcmp(token, "BP-512") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512);
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'",
+ token);
+ return -1;
+ }
+ }
+ bi->supported_curves = curves;
+
+ wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
+ bi->supported_curves);
+
+ return 0;
+}
+
+
int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
{
char *mac = NULL, *info = NULL, *curve = NULL;
- char *key = NULL;
+ char *key = NULL, *supported_curves = NULL;
u8 *privkey = NULL;
size_t privkey_len = 0;
int ret = -1;
@@ -3933,6 +4260,7 @@
info = get_param(cmd, " info=");
curve = get_param(cmd, " curve=");
key = get_param(cmd, " key=");
+ supported_curves = get_param(cmd, " supported_curves=");
if (key) {
privkey_len = os_strlen(key) / 2;
@@ -3946,6 +4274,7 @@
dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
dpp_parse_uri_mac(bi, mac) < 0 ||
dpp_parse_uri_info(bi, info) < 0 ||
+ dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
dpp_gen_uri(bi) < 0)
goto fail;
@@ -3958,6 +4287,7 @@
os_free(mac);
os_free(info);
str_clear_free(key);
+ os_free(supported_curves);
bin_clear_free(privkey, privkey_len);
dpp_bootstrap_info_free(bi);
return ret;
@@ -4012,12 +4342,43 @@
{
struct dpp_bootstrap_info *bi;
char pkhash[2 * SHA256_MAC_LEN + 1];
+ char supp_curves[100];
bi = dpp_bootstrap_get_id(dpp, id);
if (!bi)
return -1;
wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
SHA256_MAC_LEN);
+
+ supp_curves[0] = '\0';
+ if (bi->supported_curves) {
+ int ret;
+ size_t i;
+ char *pos = supp_curves;
+ char *end = &supp_curves[sizeof(supp_curves)];
+ const char *curve[6] = { "P-256", "P-384", "P-521",
+ "BP-256", "BP-384", "BP-512" };
+
+ ret = os_snprintf(pos, end - pos, "supp_curves=");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+
+ for (i = 0; i < ARRAY_SIZE(curve); i++) {
+ if (!(bi->supported_curves & BIT(i)))
+ continue;
+ ret = os_snprintf(pos, end - pos, "%s:", curve[i]);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (pos[-1] == ':')
+ pos[-1] = '\n';
+ else
+ supp_curves[0] = '\0';
+ }
+
return os_snprintf(reply, reply_size, "type=%s\n"
"mac_addr=" MACSTR "\n"
"info=%s\n"
@@ -4025,7 +4386,7 @@
"use_freq=%u\n"
"curve=%s\n"
"pkhash=%s\n"
- "version=%d\n",
+ "version=%d\n%s",
dpp_bootstrap_type_txt(bi->type),
MAC2STR(bi->mac_addr),
bi->info ? bi->info : "",
@@ -4033,7 +4394,8 @@
bi->num_freq == 1 ? bi->freq[0] : 0,
bi->curve->name,
pkhash,
- bi->version);
+ bi->version,
+ supp_curves);
}
@@ -4210,12 +4572,25 @@
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
{
- char *curve = NULL;
+ char *curve;
char *key = NULL, *ppkey = NULL;
u8 *privkey = NULL, *pp_key = NULL;
size_t privkey_len = 0, pp_key_len = 0;
int ret = -1;
struct dpp_configurator *conf = NULL;
+ const struct dpp_curve_params *net_access_key_curve = NULL;
+
+ curve = get_param(cmd, " net_access_key_curve=");
+ if (curve) {
+ net_access_key_curve = dpp_get_curve_name(curve);
+ if (!net_access_key_curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported net_access_key_curve: %s",
+ curve);
+ goto fail;
+ }
+ os_free(curve);
+ }
curve = get_param(cmd, " curve=");
key = get_param(cmd, " key=");
@@ -4242,6 +4617,7 @@
if (!conf)
goto fail;
+ conf->net_access_key_curve = net_access_key_curve;
conf->id = dpp_next_configurator_id(dpp);
dl_list_add(&dpp->configurator, &conf->list);
ret = conf->id;
@@ -4257,6 +4633,32 @@
}
+int dpp_configurator_set(struct dpp_global *dpp, const char *cmd)
+{
+ unsigned int id;
+ struct dpp_configurator *conf;
+ char *curve;
+
+ id = atoi(cmd);
+ conf = dpp_configurator_get_id(dpp, id);
+ if (!conf)
+ return -1;
+
+ curve = get_param(cmd, " net_access_key_curve=");
+ if (curve) {
+ const struct dpp_curve_params *net_access_key_curve;
+
+ net_access_key_curve = dpp_get_curve_name(curve);
+ os_free(curve);
+ if (!net_access_key_curve)
+ return -1;
+ conf->net_access_key_curve = net_access_key_curve;
+ }
+
+ return 0;
+}
+
+
static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
{
struct dpp_configurator *conf, *tmp;
diff --git a/src/common/dpp.h b/src/common/dpp.h
index 2f85ebd..fba4119 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -110,6 +110,7 @@
DPP_STATUS_CONFIGURE_PENDING = 11,
DPP_STATUS_CSR_NEEDED = 12,
DPP_STATUS_CSR_BAD = 13,
+ DPP_STATUS_NEW_KEY_NEEDED = 14,
};
/* DPP Reconfig Flags object - connectorKey values */
@@ -145,6 +146,15 @@
DPP_BOOTSTRAP_NFC_URI,
};
+enum dpp_bootstrap_supported_curves {
+ DPP_BOOTSTRAP_CURVE_P_256 = 0,
+ DPP_BOOTSTRAP_CURVE_P_384 = 1,
+ DPP_BOOTSTRAP_CURVE_P_521 = 2,
+ DPP_BOOTSTRAP_CURVE_BP_256 = 3,
+ DPP_BOOTSTRAP_CURVE_BP_384 = 4,
+ DPP_BOOTSTRAP_CURVE_BP_512 = 5,
+};
+
struct dpp_bootstrap_info {
struct dl_list list;
unsigned int id;
@@ -158,6 +168,7 @@
unsigned int num_freq;
bool channels_listed;
u8 version;
+ u8 supported_curves; /* enum dpp_bootstrap_supported_curves bitmap */
int own;
struct crypto_ec_key *pubkey;
u8 pubkey_hash[SHA256_MAC_LEN];
@@ -172,6 +183,12 @@
#define PKEX_COUNTER_T_LIMIT 5
+enum dpp_pkex_ver {
+ PKEX_VER_AUTO,
+ PKEX_VER_ONLY_1,
+ PKEX_VER_ONLY_2,
+};
+
struct dpp_pkex {
void *msg_ctx;
unsigned int initiator:1;
@@ -253,6 +270,7 @@
void *msg_ctx;
u8 peer_version;
const struct dpp_curve_params *curve;
+ const struct dpp_curve_params *new_curve;
struct dpp_bootstrap_info *peer_bi;
struct dpp_bootstrap_info *own_bi;
struct dpp_bootstrap_info *tmp_own_bi;
@@ -353,6 +371,8 @@
char *trusted_eap_server_name;
struct wpabuf *cacert;
struct wpabuf *certbag;
+ bool waiting_new_key;
+ bool new_key_received;
void *config_resp_ctx;
void *gas_server_ctx;
bool use_config_query;
@@ -378,6 +398,7 @@
u8 kid_hash[SHA256_MAC_LEN];
char *kid;
const struct dpp_curve_params *curve;
+ const struct dpp_curve_params *net_access_key_curve;
char *connector; /* own Connector for reconfiguration */
struct crypto_ec_key *connector_key;
struct crypto_ec_key *pp_key;
@@ -512,6 +533,8 @@
DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP = 93,
DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_REQ = 94,
DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_RESP = 95,
+ DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 96,
+ DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 97,
};
extern enum dpp_test_behavior dpp_test;
@@ -681,6 +704,7 @@
struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
const u8 *hash);
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
+int dpp_configurator_set(struct dpp_global *dpp, const char *cmd);
int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
char *buf, size_t buflen);
@@ -698,6 +722,8 @@
size_t data_len);
int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config);
+int dpp_controller_set_params(struct dpp_global *dpp,
+ const char *configurator_params);
void dpp_controller_stop(struct dpp_global *dpp);
void dpp_controller_stop_for_ctx(struct dpp_global *dpp, void *cb_ctx);
struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index 4fac7de..47f56c2 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -2355,6 +2355,97 @@
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i)
+{
+ int ret = -1, res;
+ u8 Sx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Sx_len;
+ unsigned int hash_len;
+ const char *info = "New DPP Protocol Key";
+ const u8 *addr[3];
+ size_t len[3];
+ u8 tmp[DPP_MAX_HASH_LEN], k[DPP_MAX_HASH_LEN];
+ struct wpabuf *pcx = NULL, *pex = NULL;
+
+ hash_len = auth->curve->hash_len;
+
+ /*
+ * Configurator: S = pc * Pe
+ * Enrollee: S = pe * Pc
+ * k = HKDF(bk, "New DPP Protocol Key", S.x)
+ * = HKDF-Expand(HKDF-Extract(bk, S.X), "New DPP Protocol Key",
+ * len(new-curve-hash-out))
+ * Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)
+ *
+ * auth->own_protocol_key and auth->peer_protocol_key have already been
+ * updated to use the new keys. The new curve determines the size of
+ * the (new) protocol keys and S.x. The other parameters (bk, hash
+ * algorithm, k) are determined based on the initially determined curve
+ * during the (re)authentication exchange.
+ */
+
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
+ Sx, &Sx_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: S.x", Sx, Sx_len);
+
+ /* tmp = HKDF-Extract(bk, S.x) */
+ addr[0] = Sx;
+ len[0] = Sx_len;
+ res = dpp_hmac_vector(hash_len, auth->bk, hash_len, 1, addr, len, tmp);
+ if (res < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: HKDF-Extract(bk, S.x)",
+ tmp, hash_len);
+ /* k = HKDF-Expand(tmp, "New DPP Protocol Key", len(hash-output))
+ */
+ res = dpp_hkdf_expand(hash_len, tmp, hash_len, info, k, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: k = HKDF-Expand(\"New DPP Protocol Key\")",
+ k, hash_len);
+
+ /* Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x) */
+ addr[0] = auth->e_nonce;
+ len[0] = auth->curve->nonce_len;
+
+ if (auth->configurator) {
+ pcx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
+ pex = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
+ 0);
+ } else {
+ pcx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
+ 0);
+ pex = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
+ }
+ if (!pcx || !pex)
+ goto fail;
+ addr[1] = wpabuf_head(pcx);
+ len[1] = wpabuf_len(pcx) / 2;
+ addr[2] = wpabuf_head(pex);
+ len[2] = wpabuf_len(pex) / 2;
+
+ if (dpp_hmac_vector(hash_len, k, hash_len, 3, addr, len, auth_i) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)",
+ auth_i, hash_len);
+ ret = 0;
+fail:
+ forced_memzero(Sx, sizeof(Sx));
+ forced_memzero(tmp, sizeof(tmp));
+ forced_memzero(k, sizeof(k));
+ wpabuf_free(pcx);
+ wpabuf_free(pex);
+ return ret;
+}
+#endif /* CONFIG_DPP3 */
+
+
#ifdef CONFIG_TESTING_OPTIONS
int dpp_test_gen_invalid_key(struct wpabuf *msg,
diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h
index 0f31ae5..10db4e8 100644
--- a/src/common/dpp_i.h
+++ b/src/common/dpp_i.h
@@ -136,6 +136,7 @@
struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
struct crypto_ec_key *a_nonce,
struct crypto_ec_key *e_prime_id);
+int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i);
char * dpp_sign_connector(struct dpp_configurator *conf,
const struct wpabuf *dppcon);
int dpp_test_gen_invalid_key(struct wpabuf *msg,
diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c
index 7137bc5..452c502 100644
--- a/src/common/dpp_reconfig.c
+++ b/src/common/dpp_reconfig.c
@@ -131,6 +131,7 @@
{
struct wpabuf *msg;
size_t attr_len;
+ u8 ver = DPP_VERSION;
/* Build DPP Reconfig Authentication Request frame attributes */
attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) +
@@ -144,10 +145,25 @@
wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, auth->transaction_id);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version");
+ goto skip_proto_ver;
+ }
+ if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version");
+ ver = 1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* Protocol Version */
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, DPP_VERSION);
+ wpabuf_put_u8(msg, ver);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_proto_ver:
+#endif /* CONFIG_TESTING_OPTIONS */
/* DPP Connector */
wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c
index e88c6de..c83fb2d 100644
--- a/src/common/dpp_tcp.c
+++ b/src/common/dpp_tcp.c
@@ -89,6 +89,9 @@
static void dpp_controller_auth_success(struct dpp_connection *conn,
int initiator);
static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx);
+#ifdef CONFIG_DPP3
+static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_DPP3 */
static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx);
static void dpp_relay_conn_timeout(void *eloop_ctx, void *timeout_ctx);
@@ -107,6 +110,9 @@
eloop_cancel_timeout(dpp_tcp_build_csr, conn, NULL);
eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL);
eloop_cancel_timeout(dpp_relay_conn_timeout, conn, NULL);
+#ifdef CONFIG_DPP3
+ eloop_cancel_timeout(dpp_tcp_build_new_key, conn, NULL);
+#endif /* CONFIG_DPP3 */
wpabuf_free(conn->msg);
wpabuf_free(conn->msg_out);
dpp_auth_deinit(conn->auth);
@@ -193,6 +199,14 @@
return;
}
+#ifdef CONFIG_DPP3
+ if (auth->waiting_new_key) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key");
+ conn->on_tcp_tx_complete_gas_done = 0;
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+
if (auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
@@ -999,7 +1013,7 @@
return 0;
}
- conn->pkex = dpp_pkex_rx_exchange_req(conn->ctrl->global, ctrl->pkex_bi,
+ conn->pkex = dpp_pkex_rx_exchange_req(conn->msg_ctx, ctrl->pkex_bi,
NULL, NULL,
ctrl->pkex_identifier,
ctrl->pkex_code,
@@ -1440,6 +1454,21 @@
}
+#ifdef CONFIG_DPP3
+static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ struct dpp_authentication *auth = conn->auth;
+
+ if (!auth || !auth->waiting_new_key)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key");
+ dpp_controller_start_gas_client(conn);
+}
+#endif /* CONFIG_DPP3 */
+
+
static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
{
struct dpp_authentication *auth = conn->auth;
@@ -1460,6 +1489,14 @@
eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL);
return 0;
}
+#ifdef CONFIG_DPP3
+ if (res == -3) {
+ wpa_printf(MSG_DEBUG, "DPP: New protocol key needed");
+ eloop_register_timeout(0, 0, dpp_tcp_build_new_key, conn,
+ NULL);
+ return 0;
+ }
+#endif /* CONFIG_DPP3 */
if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
return -1;
@@ -2047,6 +2084,29 @@
}
+int dpp_controller_set_params(struct dpp_global *dpp,
+ const char *configurator_params)
+{
+
+ if (!dpp || !dpp->controller)
+ return -1;
+
+ if (configurator_params) {
+ char *val = os_strdup(configurator_params);
+
+ if (!val)
+ return -1;
+ os_free(dpp->controller->configurator_params);
+ dpp->controller->configurator_params = val;
+ } else {
+ os_free(dpp->controller->configurator_params);
+ dpp->controller->configurator_params = NULL;
+ }
+
+ return 0;
+}
+
+
void dpp_controller_stop(struct dpp_global *dpp)
{
if (dpp) {
@@ -2183,6 +2243,9 @@
{
struct dpp_connection *conn;
+ if (!dpp)
+ return false;
+
dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) {
if (conn->auth && conn->auth->conn_status_requested)
return true;
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index f168d4e..732124f 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -383,10 +383,11 @@
int freq, int channel, int enable_edmg,
u8 edmg_channel, int ht_enabled,
int vht_enabled, int he_enabled,
- int sec_channel_offset,
+ bool eht_enabled, int sec_channel_offset,
int oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps,
- struct he_capabilities *he_cap)
+ struct he_capabilities *he_cap,
+ struct eht_capabilities *eht_cap)
{
if (!he_cap || !he_cap->he_supported)
he_enabled = 0;
@@ -397,6 +398,7 @@
data->ht_enabled = ht_enabled;
data->vht_enabled = vht_enabled;
data->he_enabled = he_enabled;
+ data->eht_enabled = eht_enabled;
data->sec_channel_offset = sec_channel_offset;
data->center_freq1 = freq + sec_channel_offset * 10;
data->center_freq2 = 0;
@@ -415,9 +417,9 @@
&data->edmg);
if (is_6ghz_freq(freq)) {
- if (!data->he_enabled) {
+ if (!data->he_enabled && !data->eht_enabled) {
wpa_printf(MSG_ERROR,
- "Can't set 6 GHz mode - HE isn't enabled");
+ "Can't set 6 GHz mode - HE or EHT aren't enabled");
return -1;
}
@@ -480,7 +482,20 @@
return 0;
}
- if (data->he_enabled) switch (oper_chwidth) {
+#if 0 /* FIX: Figure out how to handle CHANWIDTH_320MHZ */
+ if (data->eht_enabled) switch (oper_chwidth) {
+ case CHANWIDTH_320MHZ:
+ if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) {
+ wpa_printf(MSG_ERROR,
+ "320 MHz channel width is not supported in 5 or 6 GHz");
+ return -1;
+ }
+ break;
+ }
+#endif
+
+ if (data->he_enabled || data->eht_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
if (sec_channel_offset == 0)
break;
@@ -543,7 +558,8 @@
break;
}
- if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) {
+ if (data->eht_enabled || data->he_enabled ||
+ data->vht_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
if (center_segment1 ||
(center_segment0 != 0 &&
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 0e92aa0..d87a2ca 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -40,10 +40,11 @@
int freq, int channel, int edmg, u8 edmg_channel,
int ht_enabled,
int vht_enabled, int he_enabled,
- int sec_channel_offset,
+ bool eht_enabled, int sec_channel_offset,
int oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps,
- struct he_capabilities *he_caps);
+ struct he_capabilities *he_caps,
+ struct eht_capabilities *eht_cap);
void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
int disabled);
int ieee80211ac_cap_check(u32 hw, u32 conf);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index adc6f59..44335de 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -311,6 +311,14 @@
elems->pasn_params = pos;
elems->pasn_params_len = elen;
break;
+ case WLAN_EID_EXT_EHT_CAPABILITIES:
+ elems->eht_capabilities = pos;
+ elems->eht_capabilities_len = elen;
+ break;
+ case WLAN_EID_EXT_EHT_OPERATION:
+ elems->eht_operation = pos;
+ elems->eht_operation_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -1902,7 +1910,7 @@
{ HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP },
/*
- * IEEE P802.11ax/D8.0 Table E-4 actually talks about channel center
+ * IEEE Std 802.11ax-2021, Table E-4 actually talks about channel center
* frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing
* of 80 MHz, but currently use the following definition for simplicity
* (these center frequencies are not actual channels, which makes
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index ec6556f..e21f7be 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -117,6 +117,8 @@
const u8 *sae_pk;
const u8 *s1g_capab;
const u8 *pasn_params;
+ const u8 *eht_capabilities;
+ const u8 *eht_operation;
u8 ssid_len;
u8 supp_rates_len;
@@ -171,6 +173,8 @@
u8 short_ssid_list_len;
u8 sae_pk_len;
u8 pasn_params_len;
+ u8 eht_capabilities_len;
+ u8 eht_operation_len;
struct mb_ies_info mb_ies;
struct frag_ies_info frag_ies;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 4300ae5..c341a1d 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -479,6 +479,7 @@
#define WLAN_EID_EXT_HE_OPERATION 36
#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
#define WLAN_EID_EXT_SPATIAL_REUSE 39
+#define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42
#define WLAN_EID_EXT_OCV_OCI 54
#define WLAN_EID_EXT_SHORT_SSID_LIST 58
#define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59
@@ -489,6 +490,11 @@
#define WLAN_EID_EXT_REJECTED_GROUPS 92
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
#define WLAN_EID_EXT_PASN_PARAMS 100
+#define WLAN_EID_EXT_EHT_OPERATION 106
+#define WLAN_EID_EXT_MULTI_LINK 107
+#define WLAN_EID_EXT_EHT_CAPABILITIES 108
+#define WLAN_EID_EXT_TID_TO_LINK_MAPPING 109
+#define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -1953,6 +1959,26 @@
u8 link_margin;
} STRUCT_PACKED;
+/*
+ * IEEE Std 802.11ax-2021, Table 9-275a - Maximum Transmit Power
+ * Interpretation subfield encoding
+ */
+enum max_tx_pwr_interpretation {
+ LOCAL_EIRP = 0,
+ LOCAL_EIRP_PSD = 1,
+ REGULATORY_CLIENT_EIRP = 2,
+ REGULATORY_CLIENT_EIRP_PSD = 3,
+};
+
+/*
+ * IEEE Std 802.11ax-2021, Table E-13 - Maximum Transmit Power
+ * Category subfield encoding in the United States
+ */
+enum reg_6g_client_type {
+ REG_DEFAULT_CLIENT = 0,
+ REG_SUBORDINATE_CLIENT = 1,
+};
+
#define RRM_CAPABILITIES_IE_LEN 5
/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
@@ -2173,6 +2199,7 @@
#define NEI_REP_BSSID_INFO_VHT BIT(12)
#define NEI_REP_BSSID_INFO_FTM BIT(13)
#define NEI_REP_BSSID_INFO_HE BIT(14)
+#define NEI_REP_BSSID_INFO_EHT BIT(21)
/*
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
@@ -2209,7 +2236,7 @@
* Operation Information subfield (5 octets). */
} STRUCT_PACKED;
-/* IEEE P802.11ax/D6.0, Figure 9-787k - 6 GHz Operation Information field */
+/* IEEE Std 802.11ax-2021, Figure 9-788k - 6 GHz Operation Information field */
struct ieee80211_he_6ghz_oper_info {
u8 primary_chan;
u8 control;
@@ -2218,15 +2245,22 @@
u8 min_rate;
} STRUCT_PACKED;
+/* IEEE Std 802.11ax-2021, Figure 9-788l - Control field format */
#define HE_6GHZ_OPER_INFO_CTRL_CHAN_WIDTH_MASK (BIT(0) | BIT(1))
#define HE_6GHZ_OPER_INFO_CTRL_DUP_BEACON BIT(2)
+#define HE_6GHZ_OPER_INFO_CTRL_REG_INFO_MASK (BIT(3) | BIT(4) | BIT(5))
+#define HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT 3
-/* IEEE P802.11ax/D6.0, 9.4.2.261 HE 6 GHz Band Capabilities element */
+/* IEEE Std 802.11ax-2021, 9.4.2.263 HE 6 GHz Band Capabilities element */
struct ieee80211_he_6ghz_band_cap {
/* Minimum MPDU Start Spacing B0..B2
* Maximum A-MPDU Length Exponent B3..B5
- * Maximum MPDU Length B6..B7 */
- le16 capab;
+ * Maximum MPDU Length B6..B7
+ * SM Power Save B9..B10
+ * RD Responder B11
+ * Rx Antenna Pattern Consistency B12
+ * Tx Antenna Consistency B13 */
+ le16 capab; /* Capabilities Information field */
} STRUCT_PACKED;
#define HE_6GHZ_BAND_CAP_MIN_MPDU_START (BIT(0) | BIT(1) | BIT(2))
@@ -2252,7 +2286,7 @@
#define HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS BIT(13)
/*
- * IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
+ * IEEE Std 802.11ax-2021, 9.4.2.252 Spatial Reuse Parameter Set element
*/
struct ieee80211_spatial_reuse {
u8 sr_ctrl; /* SR Control */
@@ -2323,6 +2357,7 @@
#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30))
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
#define HE_OPERATION_BSS_COLOR_OFFSET 24
+#define HE_OPERATION_BSS_COLOR_MAX 64
/* HE operation fields length*/
#define HE_OPERATION_IE_MIN_LEN 6
@@ -2330,6 +2365,17 @@
#define HE_OPERATION_COHOSTED_BSSID_INDICATOR_LEN 1
#define HE_OPERATION_6GHZ_OPER_INFO_LEN 5
+/**
+ * enum he_6ghz_ap_type - Allowed Access Point types for 6 GHz Band
+ *
+ * IEEE Std 802.11ax-2021, Table E-12 (Regulatory Info subfield encoding in the
+ * United States)
+ */
+enum he_6ghz_ap_type {
+ HE_6GHZ_INDOOR_AP = 0,
+ HE_6GHZ_STANDARD_POWER_AP = 1,
+};
+
/* Spatial Reuse defines */
#define SPATIAL_REUSE_SRP_DISALLOWED BIT(0)
#define SPATIAL_REUSE_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1)
@@ -2394,6 +2440,105 @@
#define RNR_BSS_PARAM_CO_LOCATED BIT(6)
#define RNR_20_MHZ_PSD_MAX_TXPOWER 255 /* dBm */
+/* IEEE P802.11be/D1.5, 9.4.2.311 - EHT Operation element */
+
+/* Figure 9-1002b: EHT Operation Parameters field subfields */
+#define EHT_OPER_INFO_PRESENT BIT(0)
+#define EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT BIT(1)
+
+/* Control subfield: Channel Width subfield; see Table 9-401b */
+#define EHT_OPER_CHANNEL_WIDTH_20MHZ 0
+#define EHT_OPER_CHANNEL_WIDTH_40MHZ 1
+#define EHT_OPER_CHANNEL_WIDTH_80MHZ 2
+#define EHT_OPER_CHANNEL_WIDTH_160MHZ 3
+#define EHT_OPER_CHANNEL_WIDTH_320MHZ 4
+
+/* Figure 9-1002c: EHT Operation Information field format */
+struct ieee80211_eht_oper_info {
+ u8 control; /* B0..B2: Channel Width */
+ u8 ccfs0;
+ u8 ccfs1;
+ le16 disabled_chan_bitmap; /* 0 or 2 octets */
+} STRUCT_PACKED;
+
+/* Figure 9-1002a: EHT Operation element format */
+struct ieee80211_eht_operation {
+ u8 oper_params; /* EHT Operation Parameters: EHT_OPER_* bits */
+ struct ieee80211_eht_oper_info oper_info; /* 0 or 3 or 5 octets */
+} STRUCT_PACKED;
+
+/* IEEE P802.11be/D1.5, 9.4.2.313 - EHT Capabilities element */
+
+/* Figure 9-1002af: EHT MAC Capabilities Information field */
+#define EHT_MACCAP_EPCS_PRIO BIT(0)
+#define EHT_MACCAP_OM_CONTROL BIT(1)
+#define EHT_MACCAP_TRIGGERED_TXOP_MODE1 BIT(2)
+#define EHT_MACCAP_TRIGGERED_TXOP_MODE2 BIT(3)
+#define EHT_MACCAP_RESTRICTED_TWT BIT(4)
+#define EHT_MACCAP_SCS_TRAFFIC_DESC BIT(5)
+#define EHT_MACCAP_MAX_MPDU_LEN_MASK (BIT(6) | BIT(7))
+#define EHT_MACCAP_MAX_MPDU_LEN_3895 0
+#define EHT_MACCAP_MAX_MPDU_LEN_7991 BIT(6)
+#define EHT_MACCAP_MAX_MPDU_LEN_11454 BIT(7)
+#define EHT_MACCAP_MAX_AMPDU_LEN_EXP_EXT BIT(8)
+
+/* Figure 9-1002ag: EHT PHY Capabilities Information field format
+ * _IDX indicates the octet index within the field */
+#define EHT_PHY_CAPAB_LEN 9
+
+#define EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX 0
+#define EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK ((u8) BIT(1))
+
+#define EHT_PHYCAP_SU_BEAMFORMER_IDX 0
+#define EHT_PHYCAP_SU_BEAMFORMER ((u8) BIT(5))
+#define EHT_PHYCAP_SU_BEAMFORMEE_IDX 0
+#define EHT_PHYCAP_SU_BEAMFORMEE ((u8) BIT(6))
+
+#define EHT_PHYCAP_PPE_THRESHOLD_PRESENT_IDX 5
+#define EHT_PHYCAP_PPE_THRESHOLD_PRESENT ((u8) BIT(3))
+
+#define EHT_PHYCAP_MU_BEAMFORMER_IDX 7
+#define EHT_PHYCAP_MU_BEAMFORMER_80MHZ ((u8) BIT(4))
+#define EHT_PHYCAP_MU_BEAMFORMER_160MHZ ((u8) BIT(5))
+#define EHT_PHYCAP_MU_BEAMFORMER_320MHZ ((u8) BIT(6))
+#define EHT_PHYCAP_MU_BEAMFORMER_MASK (EHT_PHYCAP_MU_BEAMFORMER_80MHZ | \
+ EHT_PHYCAP_MU_BEAMFORMER_160MHZ | \
+ EHT_PHYCAP_MU_BEAMFORMER_320MHZ)
+
+/* Figure 9-1002ah: Supported EHT-MCS and NSS Set field format */
+#define EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY 4
+#define EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS 3
+
+#define EHT_MCS_NSS_CAPAB_LEN 9
+/*
+ * Figure 9-1002ak: EHT PPE Thresholds field format
+ * Maximum PPE threshold length: 62 octets
+ * NSS: 4 bits (maximum NSS: 16), RU index: 5 bits, each pair: 6 bits
+ * 4 + 5 + 5 * 16 * 6 = 489 bits, Padding: 7 bits
+ */
+#define EHT_PPE_THRESH_CAPAB_LEN 62
+
+/* 9.4.2.313.5: EHT PPE Thresholds field */
+#define EHT_PPE_THRES_NSS_SHIFT 0
+#define EHT_PPE_THRES_NSS_MASK ((u8) (BIT(0) | BIT(1) | \
+ BIT(2) | BIT(3)))
+#define EHT_PPE_THRES_RU_INDEX_SHIFT 4
+#define EHT_PPE_THRES_RU_INDEX_MASK ((u16) (BIT(4) | BIT(5) | \
+ BIT(6) | BIT(7) | \
+ BIT(8)))
+
+#define EHT_NSS_MAX_STREAMS 8
+
+/* Figure 9-1002ae: EHT Capabilities element format */
+struct ieee80211_eht_capabilities {
+ /* EHT MAC Capabilities Information */
+ le16 mac_cap;
+ /* EHT PHY Capabilities Information */
+ u8 phy_cap[EHT_PHY_CAPAB_LEN];
+ /* Supported EHT-MCS And NSS Set and EHT PPE thresholds (Optional) */
+ u8 optional[EHT_MCS_NSS_CAPAB_LEN + EHT_PPE_THRESH_CAPAB_LEN];
+} STRUCT_PACKED;
+
/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
@@ -2494,10 +2639,16 @@
#define FD_CAP_PHY_INDEX_SHIFT 10
/*
- * IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning
+ * IEEE Std 802.11ax-2021, 26.17.2.3.2, AP behavior for fast passive scanning
*/
#define FD_MAX_INTERVAL_6GHZ 20 /* TUs */
+/* IEEE Std 802.11ax-2021, 26.17.3.5.1: AP needs to wait and see the collision
+ * persists for at least the minimum default timeout
+ * dot11BSSColorCollisionAPPeriod (50 seconds)
+ */
+#define DOT11BSS_COLOR_COLLISION_AP_PERIOD 50
+
/* Protected Vendor-specific QoS Management Action frame identifiers - WFA */
#define QM_ACTION_VENDOR_TYPE 0x506f9a1a
#define QM_ACTION_OUI_TYPE 0x1a
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 0f7d3af..d04c8d1 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1599,6 +1599,18 @@
* synchronous (in vendor command reply) to the request. Each TWT
* operation is specifically mentioned (against its respective
* documentation) to support either of these or both modes.
+ * @QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI: Flag indicates
+ * that the driver requires add/del virtual interface path using the
+ * generic nl80211 commands for NDP interface create/delete and to
+ * register/unregister the netdev instead of creating/deleting the NDP
+ * interface using the vendor commands
+ * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE and
+ * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE. With the latest kernel
+ * (5.12 version onward), interface creation/deletion is not allowed using
+ * vendor commands as it leads to a deadlock while acquiring the RTNL_LOCK
+ * during the register/unregister of netdev. Create and delete NDP
+ * interface using NL80211_CMD_NEW_INTERFACE and NL80211_CMD_DEL_INTERFACE
+ * commands respectively if the driver advertises this capability set.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1617,6 +1629,7 @@
QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R = 12,
QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS = 13,
QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT = 14,
+ QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI = 15,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -2390,7 +2403,10 @@
QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES = 58,
/* 8-bit unsigned value for ELNA bypass.
- * 1-Enable, 0-Disable
+ * 0 - Disable eLNA bypass.
+ * 1 - Enable eLNA bypass.
+ * 2 - Reset eLNA bypass configuration, the driver should
+ * revert to the default configuration of eLNA bypass.
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
@@ -5627,6 +5643,8 @@
* current channel.
*/
QCA_WLAN_VENDOR_ACS_SELECT_REASON_JAMMER_INTERFERENCE,
+ /* Represents the reason that ACS triggered by AFC */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_AFC_TRIGGER,
};
/**
@@ -5834,6 +5852,21 @@
*/
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = 13,
+ /*
+ * 16-bit attribute of bits indicating the AP power modes supported by
+ * the channel (u16).
+ * Note: Currently, only 3 bits are used in the attribute and each bit
+ * corresponds to the power mode mentioned in enum
+ * qca_wlan_vendor_external_acs_chan_power_mode and a given bit is
+ * set if the associated mode is supported.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_SUPP_POWER_MODES
+ = 14,
+ /* Array of nested attributes for each power mode. It takes attr as
+ * defined in enum
+ * qca_wlan_vendor_external_acs_event_chan_power_info_attr.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR = 15,
/* keep last */
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST,
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX =
@@ -5841,6 +5874,56 @@
};
/**
+ * qca_wlan_vendor_external_acs_chan_power_mode - Specifies the valid
+ * values that the vendor external ACS channel power attribute
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE can
+ * take.
+ * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_LOW_POWER: Low power/Indoor mode
+ * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_STANDARD_POWER: Standard power mode
+ * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_VERY_LOW_POWER: Very low power mode
+ */
+enum qca_wlan_vendor_external_acs_chan_power_level {
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_LOW_POWER = 0,
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_STANDARD_POWER = 1,
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_VERY_LOW_POWER = 2,
+};
+
+/**
+ * qca_wlan_vendor_external_acs_event_chan_power_info_attr: Represents nested
+ * attributes for power mode type and power values corresponding to that.
+ * These attributes are sent as part of
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR.
+ */
+enum qca_wlan_vendor_external_acs_event_chan_power_info_attr {
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_INVALID = 0,
+ /*
+ * Power mode (u8) takes the values defined in enum
+ * qca_wlan_vendor_external_acs_chan_power_mode
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE
+ = 1,
+ /*
+ * Indicates if power value is a PSD/EIRP value (flag). If flag is
+ * present, it indicates a PSD value.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_PSD_FLAG = 2,
+ /*
+ * Power value (u32) PSD/EIRP as indicated by
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_PSD_FLAG,
+ * for power mode corresponding to the
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE.
+ * Units for PSD - dBm/MHz
+ * Units for EIRP - dBm
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_VALUE
+ = 3,
+ /* keep last */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_LAST,
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_MAX =
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_LAST - 1,
+};
+
+/**
* qca_wlan_vendor_attr_pcl: Represents attributes for
* preferred channel list (PCL). These attributes are sent as part of
* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL and
@@ -5864,6 +5947,10 @@
* bit 3 set: channel should be excluded in GO negotiation
*/
QCA_WLAN_VENDOR_ATTR_PCL_FLAG = 4,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_PCL_LAST,
+ QCA_WLAN_VENDOR_ATTR_PCL_MAX = QCA_WLAN_VENDOR_ATTR_PCL_LAST - 1
};
/**
@@ -5926,6 +6013,10 @@
* qca_wlan_vendor_attr_rropavail_info.
*/
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_RROPAVAIL_INFO = 14,
+ /* Flag attribute to indicate if driver supports 6 GHz AFC trigger
+ * for External ACS
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AFC_CAPABILITY = 15,
/* keep last */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST,
@@ -6529,6 +6620,12 @@
* for the current operating bandwidth.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BANDWIDTH = 30,
+ /* Spectral FFT recapture flag attribute, to enable FFT recapture.
+ * Recapture can only be enabled for scan period greater than 52 us.
+ * If this attribute is enabled, re-triggers will be enabled when AGC
+ * gain changes.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_RECAPTURE = 31,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
@@ -7032,7 +7129,7 @@
* Use XR level to benefit XR (extended reality) application to achieve
* latency and power by via constraint scan/roaming/adaptive PS.
* @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW:
- * Use low latency level to benifit application like concurrent
+ * Use low latency level to benefit application like concurrent
* downloading or video streaming via constraint scan/adaptive PS.
* @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW:
* Use ultra low latency level to benefit for gaming/voice
@@ -7356,6 +7453,14 @@
* 1:support 0:not support
*/
QCA_WLAN_VENDOR_ATTR_PEER_NDPE_SUPPORT = 30,
+ /* As per Wi-Fi Aware Specification v3.2 Service Id is the first
+ * 48 bits of the SHA-256 hash of the Service Name.
+ * A lower-case representation of the Service Name shall be used to
+ * calculate the Service ID.
+ * Array of u8: length is 6 bytes
+ * This attribute is used and optional for ndp indication.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_ID = 31,
/* keep last */
QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST,
@@ -7365,9 +7470,24 @@
enum qca_wlan_ndp_sub_cmd {
QCA_WLAN_VENDOR_ATTR_NDP_INVALID = 0,
- /* Command to create a NAN data path interface */
+ /* Command to create a NAN data path interface.
+ * This command was initially designed to both create and start a NAN
+ * data path interface. However, changes to Linux 5.12 no longer allow
+ * interface creation via vendor commands. When the driver advertises
+ * QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI
+ * userspace must explicitly first create the interface using
+ * NL80211_CMD_NEW_INTERFACE before subsequently invoking this command
+ * to start the interface.
+ */
QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE = 1,
- /* Command to delete a NAN data path interface */
+ /* Command to delete a NAN data path interface.
+ * This command was initially designed to both stop and delete a NAN
+ * data path interface. However, changes to Linux 5.12 no longer allow
+ * interface deletion via vendor commands. When the driver advertises
+ * QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI
+ * userspace must explicitly delete the interface using
+ * NL80211_CMD_DEL_INTERFACE after calling this command.
+ */
QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE = 2,
/* Command to initiate a NAN data path session */
QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST = 3,
@@ -8515,6 +8635,18 @@
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BCAST_TWT_SUPPORT = 57,
+ /* 8-bit unsigned value to configure the driver/firmware to allow eMLSR
+ * mode for IEEE 802.11be MLO capable devices. If the attribute is set
+ * to 1, and if the firmware supports this capability too, the STA
+ * advertises this capability to the AP over Association Request frame.
+ * This attribute will not have any effect on legacy devices with no
+ * IEEE 802.11be support.
+ * 0 - Default behavior
+ * 1 - Enable eMLSR (Enhanced Multi-link Single-Radio) mode
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_11BE_EMLSR_MODE = 58,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -8585,12 +8717,17 @@
* peer. Refers the enum qca_wlan_vendor_attr_twt_capability. It's a synchronous
* operation.
*
- * @QCA_WLAN_TWT_SETUP_READY_NOTIFY: Notify userspace that the firmare is
+ * @QCA_WLAN_TWT_SETUP_READY_NOTIFY: Notify userspace that the firmware is
* ready for a new TWT session setup after it issued a TWT teardown.
*
* @QCA_WLAN_TWT_SET_PARAM: Configure TWT related parameters. Required
* parameters are obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refer
* the enum qca_wlan_vendor_attr_twt_set_param.
+ *
+ * @QCA_WLAN_TWT_NOTIFY: Used to notify userspace about changes in TWT
+ * related information for example TWT required bit in AP capabilities etc.
+ * The reason for the notification is sent using
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS.
*/
enum qca_wlan_twt_operation {
QCA_WLAN_TWT_SET = 0,
@@ -8604,6 +8741,7 @@
QCA_WLAN_TWT_GET_CAPABILITIES = 8,
QCA_WLAN_TWT_SETUP_READY_NOTIFY = 9,
QCA_WLAN_TWT_SET_PARAM = 10,
+ QCA_WLAN_TWT_NOTIFY = 11,
};
/**
@@ -8620,11 +8758,17 @@
* enum qca_wlan_vendor_attr_twt_setup, enum qca_wlan_vendor_attr_twt_resume,
* enum qca_wlan_vendor_attr_twt_set_param, or
* enum qca_wlan_vendor_attr_twt_stats based on the operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS: Size is u8, mandatory when
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION is set to QCA_WLAN_TWT_NOTIFY.
+ * The values used by this attribute are defined in
+ * enum qca_wlan_vendor_twt_status.
*/
enum qca_wlan_vendor_attr_config_twt {
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION = 1,
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS = 2,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST,
@@ -9100,6 +9244,10 @@
* QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE: The driver requested to
* terminate an existing TWT session on power save exit request from userspace.
* Used on the TWT_TERMINATE notification from the driver/firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED: The peer has set the TWT
+ * required bit in its capabilities.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED: The peer has cleared
+ * the TWT required bit(1->0) in its capabilities.
*/
enum qca_wlan_vendor_twt_status {
QCA_WLAN_VENDOR_TWT_STATUS_OK = 0,
@@ -9125,6 +9273,8 @@
QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS = 20,
QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS = 21,
QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE = 22,
+ QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED = 23,
+ QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED = 24,
};
/**
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index b78db05..27336c9 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1599,6 +1599,13 @@
"%s: invalid group cipher 0x%x (%08x)",
__func__, data->group_cipher,
WPA_GET_BE32(pos));
+#ifdef CONFIG_NO_TKIP
+ if (RSN_SELECTOR_GET(pos) == RSN_CIPHER_SUITE_TKIP) {
+ wpa_printf(MSG_DEBUG,
+ "%s: TKIP as group cipher not supported in CONFIG_NO_TKIP=y build",
+ __func__);
+ }
+#endif /* CONFIG_NO_TKIP */
return -1;
}
pos += RSN_SELECTOR_LEN;
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index c1ce68c..779b2cf 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -487,7 +487,7 @@
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
- struct os_reltime started_at;
+ struct os_reltime started_at, ending_at;
int res;
fd_set rfds;
const char *_cmd;
@@ -543,9 +543,19 @@
}
os_free(cmd_buf);
+ os_get_reltime(&ending_at);
+ ending_at.sec += 10;
+
for (;;) {
- tv.tv_sec = 10;
- tv.tv_usec = 0;
+ struct os_reltime diff;
+
+ os_get_reltime(&started_at);
+ if (os_reltime_before(&ending_at, &started_at))
+ return -2;
+ os_reltime_sub(&ending_at, &started_at, &diff);
+ tv.tv_sec = diff.sec;
+ tv.tv_usec = diff.usec;
+
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 3d3a62a..055bf73 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -363,6 +363,9 @@
#define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED "
#define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON "
+/* BSS Transition Management Query frame received */
+#define BSS_TM_QUERY "BSS-TM-QUERY "
+
/* BSS Transition Management Response frame received */
#define BSS_TM_RESP "BSS-TM-RESP "
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index e6150b0..e4f3eb3 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -1275,4 +1275,46 @@
struct crypto_ec_key *key,
enum crypto_hash_alg algo);
+struct crypto_rsa_key;
+
+/**
+ * crypto_rsa_key_read - Read an RSA key
+ * @file: File from which to read (PEM encoded, can be X.509v3 certificate)
+ * @private_key: Whether to read the private key instead of public key
+ * Returns: RSA key or %NULL on failure
+ */
+struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key);
+
+/**
+ * crypto_rsa_oaep_sha256_encrypt - RSA-OAEP-SHA-256 encryption
+ * @key: RSA key from crypto_rsa_key_read()
+ * @in: Plaintext input data
+ * Returns: Encrypted output data or %NULL on failure
+ */
+struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in);
+
+/**
+ * crypto_rsa_oaep_sha256_decrypt - RSA-OAEP-SHA-256 decryption
+ * @key: RSA key from crypto_rsa_key_read()
+ * @in: Encrypted input data
+ * Returns: Decrypted output data or %NULL on failure
+ */
+struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in);
+
+/**
+ * crypto_rsa_key_free - Free an RSA key
+ * @key: RSA key from crypto_rsa_key_read()
+ */
+void crypto_rsa_key_free(struct crypto_rsa_key *key);
+
+/**
+ * crypto_unload - Unload crypto resources
+ *
+ * This function is called just before the process exits to allow dynamic
+ * resource allocations to be freed.
+ */
+void crypto_unload(void);
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_gnutls.c b/src/crypto/crypto_gnutls.c
index 4ef1146..a7a163f 100644
--- a/src/crypto/crypto_gnutls.c
+++ b/src/crypto/crypto_gnutls.c
@@ -504,3 +504,8 @@
gcry_cipher_close(ctx->dec);
os_free(ctx);
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index aad40af..d15c363 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -326,3 +326,8 @@
void crypto_global_deinit(void)
{
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_libtomcrypt.c b/src/crypto/crypto_libtomcrypt.c
index ed30efa..fd79c1a 100644
--- a/src/crypto/crypto_libtomcrypt.c
+++ b/src/crypto/crypto_libtomcrypt.c
@@ -766,3 +766,8 @@
}
#endif /* CONFIG_MODEXP */
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_linux.c b/src/crypto/crypto_linux.c
index 1724456..9278e27 100644
--- a/src/crypto/crypto_linux.c
+++ b/src/crypto/crypto_linux.c
@@ -1007,3 +1007,8 @@
void crypto_global_deinit(void)
{
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_nettle.c b/src/crypto/crypto_nettle.c
index f85d365..d745027 100644
--- a/src/crypto/crypto_nettle.c
+++ b/src/crypto/crypto_nettle.c
@@ -467,3 +467,8 @@
{
bin_clear_free(ctx, sizeof(*ctx));
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_none.c b/src/crypto/crypto_none.c
index 5479194..a0dc0f5 100644
--- a/src/crypto/crypto_none.c
+++ b/src/crypto/crypto_none.c
@@ -22,3 +22,8 @@
{
return 0;
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 82c8576..c6e065f 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
* Wrapper functions for OpenSSL libcrypto
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -16,16 +16,17 @@
#include <openssl/dh.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
-#ifdef CONFIG_OPENSSL_CMAC
-#include <openssl/cmac.h>
-#endif /* CONFIG_OPENSSL_CMAC */
+#include <openssl/pem.h>
#ifdef CONFIG_ECC
#include <openssl/ec.h>
#include <openssl/x509.h>
-#include <openssl/pem.h>
#endif /* CONFIG_ECC */
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/provider.h>
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#else /* OpenSSL version >= 3.0 */
+#include <openssl/cmac.h>
#endif /* OpenSSL version >= 3.0 */
#include "common.h"
@@ -40,9 +41,7 @@
#include "aes_wrap.h"
#include "crypto.h"
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
/* Compatibility wrappers for older versions. */
static HMAC_CTX * HMAC_CTX_new(void)
@@ -121,30 +120,89 @@
#endif /* OpenSSL version < 1.1.0 */
+#if OPENSSL_VERSION_NUMBER < 0x10101000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x30400000L)
+
+static int EC_POINT_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point, BIGNUM *x,
+ BIGNUM *y, BN_CTX *ctx)
+{
+ return EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx);
+}
+
+
+static int EC_POINT_set_affine_coordinates(const EC_GROUP *group,
+ EC_POINT *point, const BIGNUM *x,
+ const BIGNUM *y, BN_CTX *ctx)
+{
+ return EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx);
+}
+
+#endif /* OpenSSL version < 1.1.1 */
+
+
+#if OPENSSL_VERSION_NUMBER < 0x10101000L || \
+ defined(OPENSSL_IS_BORINGSSL) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x30400000L)
+
+static int EC_POINT_set_compressed_coordinates(const EC_GROUP *group,
+ EC_POINT *point, const BIGNUM *x,
+ int y_bit, BN_CTX *ctx)
+{
+ return EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit,
+ ctx);
+}
+
+
+static int EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
+ BIGNUM *b, BN_CTX *ctx)
+{
+ return EC_GROUP_get_curve_GFp(group, p, a, b, ctx);
+}
+
+#endif /* OpenSSL version < 1.1.1 */
+
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static OSSL_PROVIDER *openssl_default_provider = NULL;
+static OSSL_PROVIDER *openssl_legacy_provider = NULL;
+#endif /* OpenSSL version >= 3.0 */
+
void openssl_load_legacy_provider(void)
{
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- static bool loaded = false;
- OSSL_PROVIDER *legacy;
-
- if (loaded)
+ if (openssl_legacy_provider)
return;
- legacy = OSSL_PROVIDER_load(NULL, "legacy");
+ openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
+ if (openssl_legacy_provider && !openssl_default_provider)
+ openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
+#endif /* OpenSSL version >= 3.0 */
+}
- if (legacy) {
- OSSL_PROVIDER_load(NULL, "default");
- loaded = true;
+
+static void openssl_unload_legacy_provider(void)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (openssl_legacy_provider) {
+ OSSL_PROVIDER_unload(openssl_legacy_provider);
+ openssl_legacy_provider = NULL;
+ }
+ if (openssl_default_provider) {
+ OSSL_PROVIDER_unload(openssl_default_provider);
+ openssl_default_provider = NULL;
}
#endif /* OpenSSL version >= 3.0 */
}
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+
static BIGNUM * get_group5_prime(void)
{
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
return BN_get_rfc3526_prime_1536(NULL);
#elif !defined(OPENSSL_IS_BORINGSSL)
return get_rfc3526_prime_1536(NULL);
@@ -195,6 +253,8 @@
return BN_bin2bn(RFC3526_ORDER_1536, sizeof(RFC3526_ORDER_1536), NULL);
}
+#endif /* OpenSSL version < 3.0 */
+
#ifdef OPENSSL_NO_SHA256
#define NO_SHA256_WRAPPER
@@ -403,7 +463,7 @@
if (ctx == NULL)
return NULL;
if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
- os_free(ctx);
+ EVP_CIPHER_CTX_free(ctx);
return NULL;
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
@@ -501,8 +561,52 @@
#ifndef CONFIG_FIPS
#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static const EVP_CIPHER * aes_get_evp_wrap_cipher(size_t keylen)
+{
+ switch (keylen) {
+ case 16:
+ return EVP_aes_128_wrap();
+ case 24:
+ return EVP_aes_192_wrap();
+ case 32:
+ return EVP_aes_256_wrap();
+ default:
+ return NULL;
+ }
+}
+#endif /* OpenSSL version >= 3.0 */
+
+
int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *type;
+ int ret = -1, len;
+ u8 buf[16];
+
+ if (TEST_FAIL())
+ return -1;
+
+ type = aes_get_evp_wrap_cipher(kek_len);
+ if (!type)
+ return -1;
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ return -1;
+
+ if (EVP_EncryptInit_ex(ctx, type, NULL, kek, NULL) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_EncryptUpdate(ctx, cipher, &len, plain, n * 8) == 1 &&
+ len == (n + 1) * 8 &&
+ EVP_EncryptFinal_ex(ctx, buf, &len) == 1)
+ ret = 0;
+
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+#else /* OpenSSL version >= 3.0 */
AES_KEY actx;
int res;
@@ -513,12 +617,40 @@
res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
OPENSSL_cleanse(&actx, sizeof(actx));
return res <= 0 ? -1 : 0;
+#endif /* OpenSSL version >= 3.0 */
}
int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
u8 *plain)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *type;
+ int ret = -1, len;
+ u8 buf[16];
+
+ if (TEST_FAIL())
+ return -1;
+
+ type = aes_get_evp_wrap_cipher(kek_len);
+ if (!type)
+ return -1;
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ return -1;
+
+ if (EVP_DecryptInit_ex(ctx, type, NULL, kek, NULL) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_DecryptUpdate(ctx, plain, &len, cipher, (n + 1) * 8) == 1 &&
+ len == n * 8 &&
+ EVP_DecryptFinal_ex(ctx, buf, &len) == 1)
+ ret = 0;
+
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+#else /* OpenSSL version >= 3.0 */
AES_KEY actx;
int res;
@@ -529,6 +661,7 @@
res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
OPENSSL_cleanse(&actx, sizeof(actx));
return res <= 0 ? -1 : 0;
+#endif /* OpenSSL version >= 3.0 */
}
#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
@@ -819,9 +952,7 @@
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
size_t publen, privlen;
@@ -870,6 +1001,57 @@
wpabuf_clear_free(privkey);
DH_free(dh);
return NULL;
+#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *pkey = NULL;
+ OSSL_PARAM params[2];
+ size_t pub_len = OSSL_PARAM_UNMODIFIED;
+ size_t priv_len;
+ struct wpabuf *pubkey = NULL, *privkey = NULL;
+ BIGNUM *priv_bn = NULL;
+ EVP_PKEY_CTX *gctx;
+
+ *priv = NULL;
+ wpabuf_free(*publ);
+ *publ = NULL;
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+ "modp_1536", 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ gctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
+ if (!gctx ||
+ EVP_PKEY_keygen_init(gctx) != 1 ||
+ EVP_PKEY_CTX_set_params(gctx, params) != 1 ||
+ EVP_PKEY_generate(gctx, &pkey) != 1 ||
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
+ &priv_bn) != 1 ||
+ EVP_PKEY_get_octet_string_param(pkey,
+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+ NULL, 0, &pub_len) < 0 ||
+ pub_len == OSSL_PARAM_UNMODIFIED ||
+ (priv_len = BN_num_bytes(priv_bn)) == 0 ||
+ !(pubkey = wpabuf_alloc(pub_len)) ||
+ !(privkey = wpabuf_alloc(priv_len)) ||
+ EVP_PKEY_get_octet_string_param(pkey,
+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+ wpabuf_put(pubkey, pub_len),
+ pub_len, NULL) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ wpabuf_free(pubkey);
+ wpabuf_clear_free(privkey);
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ } else {
+ BN_bn2bin(priv_bn, wpabuf_put(privkey, priv_len));
+
+ *priv = privkey;
+ *publ = pubkey;
+ }
+
+ BN_clear_free(priv_bn);
+ EVP_PKEY_CTX_free(gctx);
+ return pkey;
#else
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
@@ -929,9 +1111,7 @@
void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
DH *dh;
dh = DH_new();
@@ -962,6 +1142,39 @@
err:
DH_free(dh);
return NULL;
+#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *pkey = NULL;
+ OSSL_PARAM_BLD *bld;
+ OSSL_PARAM *params = NULL;
+ BIGNUM *priv_key, *pub_key;
+ EVP_PKEY_CTX *fctx;
+
+ fctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
+ priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+ pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+ bld = OSSL_PARAM_BLD_new();
+ if (!fctx || !priv_key || !pub_key || !bld ||
+ OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME,
+ "modp_1536", 0) != 1 ||
+ OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY,
+ priv_key) != 1 ||
+ OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY,
+ pub_key) != 1 ||
+ !(params = OSSL_PARAM_BLD_to_param(bld)) ||
+ EVP_PKEY_fromdata_init(fctx) != 1 ||
+ EVP_PKEY_fromdata(fctx, &pkey, EVP_PKEY_KEYPAIR, params) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_fromdata failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+
+ BN_clear_free(priv_key);
+ BN_free(pub_key);
+ EVP_PKEY_CTX_free(fctx);
+ OSSL_PARAM_BLD_free(bld);
+ OSSL_PARAM_free(params);
+ return pkey;
#else
DH *dh;
BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL;
@@ -1004,6 +1217,36 @@
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *pkey = ctx;
+ EVP_PKEY *peer_pub;
+ size_t len;
+ struct wpabuf *res = NULL;
+ EVP_PKEY_CTX *dctx = NULL;
+
+ peer_pub = EVP_PKEY_new();
+ if (!pkey || !peer_pub ||
+ EVP_PKEY_copy_parameters(peer_pub, pkey) != 1 ||
+ EVP_PKEY_set1_encoded_public_key(peer_pub, wpabuf_head(peer_public),
+ wpabuf_len(peer_public)) != 1 ||
+ !(dctx = EVP_PKEY_CTX_new(pkey, NULL)) ||
+ EVP_PKEY_derive_init(dctx) != 1 ||
+ EVP_PKEY_derive_set_peer(dctx, peer_pub) != 1 ||
+ EVP_PKEY_derive(dctx, NULL, &len) != 1 ||
+ !(res = wpabuf_alloc(len)) ||
+ EVP_PKEY_derive(dctx, wpabuf_mhead(res), &len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ wpabuf_free(res);
+ res = NULL;
+ } else {
+ wpabuf_put(res, len);
+ }
+
+ EVP_PKEY_free(peer_pub);
+ EVP_PKEY_CTX_free(dctx);
+ return res;
+#else /* OpenSSL version >= 3.0 */
BIGNUM *pub_key;
struct wpabuf *res = NULL;
size_t rlen;
@@ -1035,27 +1278,93 @@
BN_clear_free(pub_key);
wpabuf_clear_free(res);
return NULL;
+#endif /* OpenSSL version >= 3.0 */
}
void dh5_free(void *ctx)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *pkey = ctx;
+
+ EVP_PKEY_free(pkey);
+#else /* OpenSSL version >= 3.0 */
DH *dh;
if (ctx == NULL)
return;
dh = ctx;
DH_free(dh);
+#endif /* OpenSSL version >= 3.0 */
}
struct crypto_hash {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_CTX *ctx;
+#else /* OpenSSL version >= 3.0 */
HMAC_CTX *ctx;
+#endif /* OpenSSL version >= 3.0 */
};
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct crypto_hash *ctx;
+ EVP_MAC *mac;
+ OSSL_PARAM params[2];
+ char *a = NULL;
+
+ switch (alg) {
+#ifndef OPENSSL_NO_MD5
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ a = "MD5";
+ break;
+#endif /* OPENSSL_NO_MD5 */
+#ifndef OPENSSL_NO_SHA
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ a = "SHA1";
+ break;
+#endif /* OPENSSL_NO_SHA */
+#ifndef OPENSSL_NO_SHA256
+#ifdef CONFIG_SHA256
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ a = "SHA256";
+ break;
+#endif /* CONFIG_SHA256 */
+#endif /* OPENSSL_NO_SHA256 */
+ default:
+ return NULL;
+ }
+
+ mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ if (!mac)
+ return NULL;
+
+ params[0] = OSSL_PARAM_construct_utf8_string("digest", a, 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+ ctx->ctx = EVP_MAC_CTX_new(mac);
+ if (!ctx->ctx) {
+ EVP_MAC_free(mac);
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (EVP_MAC_init(ctx->ctx, key, key_len, params) != 1) {
+ EVP_MAC_CTX_free(ctx->ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+ EVP_MAC_free(mac);
+ return NULL;
+ }
+
+ EVP_MAC_free(mac);
+ return ctx;
+#else /* OpenSSL version >= 3.0 */
struct crypto_hash *ctx;
const EVP_MD *md;
@@ -1097,6 +1406,7 @@
}
return ctx;
+#endif /* OpenSSL version >= 3.0 */
}
@@ -1104,12 +1414,49 @@
{
if (ctx == NULL)
return;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_update(ctx->ctx, data, len);
+#else /* OpenSSL version >= 3.0 */
HMAC_Update(ctx->ctx, data, len);
+#endif /* OpenSSL version >= 3.0 */
}
int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ size_t mdlen;
+ int res;
+
+ if (!ctx)
+ return -2;
+
+ if (!mac || !len) {
+ EVP_MAC_CTX_free(ctx->ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+ return 0;
+ }
+
+ res = EVP_MAC_final(ctx->ctx, NULL, &mdlen, 0);
+ if (res != 1) {
+ EVP_MAC_CTX_free(ctx->ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+ return -1;
+ }
+ res = EVP_MAC_final(ctx->ctx, mac, &mdlen, mdlen);
+ EVP_MAC_CTX_free(ctx->ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (res == 1) {
+ *len = mdlen;
+ return 0;
+ }
+
+ return -1;
+#else /* OpenSSL version >= 3.0 */
unsigned int mdlen;
int res;
@@ -1136,9 +1483,148 @@
}
return -1;
+#endif /* OpenSSL version >= 3.0 */
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+static int openssl_hmac_vector(char *digest, const u8 *key,
+ size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac,
+ unsigned int mdlen)
+{
+ EVP_MAC *hmac;
+ OSSL_PARAM params[2];
+ EVP_MAC_CTX *ctx;
+ size_t i, mlen;
+ int res;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ if (!hmac)
+ return -1;
+
+ params[0] = OSSL_PARAM_construct_utf8_string("digest", digest, 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ ctx = EVP_MAC_CTX_new(hmac);
+ EVP_MAC_free(hmac);
+ if (!ctx)
+ return -1;
+
+ if (EVP_MAC_init(ctx, key, key_len, params) != 1)
+ goto fail;
+
+ for (i = 0; i < num_elem; i++) {
+ if (EVP_MAC_update(ctx, addr[i], len[i]) != 1)
+ goto fail;
+ }
+
+ res = EVP_MAC_final(ctx, mac, &mlen, mdlen);
+ EVP_MAC_CTX_free(ctx);
+
+ return res == 1 ? 0 : -1;
+fail:
+ EVP_MAC_CTX_free(ctx);
+ return -1;
+}
+
+
+#ifndef CONFIG_FIPS
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("MD5", key ,key_len, num_elem, addr, len,
+ mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("SHA1", key, key_len, num_elem, addr,
+ len, mac, 20);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("SHA256", key, key_len, num_elem, addr,
+ len, mac, 32);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("SHA384", key, key_len, num_elem, addr,
+ len, mac, 48);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("SHA512", key, key_len, num_elem, addr,
+ len, mac, 64);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+#else /* OpenSSL version >= 3.0 */
+
static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac,
@@ -1188,16 +1674,6 @@
#endif /* CONFIG_FIPS */
-int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
- int iterations, u8 *buf, size_t buflen)
-{
- if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
- ssid_len, iterations, buflen, buf) != 1)
- return -1;
- return 0;
-}
-
-
int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
@@ -1269,6 +1745,18 @@
#endif /* CONFIG_SHA512 */
+#endif /* OpenSSL version >= 3.0 */
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+ int iterations, u8 *buf, size_t buflen)
+{
+ if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+ ssid_len, iterations, buflen, buf) != 1)
+ return -1;
+ return 0;
+}
+
int crypto_get_random(void *buf, size_t len)
{
@@ -1278,10 +1766,49 @@
}
-#ifdef CONFIG_OPENSSL_CMAC
int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_CTX *ctx = NULL;
+ EVP_MAC *emac;
+ int ret = -1;
+ size_t outlen, i;
+ OSSL_PARAM params[2];
+ char *cipher = NULL;
+
+ if (TEST_FAIL())
+ return -1;
+
+ emac = EVP_MAC_fetch(NULL, "CMAC", NULL);
+
+ if (key_len == 32)
+ cipher = "aes-256-cbc";
+ else if (key_len == 24)
+ cipher = "aes-192-cbc";
+ else if (key_len == 16)
+ cipher = "aes-128-cbc";
+
+ params[0] = OSSL_PARAM_construct_utf8_string("cipher", cipher, 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ if (!emac || !cipher ||
+ !(ctx = EVP_MAC_CTX_new(emac)) ||
+ EVP_MAC_init(ctx, key, key_len, params) != 1)
+ goto fail;
+
+ for (i = 0; i < num_elem; i++) {
+ if (!EVP_MAC_update(ctx, addr[i], len[i]))
+ goto fail;
+ }
+ if (EVP_MAC_final(ctx, mac, &outlen, 16) != 1 || outlen != 16)
+ goto fail;
+
+ ret = 0;
+fail:
+ EVP_MAC_CTX_free(ctx);
+ return ret;
+#else /* OpenSSL version >= 3.0 */
CMAC_CTX *ctx;
int ret = -1;
size_t outlen, i;
@@ -1296,6 +1823,9 @@
if (key_len == 32) {
if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL))
goto fail;
+ } else if (key_len == 24) {
+ if (!CMAC_Init(ctx, key, 24, EVP_aes_192_cbc(), NULL))
+ goto fail;
} else if (key_len == 16) {
if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
goto fail;
@@ -1313,6 +1843,7 @@
fail:
CMAC_CTX_free(ctx);
return ret;
+#endif /* OpenSSL version >= 3.0 */
}
@@ -1333,7 +1864,6 @@
{
return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
}
-#endif /* CONFIG_OPENSSL_CMAC */
struct crypto_bignum * crypto_bignum_init(void)
@@ -1752,7 +2282,7 @@
e->b = BN_new();
if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
e->order == NULL || e->a == NULL || e->b == NULL ||
- !EC_GROUP_get_curve_GFp(e->group, e->prime, e->a, e->b, e->bnctx) ||
+ !EC_GROUP_get_curve(e->group, e->prime, e->a, e->b, e->bnctx) ||
!EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
crypto_ec_deinit(e);
e = NULL;
@@ -1847,10 +2377,10 @@
int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
struct crypto_bignum *x)
{
- return EC_POINT_get_affine_coordinates_GFp(e->group,
- (const EC_POINT *) p,
- (BIGNUM *) x, NULL,
- e->bnctx) == 1 ? 0 : -1;
+ return EC_POINT_get_affine_coordinates(e->group,
+ (const EC_POINT *) p,
+ (BIGNUM *) x, NULL,
+ e->bnctx) == 1 ? 0 : -1;
}
@@ -1868,8 +2398,8 @@
y_bn = BN_new();
if (x_bn && y_bn &&
- EC_POINT_get_affine_coordinates_GFp(e->group, (EC_POINT *) point,
- x_bn, y_bn, e->bnctx)) {
+ EC_POINT_get_affine_coordinates(e->group, (EC_POINT *) point,
+ x_bn, y_bn, e->bnctx)) {
if (x) {
crypto_bignum_to_bin((struct crypto_bignum *) x_bn,
x, len, len);
@@ -1907,8 +2437,7 @@
return NULL;
}
- if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y,
- e->bnctx)) {
+ if (!EC_POINT_set_affine_coordinates(e->group, elem, x, y, e->bnctx)) {
EC_POINT_clear_free(elem);
elem = NULL;
}
@@ -2009,8 +2538,8 @@
x = BN_new();
y = BN_new();
if (!x || !y ||
- EC_POINT_get_affine_coordinates_GFp(e->group, (const EC_POINT *) p,
- x, y, e->bnctx) != 1)
+ EC_POINT_get_affine_coordinates(e->group, (const EC_POINT *) p,
+ x, y, e->bnctx) != 1)
goto fail;
x_str = BN_bn2hex(x);
@@ -2035,6 +2564,33 @@
struct crypto_ecdh * crypto_ecdh_init(int group)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct crypto_ecdh *ecdh;
+ const char *name;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ name = OSSL_EC_curve_nid2name(ecdh->ec->nid);
+ if (!name)
+ goto fail;
+
+ ecdh->pkey = EVP_EC_gen(name);
+ if (!ecdh->pkey)
+ goto fail;
+
+done:
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ ecdh = NULL;
+ goto done;
+#else /* OpenSSL version >= 3.0 */
struct crypto_ecdh *ecdh;
EVP_PKEY *params = NULL;
EC_KEY *ec_params = NULL;
@@ -2089,11 +2645,32 @@
crypto_ecdh_deinit(ecdh);
ecdh = NULL;
goto done;
+#endif /* OpenSSL version >= 3.0 */
}
struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct crypto_ecdh *ecdh;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ ecdh->pkey = EVP_PKEY_dup((EVP_PKEY *) own_key);
+ if (!ecdh->pkey)
+ goto fail;
+
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ return NULL;
+#else /* OpenSSL version >= 3.0 */
struct crypto_ecdh *ecdh;
ecdh = os_zalloc(sizeof(*ecdh));
@@ -2115,11 +2692,34 @@
fail:
crypto_ecdh_deinit(ecdh);
return NULL;
+#endif /* OpenSSL version >= 3.0 */
}
struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct wpabuf *buf = NULL;
+ unsigned char *pub;
+ size_t len, exp_len;
+
+ len = EVP_PKEY_get1_encoded_public_key(ecdh->pkey, &pub);
+ if (len == 0)
+ return NULL;
+
+ /* Encoded using SECG SEC 1, Sec. 2.3.4 format */
+ exp_len = 1 + 2 * crypto_ec_prime_len(ecdh->ec);
+ if (len != exp_len) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL:%s: Unexpected encoded public key length %zu (expected %zu)",
+ __func__, len, exp_len);
+ goto fail;
+ }
+ buf = wpabuf_alloc_copy(pub + 1, inc_y ? len - 1 : len / 2);
+fail:
+ OPENSSL_free(pub);
+ return buf;
+#else /* OpenSSL version >= 3.0 */
struct wpabuf *buf = NULL;
EC_KEY *eckey;
const EC_POINT *pubkey;
@@ -2145,10 +2745,10 @@
if (!x || !buf)
goto fail;
- if (EC_POINT_get_affine_coordinates_GFp(ecdh->ec->group, pubkey,
- x, y, ecdh->ec->bnctx) != 1) {
+ if (EC_POINT_get_affine_coordinates(ecdh->ec->group, pubkey,
+ x, y, ecdh->ec->bnctx) != 1) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EC_POINT_get_affine_coordinates_GFp failed: %s",
+ "OpenSSL: EC_POINT_get_affine_coordinates failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
@@ -2175,12 +2775,57 @@
wpabuf_free(buf);
buf = NULL;
goto done;
+#endif /* OpenSSL version >= 3.0 */
}
struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
const u8 *key, size_t len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *peerkey = EVP_PKEY_new();
+ EVP_PKEY_CTX *ctx;
+ size_t res_len;
+ struct wpabuf *res = NULL;
+ u8 *peer;
+
+ /* Encode using SECG SEC 1, Sec. 2.3.4 format */
+ peer = os_malloc(1 + len);
+ if (!peer)
+ return NULL;
+ peer[0] = inc_y ? 0x04 : 0x02;
+ os_memcpy(peer + 1, key, len);
+
+ if (!peerkey ||
+ EVP_PKEY_copy_parameters(peerkey, ecdh->pkey) != 1 ||
+ EVP_PKEY_set1_encoded_public_key(peerkey, peer, 1 + len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_set1_encoded_public_key failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_PKEY_free(peerkey);
+ os_free(peer);
+ return NULL;
+ }
+ os_free(peer);
+
+ ctx = EVP_PKEY_CTX_new(ecdh->pkey, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, peerkey) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &res_len) != 1 ||
+ !(res = wpabuf_alloc(res_len)) ||
+ EVP_PKEY_derive(ctx, wpabuf_mhead(res), &res_len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ wpabuf_free(res);
+ res = NULL;
+ } else {
+ wpabuf_put(res, res_len);
+ }
+
+ EVP_PKEY_free(peerkey);
+ EVP_PKEY_CTX_free(ctx);
+ return res;
+#else /* OpenSSL version >= 3.0 */
BIGNUM *x, *y = NULL;
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *peerkey = NULL;
@@ -2198,19 +2843,18 @@
y = BN_bin2bn(key + len / 2, len / 2, NULL);
if (!y)
goto fail;
- if (!EC_POINT_set_affine_coordinates_GFp(ecdh->ec->group, pub,
- x, y,
- ecdh->ec->bnctx)) {
+ if (!EC_POINT_set_affine_coordinates(ecdh->ec->group, pub,
+ x, y, ecdh->ec->bnctx)) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+ "OpenSSL: EC_POINT_set_affine_coordinates failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
- } else if (!EC_POINT_set_compressed_coordinates_GFp(ecdh->ec->group,
- pub, x, 0,
- ecdh->ec->bnctx)) {
+ } else if (!EC_POINT_set_compressed_coordinates(ecdh->ec->group,
+ pub, x, 0,
+ ecdh->ec->bnctx)) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EC_POINT_set_compressed_coordinates_GFp failed: %s",
+ "OpenSSL: EC_POINT_set_compressed_coordinates failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
@@ -2270,6 +2914,7 @@
wpabuf_free(secret);
secret = NULL;
goto done;
+#endif /* OpenSSL version >= 3.0 */
}
@@ -2370,9 +3015,9 @@
if (!x || !y || !point)
goto fail;
- if (!EC_POINT_set_affine_coordinates_GFp(ec_group, point, x, y, ctx)) {
+ if (!EC_POINT_set_affine_coordinates(ec_group, point, x, y, ctx)) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+ "OpenSSL: EC_POINT_set_affine_coordinates failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
@@ -2777,12 +3422,53 @@
}
-struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
- const u8 *data, size_t len)
+static int openssl_evp_pkey_ec_prime_len(struct crypto_ec_key *key)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ char gname[50];
+ int nid;
+ EC_GROUP *group;
+ BIGNUM *prime = NULL;
+ int prime_len = -1;
+
+ if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname),
+ NULL) != 1)
+ return -1;
+ nid = OBJ_txt2nid(gname);
+ group = EC_GROUP_new_by_curve_name(nid);
+ prime = BN_new();
+ if (!group || !prime)
+ return -1;
+ if (EC_GROUP_get_curve(group, prime, NULL, NULL, NULL) == 1)
+ prime_len = BN_num_bytes(prime);
+ EC_GROUP_free(group);
+ BN_free(prime);
+ return prime_len;
+#else
const EC_GROUP *group;
const EC_KEY *eckey;
BIGNUM *prime = NULL;
+ int prime_len = -1;
+
+ eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!eckey)
+ goto fail;
+ group = EC_KEY_get0_group(eckey);
+ prime = BN_new();
+ if (!prime || !group ||
+ !EC_GROUP_get_curve(group, prime, NULL, NULL, NULL))
+ goto fail;
+ prime_len = BN_num_bytes(prime);
+fail:
+ BN_free(prime);
+ return prime_len;
+#endif
+}
+
+
+struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
+ const u8 *data, size_t len)
+{
ECDSA_SIG *sig = NULL;
const BIGNUM *r, *s;
u8 *r_buf, *s_buf;
@@ -2790,20 +3476,15 @@
const unsigned char *p;
int prime_len;
+ prime_len = openssl_evp_pkey_ec_prime_len(key);
+ if (prime_len < 0)
+ return NULL;
+
buf = crypto_ec_key_sign(key, data, len);
if (!buf)
return NULL;
/* Extract (r,s) from Ecdsa-Sig-Value */
- eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
- if (!eckey)
- goto fail;
- group = EC_KEY_get0_group(eckey);
- prime = BN_new();
- if (!prime || !group ||
- !EC_GROUP_get_curve_GFp(group, prime, NULL, NULL, NULL))
- goto fail;
- prime_len = BN_num_bytes(prime);
p = wpabuf_head(buf);
sig = d2i_ECDSA_SIG(NULL, &p, wpabuf_len(buf));
@@ -2822,7 +3503,6 @@
goto fail;
out:
- BN_free(prime);
ECDSA_SIG_free(sig);
return buf;
fail:
@@ -2893,6 +3573,15 @@
int crypto_ec_key_group(struct crypto_ec_key *key)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ char gname[50];
+ int nid;
+
+ if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname),
+ NULL) != 1)
+ return -1;
+ nid = OBJ_txt2nid(gname);
+#else
const EC_KEY *eckey;
const EC_GROUP *group;
int nid;
@@ -2904,6 +3593,7 @@
if (!group)
return -1;
nid = EC_GROUP_get_curve_name(group);
+#endif
switch (nid) {
case NID_X9_62_prime256v1:
return 19;
@@ -2932,8 +3622,13 @@
int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (EVP_PKEY_eq((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1)
+ return -1;
+#else
if (EVP_PKEY_cmp((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1)
return -1;
+#endif
return 0;
}
@@ -3242,3 +3937,138 @@
}
#endif /* CONFIG_ECC */
+
+
+static EVP_PKEY * crypto_rsa_key_read_public(FILE *f)
+{
+ EVP_PKEY *pkey;
+ X509 *x509;
+
+ pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
+ if (pkey)
+ return pkey;
+
+ rewind(f);
+ x509 = PEM_read_X509(f, NULL, NULL, NULL);
+ if (!x509)
+ return NULL;
+
+ pkey = X509_get_pubkey(x509);
+ X509_free(x509);
+
+ if (!pkey)
+ return NULL;
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+
+ return pkey;
+}
+
+
+struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key)
+{
+ FILE *f;
+ EVP_PKEY *pkey;
+
+ f = fopen(file, "r");
+ if (!f)
+ return NULL;
+ if (private_key)
+ pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL);
+ else
+ pkey = crypto_rsa_key_read_public(f);
+ fclose(f);
+ return (struct crypto_rsa_key *) pkey;
+}
+
+
+#ifndef OPENSSL_NO_SHA256
+
+struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in)
+{
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+ EVP_PKEY_CTX *pkctx;
+ struct wpabuf *res = NULL;
+ size_t outlen;
+
+ pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (!pkctx)
+ goto fail;
+
+ if (EVP_PKEY_encrypt_init(pkctx) != 1 ||
+ EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 ||
+ EVP_PKEY_encrypt(pkctx, NULL, &outlen, wpabuf_head(in),
+ wpabuf_len(in)) != 1 ||
+ !(res = wpabuf_alloc(outlen)) ||
+ EVP_PKEY_encrypt(pkctx, wpabuf_put(res, 0), &outlen,
+ wpabuf_head(in), wpabuf_len(in)) != 1) {
+ wpabuf_free(res);
+ res = NULL;
+ goto fail;
+ }
+ wpabuf_put(res, outlen);
+
+fail:
+ EVP_PKEY_CTX_free(pkctx);
+ return res;
+#else
+ wpa_printf(MSG_ERROR, "%s() not supported", __func__);
+ return NULL;
+#endif
+}
+
+
+struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in)
+{
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+ EVP_PKEY_CTX *pkctx;
+ struct wpabuf *res = NULL;
+ size_t outlen;
+
+ pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (!pkctx)
+ goto fail;
+
+ if (EVP_PKEY_decrypt_init(pkctx) != 1 ||
+ EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 ||
+ EVP_PKEY_decrypt(pkctx, NULL, &outlen, wpabuf_head(in),
+ wpabuf_len(in)) != 1 ||
+ !(res = wpabuf_alloc(outlen)) ||
+ EVP_PKEY_decrypt(pkctx, wpabuf_put(res, 0), &outlen,
+ wpabuf_head(in), wpabuf_len(in)) != 1) {
+ wpabuf_free(res);
+ res = NULL;
+ goto fail;
+ }
+ wpabuf_put(res, outlen);
+
+fail:
+ EVP_PKEY_CTX_free(pkctx);
+ return res;
+#else
+ wpa_printf(MSG_ERROR, "%s() not supported", __func__);
+ return NULL;
+#endif
+}
+
+#endif /* OPENSSL_NO_SHA256 */
+
+
+void crypto_rsa_key_free(struct crypto_rsa_key *key)
+{
+ EVP_PKEY_free((EVP_PKEY *) key);
+}
+
+
+void crypto_unload(void)
+{
+ openssl_unload_legacy_provider();
+}
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 00ecf61..f47beeb 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -26,6 +26,8 @@
#include <wolfssl/wolfcrypt/dh.h>
#include <wolfssl/wolfcrypt/cmac.h>
#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/wolfcrypt/asn_public.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/openssl/bn.h>
@@ -85,6 +87,7 @@
wc_ShaUpdate(&sha, addr[i], len[i]);
wc_ShaFinal(&sha, mac);
+ wc_ShaFree(&sha);
return 0;
}
@@ -106,6 +109,7 @@
wc_Sha256Update(&sha256, addr[i], len[i]);
wc_Sha256Final(&sha256, mac);
+ wc_Sha256Free(&sha256);
return 0;
}
@@ -128,6 +132,7 @@
wc_Sha384Update(&sha384, addr[i], len[i]);
wc_Sha384Final(&sha384, mac);
+ wc_Sha384Free(&sha384);
return 0;
}
@@ -150,6 +155,7 @@
wc_Sha512Update(&sha512, addr[i], len[i]);
wc_Sha512Final(&sha512, mac);
+ wc_Sha512Free(&sha512);
return 0;
}
@@ -169,13 +175,16 @@
if (TEST_FAIL())
return -1;
- if (wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
+ if (wc_HmacInit(&hmac, NULL, INVALID_DEVID) != 0 ||
+ wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
return -1;
for (i = 0; i < num_elem; i++)
if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0)
return -1;
if (wc_HmacFinal(&hmac, mac) != 0)
return -1;
+ wc_HmacFree(&hmac);
+
return 0;
}
@@ -274,9 +283,18 @@
int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen)
{
- if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
- ssid_len, iterations, buflen, WC_SHA) != 0)
+ int ret;
+
+ ret = wc_PBKDF2(buf, (const byte *) passphrase, os_strlen(passphrase),
+ ssid, ssid_len, iterations, buflen, WC_SHA);
+ if (ret != 0) {
+ if (ret == HMAC_MIN_KEYLEN_E) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Password is too short. Make sure your password is at least %d characters long. This is a requirement for FIPS builds.",
+ HMAC_FIPS_MIN_KEY);
+ }
return -1;
+ }
return 0;
}
@@ -409,8 +427,11 @@
}
+#ifndef CONFIG_FIPS
+#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
{
+#ifdef HAVE_AES_KEYWRAP
int ret;
if (TEST_FAIL())
@@ -419,12 +440,16 @@
ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
NULL);
return ret != (n + 1) * 8 ? -1 : 0;
+#else /* HAVE_AES_KEYWRAP */
+ return -1;
+#endif /* HAVE_AES_KEYWRAP */
}
int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
u8 *plain)
{
+#ifdef HAVE_AES_KEYWRAP
int ret;
if (TEST_FAIL())
@@ -433,7 +458,12 @@
ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
NULL);
return ret != n * 8 ? -1 : 0;
+#else /* HAVE_AES_KEYWRAP */
+ return -1;
+#endif /* HAVE_AES_KEYWRAP */
}
+#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
+#endif /* CONFIG_FIPS */
#ifndef CONFIG_NO_RC4
@@ -670,6 +700,7 @@
!= 0)
goto done;
+ priv_sz = pub_sz = RFC3526_LEN;
if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &priv_sz,
wpabuf_mhead(pubkey), &pub_sz) != 0)
goto done;
@@ -803,6 +834,7 @@
if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
goto done;
+ priv_sz = pub_sz = prime_len;
if (wc_DhGenerateKeyPair(dh, &rng, privkey, &priv_sz, pubkey, &pub_sz)
!= 0)
goto done;
@@ -919,7 +951,8 @@
goto done;
}
- if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
+ if (wc_HmacInit(&hash->hmac, NULL, INVALID_DEVID) != 0 ||
+ wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
goto done;
ret = hash;
@@ -1634,35 +1667,21 @@
crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
const struct crypto_bignum *x)
{
- mp_int *y2 = NULL;
- mp_int t;
- int calced = 0;
+ mp_int *y2;
if (TEST_FAIL())
return NULL;
- if (mp_init(&t) != MP_OKAY)
- return NULL;
-
+ /* y^2 = x^3 + ax + b = (x^2 + a)x + b */
y2 = (mp_int *) crypto_bignum_init();
- if (!y2)
- goto done;
-
- if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+ if (!y2 ||
+ mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+ mp_addmod(y2, &e->a, &e->prime, y2) != 0 ||
mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 ||
- mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 ||
- mp_addmod(y2, &t, &e->prime, y2) != 0 ||
- mp_addmod(y2, &e->b, &e->prime, y2) != 0)
- goto done;
-
- calced = 1;
-done:
- if (!calced) {
- if (y2) {
- mp_clear(y2);
- os_free(y2);
- }
- mp_clear(&t);
+ mp_addmod(y2, &e->b, &e->prime, y2) != 0) {
+ mp_clear(y2);
+ os_free(y2);
+ y2 = NULL;
}
return (struct crypto_bignum *) y2;
@@ -1694,33 +1713,37 @@
struct crypto_ecdh {
struct crypto_ec *ec;
+ WC_RNG rng;
};
struct crypto_ecdh * crypto_ecdh_init(int group)
{
struct crypto_ecdh *ecdh = NULL;
- WC_RNG rng;
int ret;
- if (wc_InitRng(&rng) != 0)
- goto fail;
-
ecdh = os_zalloc(sizeof(*ecdh));
if (!ecdh)
goto fail;
+ if (wc_InitRng(&ecdh->rng) != 0)
+ goto fail;
+
ecdh->ec = crypto_ec_init(group);
if (!ecdh->ec)
goto fail;
- ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key,
- ecdh->ec->key.dp->id);
+ ret = wc_ecc_make_key_ex(&ecdh->rng, ecdh->ec->key.dp->size,
+ &ecdh->ec->key, ecdh->ec->key.dp->id);
if (ret < 0)
goto fail;
-done:
- wc_FreeRng(&rng);
+#if defined(ECC_TIMING_RESISTANT) && !defined(CONFIG_FIPS)
+ ret = wc_ecc_set_rng(&ecdh->ec->key, &ecdh->rng);
+ if (ret < 0)
+ goto fail;
+#endif /* ECC_TIMING_RESISTANT && !CONFIG_FIPS */
+done:
return ecdh;
fail:
crypto_ecdh_deinit(ecdh);
@@ -1733,6 +1756,7 @@
{
if (ecdh) {
crypto_ec_deinit(ecdh->ec);
+ wc_FreeRng(&ecdh->rng);
os_free(ecdh);
}
}
@@ -1822,4 +1846,266 @@
return crypto_ec_prime_len(ecdh->ec);
}
+
+struct crypto_ec_key {
+ ecc_key *eckey;
+ WC_RNG *rng; /* Needs to be initialized before use.
+ * *NOT* initialized in crypto_ec_key_init */
+};
+
+
+static struct crypto_ec_key * crypto_ec_key_init(void)
+{
+ struct crypto_ec_key *key;
+
+ key = os_zalloc(sizeof(struct crypto_ec_key));
+ if (key) {
+#ifdef CONFIG_FIPS
+ key->eckey = os_zalloc(sizeof(ecc_key));
+#else /* CONFIG_FIPS */
+ key->eckey = wc_ecc_key_new(NULL);
+#endif /* CONFIG_FIPS */
+ /* Omit key->rng initialization because it seeds itself and thus
+ * consumes entropy that may never be used. Lazy initialize when
+ * necessary. */
+ if (!key->eckey) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: crypto_ec_key_init() failed");
+ crypto_ec_key_deinit(key);
+ key = NULL;
+ }
+#ifdef CONFIG_FIPS
+ else if (wc_ecc_init_ex(key->eckey, NULL, INVALID_DEVID) != 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_init_ex failed");
+ crypto_ec_key_deinit(key);
+ key = NULL;
+ }
+#endif /* CONFIG_FIPS */
+ }
+ return key;
+}
+
+
+void crypto_ec_key_deinit(struct crypto_ec_key *key)
+{
+ if (key) {
+#ifdef CONFIG_FIPS
+ os_free(key->rng);
+ os_free(key->eckey);
+#else /* CONFIG_FIPS */
+ wc_rng_free(key->rng);
+ wc_ecc_key_free(key->eckey);
+#endif /* CONFIG_FIPS */
+ os_free(key);
+ }
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
+{
+ struct crypto_ec_key *ret;
+ word32 idx = 0;
+
+ ret = crypto_ec_key_init();
+ if (!ret) {
+ wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+ goto fail;
+ }
+
+ if (wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len) !=
+ 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPrivateKeyDecode failed");
+ goto fail;
+ }
+
+ return ret;
+fail:
+ if (ret)
+ crypto_ec_key_deinit(ret);
+ return NULL;
+}
+
+
+int crypto_ec_key_group(struct crypto_ec_key *key)
+{
+
+ if (!key || !key->eckey || !key->eckey->dp) {
+ wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+ __func__);
+ return -1;
+ }
+
+ switch (key->eckey->dp->id) {
+ case ECC_SECP256R1:
+ return 19;
+ case ECC_SECP384R1:
+ return 20;
+ case ECC_SECP521R1:
+ return 21;
+ case ECC_BRAINPOOLP256R1:
+ return 28;
+ case ECC_BRAINPOOLP384R1:
+ return 29;
+ case ECC_BRAINPOOLP512R1:
+ return 30;
+ }
+
+ wpa_printf(MSG_ERROR, "wolfSSL: Unsupported curve (id=%d) in EC key",
+ key->eckey->dp->id);
+ return -1;
+}
+
+
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
+{
+ byte *der = NULL;
+ int der_len;
+ struct wpabuf *ret = NULL;
+
+ if (!key || !key->eckey) {
+ wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+ __func__);
+ goto fail;
+ }
+
+ der_len = wc_EccPublicKeyDerSize(key->eckey, 1);
+ if (der_len <= 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDerSize failed");
+ goto fail;
+ }
+
+ der = os_malloc(der_len);
+ if (!der)
+ goto fail;
+
+ der_len = wc_EccPublicKeyToDer(key->eckey, der, der_len, 1);
+ if (der_len <= 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyToDer failed");
+ goto fail;
+ }
+
+ ret = wpabuf_alloc_copy(der, der_len);
+ os_free(der);
+ return ret;
+
+fail:
+ os_free(der);
+ return NULL;
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
+{
+ word32 idx = 0;
+ struct crypto_ec_key *ret = NULL;
+
+ ret = crypto_ec_key_init();
+ if (!ret) {
+ wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+ goto fail;
+ }
+
+ if (wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len) != 0)
+ {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDecode failed");
+ goto fail;
+ }
+
+ return ret;
+fail:
+ crypto_ec_key_deinit(ret);
+ return NULL;
+}
+
+
+struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
+ size_t len)
+{
+ byte *der = NULL;
+ int der_len;
+ word32 w32_der_len;
+ struct wpabuf *ret = NULL;
+
+ if (!key || !key->eckey || !data || len == 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+ __func__);
+ goto fail;
+ }
+
+ if (!key->rng) {
+ /* Lazy init key->rng */
+#ifdef CONFIG_FIPS
+ key->rng = os_zalloc(sizeof(WC_RNG));
+#else /* CONFIG_FIPS */
+ key->rng = wc_rng_new(NULL, 0, NULL);
+#endif /* CONFIG_FIPS */
+ if (!key->rng) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_rng_new failed");
+ goto fail;
+ }
+#ifdef CONFIG_FIPS
+ if (wc_InitRng(key->rng) != 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_InitRng failed");
+ goto fail;
+ }
+#endif /* CONFIG_FIPS */
+ }
+
+ der_len = wc_ecc_sig_size(key->eckey);
+ if (der_len <= 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sig_size failed");
+ goto fail;
+ }
+
+ der = os_malloc(der_len);
+ if (!der)
+ goto fail;
+
+ w32_der_len = (word32) der_len;
+ if (wc_ecc_sign_hash(data, len, der, &w32_der_len, key->rng, key->eckey)
+ != 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sign_hash failed");
+ goto fail;
+ }
+
+ ret = wpabuf_alloc_copy(der, der_len);
+ os_free(der);
+ if (!ret)
+ wpa_printf(MSG_ERROR, "wolfSSL: wpabuf_alloc_copy failed");
+ return ret;
+fail:
+ os_free(der);
+ return NULL;
+}
+
+
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+ size_t len, const u8 *sig, size_t sig_len)
+{
+ int res = 0;
+
+ if (!key || !key->eckey || !data || len == 0 || !sig || sig_len == 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+ __func__);
+ return -1;
+ }
+
+ if (wc_ecc_verify_hash(sig, sig_len, data, len, &res, key->eckey) != 0)
+ {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_verify_hash failed");
+ return -1;
+ }
+
+ if (res != 1)
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: crypto_ec_key_verify_signature failed");
+
+ return res;
+}
+
#endif /* CONFIG_ECC */
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c
index 8effe2f..d2bdc95 100644
--- a/src/crypto/sha1-pbkdf2.c
+++ b/src/crypto/sha1-pbkdf2.c
@@ -50,6 +50,8 @@
for (j = 0; j < SHA1_MAC_LEN; j++)
digest[j] ^= tmp2[j];
}
+ forced_memzero(tmp, SHA1_MAC_LEN);
+ forced_memzero(tmp2, SHA1_MAC_LEN);
return 0;
}
@@ -87,6 +89,7 @@
pos += plen;
left -= plen;
}
+ forced_memzero(digest, SHA1_MAC_LEN);
return 0;
}
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 09fb73b..7a2ee32 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -22,7 +22,8 @@
TLS_CERT_CHAIN_SUCCESS,
TLS_CERT_CHAIN_FAILURE,
TLS_PEER_CERTIFICATE,
- TLS_ALERT
+ TLS_ALERT,
+ TLS_UNSAFE_RENEGOTIATION_DISABLED,
};
/*
@@ -112,6 +113,7 @@
#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
#define TLS_CONN_TEAP_ANON_DH BIT(17)
+#define TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION BIT(18)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -148,8 +150,6 @@
* @private_key_passwd: Passphrase for decrypted private key, %NULL if no
* passphrase is used.
* @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
- * @dh_blob: dh_file as inlined data or %NULL if not used
- * @dh_blob_len: dh_blob length
* @engine: 1 = use engine (e.g., a smartcard) for private key operations
* (this is OpenSSL specific for now)
* @engine_id: engine id string (this is OpenSSL specific for now)
@@ -198,8 +198,6 @@
const char *private_key_passwd;
const char *private_key_passwd2;
const char *dh_file;
- const u8 *dh_blob;
- size_t dh_blob_len;
/* OpenSSL specific variables */
int engine;
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index daa01d9..e3f5b5a 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -1766,6 +1766,7 @@
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
+ wpabuf_free(data);
}
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 8095b43..f3e05ce 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -281,13 +281,6 @@
return -1;
}
- if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
- params->dh_blob_len)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
- tlsv1_cred_free(cred);
- return -1;
- }
-
if (tlsv1_client_set_cred(conn->client, cred) < 0) {
tlsv1_cred_free(cred);
return -1;
@@ -342,8 +335,7 @@
return -1;
}
- if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
- params->dh_blob_len)) {
+ if (tlsv1_set_dhparams(cred, params->dh_file, NULL, 0)) {
wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
return -1;
}
@@ -791,6 +783,7 @@
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
+ wpabuf_free(data);
}
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 6d6fb0c..87f45f8 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -212,6 +212,7 @@
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
+ wpabuf_free(data);
}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index ba3ef80..a1b5166 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -7,6 +7,9 @@
*/
#include "includes.h"
+#ifdef CONFIG_TESTING_OPTIONS
+#include <fcntl.h>
+#endif /* CONFIG_TESTING_OPTIONS */
#ifndef CONFIG_SMARTCARD
#ifndef OPENSSL_NO_ENGINE
@@ -24,14 +27,21 @@
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif /* OPENSSL_NO_ENGINE */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/core_names.h>
+#include <openssl/decoder.h>
+#include <openssl/param_build.h>
+#else /* OpenSSL version >= 3.0 */
#ifndef OPENSSL_NO_DSA
#include <openssl/dsa.h>
#endif
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
+#endif /* OpenSSL version >= 3.0 */
#include "common.h"
+#include "utils/list.h"
#include "crypto.h"
#include "sha1.h"
#include "sha256.h"
@@ -65,9 +75,7 @@
#endif /* OPENSSL_NO_TLSEXT */
#endif /* SSL_set_tlsext_status_type */
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \
+#if OPENSSL_VERSION_NUMBER < 0x10100000L && \
!defined(BORINGSSL_API_VERSION)
/*
* SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
@@ -111,17 +119,7 @@
#endif
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-#ifdef CONFIG_SUITEB
-static int RSA_bits(const RSA *r)
-{
- return BN_num_bits(r->n);
-}
-#endif /* CONFIG_SUITEB */
-
-
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
{
return ASN1_STRING_data((ASN1_STRING *) x);
@@ -234,12 +232,18 @@
static int tls_openssl_ref_count = 0;
static int tls_ex_idx_session = -1;
+struct tls_session_data {
+ struct dl_list list;
+ struct wpabuf *buf;
+};
+
struct tls_context {
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
void *cb_ctx;
int cert_in_cb;
char *ocsp_stapling_response;
+ struct dl_list sessions; /* struct tls_session_data */
};
static struct tls_context *tls_global = NULL;
@@ -307,6 +311,7 @@
struct tls_context *context = os_zalloc(sizeof(*context));
if (context == NULL)
return NULL;
+ dl_list_init(&context->sessions);
if (conf) {
context->event_cb = conf->event_cb;
context->cb_ctx = conf->cb_ctx;
@@ -958,21 +963,53 @@
#endif /* OPENSSL_NO_ENGINE */
+static struct tls_session_data * get_session_data(struct tls_context *context,
+ const struct wpabuf *buf)
+{
+ struct tls_session_data *data;
+
+ dl_list_for_each(data, &context->sessions, struct tls_session_data,
+ list) {
+ if (data->buf == buf)
+ return data;
+ }
+
+ return NULL;
+}
+
+
static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
{
struct wpabuf *buf;
+ struct tls_context *context;
+ struct tls_session_data *found;
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Remove session %p (tls_ex_idx_session=%d)", sess,
+ tls_ex_idx_session);
if (tls_ex_idx_session < 0)
return;
buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
if (!buf)
return;
+
+ context = SSL_CTX_get_app_data(ctx);
+ SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+ found = get_session_data(context, buf);
+ if (!found) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Do not free application session data %p (sess %p)",
+ buf, sess);
+ return;
+ }
+
+ dl_list_del(&found->list);
+ os_free(found);
wpa_printf(MSG_DEBUG,
"OpenSSL: Free application session data %p (sess %p)",
buf, sess);
wpabuf_free(buf);
-
- SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
}
@@ -1019,9 +1056,7 @@
}
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_load_error_strings();
SSL_library_init();
#ifndef OPENSSL_NO_SHA256
@@ -1098,8 +1133,19 @@
SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ /* One session ticket is sufficient for EAP-TLS */
+ SSL_CTX_set_num_tickets(ssl, 1);
+#endif
} else {
SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ SSL_CTX_set_num_tickets(ssl, 0);
+#endif
}
if (tls_ex_idx_session < 0) {
@@ -1148,18 +1194,30 @@
struct tls_data *data = ssl_ctx;
SSL_CTX *ssl = data->ssl;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
+ struct tls_session_data *sess_data;
+
+ if (data->tls_session_lifetime > 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions");
+ SSL_CTX_flush_sessions(ssl, 0);
+ wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions - done");
+ }
+ while ((sess_data = dl_list_first(&context->sessions,
+ struct tls_session_data, list))) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Freeing not-flushed session data %p",
+ sess_data->buf);
+ wpabuf_free(sess_data->buf);
+ dl_list_del(&sess_data->list);
+ os_free(sess_data);
+ }
if (context != tls_global)
os_free(context);
- if (data->tls_session_lifetime > 0)
- SSL_CTX_flush_sessions(ssl, 0);
os_free(data->ca_cert);
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
if (tls_openssl_ref_count == 0) {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
@@ -1561,6 +1619,63 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+/*
+ * By setting the environment variable SSLKEYLOGFILE to a filename keying
+ * material will be exported that you may use with Wireshark to decode any
+ * TLS flows. Please see the following for more details:
+ *
+ * https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption
+ *
+ * Example logging sessions are (you should delete the file on each run):
+ *
+ * rm -f /tmp/sslkey.log
+ * env SSLKEYLOGFILE=/tmp/sslkey.log hostapd ...
+ *
+ * rm -f /tmp/sslkey.log
+ * env SSLKEYLOGFILE=/tmp/sslkey.log wpa_supplicant ...
+ *
+ * rm -f /tmp/sslkey.log
+ * env SSLKEYLOGFILE=/tmp/sslkey.log eapol_test ...
+ */
+static void tls_keylog_cb(const SSL *ssl, const char *line)
+{
+ int fd;
+ const char *filename;
+ struct iovec iov[2];
+
+ filename = getenv("SSLKEYLOGFILE");
+ if (!filename)
+ return;
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to open keylog file %s: %s",
+ filename, strerror(errno));
+ return;
+ }
+
+ /* Assume less than _POSIX_PIPE_BUF (512) where writes are guaranteed
+ * to be atomic for O_APPEND. */
+ iov[0].iov_base = (void *) line;
+ iov[0].iov_len = os_strlen(line);
+ iov[1].iov_base = "\n";
+ iov[1].iov_len = 1;
+
+ if (writev(fd, iov, ARRAY_SIZE(iov)) < 01) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Failed to write to keylog file %s: %s",
+ filename, strerror(errno));
+ }
+
+ close(fd);
+}
+#endif
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
struct tls_data *data = ssl_ctx;
@@ -1618,6 +1733,14 @@
SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
#endif
+#ifdef CONFIG_TESTING_OPTIONS
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+ /* Set the keylog file if the admin requested it. */
+ if (getenv("SSLKEYLOGFILE"))
+ SSL_CTX_set_keylog_callback(conn->ssl_ctx, tls_keylog_cb);
+#endif
+#endif /* CONFIG_TESTING_OPTIONS */
+
conn->ssl_in = BIO_new(BIO_s_mem());
if (!conn->ssl_in) {
tls_show_errors(MSG_INFO, __func__,
@@ -2560,16 +2683,11 @@
#ifdef CONFIG_SUITEB
if (conn->flags & TLS_CONN_SUITEB) {
EVP_PKEY *pk;
- RSA *rsa;
int len = -1;
pk = X509_get_pubkey(err_cert);
if (pk) {
- rsa = EVP_PKEY_get1_RSA(pk);
- if (rsa) {
- len = RSA_bits(rsa);
- RSA_free(rsa);
- }
+ len = EVP_PKEY_bits(pk);
EVP_PKEY_free(pk);
}
@@ -2960,7 +3078,6 @@
#ifdef CONFIG_SUITEB
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
static int suiteb_cert_cb(SSL *ssl, void *arg)
{
struct tls_connection *conn = arg;
@@ -2987,7 +3104,6 @@
conn->server_dh_prime_len);
return 0;
}
-#endif /* OPENSSL_VERSION_NUMBER */
#endif /* CONFIG_SUITEB */
@@ -3003,6 +3119,11 @@
SSL_clear_options(ssl, SSL_OP_NO_TICKET);
#endif /* SSL_OP_NO_TICKET */
+#ifdef SSL_OP_LEGACY_SERVER_CONNECT
+ if (flags & TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION)
+ SSL_set_options(ssl, SSL_OP_LEGACY_SERVER_CONNECT);
+#endif /* SSL_OP_LEGACY_SERVER_CONNECT */
+
#ifdef SSL_OP_NO_TLSv1
if (flags & TLS_CONN_DISABLE_TLSv1_0)
SSL_set_options(ssl, SSL_OP_NO_TLSv1);
@@ -3082,7 +3203,6 @@
/* Start with defaults from BoringSSL */
SSL_set_verify_algorithm_prefs(conn->ssl, NULL, 0);
#endif /* OPENSSL_IS_BORINGSSL */
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (flags & TLS_CONN_SUITEB_NO_ECDH) {
const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
@@ -3098,7 +3218,9 @@
return -1;
}
} else if (flags & TLS_CONN_SUITEB) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
EC_KEY *ecdh;
+#endif
const char *ciphers =
"ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
int nid[1] = { NID_secp384r1 };
@@ -3115,6 +3237,14 @@
return -1;
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (SSL_set1_groups(ssl, nid, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B groups");
+ return -1;
+ }
+
+#else
if (SSL_set1_curves(ssl, nid, 1) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set Suite B curves");
@@ -3129,6 +3259,7 @@
return -1;
}
EC_KEY_free(ecdh);
+#endif
}
if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
#ifdef OPENSSL_IS_BORINGSSL
@@ -3153,13 +3284,6 @@
SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
SSL_set_cert_cb(ssl, suiteb_cert_cb, conn);
}
-#else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
- if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
- wpa_printf(MSG_ERROR,
- "OpenSSL: Suite B RSA case not supported with this OpenSSL version");
- return -1;
- }
-#endif /* OPENSSL_VERSION_NUMBER */
#ifdef OPENSSL_IS_BORINGSSL
if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
@@ -3293,14 +3417,14 @@
return 0;
#ifdef PKCS12_FUNCS
-#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
+#ifdef LIBRESSL_VERSION_NUMBER
/*
* Clear previously set extra chain certificates, if any, from PKCS#12
- * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
+ * processing in tls_parse_pkcs12() to allow LibreSSL to build a new
* chain properly.
*/
SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
-#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+#endif /* LIBRESSL_VERSION_NUMBER */
#endif /* PKCS12_FUNCS */
if (client_cert_blob &&
@@ -3493,7 +3617,7 @@
}
if (certs) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
+#ifndef LIBRESSL_VERSION_NUMBER
if (ssl)
SSL_clear_chain_certs(ssl);
else
@@ -3542,7 +3666,7 @@
* the extra certificates not to be required.
*/
res = 0;
-#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
+#else /* LIBRESSL_VERSION_NUMBER */
SSL_CTX_clear_extra_chain_certs(data->ssl);
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
@@ -3561,7 +3685,7 @@
}
}
sk_X509_pop_free(certs, X509_free);
-#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
+#endif /* LIBRSESSL_VERSION_NUMBER */
}
PKCS12_free(p12);
@@ -3862,6 +3986,7 @@
}
#endif /* OPENSSL_NO_EC */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
(u8 *) private_key_blob,
private_key_blob_len) == 1) {
@@ -3870,6 +3995,7 @@
ok = 1;
break;
}
+#endif
bio = BIO_new_mem_buf((u8 *) private_key_blob,
private_key_blob_len);
@@ -3977,79 +4103,44 @@
}
-static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
-{
-#ifdef OPENSSL_NO_DH
- if (dh_file == NULL)
- return 0;
- wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
- "dh_file specified");
- return -1;
-#else /* OPENSSL_NO_DH */
- DH *dh;
- BIO *bio;
-
- /* TODO: add support for dh_blob */
- if (dh_file == NULL)
- return 0;
- if (conn == NULL)
- return -1;
-
- bio = BIO_new_file(dh_file, "r");
- if (bio == NULL) {
- wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
- dh_file, ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
- dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
- BIO_free(bio);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#ifndef OPENSSL_NO_DH
#ifndef OPENSSL_NO_DSA
- while (dh == NULL) {
- DSA *dsa;
- wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
- " trying to parse as DSA params", dh_file,
- ERR_error_string(ERR_get_error(), NULL));
- bio = BIO_new_file(dh_file, "r");
- if (bio == NULL)
- break;
- dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
- BIO_free(bio);
- if (!dsa) {
- wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
- "'%s': %s", dh_file,
- ERR_error_string(ERR_get_error(), NULL));
- break;
- }
+/* This is needed to replace the deprecated DSA_dup_DH() function */
+static EVP_PKEY * openssl_dsa_to_dh(EVP_PKEY *dsa)
+{
+ OSSL_PARAM_BLD *bld = NULL;
+ OSSL_PARAM *params = NULL;
+ BIGNUM *p = NULL, *q = NULL, *g = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *pkey = NULL;
- wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
- dh = DSA_dup_DH(dsa);
- DSA_free(dsa);
- if (dh == NULL) {
- wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
- "params into DH params");
- break;
- }
- break;
- }
-#endif /* !OPENSSL_NO_DSA */
- if (dh == NULL) {
- wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
- "'%s'", dh_file);
- return -1;
- }
+ if (!EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_P, &p) ||
+ !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_Q, &q) ||
+ !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_G, &g) ||
+ !(bld = OSSL_PARAM_BLD_new()) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) ||
+ !(params = OSSL_PARAM_BLD_to_param(bld)) ||
+ !(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL)) ||
+ EVP_PKEY_fromdata_init(ctx) != 1 ||
+ EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEY_PARAMETERS,
+ params) != 1)
+ wpa_printf(MSG_INFO,
+ "TLS: Failed to convert DSA parameters to DH parameters");
- if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
- wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
- "%s", dh_file,
- ERR_error_string(ERR_get_error(), NULL));
- DH_free(dh);
- return -1;
- }
- DH_free(dh);
- return 0;
-#endif /* OPENSSL_NO_DH */
+ EVP_PKEY_CTX_free(ctx);
+ OSSL_PARAM_free(params);
+ OSSL_PARAM_BLD_free(bld);
+ BN_free(p);
+ BN_free(q);
+ BN_free(g);
+ return pkey;
}
-
+#endif /* !OPENSSL_NO_DSA */
+#endif /* OPENSSL_NO_DH */
+#endif /* OpenSSL version >= 3.0 */
static int tls_global_dh(struct tls_data *data, const char *dh_file)
{
@@ -4060,15 +4151,88 @@
"dh_file specified");
return -1;
#else /* OPENSSL_NO_DH */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ SSL_CTX *ssl_ctx = data->ssl;
+ BIO *bio;
+ OSSL_DECODER_CTX *ctx = NULL;
+ EVP_PKEY *pkey = NULL, *tmpkey = NULL;
+ bool dsa = false;
+
+ if (!ssl_ctx)
+ return -1;
+ if (!dh_file) {
+ SSL_CTX_set_dh_auto(ssl_ctx, 1);
+ return 0;
+ }
+
+ bio = BIO_new_file(dh_file, "r");
+ if (!bio) {
+ wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
+ dh_file, ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ ctx = OSSL_DECODER_CTX_new_for_pkey(
+ &tmpkey, "PEM", NULL, NULL,
+ OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, NULL, NULL);
+ if (!ctx ||
+ OSSL_DECODER_from_bio(ctx, bio) != 1) {
+ wpa_printf(MSG_INFO,
+ "TLS: Failed to decode domain parameters from '%s': %s",
+ dh_file, ERR_error_string(ERR_get_error(), NULL));
+ BIO_free(bio);
+ return -1;
+ }
+ BIO_free(bio);
+
+ if (!tmpkey) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load domain parameters");
+ return -1;
+ }
+
+#ifndef OPENSSL_NO_DSA
+ if (EVP_PKEY_is_a(tmpkey, "DSA")) {
+ pkey = openssl_dsa_to_dh(tmpkey);
+ EVP_PKEY_free(tmpkey);
+ if (!pkey)
+ return -1;
+ dsa = true;
+ }
+#endif /* !OPENSSL_NO_DSA */
+ if (!dsa) {
+ if (EVP_PKEY_is_a(tmpkey, "DH") ||
+ EVP_PKEY_is_a(tmpkey, "DHX")) {
+ } else {
+ wpa_printf(MSG_INFO,
+ "TLS: No DH parameters found in %s",
+ dh_file);
+ EVP_PKEY_free(tmpkey);
+ return -1;
+ }
+ pkey = tmpkey;
+ tmpkey = NULL;
+ }
+
+ if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, pkey) != 1) {
+ wpa_printf(MSG_INFO,
+ "TLS: Failed to set DH params from '%s': %s",
+ dh_file, ERR_error_string(ERR_get_error(), NULL));
+ EVP_PKEY_free(pkey);
+ return -1;
+ }
+ return 0;
+#else /* OpenSSL version >= 3.0 */
SSL_CTX *ssl_ctx = data->ssl;
DH *dh;
BIO *bio;
- /* TODO: add support for dh_blob */
- if (dh_file == NULL)
- return 0;
- if (ssl_ctx == NULL)
+ if (!ssl_ctx)
return -1;
+ if (!dh_file) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+ SSL_CTX_set_dh_auto(ssl_ctx, 1);
+#endif
+ return 0;
+ }
bio = BIO_new_file(dh_file, "r");
if (bio == NULL) {
@@ -4122,6 +4286,7 @@
}
DH_free(dh);
return 0;
+#endif /* OpenSSL version >= 3.0 */
#endif /* OPENSSL_NO_DH */
}
@@ -4152,9 +4317,7 @@
#ifdef OPENSSL_NEED_EAP_FAST_PRF
static int openssl_get_keyblock_size(SSL *ssl)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
const EVP_CIPHER *c;
const EVP_MD *h;
int md_size;
@@ -4322,6 +4485,7 @@
static struct wpabuf *
openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
{
+ struct tls_context *context = conn->context;
int res;
struct wpabuf *out_data;
@@ -4351,7 +4515,19 @@
wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
"write");
else {
+ unsigned long error = ERR_peek_last_error();
+
tls_show_errors(MSG_INFO, __func__, "SSL_connect");
+
+ if (context->event_cb &&
+ ERR_GET_LIB(error) == ERR_LIB_SSL &&
+ ERR_GET_REASON(error) ==
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED) {
+ context->event_cb(
+ context->cb_ctx,
+ TLS_UNSAFE_RENEGOTIATION_DISABLED,
+ NULL);
+ }
conn->failed++;
if (!conn->server && !conn->client_hello_generated) {
/* The server would not understand TLS Alert
@@ -4374,8 +4550,6 @@
if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
conn->server_dh_prime_len < 3072) {
- struct tls_context *context = conn->context;
-
/*
* This should not be reached since earlier cert_cb should have
* terminated the handshake. Keep this check here for extra
@@ -4867,6 +5041,21 @@
len = SSL_get_tlsext_status_ocsp_resp(s, &p);
if (!p) {
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
+ if (SSL_version(s) == TLS1_3_VERSION && SSL_session_reused(s)) {
+ /* TLS 1.3 sends the OCSP response with the server
+ * Certificate message. Since that Certificate message
+ * is not sent when resuming a session, there can be no
+ * new OCSP response. Allow this since the OCSP response
+ * was validated when checking the initial certificate
+ * exchange. */
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Allow no OCSP response when using TLS 1.3 and a resumed session");
+ return 1;
+ }
+#endif
+#endif
wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
}
@@ -5268,12 +5457,6 @@
return -1;
}
- if (tls_connection_dh(conn, params->dh_file)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
- params->dh_file);
- return -1;
- }
-
ciphers = params->openssl_ciphers;
#ifdef CONFIG_SUITEB
#ifdef OPENSSL_IS_BORINGSSL
@@ -5295,22 +5478,21 @@
if (!params->openssl_ecdh_curves) {
#ifndef OPENSSL_IS_BORINGSSL
#ifndef OPENSSL_NO_EC
-#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
- (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set ECDH curves to auto");
return -1;
}
-#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* < 1.1.0 */
#endif /* OPENSSL_NO_EC */
#endif /* OPENSSL_IS_BORINGSSL */
} else if (params->openssl_ecdh_curves[0]) {
-#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+#ifdef OPENSSL_IS_BORINGSSL
wpa_printf(MSG_INFO,
- "OpenSSL: ECDH configuration nnot supported");
+ "OpenSSL: ECDH configuration not supported");
return -1;
-#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#else /* !OPENSSL_IS_BORINGSSL */
#ifndef OPENSSL_NO_EC
if (SSL_set1_curves_list(conn->ssl,
params->openssl_ecdh_curves) != 1) {
@@ -5520,22 +5702,21 @@
if (!params->openssl_ecdh_curves) {
#ifndef OPENSSL_IS_BORINGSSL
#ifndef OPENSSL_NO_EC
-#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
- (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set ECDH curves to auto");
return -1;
}
-#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* < 1.1.0 */
#endif /* OPENSSL_NO_EC */
#endif /* OPENSSL_IS_BORINGSSL */
} else if (params->openssl_ecdh_curves[0]) {
-#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+#ifdef OPENSSL_IS_BORINGSSL
wpa_printf(MSG_INFO,
- "OpenSSL: ECDH configuration nnot supported");
+ "OpenSSL: ECDH configuration not supported");
return -1;
-#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#else /* !OPENSSL_IS_BORINGSSL */
#ifndef OPENSSL_NO_EC
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
@@ -5597,9 +5778,7 @@
struct tls_connection *conn = arg;
int ret;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
@@ -5710,6 +5889,7 @@
{
SSL_SESSION *sess;
struct wpabuf *old;
+ struct tls_session_data *sess_data = NULL;
if (tls_ex_idx_session < 0)
goto fail;
@@ -5718,20 +5898,35 @@
goto fail;
old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
if (old) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
- old);
- wpabuf_free(old);
+ struct tls_session_data *found;
+
+ found = get_session_data(conn->context, old);
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Replacing old success data %p (sess %p)%s",
+ old, sess, found ? "" : " (not freeing)");
+ if (found) {
+ dl_list_del(&found->list);
+ os_free(found);
+ wpabuf_free(old);
+ }
}
- if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+
+ sess_data = os_zalloc(sizeof(*sess_data));
+ if (!sess_data ||
+ SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
goto fail;
- wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
+ sess_data->buf = data;
+ dl_list_add(&conn->context->sessions, &sess_data->list);
+ wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p (sess %p)",
+ data, sess);
conn->success_data = 1;
return;
fail:
wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
wpabuf_free(data);
+ os_free(sess_data);
}
diff --git a/src/crypto/tls_openssl_ocsp.c b/src/crypto/tls_openssl_ocsp.c
index 67c329c..a74e6f3 100644
--- a/src/crypto/tls_openssl_ocsp.c
+++ b/src/crypto/tls_openssl_ocsp.c
@@ -638,13 +638,12 @@
buf);
ctx = X509_STORE_CTX_new();
- if (!ctx ||
- !X509_STORE_CTX_init(ctx, store, signer, untrusted) ||
- !X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER)) {
+ if (!ctx || !X509_STORE_CTX_init(ctx, store, signer, untrusted))
goto fail;
- }
+ X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER);
ret = X509_verify_cert(ctx);
chain = X509_STORE_CTX_get1_chain(ctx);
+ X509_STORE_CTX_cleanup(ctx);
if (ret <= 0) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Could not validate OCSP signer certificate");
@@ -657,6 +656,7 @@
}
if (!signer_trusted) {
+ X509_check_purpose(signer, -1, 0);
if ((X509_get_extension_flags(signer) & EXFLAG_XKUSAGE) &&
(X509_get_extended_key_usage(signer) & XKU_OCSP_SIGN)) {
wpa_printf(MSG_DEBUG,
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index cf482bf..b4f1bbe 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -26,6 +26,10 @@
#include <wolfssl/wolfcrypt/aes.h>
#endif
+#ifdef CONFIG_FIPS
+#include <wolfssl/wolfcrypt/fips_test.h>
+#endif /* CONFIG_FIPS */
+
#if !defined(CONFIG_FIPS) && \
(defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
defined(EAP_SERVER_FAST))
@@ -58,6 +62,7 @@
void *cb_ctx;
int cert_in_cb;
char *ocsp_stapling_response;
+ unsigned int tls_session_lifetime;
};
static struct tls_context *tls_global = NULL;
@@ -94,6 +99,7 @@
WOLFSSL_X509 *peer_cert;
WOLFSSL_X509 *peer_issuer;
WOLFSSL_X509 *peer_issuer_issuer;
+ char *peer_subject; /* peer subject info for authenticated peer */
};
@@ -190,6 +196,33 @@
}
+#if defined(CONFIG_FIPS) && defined(HAVE_FIPS)
+static void wcFipsCb(int ok, int err, const char *hash)
+{
+ wpa_printf(MSG_INFO,
+ "wolfFIPS: wolfCrypt Fips error callback, ok = %d, err = %d",
+ ok, err);
+ wpa_printf(MSG_INFO, "wolfFIPS: message = %s", wc_GetErrorString(err));
+ wpa_printf(MSG_INFO, "wolfFIPS: hash = %s", hash);
+ if (err == IN_CORE_FIPS_E) {
+ wpa_printf(MSG_ERROR,
+ "wolfFIPS: In core integrity hash check failure, copy above hash");
+ wpa_printf(MSG_ERROR, "wolfFIPS: into verifyCore[] in fips_test.c and rebuild");
+ }
+}
+#endif /* CONFIG_FIPS && HAVE_FIPS */
+
+
+#ifdef DEBUG_WOLFSSL
+static void wolfSSL_logging_cb(const int log_level,
+ const char * const log_message)
+{
+ (void) log_level;
+ wpa_printf(MSG_DEBUG, "wolfSSL log:%s", log_message);
+}
+#endif /* DEBUG_WOLFSSL */
+
+
void * tls_init(const struct tls_config *conf)
{
WOLFSSL_CTX *ssl_ctx;
@@ -197,6 +230,7 @@
const char *ciphers;
#ifdef DEBUG_WOLFSSL
+ wolfSSL_SetLoggingCb(wolfSSL_logging_cb);
wolfSSL_Debugging_ON();
#endif /* DEBUG_WOLFSSL */
@@ -209,7 +243,9 @@
if (wolfSSL_Init() < 0)
return NULL;
- /* wolfSSL_Debugging_ON(); */
+#if defined(CONFIG_FIPS) && defined(HAVE_FIPS)
+ wolfCrypt_SetCb_fips(wcFipsCb);
+#endif /* CONFIG_FIPS && HAVE_FIPS */
}
tls_ref_count++;
@@ -227,17 +263,21 @@
}
wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb);
wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb);
+ context->tls_session_lifetime = conf->tls_session_lifetime;
wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context);
if (conf->tls_session_lifetime > 0) {
+ wolfSSL_CTX_set_session_id_context(ssl_ctx,
+ (const unsigned char *)
+ "hostapd", 7);
wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1);
wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
- SSL_SESS_CACHE_SERVER);
+ WOLFSSL_SESS_CACHE_SERVER);
wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime);
wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb);
} else {
wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
- SSL_SESS_CACHE_CLIENT);
+ WOLFSSL_SESS_CACHE_OFF);
}
if (conf && conf->openssl_ciphers)
@@ -336,6 +376,7 @@
os_free(conn->alt_subject_match);
os_free(conn->suffix_match);
os_free(conn->domain_match);
+ os_free(conn->peer_subject);
/* self */
os_free(conn);
@@ -369,10 +410,13 @@
wolfSSL_set_quiet_shutdown(conn->ssl, 1);
wolfSSL_shutdown(conn->ssl);
- session = wolfSSL_get_session(conn->ssl);
- if (wolfSSL_clear(conn->ssl) != 1)
+ session = wolfSSL_get1_session(conn->ssl);
+ if (wolfSSL_clear(conn->ssl) != 1) {
+ wolfSSL_SESSION_free(session);
return -1;
+ }
wolfSSL_set_session(conn->ssl, session);
+ wolfSSL_SESSION_free(session);
return 0;
}
@@ -420,44 +464,6 @@
}
-static int tls_connection_dh(struct tls_connection *conn, const char *dh_file,
- const u8 *dh_blob, size_t blob_len)
-{
- if (!dh_file && !dh_blob)
- return 0;
-
- wolfSSL_set_accept_state(conn->ssl);
-
- if (dh_blob) {
- if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
- wpa_printf(MSG_INFO, "SSL: use DH DER blob failed");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "SSL: use DH blob OK");
- return 0;
- }
-
- if (dh_file) {
- wpa_printf(MSG_INFO, "SSL: use DH PEM file: %s", dh_file);
- if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
- SSL_FILETYPE_PEM) < 0) {
- wpa_printf(MSG_INFO, "SSL: use DH PEM file failed");
- if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
- SSL_FILETYPE_ASN1) < 0) {
- wpa_printf(MSG_INFO,
- "SSL: use DH DER file failed");
- return -1;
- }
- }
- wpa_printf(MSG_DEBUG, "SSL: use DH file OK");
- return 0;
- }
-
- return 0;
-}
-
-
static int tls_connection_client_cert(struct tls_connection *conn,
const char *client_cert,
const u8 *client_cert_blob,
@@ -472,7 +478,13 @@
SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert DER blob failed");
- return -1;
+ if (wolfSSL_use_certificate_chain_buffer_format(
+ conn->ssl, client_cert_blob, blob_len,
+ SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert PEM blob failed");
+ return -1;
+ }
}
wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK");
return 0;
@@ -534,23 +546,35 @@
if (private_key_blob) {
if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
private_key_blob, blob_len,
- SSL_FILETYPE_ASN1) <= 0) {
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use private DER blob failed");
+ if (wolfSSL_use_PrivateKey_buffer(
+ conn->ssl,
+ private_key_blob, blob_len,
+ SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: use private PEM blob failed");
+ } else {
+ ok = 1;
+ }
} else {
- wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
ok = 1;
}
+ if (ok)
+ wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
}
if (!ok && private_key) {
if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) <= 0) {
+ SSL_FILETYPE_PEM) !=
+ SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use private key PEM file failed");
if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_ASN1) <= 0)
- {
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use private key DER file failed");
} else {
@@ -721,8 +745,7 @@
WOLFSSL_X509_NAME_ENTRY *e;
WOLFSSL_ASN1_STRING *cn;
- i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME,
- i);
+ i = wolfSSL_X509_NAME_get_index_by_NID(name, NID_commonName, i);
if (i == -1)
break;
e = wolfSSL_X509_NAME_get_entry(name, i);
@@ -1134,6 +1157,11 @@
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
+ if (depth == 0 && preverify_ok) {
+ os_free(conn->peer_subject);
+ conn->peer_subject = os_strdup(buf);
+ }
+
return preverify_ok;
}
@@ -1194,8 +1222,14 @@
if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len,
SSL_FILETYPE_ASN1) !=
SSL_SUCCESS) {
- wpa_printf(MSG_INFO, "SSL: failed to load CA blob");
- return -1;
+ wpa_printf(MSG_INFO, "SSL: failed to load DER CA blob");
+ if (wolfSSL_CTX_load_verify_buffer(
+ ctx, ca_cert_blob, blob_len,
+ SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to load PEM CA blob");
+ return -1;
+ }
}
wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK");
return 0;
@@ -1238,10 +1272,8 @@
static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
{
#ifdef HAVE_SESSION_TICKET
-#if 0
if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
wolfSSL_UseSessionTicket(ssl);
-#endif
#endif /* HAVE_SESSION_TICKET */
if (flags & TLS_CONN_DISABLE_TLSv1_0)
@@ -1250,6 +1282,8 @@
wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
if (flags & TLS_CONN_DISABLE_TLSv1_2)
wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+ if (flags & TLS_CONN_DISABLE_TLSv1_3)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
}
@@ -1289,12 +1323,6 @@
return -1;
}
- if (tls_connection_dh(conn, params->dh_file, params->dh_blob,
- params->dh_blob_len) < 0) {
- wpa_printf(MSG_INFO, "Error setting DH");
- return -1;
- }
-
if (params->openssl_ciphers &&
wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
wpa_printf(MSG_INFO,
@@ -1311,7 +1339,8 @@
WOLFSSL_CSR_OCSP_USE_NONCE) !=
SSL_SUCCESS)
return -1;
- wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS)
+ return -1;
}
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
@@ -1320,7 +1349,8 @@
WOLFSSL_CSR2_OCSP_MULTI, 0) !=
SSL_SUCCESS)
return -1;
- wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS)
+ return -1;
}
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
@@ -1427,25 +1457,10 @@
}
-static int tls_global_dh(void *ssl_ctx, const char *dh_file,
- const u8 *dh_blob, size_t blob_len)
+static int tls_global_dh(void *ssl_ctx, const char *dh_file)
{
WOLFSSL_CTX *ctx = ssl_ctx;
- if (!dh_file && !dh_blob)
- return 0;
-
- if (dh_blob) {
- if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
- wpa_printf(MSG_INFO,
- "SSL: global use DH DER blob failed");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "SSL: global use DH blob OK");
- return 0;
- }
-
if (dh_file) {
if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) <
0) {
@@ -1532,8 +1547,7 @@
return -1;
}
- if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob,
- params->dh_blob_len) < 0) {
+ if (tls_global_dh(tls_ctx, params->dh_file) < 0) {
wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'",
params->dh_file);
return -1;
@@ -1590,6 +1604,9 @@
int verify_peer, unsigned int flags,
const u8 *session_ctx, size_t session_ctx_len)
{
+ static int counter = 0;
+ struct tls_context *context;
+
if (!conn)
return -1;
@@ -1607,6 +1624,22 @@
wolfSSL_set_accept_state(conn->ssl);
+ context = wolfSSL_CTX_get_ex_data((WOLFSSL_CTX *) ssl_ctx, 0);
+ if (context && context->tls_session_lifetime == 0) {
+ /*
+ * Set session id context to a unique value to make sure
+ * session resumption cannot be used either through session
+ * caching or TLS ticket extension.
+ */
+ counter++;
+ wolfSSL_set_session_id_context(conn->ssl,
+ (const unsigned char *) &counter,
+ sizeof(counter));
+ } else {
+ wolfSSL_set_session_id_context(conn->ssl, session_ctx,
+ session_ctx_len);
+ }
+
/* TODO: do we need to fake a session like OpenSSL does here? */
return 0;
@@ -1997,11 +2030,21 @@
const char *label, const u8 *context,
size_t context_len, u8 *out, size_t out_len)
{
- if (context)
+ if (!conn)
return -1;
- if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+#if LIBWOLFSSL_VERSION_HEX >= 0x04007000
+ if (wolfSSL_export_keying_material(conn->ssl, out, out_len,
+ label, os_strlen(label),
+ context, context_len,
+ context != NULL) != WOLFSSL_SUCCESS)
return -1;
return 0;
+#else
+ if (context ||
+ wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+ return -1;
+#endif
+ return 0;
}
@@ -2046,9 +2089,15 @@
_out, skip + out_len);
ret = 0;
} else {
+#ifdef CONFIG_FIPS
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Can't use sha1_md5 in FIPS build");
+ ret = -1;
+#else /* CONFIG_FIPS */
ret = tls_prf_sha1_md5(master_key, master_key_len,
"key expansion", seed, sizeof(seed),
_out, skip + out_len);
+#endif /* CONFIG_FIPS */
}
forced_memzero(master_key, master_key_len);
@@ -2160,6 +2209,39 @@
}
+int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
+{
+ size_t len;
+ int reused;
+
+ reused = wolfSSL_session_reused(conn->ssl);
+ if ((wolfSSL_is_server(conn->ssl) && !reused) ||
+ (!wolfSSL_is_server(conn->ssl) && reused))
+ len = wolfSSL_get_peer_finished(conn->ssl, buf, max_len);
+ else
+ len = wolfSSL_get_finished(conn->ssl, buf, max_len);
+
+ if (len == 0 || len > max_len)
+ return -1;
+
+ return len;
+}
+
+
+u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
+{
+ return (u16) wolfSSL_get_current_cipher_suite(conn->ssl);
+}
+
+
+const char * tls_connection_get_peer_subject(struct tls_connection *conn)
+{
+ if (conn)
+ return conn->peer_subject;
+ return NULL;
+}
+
+
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
@@ -2206,3 +2288,11 @@
return NULL;
return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
}
+
+
+bool tls_connection_get_own_cert_used(struct tls_connection *conn)
+{
+ if (conn)
+ return wolfSSL_get_certificate(conn->ssl) != NULL;
+ return false;
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 8b92e12..46cee44 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -200,6 +200,15 @@
u16 he_6ghz_capa;
};
+/* struct eht_capabilities - IEEE 802.11be EHT capabilities */
+struct eht_capabilities {
+ bool eht_supported;
+ u16 mac_cap;
+ u8 phy_cap[EHT_PHY_CAPAB_LEN];
+ u8 mcs[EHT_MCS_NSS_CAPAB_LEN];
+ u8 ppet[EHT_PPE_THRESH_CAPAB_LEN];
+};
+
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
@@ -298,6 +307,11 @@
* for IEEE 802.11ay EDMG configuration.
*/
struct ieee80211_edmg_config edmg;
+
+ /**
+ * eht_capab - EHT (IEEE 802.11be) capabilities
+ */
+ struct eht_capabilities eht_capab[IEEE80211_MODE_NUM];
};
@@ -338,6 +352,7 @@
* @parent_tsf: Time when the Beacon/Probe Response frame was received in terms
* of TSF of the BSS specified by %tsf_bssid.
* @tsf_bssid: The BSS that %parent_tsf TSF time refers to.
+ * @beacon_newer: Whether the Beacon frame data is known to be newer
* @ie_len: length of the following IE field in octets
* @beacon_ie_len: length of the following Beacon IE field in octets
*
@@ -370,6 +385,7 @@
int snr;
u64 parent_tsf;
u8 tsf_bssid[ETH_ALEN];
+ bool beacon_newer;
size_t ie_len;
size_t beacon_ie_len;
/* Followed by ie_len + beacon_ie_len octets of IE data */
@@ -782,6 +798,16 @@
* for IEEE 802.11ay EDMG configuration.
*/
struct ieee80211_edmg_config edmg;
+
+ /**
+ * radar_background - Whether radar/CAC background is requested
+ */
+ bool radar_background;
+
+ /**
+ * eht_enabled - Whether EHT is enabled
+ */
+ bool eht_enabled;
};
/**
@@ -1036,7 +1062,7 @@
*
* If the driver needs to do special configuration for WPS association,
* this variable provides more information on what type of association
- * is being requested. Most drivers should not need ot use this.
+ * is being requested. Most drivers should not need to use this.
*/
enum wps_mode wps;
@@ -1781,7 +1807,7 @@
WPA_IF_P2P_GROUP,
/**
- * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
+ * WPA_IF_P2P_DEVICE - P2P Device interface is used to identify the
* abstracted P2P Device function in the driver
*/
WPA_IF_P2P_DEVICE,
@@ -2033,6 +2059,10 @@
#define WPA_DRIVER_FLAGS2_OCV 0x0000000000000080ULL
/** Driver expects user space implementation of SME in AP mode */
#define WPA_DRIVER_FLAGS2_AP_SME 0x0000000000000100ULL
+/** Driver handles SA Query procedures in AP mode */
+#define WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP 0x0000000000000200ULL
+/** Driver supports background radar/CAC detection */
+#define WPA_DRIVER_RADAR_BACKGROUND 0x0000000000000400ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2200,6 +2230,8 @@
const struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
+ const struct ieee80211_eht_capabilities *eht_capab;
+ size_t eht_capab_len;
u32 flags; /* bitmask of WPA_STA_* flags */
u32 flags_mask; /* unset bits in flags */
#ifdef CONFIG_MESH
@@ -2403,6 +2435,27 @@
u16 counter_offset_presp[2];
};
+/**
+ * struct cca_settings - Settings for color switch command
+ * @cca_count: Count in Beacon frames (TBTT) to perform the switch
+ * @cca_color: The new color that we are switching to
+ * @beacon_cca: Beacon/Probe Response/(Re)Association Response frame info for
+ * color switch period
+ * @beacon_after: Next Beacon/Probe Response/(Re)Association Response frame info
+ * @counter_offset_beacon: Offset to the count field in Beacon frame tail
+ * @counter_offset_presp: Offset to the count field in Probe Response frame
+ */
+struct cca_settings {
+ u8 cca_count;
+ u8 cca_color;
+
+ struct beacon_data beacon_cca;
+ struct beacon_data beacon_after;
+
+ u16 counter_offset_beacon;
+ u16 counter_offset_presp;
+};
+
/* TDLS peer capabilities for send_tdls_mgmt() */
enum tdls_peer_capability {
TDLS_PEER_HT = BIT(0),
@@ -2467,6 +2520,9 @@
/* Indicates whether EDMG is enabled */
int edmg_enabled;
+
+ /* Indicates whether EHT is enabled */
+ bool eht_enabled;
};
struct wpa_bss_trans_info {
@@ -2608,7 +2664,7 @@
* some drivers may expect them in different order than wpa_supplicant
* is using. If the TX/RX keys are swapped, all TKIP encrypted packets
* will trigger Michael MIC errors. This can be fixed by changing the
- * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
+ * order of MIC keys by swapping the bytes 16..23 and 24..31 of the key
* in driver_*.c set_key() implementation, see driver_ndis.c for an
* example on how this can be done.
*/
@@ -3989,6 +4045,17 @@
int (*switch_channel)(void *priv, struct csa_settings *settings);
/**
+ * switch_color - Announce color switch and migrate the BSS to the
+ * given color
+ * @priv: Private driver interface data
+ * @settings: Settings for CCA period and new color
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to move the BSS to its new color.
+ */
+ int (*switch_color)(void *priv, struct cca_settings *settings);
+
+ /**
* add_tx_ts - Add traffic stream
* @priv: Private driver interface data
* @tsid: Traffic stream ID
@@ -4617,7 +4684,7 @@
* This event must be delivered when a Michael MIC error is detected by
* the local driver. Additional data for event processing is
* provided with union wpa_event_data::michael_mic_failure. This
- * information is used to request new encyption key and to initiate
+ * information is used to request new encryption key and to initiate
* TKIP countermeasures if needed.
*/
EVENT_MICHAEL_MIC_FAILURE,
@@ -5147,6 +5214,26 @@
* non-zero wait time and that has not been explicitly cancelled.
*/
EVENT_TX_WAIT_EXPIRE,
+
+ /**
+ * EVENT_BSS_COLOR_COLLISION - Notification of a BSS color collision
+ */
+ EVENT_BSS_COLOR_COLLISION,
+
+ /**
+ * EVENT_CCA_STARTED_NOTIFY - Notification that CCA has started
+ */
+ EVENT_CCA_STARTED_NOTIFY,
+
+ /**
+ * EVENT_CCA_ABORTED_NOTIFY - Notification that CCA has aborted
+ */
+ EVENT_CCA_ABORTED_NOTIFY,
+
+ /**
+ * EVENT_CCA_NOTIFY - Notification that CCA has completed
+ */
+ EVENT_CCA_NOTIFY,
};
@@ -6039,6 +6126,13 @@
struct unprot_beacon {
const u8 *sa;
} unprot_beacon;
+
+ /**
+ * struct bss_color_collision - Data for EVENT_BSS_COLOR_COLLISION
+ */
+ struct bss_color_collision {
+ u64 bitmap;
+ } bss_color_collision;
};
/**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 9b4166d..cb66dfa 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -17,7 +17,6 @@
#include "eloop.h"
#include "common/ieee802_11_defs.h"
#include "l2_packet/l2_packet.h"
-#include "p2p/p2p.h"
#include "common.h"
#ifndef _BYTE_ORDER
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 741521c..8db7861 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -91,6 +91,10 @@
E2S(UPDATE_DH);
E2S(UNPROT_BEACON);
E2S(TX_WAIT_EXPIRE);
+ E2S(BSS_COLOR_COLLISION);
+ E2S(CCA_STARTED_NOTIFY);
+ E2S(CCA_ABORTED_NOTIFY);
+ E2S(CCA_NOTIFY);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index 3dba13c..b609bbf 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -77,6 +77,9 @@
u8 encoding_sa;
bool encoding_sa_set;
+
+ u64 cipher_suite;
+ bool cipher_suite_set;
};
@@ -460,8 +463,14 @@
*/
static int macsec_drv_set_current_cipher_suite(void *priv, u64 cs)
{
+ struct macsec_drv_data *drv = priv;
+
wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs);
- return 0;
+
+ drv->cipher_suite_set = true;
+ drv->cipher_suite = cs;
+
+ return try_commit(drv);
}
@@ -1063,7 +1072,8 @@
}
-static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci)
+static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci,
+ u64 cs)
{
struct rtnl_link *needle;
void *match;
@@ -1074,6 +1084,8 @@
rtnl_link_set_link(needle, parent);
rtnl_link_macsec_set_sci(needle, sci);
+ if (cs)
+ rtnl_link_macsec_set_cipher_suite(needle, cs);
match = nl_cache_find(cache, (struct nl_object *) needle);
rtnl_link_put(needle);
@@ -1098,6 +1110,7 @@
char *ifname;
u64 sci;
int err;
+ u64 cs = 0;
wpa_printf(MSG_DEBUG, DRV_PREFIX
"%s: create_transmit_sc -> " SCISTR " (conf_offset=%d)",
@@ -1122,6 +1135,12 @@
drv->created_link = true;
+ if (drv->cipher_suite_set) {
+ cs = drv->cipher_suite;
+ drv->cipher_suite_set = false;
+ rtnl_link_macsec_set_cipher_suite(link, cs);
+ }
+
err = rtnl_link_add(drv->sk, link, NLM_F_CREATE);
if (err == -NLE_BUSY) {
wpa_printf(MSG_INFO,
@@ -1137,7 +1156,7 @@
rtnl_link_put(link);
nl_cache_refill(drv->sk, drv->link_cache);
- link = lookup_sc(drv->link_cache, drv->parent_ifi, sci);
+ link = lookup_sc(drv->link_cache, drv->parent_ifi, sci, cs);
if (!link) {
wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link");
return -1;
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index 54964f3..eccaf63 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -861,7 +861,7 @@
}
}
- wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
+ wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
return -1;
}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index a2c4842..5892fc1 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -38,9 +38,9 @@
#include "radiotap_iter.h"
#include "rfkill.h"
#include "driver_nl80211.h"
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
#include "common/brcm_vendor.h"
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
#ifndef NETLINK_CAP_ACK
#define NETLINK_CAP_ACK 10
@@ -2943,6 +2943,8 @@
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
drv->ifindex);
+ bss->beacon_set = 0;
+ bss->freq = 0;
nl80211_put_wiphy_data_ap(bss);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
@@ -3191,7 +3193,7 @@
return num_suites;
}
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
static int wpa_driver_do_broadcom_acs(struct wpa_driver_nl80211_data *drv,
struct drv_acs_params *params)
{
@@ -3241,7 +3243,7 @@
nlmsg_free(msg);
return ret;
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
#ifdef CONFIG_DRIVER_NL80211_BRCM
static int wpa_cross_akm_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[],
@@ -3292,7 +3294,7 @@
#endif /* CONFIG_DRIVER_NL80211_QCA */
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
static int key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
const u8 *key, size_t key_len)
{
@@ -3320,7 +3322,8 @@
return ret;
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+
static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
const u8 *key, size_t key_len,
@@ -3409,12 +3412,13 @@
if (key_flag & KEY_FLAG_PMK) {
if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)
return nl80211_set_pmk(drv, key, key_len, addr);
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
if (drv->vendor_set_pmk) {
wpa_printf(MSG_INFO, "nl80211: key_mgmt_set_key with key_len %lu", (unsigned long) key_len);
return key_mgmt_set_key(drv, key, key_len);
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+
/* The driver does not have any offload mechanism for PMK, so
* there is no need to configure this key. */
return 0;
@@ -4768,10 +4772,24 @@
nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
goto fail;
- if (drv->device_ap_sme &&
- (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) &&
- nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
- goto fail;
+ if (drv->device_ap_sme) {
+ u32 flags = 0;
+
+ if (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) {
+ /* Add the previously used flag attribute to support
+ * older kernel versions and the newer flag bit for
+ * newer kernels. */
+ if (nla_put_flag(msg,
+ NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+ goto fail;
+ flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
+ }
+
+ flags |= NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT;
+
+ if (nla_put_u32(msg, NL80211_ATTR_AP_SETTINGS_FLAGS, flags))
+ goto fail;
+ }
wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
params->pairwise_ciphers);
@@ -5005,15 +5023,19 @@
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
return -ENOBUFS;
+ wpa_printf(MSG_DEBUG, " * eht_enabled=%d", freq->eht_enabled);
wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
+ wpa_printf(MSG_DEBUG, " * radar_background=%d",
+ freq->radar_background);
hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
hw_mode == HOSTAPD_MODE_IEEE80211B;
- if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) {
+ if (freq->vht_enabled ||
+ ((freq->he_enabled || freq->eht_enabled) && !is_24ghz)) {
enum nl80211_chan_width cw;
wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
@@ -5085,6 +5107,9 @@
NL80211_CHAN_NO_HT))
return -ENOBUFS;
}
+ if (freq->radar_background)
+ nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND);
+
return 0;
}
@@ -5097,9 +5122,10 @@
int ret;
wpa_printf(MSG_DEBUG,
- "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
- freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
- freq->bandwidth, freq->center_freq1, freq->center_freq2);
+ "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+ freq->freq, freq->ht_enabled, freq->vht_enabled,
+ freq->he_enabled, freq->eht_enabled, freq->bandwidth,
+ freq->center_freq1, freq->center_freq2);
msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
NL80211_CMD_SET_WIPHY);
@@ -5248,6 +5274,14 @@
goto fail;
}
+ if (params->eht_capab) {
+ wpa_hexdump(MSG_DEBUG, " * eht_capab",
+ params->eht_capab, params->eht_capab_len);
+ if (nla_put(msg, NL80211_ATTR_EHT_CAPABILITY,
+ params->eht_capab_len, params->eht_capab))
+ goto fail;
+ }
+
if (params->ext_capab) {
wpa_hexdump(MSG_DEBUG, " * ext_capab",
params->ext_capab, params->ext_capab_len);
@@ -8298,6 +8332,11 @@
if (save_cookie)
drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
+ if (!wait) {
+ /* There is no need to store this cookie since there
+ * is no wait that could be canceled later. */
+ goto fail;
+ }
if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
wpa_printf(MSG_DEBUG,
"nl80211: Drop oldest pending send frame cookie 0x%llx",
@@ -8428,7 +8467,8 @@
u64 cookie;
/* Cancel the last pending TX cookie */
- nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
+ if (drv->send_frame_cookie != (u64) -1)
+ nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
/*
* Cancel the other pending TX cookies, if any. This is needed since
@@ -8620,7 +8660,6 @@
if (!is_ap_interface(drv->nlmode))
return -1;
wpa_driver_nl80211_del_beacon(bss);
- bss->beacon_set = 0;
/*
* If the P2P GO interface was dynamically added, then it is
@@ -8640,7 +8679,6 @@
if (!is_ap_interface(drv->nlmode))
return -1;
wpa_driver_nl80211_del_beacon(bss);
- bss->beacon_set = 0;
return 0;
}
@@ -10078,6 +10116,87 @@
}
+#ifdef CONFIG_IEEE80211AX
+static int nl80211_switch_color(void *priv, struct cca_settings *settings)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nlattr *beacon_cca;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Color change request (cca_count=%u color=%d)",
+ settings->cca_count, settings->cca_color);
+
+ if (drv->nlmode != NL80211_IFTYPE_AP)
+ return -EOPNOTSUPP;
+
+ if (!settings->beacon_cca.tail)
+ return -EINVAL;
+
+ if (settings->beacon_cca.tail_len <= settings->counter_offset_beacon ||
+ settings->beacon_cca.tail[settings->counter_offset_beacon] !=
+ settings->cca_count)
+ return -EINVAL;
+
+ if (settings->beacon_cca.probe_resp &&
+ (settings->beacon_cca.probe_resp_len <=
+ settings->counter_offset_presp ||
+ settings->beacon_cca.probe_resp[settings->counter_offset_presp] !=
+ settings->cca_count))
+ return -EINVAL;
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_COLOR_CHANGE_REQUEST);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COUNT,
+ settings->cca_count) ||
+ nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COLOR,
+ settings->cca_color))
+ goto error;
+
+ /* beacon_after params */
+ ret = set_beacon_data(msg, &settings->beacon_after);
+ if (ret)
+ goto error;
+
+ /* beacon_csa params */
+ beacon_cca = nla_nest_start(msg, NL80211_ATTR_COLOR_CHANGE_ELEMS);
+ if (!beacon_cca) {
+ ret = -ENOBUFS;
+ goto error;
+ }
+
+ ret = set_beacon_data(msg, &settings->beacon_cca);
+ if (ret)
+ goto error;
+
+ if (nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_BEACON,
+ settings->counter_offset_beacon) ||
+ (settings->beacon_cca.probe_resp &&
+ nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_PRESP,
+ settings->counter_offset_presp))) {
+ ret = -ENOBUFS;
+ goto error;
+ }
+
+ nla_nest_end(msg, beacon_cca);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: switch_color failed err=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+
+error:
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG, "nl80211: Could not build color switch request");
+ return ret;
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
u8 user_priority, u16 admitted_time)
{
@@ -10547,17 +10666,17 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int new_addr = addr != NULL;
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
struct nl_msg *msg;
struct nlattr *params;
int ret;
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
wpa_printf(MSG_DEBUG, "Enter: %s", __FUNCTION__);
if (TEST_FAIL())
return -1;
if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) {
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
if (!addr ) {
addr = drv->global->p2p_perm_addr;
}
@@ -10584,7 +10703,7 @@
return ret;
#else
return -ENOTSUP;
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
}
if (!addr)
addr = drv->perm_addr;
@@ -11233,6 +11352,8 @@
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
(params->vht_enabled &&
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
+ (params->eht_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED)) ||
nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
params->ch_width) ||
add_acs_ch_list(msg, params->freq_list) ||
@@ -11245,9 +11366,10 @@
nla_nest_end(msg, data);
wpa_printf(MSG_DEBUG,
- "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d",
+ "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d EHT: %d BW: %d EDMG: %d",
params->hw_mode, params->ht_enabled, params->ht40_enabled,
- params->vht_enabled, params->ch_width, params->edmg_enabled);
+ params->vht_enabled, params->eht_enabled, params->ch_width,
+ params->edmg_enabled);
ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
@@ -11889,20 +12011,22 @@
static int nl80211_do_acs(void *priv, struct drv_acs_params *params)
{
-#if defined(CONFIG_DRIVER_NL80211_QCA) || defined(CONFIG_DRIVER_NL80211_BRCM)
+#if defined(CONFIG_DRIVER_NL80211_QCA) || defined(CONFIG_DRIVER_NL80211_BRCM) \
+ || defined(CONFIG_DRIVER_NL80211_SYNA)
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
-#endif /* CONFIG_DRIVER_NL80211_QCA || CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_QCA || CONFIG_DRIVER_NL80211_BRCM \
+ || defined(CONFIG_DRIVER_NL80211_SYNA) */
#ifdef CONFIG_DRIVER_NL80211_QCA
if (drv->qca_do_acs)
return nl80211_qca_do_acs(drv, params);
#endif /* CONFIG_DRIVER_NL80211_QCA */
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
if (drv->brcm_do_acs)
return wpa_driver_do_broadcom_acs(drv, params);
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
return -1;
}
@@ -12395,6 +12519,9 @@
.get_survey = wpa_driver_nl80211_get_survey,
.status = wpa_driver_nl80211_status,
.switch_channel = nl80211_switch_channel,
+#ifdef CONFIG_IEEE80211AX
+ .switch_color = nl80211_switch_color,
+#endif /* CONFIG_IEEE80211AX */
#ifdef ANDROID_P2P
.set_noa = wpa_driver_set_p2p_noa,
.get_noa = wpa_driver_get_p2p_noa,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index dcf482a..8ad7184 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -228,9 +228,9 @@
* (NL80211_CMD_VENDOR). 0 if no pending scan request.
*/
int last_scan_cmd;
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
unsigned int vendor_set_pmk:1; /* for legacy set_pmk method before NL80211_CMD_SET_PMK */
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
#ifdef CONFIG_DRIVER_NL80211_QCA
bool roam_indication_done;
u8 *pending_roam_data;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 392b0c6..75df36c 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -664,6 +664,10 @@
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION))
capa->flags2 |= WPA_DRIVER_FLAGS2_OCV;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_RADAR_BACKGROUND))
+ capa->flags2 |= WPA_DRIVER_RADAR_BACKGROUND;
}
@@ -919,8 +923,15 @@
wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
- if (tb[NL80211_ATTR_DEVICE_AP_SME])
+ if (tb[NL80211_ATTR_DEVICE_AP_SME]) {
+ u32 ap_sme_features_flags =
+ nla_get_u32(tb[NL80211_ATTR_DEVICE_AP_SME]);
+
+ if (ap_sme_features_flags & NL80211_AP_SME_SA_QUERY_OFFLOAD)
+ capa->flags2 |= WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP;
+
info->device_ap_sme = 1;
+ }
wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]);
@@ -1020,7 +1031,7 @@
break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
} else if (vinfo->vendor_id == OUI_BRCM) {
switch (vinfo->subcmd) {
case BRCM_VENDOR_SCMD_ACS:
@@ -1038,7 +1049,7 @@
default:
break;
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
}
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
vinfo->vendor_id, vinfo->subcmd);
@@ -1335,7 +1346,7 @@
drv->has_capability = 1;
drv->has_driver_key_mgmt = info.has_key_mgmt | info.has_key_mgmt_iftype;
- /* Fallback to hardcoded defaults if the driver does nott advertize any
+ /* Fallback to hardcoded defaults if the driver does not advertise any
* AKM capabilities. */
if (!drv->has_driver_key_mgmt) {
drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
@@ -1772,12 +1783,14 @@
}
-static void phy_info_iftype_copy(struct he_capabilities *he_capab,
+static void phy_info_iftype_copy(struct hostapd_hw_modes *mode,
enum ieee80211_op_mode opmode,
struct nlattr **tb, struct nlattr **tb_flags)
{
enum nl80211_iftype iftype;
size_t len;
+ struct he_capabilities *he_capab = &mode->he_capab[opmode];
+ struct eht_capabilities *eht_capab = &mode->eht_capab[opmode];
switch (opmode) {
case IEEE80211_MODE_INFRA:
@@ -1847,6 +1860,47 @@
capa = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]);
he_capab->he_6ghz_capa = le_to_host16(capa);
}
+
+ if (!tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC] ||
+ !tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY])
+ return;
+
+ eht_capab->eht_supported = true;
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC] &&
+ nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]) >= 2) {
+ const u8 *pos;
+
+ pos = nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]);
+ eht_capab->mac_cap = WPA_GET_LE16(pos);
+ }
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]);
+ if (len > sizeof(eht_capab->phy_cap))
+ len = sizeof(eht_capab->phy_cap);
+ os_memcpy(eht_capab->phy_cap,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]),
+ len);
+ }
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]);
+ if (len > sizeof(eht_capab->mcs))
+ len = sizeof(eht_capab->mcs);
+ os_memcpy(eht_capab->mcs,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]),
+ len);
+ }
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]);
+ if (len > sizeof(eht_capab->ppet))
+ len = sizeof(eht_capab->ppet);
+ os_memcpy(&eht_capab->ppet,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]),
+ len);
+ }
}
@@ -1868,7 +1922,7 @@
return NL_STOP;
for (i = 0; i < IEEE80211_MODE_NUM; i++)
- phy_info_iftype_copy(&mode->he_capab[i], i, tb, tb_flags);
+ phy_info_iftype_copy(mode, i, tb, tb_flags);
return NL_OK;
}
@@ -2430,7 +2484,7 @@
for (i = 0; i < num_modes; i++) {
struct hostapd_hw_modes *mode = &modes[i];
- char str[200];
+ char str[1000];
char *pos = str;
char *end = pos + sizeof(str);
int j, res;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 177c31d..5c103a4 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -171,6 +171,13 @@
C2S(NL80211_CMD_UNPROT_BEACON)
C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS)
C2S(NL80211_CMD_SET_SAR_SPECS)
+ C2S(NL80211_CMD_OBSS_COLOR_COLLISION)
+ C2S(NL80211_CMD_COLOR_CHANGE_REQUEST)
+ C2S(NL80211_CMD_COLOR_CHANGE_STARTED)
+ C2S(NL80211_CMD_COLOR_CHANGE_ABORTED)
+ C2S(NL80211_CMD_COLOR_CHANGE_COMPLETED)
+ C2S(NL80211_CMD_SET_FILS_AAD)
+ C2S(NL80211_CMD_ASSOC_COMEBACK)
C2S(__NL80211_CMD_AFTER_LAST)
}
#undef C2S
@@ -2410,7 +2417,7 @@
}
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
static void brcm_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
const u8 *data, size_t len)
@@ -2488,7 +2495,7 @@
}
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
@@ -2535,11 +2542,11 @@
case OUI_QCA:
nl80211_vendor_event_qca(drv, subcmd, data, len);
break;
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
case OUI_BRCM:
nl80211_vendor_event_brcm(drv, subcmd, data, len);
break;
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
default:
wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
break;
@@ -2822,7 +2829,8 @@
nla_len(tb[NL80211_ATTR_FRAME]));
break;
default:
- wpa_printf(MSG_INFO, "nl80211: Unxpected ethertype 0x%04x from "
+ wpa_printf(MSG_INFO,
+ "nl80211: Unexpected ethertype 0x%04x from "
MACSTR " over control port",
ethertype, MAC2STR(src_addr));
break;
@@ -2871,9 +2879,12 @@
}
}
wpa_printf(MSG_DEBUG,
- "nl80211: TX frame wait expired for cookie 0x%llx%s",
+ "nl80211: TX frame wait expired for cookie 0x%llx%s%s",
(long long unsigned int) cookie,
- match ? " (match)" : "");
+ match ? " (match)" : "",
+ drv->send_frame_cookie == cookie ? " (match-saved)" : "");
+ if (drv->send_frame_cookie == cookie)
+ drv->send_frame_cookie = (u64) -1;
if (!match)
return;
@@ -2887,6 +2898,69 @@
}
+static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *mac, struct nlattr *timeout)
+{
+ if (!mac || !timeout)
+ return;
+ wpa_printf(MSG_DEBUG, "nl80211: Association comeback requested by "
+ MACSTR " (timeout: %u ms)",
+ MAC2STR((u8 *) nla_data(mac)), nla_get_u32(timeout));
+}
+
+
+#ifdef CONFIG_IEEE80211AX
+
+static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ if (!tb[NL80211_ATTR_OBSS_COLOR_BITMAP])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.bss_color_collision.bitmap =
+ nla_get_u64(tb[NL80211_ATTR_OBSS_COLOR_BITMAP]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08lx",
+ data.bss_color_collision.bitmap);
+ wpa_supplicant_event(drv->ctx, EVENT_BSS_COLOR_COLLISION, &data);
+}
+
+
+static void
+nl80211_color_change_announcement_started(struct wpa_driver_nl80211_data *drv)
+{
+ union wpa_event_data data = {};
+
+ wpa_printf(MSG_DEBUG, "nl80211: CCA started");
+ wpa_supplicant_event(drv->ctx, EVENT_CCA_STARTED_NOTIFY, &data);
+}
+
+
+static void
+nl80211_color_change_announcement_aborted(struct wpa_driver_nl80211_data *drv)
+{
+ union wpa_event_data data = {};
+
+ wpa_printf(MSG_DEBUG, "nl80211: CCA aborted");
+ wpa_supplicant_event(drv->ctx, EVENT_CCA_ABORTED_NOTIFY, &data);
+}
+
+
+static void
+nl80211_color_change_announcement_completed(struct wpa_driver_nl80211_data *drv)
+{
+ union wpa_event_data data = {};
+
+ wpa_printf(MSG_DEBUG, "nl80211: CCA completed");
+ wpa_supplicant_event(drv->ctx, EVENT_CCA_NOTIFY, &data);
+}
+
+#endif /* CONFIG_IEEE80211AX */
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
@@ -3136,6 +3210,24 @@
case NL80211_CMD_FRAME_WAIT_CANCEL:
nl80211_frame_wait_cancel(drv, tb[NL80211_ATTR_COOKIE]);
break;
+ case NL80211_CMD_ASSOC_COMEBACK:
+ nl80211_assoc_comeback(drv, tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_TIMEOUT]);
+ break;
+#ifdef CONFIG_IEEE80211AX
+ case NL80211_CMD_OBSS_COLOR_COLLISION:
+ nl80211_obss_color_collision(drv, tb);
+ break;
+ case NL80211_CMD_COLOR_CHANGE_STARTED:
+ nl80211_color_change_announcement_started(drv);
+ break;
+ case NL80211_CMD_COLOR_CHANGE_ABORTED:
+ nl80211_color_change_announcement_aborted(drv);
+ break;
+ case NL80211_CMD_COLOR_CHANGE_COMPLETED:
+ nl80211_color_change_announcement_completed(drv);
+ break;
+#endif /* CONFIG_IEEE80211AX */
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 1316084..b82e5af 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -713,6 +713,7 @@
[NL80211_BSS_STATUS] = { .type = NLA_U32 },
[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_BEACON_TSF] = { .type = NLA_U64 },
[NL80211_BSS_PARENT_TSF] = { .type = NLA_U64 },
[NL80211_BSS_PARENT_BSSID] = { .type = NLA_UNSPEC },
[NL80211_BSS_LAST_SEEN_BOOTTIME] = { .type = NLA_U64 },
@@ -774,8 +775,10 @@
r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
if (bss[NL80211_BSS_BEACON_TSF]) {
u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]);
- if (tsf > r->tsf)
+ if (tsf > r->tsf) {
r->tsf = tsf;
+ r->beacon_newer = true;
+ }
}
if (bss[NL80211_BSS_SEEN_MS_AGO])
r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index a03d4a0..0186099 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -30,6 +30,10 @@
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
endif
+ifdef CONFIG_DRIVER_NL80211_SYNA
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_SYNA
+endif
+
ifdef CONFIG_DRIVER_MACSEC_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA
DRV_OBJS += ../src/drivers/driver_macsec_qca.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 10eab6a..8c58456 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -44,6 +44,9 @@
ifdef CONFIG_DRIVER_NL80211_BRCM
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
endif
+ifdef CONFIG_DRIVER_NL80211_SYNA
+DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_SYNA
+endif
NEED_SME=y
NEED_AP_MLME=y
NEED_NETLINK=y
diff --git a/src/drivers/ndis_events.c b/src/drivers/ndis_events.c
index 93673a3..4d4ec81 100644
--- a/src/drivers/ndis_events.c
+++ b/src/drivers/ndis_events.c
@@ -372,8 +372,9 @@
L"MSNdis_NotifyAdapterRemoval") == 0) {
ndis_events_adapter_removal(events);
} else {
- wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
- "'%S'", vtClass.bstrVal);
+ wpa_printf(MSG_DEBUG,
+ "Unexpected event - __CLASS: '%S'",
+ vtClass.bstrVal);
}
VariantClear(&vtClass);
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index f962c06..0568a79 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -11,7 +11,7 @@
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -301,6 +301,29 @@
*/
/**
+ * DOC: FILS shared key crypto offload
+ *
+ * This feature is applicable to drivers running in AP mode.
+ *
+ * FILS shared key crypto offload can be advertised by drivers by setting
+ * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD flag. The drivers that support
+ * FILS shared key crypto offload should be able to encrypt and decrypt
+ * association frames for FILS shared key authentication as per IEEE 802.11ai.
+ * With this capability, for FILS key derivation, drivers depend on userspace.
+ *
+ * After FILS key derivation, userspace shares the FILS AAD details with the
+ * driver and the driver stores the same to use in decryption of association
+ * request and in encryption of association response. The below parameters
+ * should be given to the driver in %NL80211_CMD_SET_FILS_AAD.
+ * %NL80211_ATTR_MAC - STA MAC address, used for storing FILS AAD per STA
+ * %NL80211_ATTR_FILS_KEK - Used for encryption or decryption
+ * %NL80211_ATTR_FILS_NONCES - Used for encryption or decryption
+ * (STA Nonce 16 bytes followed by AP Nonce 16 bytes)
+ *
+ * Once the association is done, the driver cleans the FILS AAD data.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -337,7 +360,10 @@
* @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
* %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
* userspace to request deletion of a virtual interface, then requires
- * attribute %NL80211_ATTR_IFINDEX.
+ * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are
+ * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS,
+ * and if this command is used for the transmitting interface, then all
+ * the non-transmitting interfaces are deleted as well.
*
* @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
* by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
@@ -1185,6 +1211,32 @@
* passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
* specify the wiphy index to be applied to.
*
+ * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever
+ * mac80211/drv detects a bss color collision.
+ *
+ * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that
+ * userspace wants to change the BSS color.
+ *
+ * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has
+ * started
+ *
+ * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has
+ * been aborted
+ *
+ * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change
+ * has completed
+ *
+ * @NL80211_CMD_SET_FILS_AAD: Set FILS AAD data to the driver using -
+ * &NL80211_ATTR_MAC - for STA MAC address
+ * &NL80211_ATTR_FILS_KEK - for KEK
+ * &NL80211_ATTR_FILS_NONCES - for FILS Nonces
+ * (STA Nonce 16 bytes followed by AP Nonce 16 bytes)
+ *
+ * @NL80211_CMD_ASSOC_COMEBACK: notification about an association
+ * temporal rejection with comeback. The event includes %NL80211_ATTR_MAC
+ * to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to
+ * specify the timeout value.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1417,6 +1469,18 @@
NL80211_CMD_SET_SAR_SPECS,
+ NL80211_CMD_OBSS_COLOR_COLLISION,
+
+ NL80211_CMD_COLOR_CHANGE_REQUEST,
+
+ NL80211_CMD_COLOR_CHANGE_STARTED,
+ NL80211_CMD_COLOR_CHANGE_ABORTED,
+ NL80211_CMD_COLOR_CHANGE_COMPLETED,
+
+ NL80211_CMD_SET_FILS_AAD,
+
+ NL80211_CMD_ASSOC_COMEBACK,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2413,7 +2477,9 @@
* space supports external authentication. This attribute shall be used
* with %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP request. The driver
* may offload authentication processing to user space if this capability
- * is indicated in the respective requests from the user space.
+ * is indicated in the respective requests from the user space. (This flag
+ * attribute deprecated for %NL80211_CMD_START_AP, use
+ * %NL80211_ATTR_AP_SETTINGS_FLAGS)
*
* @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this
* u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
@@ -2560,6 +2626,43 @@
* disassoc events to indicate that an immediate reconnect to the AP
* is desired.
*
+ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the
+ * %NL80211_CMD_OBSS_COLOR_COLLISION event.
+ *
+ * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's
+ * until the color switch event.
+ * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are
+ * switching to
+ * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE
+ * information for the time while performing a color switch.
+ *
+ * @NL80211_ATTR_MBSSID_CONFIG: Nested attribute for multiple BSSID
+ * advertisements (MBSSID) parameters in AP mode.
+ * Kernel uses this attribute to indicate the driver's support for MBSSID
+ * and enhanced multi-BSSID advertisements (EMA AP) to the userspace.
+ * Userspace should use this attribute to configure per interface MBSSID
+ * parameters.
+ * See &enum nl80211_mbssid_config_attributes for details.
+ *
+ * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements.
+ * Mandatory parameter for the transmitting interface to enable MBSSID.
+ * Optional for the non-transmitting interfaces.
+ *
+ * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain
+ * available for radar/CAC detection on some hw. This chain can't be used
+ * to transmit or receive frames and it is bounded to a running wdev.
+ * Background radar/CAC detection allows to avoid the CAC downtime
+ * switching on a different channel during CAC detection on the selected
+ * radar channel.
+ *
+ * @NL80211_ATTR_AP_SETTINGS_FLAGS: u32 attribute contains ap settings flags,
+ * enumerated in &enum nl80211_ap_settings_flags. This attribute shall be
+ * used with %NL80211_CMD_START_AP request.
+ *
+ * @NL80211_ATTR_EHT_CAPABILITY: EHT Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION). Can be set
+ * only if %NL80211_STA_FLAG_WME is set.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3057,6 +3160,21 @@
NL80211_ATTR_DISABLE_HE,
+ NL80211_ATTR_OBSS_COLOR_BITMAP,
+
+ NL80211_ATTR_COLOR_CHANGE_COUNT,
+ NL80211_ATTR_COLOR_CHANGE_COLOR,
+ NL80211_ATTR_COLOR_CHANGE_ELEMS,
+
+ NL80211_ATTR_MBSSID_CONFIG,
+ NL80211_ATTR_MBSSID_ELEMS,
+
+ NL80211_ATTR_RADAR_BACKGROUND,
+
+ NL80211_ATTR_AP_SETTINGS_FLAGS,
+
+ NL80211_ATTR_EHT_CAPABILITY,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3112,6 +3230,8 @@
#define NL80211_HE_MAX_CAPABILITY_LEN 54
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
+#define NL80211_EHT_MIN_CAPABILITY_LEN 13
+#define NL80211_EHT_MAX_CAPABILITY_LEN 51
#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10
@@ -3139,7 +3259,7 @@
* and therefore can't be created in the normal ways, use the
* %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
* commands to create and destroy one
- * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
+ * @NL80211_IFTYPE_OCB: Outside Context of a BSS
* This mode corresponds to the MIB variable dot11OCBActivated=true
* @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev)
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
@@ -3281,6 +3401,56 @@
};
/**
+ * enum nl80211_eht_gi - EHT guard interval
+ * @NL80211_RATE_INFO_EHT_GI_0_8: 0.8 usec
+ * @NL80211_RATE_INFO_EHT_GI_1_6: 1.6 usec
+ * @NL80211_RATE_INFO_EHT_GI_3_2: 3.2 usec
+ */
+enum nl80211_eht_gi {
+ NL80211_RATE_INFO_EHT_GI_0_8,
+ NL80211_RATE_INFO_EHT_GI_1_6,
+ NL80211_RATE_INFO_EHT_GI_3_2,
+};
+
+/**
+ * enum nl80211_eht_ru_alloc - EHT RU allocation values
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_26: 26-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_52: 52-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_52P26: 52+26-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_106: 106-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_106P26: 106+26 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_242: 242-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_484: 484-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_484P242: 484+242 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_996: 996-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484: 996+484 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242: 996+484+242 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996: 2x996-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484: 2x996+484 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996: 3x996-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484: 3x996+484 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_4x996: 4x996-tone RU allocation
+ */
+enum nl80211_eht_ru_alloc {
+ NL80211_RATE_INFO_EHT_RU_ALLOC_26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_4x996,
+};
+
+/**
* enum nl80211_rate_info - bitrate information
*
* These attribute types are used with %NL80211_STA_INFO_TXRATE
@@ -3319,6 +3489,13 @@
* @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1)
* @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then
* non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc)
+ * @NL80211_RATE_INFO_320_MHZ_WIDTH: 320 MHz bitrate
+ * @NL80211_RATE_INFO_EHT_MCS: EHT MCS index (u8, 0-15)
+ * @NL80211_RATE_INFO_EHT_NSS: EHT NSS value (u8, 1-8)
+ * @NL80211_RATE_INFO_EHT_GI: EHT guard interval identifier
+ * (u8, see &enum nl80211_eht_gi)
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC: EHT RU allocation, if not present then
+ * non-OFDMA was used (u8, see &enum nl80211_eht_ru_alloc)
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -3340,6 +3517,11 @@
NL80211_RATE_INFO_HE_GI,
NL80211_RATE_INFO_HE_DCM,
NL80211_RATE_INFO_HE_RU_ALLOC,
+ NL80211_RATE_INFO_320_MHZ_WIDTH,
+ NL80211_RATE_INFO_EHT_MCS,
+ NL80211_RATE_INFO_EHT_NSS,
+ NL80211_RATE_INFO_EHT_GI,
+ NL80211_RATE_INFO_EHT_RU_ALLOC,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
@@ -3650,11 +3832,20 @@
* capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as
* defined in HE capabilities IE
- * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
- * defined
* @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16),
* given for all 6 GHz band channels
+ * @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are
+ * advertised on this band/for this iftype (binary)
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC: EHT MAC capabilities as in EHT
+ * capabilities element
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY: EHT PHY capabilities as in EHT
+ * capabilities element
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET: EHT supported NSS/MCS as in EHT
+ * capabilities element
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE: EHT PPE thresholds information as
+ * defined in EHT capabilities element
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
+ * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band attribute currently defined
*/
enum nl80211_band_iftype_attr {
__NL80211_BAND_IFTYPE_ATTR_INVALID,
@@ -3665,6 +3856,11 @@
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
+ NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE,
/* keep last */
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
@@ -3809,6 +4005,10 @@
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed
* on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_320MHZ: any 320 MHz channel using this channel
+ * as the primary or any of the secondary channels isn't possible
+ * @NL80211_FREQUENCY_ATTR_NO_EHT: EHT operation is not allowed on this channel
+ * in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3845,6 +4045,8 @@
NL80211_FREQUENCY_ATTR_4MHZ,
NL80211_FREQUENCY_ATTR_8MHZ,
NL80211_FREQUENCY_ATTR_16MHZ,
+ NL80211_FREQUENCY_ATTR_NO_320MHZ,
+ NL80211_FREQUENCY_ATTR_NO_EHT,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -4043,6 +4245,7 @@
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
* @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
* @NL80211_RRF_NO_HE: HE operation not allowed
+ * @NL80211_RRF_NO_320MHZ: 320MHz operation not allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -4061,6 +4264,7 @@
NL80211_RRF_NO_80MHZ = 1<<15,
NL80211_RRF_NO_160MHZ = 1<<16,
NL80211_RRF_NO_HE = 1<<17,
+ NL80211_RRF_NO_320MHZ = 1<<18,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
@@ -4558,6 +4762,8 @@
* @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel
* @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel
* @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_320: 320 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * attribute must be provided as well
*/
enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT,
@@ -4573,6 +4779,7 @@
NL80211_CHAN_WIDTH_4,
NL80211_CHAN_WIDTH_8,
NL80211_CHAN_WIDTH_16,
+ NL80211_CHAN_WIDTH_320,
};
/**
@@ -4887,6 +5094,7 @@
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
* @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz)
* @NL80211_BAND_S1GHZ: around 900MHz, supported by S1G PHYs
+ * @NL80211_BAND_LC: light communication band (placeholder)
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@@ -4896,6 +5104,7 @@
NL80211_BAND_60GHZ,
NL80211_BAND_6GHZ,
NL80211_BAND_S1GHZ,
+ NL80211_BAND_LC,
NUM_NL80211_BANDS,
};
@@ -5462,7 +5671,7 @@
* => allows 8 of AP/GO that can have BI gcd >= min gcd
*
* numbers = [ #{STA} <= 2 ], channels = 2, max = 2
- * => allows two STAs on different channels
+ * => allows two STAs on the same or on different channels
*
* numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
* => allows a STA plus three P2P interfaces
@@ -5507,7 +5716,7 @@
* @NL80211_PLINK_ESTAB: mesh peer link is established
* @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled
* @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh
- * plink are discarded
+ * plink are discarded, except for authentication frames
* @NUM_NL80211_PLINK_STATES: number of peer link states
* @MAX_NL80211_PLINK_STATES: highest numerical value of plink states
*/
@@ -5644,13 +5853,15 @@
NL80211_TDLS_DISABLE_LINK,
};
-/*
+/**
* enum nl80211_ap_sme_features - device-integrated AP features
- * Reserved for future use, no bits are defined in
- * NL80211_ATTR_DEVICE_AP_SME yet.
-enum nl80211_ap_sme_features {
-};
+ * @NL80211_AP_SME_SA_QUERY_OFFLOAD: SA Query procedures offloaded to driver
+ * when user space indicates support for SA Query procedures offload during
+ * "start ap" with %NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT.
*/
+enum nl80211_ap_sme_features {
+ NL80211_AP_SME_SA_QUERY_OFFLOAD = 1 << 0,
+};
/**
* enum nl80211_feature_flags - device/driver features
@@ -5950,6 +6161,17 @@
* frame protection for all management frames exchanged during the
* negotiation and range measurement procedure.
*
+ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
+ * detection and change announcemnts.
+ *
+ * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD: Driver running in AP mode supports
+ * FILS encryption and decryption for (Re)Association Request and Response
+ * frames. Userspace has to share FILS AAD details to the driver by using
+ * @NL80211_CMD_SET_FILS_AAD.
+ *
+ * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC
+ * detection.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -6014,6 +6236,9 @@
NL80211_EXT_FEATURE_SECURE_LTF,
NL80211_EXT_FEATURE_SECURE_RTT,
NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
+ NL80211_EXT_FEATURE_BSS_COLOR,
+ NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD,
+ NL80211_EXT_FEATURE_RADAR_BACKGROUND,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6912,6 +7137,9 @@
* @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only
* valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or
* %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set.
+ * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the
+ * responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED
+ * or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set.
*
* @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
* @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
@@ -6931,6 +7159,7 @@
NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED,
NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED,
NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK,
+ NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR,
/* keep last */
NUM_NL80211_PMSR_FTM_REQ_ATTR,
@@ -7299,4 +7528,76 @@
NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1,
};
+/**
+ * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced
+ * multi-BSSID advertisements (EMA) in AP mode.
+ * Kernel uses some of these attributes to advertise driver's support for
+ * MBSSID and EMA.
+ * Remaining attributes should be used by the userspace to configure the
+ * features.
+ *
+ * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise
+ * the maximum number of MBSSID interfaces supported by the driver.
+ * Driver should indicate MBSSID support by setting
+ * wiphy->mbssid_max_interfaces to a value more than or equal to 2.
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel
+ * to advertise the maximum profile periodicity supported by the driver
+ * if EMA is enabled. Driver should indicate EMA support to the userspace
+ * by setting wiphy->ema_max_profile_periodicity to
+ * a non-zero value.
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of
+ * this BSS (u8) in the multiple BSSID set.
+ * Value must be set to 0 for the transmitting interface and non-zero for
+ * all non-transmitting interfaces. The userspace will be responsible
+ * for using unique indices for the interfaces.
+ * Range: 0 to wiphy->mbssid_max_interfaces-1.
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for
+ * a non-transmitted profile which provides the interface index (u32) of
+ * the transmitted profile. The value must match one of the interface
+ * indices advertised by the kernel. Optional if the interface being set up
+ * is the transmitting one, however, if provided then the value must match
+ * the interface index of the same.
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature.
+ * Setting this flag is permitted only if the driver advertises EMA support
+ * by setting wiphy->ema_max_profile_periodicity to non-zero.
+ *
+ * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal
+ * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute
+ */
+enum nl80211_mbssid_config_attributes {
+ __NL80211_MBSSID_CONFIG_ATTR_INVALID,
+
+ NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES,
+ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY,
+ NL80211_MBSSID_CONFIG_ATTR_INDEX,
+ NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX,
+ NL80211_MBSSID_CONFIG_ATTR_EMA,
+
+ /* keep last */
+ __NL80211_MBSSID_CONFIG_ATTR_LAST,
+ NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_ap_settings_flags - AP settings flags
+ *
+ * @NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external
+ * authentication.
+ * @NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT: Userspace supports SA Query
+ * procedures offload to driver. If driver advertises
+ * %NL80211_AP_SME_SA_QUERY_OFFLOAD in AP SME features, userspace shall
+ * ignore SA Query procedures and validations when this flag is set by
+ * userspace.
+ */
+enum nl80211_ap_settings_flags {
+ NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = 1 << 0,
+ NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 70999c4..3346ec5 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -72,7 +72,7 @@
EAP_TYPE_MD5 = 4, /* RFC 3748 */
EAP_TYPE_OTP = 5 /* RFC 3748 */,
EAP_TYPE_GTC = 6, /* RFC 3748 */
- EAP_TYPE_TLS = 13 /* RFC 2716 */,
+ EAP_TYPE_TLS = 13 /* RFC 5216 */,
EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
EAP_TYPE_SIM = 18 /* RFC 4186 */,
EAP_TYPE_TTLS = 21 /* RFC 5281 */,
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 5fd370f..269d719 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1684,6 +1684,7 @@
struct wpabuf *resp;
const u8 *identity;
size_t identity_len;
+ struct wpabuf *privacy_identity = NULL;
if (config == NULL) {
wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
@@ -1706,6 +1707,30 @@
identity_len = config->machine_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
identity, identity_len);
+ } else if (config->imsi_privacy_key && config->identity &&
+ config->identity_len > 0) {
+ const u8 *pos = config->identity;
+ const u8 *end = config->identity + config->identity_len;
+
+ privacy_identity = wpabuf_alloc(9 + config->identity_len);
+ if (!privacy_identity)
+ return NULL;
+
+ /* Include method prefix */
+ if (*pos == '0' || *pos == '1' || *pos == '6')
+ wpabuf_put_u8(privacy_identity, *pos);
+ wpabuf_put_str(privacy_identity, "anonymous");
+
+ /* Include realm */
+ while (pos < end && *pos != '@')
+ pos++;
+ wpabuf_put_data(privacy_identity, pos, end - pos);
+
+ identity = wpabuf_head(privacy_identity);
+ identity_len = wpabuf_len(privacy_identity);
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP: using IMSI privacy anonymous identity",
+ identity, identity_len);
} else {
identity = config->identity;
identity_len = config->identity_len;
@@ -1742,6 +1767,7 @@
return NULL;
wpabuf_put_data(resp, identity, identity_len);
+ wpabuf_free(privacy_identity);
return resp;
}
@@ -2157,6 +2183,11 @@
eap_notify_status(sm, "remote TLS alert",
data->alert.description);
break;
+ case TLS_UNSAFE_RENEGOTIATION_DISABLED:
+ wpa_printf(MSG_INFO,
+ "TLS handshake failed due to the server not supporting safe renegotiation (RFC 5746); phase1 parameter allow_unsafe_renegotiation=1 can be used to work around this");
+ eap_notify_status(sm, "unsafe server renegotiation", "failure");
+ break;
}
os_free(hash_hex);
@@ -2785,6 +2816,63 @@
return config->identity;
}
+static const u8 * strnchr(const u8 *str, size_t len, u8 needle) {
+ const u8 *cur = str;
+
+ if (NULL == str) return NULL;
+ if (0 >= len) return NULL;
+
+ while (cur < str + len) {
+ if (*cur == needle)
+ return cur;
+ cur++;
+ }
+ return NULL;
+}
+
+const u8 * eap_get_config_realm(struct eap_sm *sm, size_t *len) {
+ struct eap_peer_config *config = eap_get_config(sm);
+ const u8 *realm = NULL;
+ size_t realm_len = 0;
+ const u8 *identity = NULL;
+ size_t identity_len = 0;
+
+ if (!config)
+ return NULL;
+
+ /* Look for the realm of the permanent identity */
+ identity = eap_get_config_identity(sm, &identity_len);
+ realm = strnchr(identity, identity_len, '@');
+ if (NULL != realm) {
+ wpa_printf(MSG_DEBUG, "Get the realm from identity.");
+ *len = identity_len - (realm - identity);
+ return realm;
+ }
+
+ /* Look for the realm of the anonymous identity. */
+ identity = config->anonymous_identity;
+ identity_len = config->anonymous_identity_len;
+ realm = strnchr(identity, identity_len, '@');
+ if (NULL != realm) {
+ wpa_printf(MSG_DEBUG, "Get the realm from anonymous identity.");
+ *len = identity_len - (realm - identity);
+ return realm;
+ }
+
+ /* Look for the realm of the real identity. */
+ identity = config->imsi_identity;
+ identity_len = config->imsi_identity_len;
+ realm = strnchr(identity, identity_len, '@');
+ if (NULL != realm) {
+ wpa_printf(MSG_DEBUG, "Get the realm from IMSI identity.");
+ *len = identity_len - (realm - identity);
+ return realm;
+ }
+ wpa_printf(MSG_DEBUG, "No realm information in identities.");
+ *len = 0;
+ return NULL;
+}
+
static int eap_get_ext_password(struct eap_sm *sm,
struct eap_peer_config *config)
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index ee7010d..e721efe 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "pcsc_funcs.h"
#include "crypto/crypto.h"
#include "crypto/sha1.h"
@@ -58,6 +59,7 @@
u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
size_t last_kdf_count;
int error_code;
+ struct crypto_rsa_key *imsi_privacy_key;
};
@@ -101,6 +103,25 @@
data->eap_method = EAP_TYPE_AKA;
+ if (config && config->imsi_privacy_key) {
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ data->imsi_privacy_key = crypto_rsa_key_read(
+ config->imsi_privacy_key, false);
+ if (!data->imsi_privacy_key) {
+ wpa_printf(MSG_ERROR,
+ "EAP-AKA: Failed to read/parse IMSI privacy key %s",
+ config->imsi_privacy_key);
+ os_free(data);
+ return NULL;
+ }
+#else /* CRYPTO_RSA_OAEP_SHA256 */
+ wpa_printf(MSG_ERROR,
+ "EAP-AKA: No support for imsi_privacy_key in the build");
+ os_free(data);
+ return NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+ }
+
/* Zero is a valid error code, so we need to initialize */
data->error_code = NO_EAP_METHOD_ERROR;
@@ -160,6 +181,9 @@
wpabuf_free(data->id_msgs);
os_free(data->network_name);
eap_aka_clear_keys(data, 0);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(data->imsi_privacy_key);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
os_free(data);
}
}
@@ -385,33 +409,16 @@
size_t identity_len = 0;
const u8 *realm = NULL;
size_t realm_len = 0;
- struct eap_peer_config *config = eap_get_config(sm);
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
attr->next_pseudonym,
attr->next_pseudonym_len);
os_free(data->pseudonym);
- /* Look for the realm of the permanent identity */
- identity = eap_get_config_identity(sm, &identity_len);
- if (identity) {
- for (realm = identity, realm_len = identity_len;
- realm_len > 0; realm_len--, realm++) {
- if (*realm == '@')
- break;
- }
- }
- // If no realm from the permanent identity, look for the
- // realm of the anonymous identity.
- if (realm_len == 0 && config && config->anonymous_identity
- && config->anonymous_identity_len > 0) {
- for (realm = config->anonymous_identity,
- realm_len = config->anonymous_identity_len;
- realm_len > 0; realm_len--, realm++) {
- if (*realm == '@')
- break;
- }
- }
+
+ /* Get realm from identities to decorate pseudonym. */
+ realm = eap_get_config_realm(sm, &realm_len);
+
data->pseudonym = os_malloc(attr->next_pseudonym_len +
realm_len);
if (data->pseudonym == NULL) {
@@ -629,6 +636,47 @@
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+static struct wpabuf *
+eap_aka_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
+ const u8 *identity, size_t identity_len)
+{
+ struct wpabuf *imsi_buf, *enc;
+ char *b64;
+ size_t b64_len;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypt permanent identity",
+ identity, identity_len);
+
+ imsi_buf = wpabuf_alloc_copy(identity, identity_len);
+ if (!imsi_buf)
+ return NULL;
+ enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf);
+ wpabuf_free(imsi_buf);
+ if (!enc)
+ return NULL;
+
+ b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len);
+ wpabuf_free(enc);
+ if (!b64)
+ return NULL;
+
+ enc = wpabuf_alloc(1 + b64_len);
+ if (!enc) {
+ os_free(b64);
+ return NULL;
+ }
+ wpabuf_put_u8(enc, '\0');
+ wpabuf_put_data(enc, b64, b64_len);
+ os_free(b64);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypted permanent identity",
+ wpabuf_head(enc), wpabuf_len(enc));
+
+ return enc;
+}
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
+
static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
struct eap_aka_data *data,
u8 id,
@@ -637,6 +685,7 @@
const u8 *identity = NULL;
size_t identity_len = 0;
struct eap_sim_msg *msg;
+ struct wpabuf *enc_identity = NULL;
data->reauth = 0;
if (id_req == ANY_ID && data->reauth_id) {
@@ -661,6 +710,22 @@
ids &= ~CLEAR_PSEUDONYM;
eap_aka_clear_identities(sm, data, ids);
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ if (identity && data->imsi_privacy_key) {
+ enc_identity = eap_aka_encrypt_identity(
+ data->imsi_privacy_key,
+ identity, identity_len);
+ if (!enc_identity) {
+ wpa_printf(MSG_INFO,
+ "EAP-AKA: Failed to encrypt permanent identity");
+ return eap_aka_client_error(
+ data, id,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+ identity = wpabuf_head(enc_identity);
+ identity_len = wpabuf_len(enc_identity);
+ }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
}
if (id_req != NO_ID_REQ)
eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
@@ -675,6 +740,7 @@
eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
identity, identity_len);
}
+ wpabuf_free(enc_identity);
return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 3238f74..eaf514b 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -104,24 +104,6 @@
char *private_key_passwd;
/**
- * dh_file - File path to DH/DSA parameters file (in PEM format)
- *
- * This is an optional configuration file for setting parameters for an
- * ephemeral DH key exchange. In most cases, the default RSA
- * authentication does not use this configuration. However, it is
- * possible setup RSA to use ephemeral DH key exchange. In addition,
- * ciphers with DSA keys always use ephemeral DH keys. This can be used
- * to achieve forward secrecy. If the file is in DSA parameters format,
- * it will be automatically converted into DH params. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
- */
- char *dh_file;
-
- /**
* subject_match - Constraint for server certificate subject
*
* This substring is matched against the subject of the authentication
@@ -336,6 +318,16 @@
size_t imsi_identity_len;
/**
+ * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate)
+ *
+ * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
+ * identity (IMSI) to improve privacy. The X.509v3 certificate needs to
+ * include a 2048-bit RSA public key and this is from the operator who
+ * authenticates the SIM/USIM.
+ */
+ char *imsi_privacy_key;
+
+ /**
* machine_identity - EAP Identity for machine credential
*
* This field is used to set the machine identity or NAI for cases where
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index f43891e..652b67e 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -392,6 +392,7 @@
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash);
const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len);
const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len);
+const u8 * eap_get_config_realm(struct eap_sm *sm, size_t *len);
void eap_clear_config_otp(struct eap_sm *sm);
const char * eap_get_config_phase1(struct eap_sm *sm);
const char * eap_get_config_phase2(struct eap_sm *sm);
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index de423e8..954c585 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -9,7 +9,9 @@
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "pcsc_funcs.h"
+#include "crypto/crypto.h"
#include "crypto/milenage.h"
#include "crypto/random.h"
#include "eap_peer/eap_i.h"
@@ -49,6 +51,7 @@
int result_ind, use_result_ind;
int use_pseudonym;
int error_code;
+ struct crypto_rsa_key *imsi_privacy_key;
};
@@ -98,6 +101,25 @@
return NULL;
}
+ if (config && config->imsi_privacy_key) {
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ data->imsi_privacy_key = crypto_rsa_key_read(
+ config->imsi_privacy_key, false);
+ if (!data->imsi_privacy_key) {
+ wpa_printf(MSG_ERROR,
+ "EAP-SIM: Failed to read/parse IMSI privacy key %s",
+ config->imsi_privacy_key);
+ os_free(data);
+ return NULL;
+ }
+#else /* CRYPTO_RSA_OAEP_SHA256 */
+ wpa_printf(MSG_ERROR,
+ "EAP-SIM: No support for imsi_privacy_key in the build");
+ os_free(data);
+ return NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+ }
+
/* Zero is a valid error code, so we need to initialize */
data->error_code = NO_EAP_METHOD_ERROR;
@@ -162,6 +184,9 @@
os_free(data->reauth_id);
os_free(data->last_eap_identity);
eap_sim_clear_keys(data, 0);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(data->imsi_privacy_key);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
os_free(data);
}
}
@@ -407,33 +432,16 @@
size_t identity_len = 0;
const u8 *realm = NULL;
size_t realm_len = 0;
- struct eap_peer_config *config = eap_get_config(sm);
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
attr->next_pseudonym,
attr->next_pseudonym_len);
os_free(data->pseudonym);
- /* Look for the realm of the permanent identity */
- identity = eap_get_config_identity(sm, &identity_len);
- if (identity) {
- for (realm = identity, realm_len = identity_len;
- realm_len > 0; realm_len--, realm++) {
- if (*realm == '@')
- break;
- }
- }
- // If no realm from the permanent identity, look for the
- // realm of the anonymous identity.
- if (realm_len == 0 && config && config->anonymous_identity
- && config->anonymous_identity_len > 0) {
- for (realm = config->anonymous_identity,
- realm_len = config->anonymous_identity_len;
- realm_len > 0; realm_len--, realm++) {
- if (*realm == '@')
- break;
- }
- }
+
+ /* Get realm from identities to decorate pseudonym. */
+ realm = eap_get_config_realm(sm, &realm_len);
+
data->pseudonym = os_malloc(attr->next_pseudonym_len +
realm_len);
if (data->pseudonym == NULL) {
@@ -493,6 +501,47 @@
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+static struct wpabuf *
+eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
+ const u8 *identity, size_t identity_len)
+{
+ struct wpabuf *imsi_buf, *enc;
+ char *b64;
+ size_t b64_len;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypt permanent identity",
+ identity, identity_len);
+
+ imsi_buf = wpabuf_alloc_copy(identity, identity_len);
+ if (!imsi_buf)
+ return NULL;
+ enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf);
+ wpabuf_free(imsi_buf);
+ if (!enc)
+ return NULL;
+
+ b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len);
+ wpabuf_free(enc);
+ if (!b64)
+ return NULL;
+
+ enc = wpabuf_alloc(1 + b64_len);
+ if (!enc) {
+ os_free(b64);
+ return NULL;
+ }
+ wpabuf_put_u8(enc, '\0');
+ wpabuf_put_data(enc, b64, b64_len);
+ os_free(b64);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypted permanent identity",
+ wpabuf_head(enc), wpabuf_len(enc));
+
+ return enc;
+}
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
+
static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
struct eap_sim_data *data, u8 id,
enum eap_sim_id_req id_req)
@@ -501,6 +550,7 @@
size_t identity_len = 0;
struct eap_sim_msg *msg;
struct wpabuf *resp;
+ struct wpabuf *enc_identity = NULL;
data->reauth = 0;
if (id_req == ANY_ID && data->reauth_id) {
@@ -525,6 +575,22 @@
ids &= ~CLEAR_PSEUDONYM;
eap_sim_clear_identities(sm, data, ids);
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ if (identity && data->imsi_privacy_key) {
+ enc_identity = eap_sim_encrypt_identity(
+ data->imsi_privacy_key,
+ identity, identity_len);
+ if (!enc_identity) {
+ wpa_printf(MSG_INFO,
+ "EAP-SIM: Failed to encrypt permanent identity");
+ return eap_sim_client_error(
+ data, id,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+ identity = wpabuf_head(enc_identity);
+ identity_len = wpabuf_len(enc_identity);
+ }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
}
if (id_req != NO_ID_REQ)
eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
@@ -538,6 +604,7 @@
eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
identity, identity_len);
}
+ wpabuf_free(enc_identity);
if (!data->reauth) {
wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT",
data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index 0d479f1..4167e99 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -1,5 +1,5 @@
/*
- * EAP peer method: EAP-TLS (RFC 2716)
+ * EAP peer method: EAP-TLS (RFC 5216, RFC 9190)
* Copyright (c) 2004-2008, 2012-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
@@ -26,6 +26,7 @@
void *ssl_ctx;
u8 eap_type;
struct wpabuf *pending_resp;
+ bool prot_success_received;
};
@@ -302,15 +303,20 @@
return NULL;
}
- /* draft-ietf-emu-eap-tls13-13 Section 2.5 */
+ /* RFC 9190 Section 2.5 */
if (res == 2 && data->ssl.tls_v13 && wpabuf_len(resp) == 1 &&
*wpabuf_head_u8(resp) == 0) {
- wpa_printf(MSG_DEBUG, "EAP-TLS: ACKing Commitment Message");
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: ACKing protected success indication (appl data 0x00)");
eap_peer_tls_reset_output(&data->ssl);
res = 1;
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ data->prot_success_received = true;
}
- if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
+ if (tls_connection_established(data->ssl_ctx, data->ssl.conn) &&
+ (!data->ssl.tls_v13 || data->prot_success_received))
eap_tls_success(sm, data, ret);
if (res == 1) {
@@ -335,6 +341,7 @@
wpabuf_free(data->pending_resp);
data->pending_resp = NULL;
+ data->prot_success_received = false;
}
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 1aaca36..3050456 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -102,6 +102,10 @@
params->flags |= TLS_CONN_SUITEB_NO_ECDH;
if (os_strstr(txt, "tls_suiteb_no_ecdh=0"))
params->flags &= ~TLS_CONN_SUITEB_NO_ECDH;
+ if (os_strstr(txt, "allow_unsafe_renegotiation=1"))
+ params->flags |= TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION;
+ if (os_strstr(txt, "allow_unsafe_renegotiation=0"))
+ params->flags &= ~TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION;
}
@@ -113,7 +117,6 @@
params->client_cert = config->client_cert;
params->private_key = config->private_key;
params->private_key_passwd = config->private_key_passwd;
- params->dh_file = config->dh_file;
params->subject_match = config->subject_match;
params->altsubject_match = config->altsubject_match;
params->check_cert_subject = config->check_cert_subject;
@@ -192,18 +195,20 @@
* TLS v1.3 changes, so disable this by default for now. */
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
}
+#ifndef EAP_TLSV1_3
if (data->eap_type == EAP_TYPE_TLS ||
data->eap_type == EAP_UNAUTH_TLS_TYPE ||
data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) {
/* While the current EAP-TLS implementation is more or less
- * complete for TLS v1.3, there has been no interoperability
- * testing with other implementations, so disable for by default
- * for now until there has been chance to confirm that no
- * significant interoperability issues show up with TLS version
- * update.
+ * complete for TLS v1.3, there has been only minimal
+ * interoperability testing with other implementations, so
+ * disable it by default for now until there has been chance to
+ * confirm that no significant interoperability issues show up
+ * with TLS version update.
*/
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
}
+#endif /* EAP_TLSV1_3 */
if (phase2 && sm->use_machine_cred) {
wpa_printf(MSG_DEBUG, "TLS: using machine config options");
eap_tls_params_from_conf2m(params, config);
@@ -228,9 +233,7 @@
¶ms->client_cert_blob_len) ||
eap_tls_check_blob(sm, ¶ms->private_key,
¶ms->private_key_blob,
- ¶ms->private_key_blob_len) ||
- eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob,
- ¶ms->dh_blob_len)) {
+ ¶ms->private_key_blob_len)) {
wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
return -1;
}
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index c401915..c8e2de0 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -1473,11 +1473,11 @@
goto start;
}
- /* draft-ietf-emu-eap-tls13-13 Section 2.5 */
+ /* RFC 9190 Section 2.5 */
if (data->ssl.tls_v13 && wpabuf_len(in_decrypted) == 1 &&
*wpabuf_head_u8(in_decrypted) == 0) {
wpa_printf(MSG_DEBUG,
- "EAP-TTLS: ACKing EAP-TLS Commitment Message");
+ "EAP-TLS: ACKing protected success indication (appl data 0x00)");
eap_peer_tls_reset_output(&data->ssl);
wpabuf_free(in_decrypted);
return 1;
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 61032cc..2894cfb 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -124,6 +124,9 @@
* callback context.
*/
void *eap_sim_db_priv;
+
+ struct crypto_rsa_key *imsi_privacy_key;
+
bool backend_auth;
int eap_server;
@@ -258,6 +261,10 @@
unsigned int max_auth_rounds;
unsigned int max_auth_rounds_short;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ bool skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
};
struct eap_session_data {
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index e9bf030..5fb19e9 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "crypto/sha256.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
@@ -737,11 +738,8 @@
sm->identity, sm->identity_len);
username = sim_get_username(sm->identity, sm->identity_len);
- if (username == NULL) {
- data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
- eap_aka_state(data, NOTIFICATION);
- return;
- }
+ if (!username)
+ goto fail;
if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
os_free(username);
@@ -785,16 +783,87 @@
username);
os_strlcpy(data->permanent, username, sizeof(data->permanent));
os_free(username);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ } else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
+ char *enc_id, *pos, *end;
+ size_t enc_id_len;
+ u8 *decoded_id;
+ size_t decoded_id_len;
+ struct wpabuf *enc, *dec;
+ u8 *new_id;
+
+ os_free(username);
+ if (!sm->cfg->imsi_privacy_key) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
+ goto fail;
+ }
+
+ enc_id = (char *) &sm->identity[1];
+ end = (char *) &sm->identity[sm->identity_len];
+ for (pos = enc_id; pos < end; pos++) {
+ if (*pos == ',')
+ break;
+ }
+ enc_id_len = pos - enc_id;
+
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-AKA: Encrypted permanent identity",
+ enc_id, enc_id_len);
+ decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
+ if (!decoded_id) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Could not base64 decode encrypted identity");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-AKA: Decoded encrypted permanent identity",
+ decoded_id, decoded_id_len);
+ enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
+ os_free(decoded_id);
+ if (!enc)
+ goto fail;
+ dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
+ enc);
+ wpabuf_free(enc);
+ if (!dec) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Failed to decrypt encrypted identity");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Decrypted permanent identity",
+ wpabuf_head(dec), wpabuf_len(dec));
+ username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
+ if (!username) {
+ wpabuf_free(dec);
+ goto fail;
+ }
+ new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
+ if (!new_id) {
+ wpabuf_free(dec);
+ goto fail;
+ }
+ os_free(sm->identity);
+ sm->identity = new_id;
+ sm->identity_len = wpabuf_len(dec);
+ wpabuf_free(dec);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
} else {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
username);
os_free(username);
- data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
- eap_aka_state(data, NOTIFICATION);
+ goto fail;
return;
}
eap_aka_fullauth(sm, data);
+ return;
+
+fail:
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
}
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
index eac3245..5440670 100644
--- a/src/eap_server/eap_server_eke.c
+++ b/src/eap_server/eap_server_eke.c
@@ -276,6 +276,7 @@
if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+ wpabuf_free(msg);
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
return eap_eke_build_failure(data, id);
}
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index f526e8b..998d0e8 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -56,6 +56,10 @@
};
+static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
+ int vendor, enum eap_type eap_type);
+
+
static const char * eap_peap_state_txt(int state)
{
switch (state) {
@@ -558,10 +562,24 @@
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
"starting Phase2");
eap_peap_state(data, PHASE2_START);
+ if (data->ssl.tls_v13 && data->ssl.tls_out &&
+ wpabuf_len(data->ssl.tls_out) == 0) {
+ /* This can happen with TLS 1.3 when a new
+ * session ticket is not generated and the
+ * Finished message from the peer terminates
+ * Phase 1. */
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: No pending data to send - move directly to Phase 2 ID query");
+ eap_peap_state(data, PHASE2_ID);
+ eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY);
+ goto phase2_id;
+ }
}
break;
case PHASE2_ID:
case PHASE2_METHOD:
+ phase2_id:
wpabuf_free(data->ssl.tls_out);
data->ssl.tls_out_pos = 0;
data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 8a68289..1bcf26c 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -9,6 +9,8 @@
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
+#include "crypto/crypto.h"
#include "crypto/random.h"
#include "eap_server/eap_i.h"
#include "eap_common/eap_sim_common.h"
@@ -512,6 +514,73 @@
username);
os_strlcpy(data->permanent, username, sizeof(data->permanent));
os_free(username);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ } else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
+ char *enc_id, *pos, *end;
+ size_t enc_id_len;
+ u8 *decoded_id;
+ size_t decoded_id_len;
+ struct wpabuf *enc, *dec;
+ u8 *new_id;
+
+ os_free(username);
+ if (!sm->cfg->imsi_privacy_key) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
+ goto failed;
+ }
+
+ enc_id = (char *) &sm->identity[1];
+ end = (char *) &sm->identity[sm->identity_len];
+ for (pos = enc_id; pos < end; pos++) {
+ if (*pos == ',')
+ break;
+ }
+ enc_id_len = pos - enc_id;
+
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-SIM: Encrypted permanent identity",
+ enc_id, enc_id_len);
+ decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
+ if (!decoded_id) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Could not base64 decode encrypted identity");
+ goto failed;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-SIM: Decoded encrypted permanent identity",
+ decoded_id, decoded_id_len);
+ enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
+ os_free(decoded_id);
+ if (!enc)
+ goto failed;
+ dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
+ enc);
+ wpabuf_free(enc);
+ if (!dec) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Failed to decrypt encrypted identity");
+ goto failed;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Decrypted permanent identity",
+ wpabuf_head(dec), wpabuf_len(dec));
+ username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
+ if (!username) {
+ wpabuf_free(dec);
+ goto failed;
+ }
+ new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
+ if (!new_id) {
+ wpabuf_free(dec);
+ goto failed;
+ }
+ os_free(sm->identity);
+ sm->identity = new_id;
+ sm->identity_len = wpabuf_len(dec);
+ wpabuf_free(dec);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
} else {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
username);
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 00a496f..443c293 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -1,5 +1,5 @@
/*
- * hostapd / EAP-TLS (RFC 2716)
+ * hostapd / EAP-TLS (RFC 5216, RFC 9190)
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
@@ -306,6 +306,14 @@
wpa_printf(MSG_DEBUG,
"EAP-TLS: Resuming previous session");
+
+ if (data->ssl.tls_v13 && data->ssl.tls_out) {
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-TLS: Additional data to be sent for TLS 1.3",
+ data->ssl.tls_out);
+ return;
+ }
+
eap_tls_state(data, SUCCESS);
tls_connection_set_success_data_resumed(data->ssl.conn);
/* TODO: Cache serial number with session and update EAP user
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index a9b53b1..717af2e 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -94,6 +94,11 @@
if (data->tls_out_limit > 100)
data->tls_out_limit -= 100;
}
+
+#ifdef CONFIG_TESTING_OPTIONS
+ data->skip_prot_success = sm->cfg->skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
+
return 0;
}
@@ -367,14 +372,14 @@
sm->cfg->ssl_ctx, data->conn);
/*
- * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5
+ * RFC 9190 Section 2.5
*
* We need to signal the other end that TLS negotiation is done. We
* can't send a zero-length application data message, so we send
* application data which is one byte of zero.
*
* Note this is only done for when there is no application data to be
- * sent. So this is done always for EAP-TLS but notibly not for PEAP
+ * sent. So this is done always for EAP-TLS but notably not for PEAP
* even on resumption.
*/
if (data->tls_v13 &&
@@ -390,8 +395,15 @@
break;
/* fallthrough */
case EAP_TYPE_TLS:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (data->skip_prot_success) {
+ wpa_printf(MSG_INFO,
+ "TESTING: Do not send protected success indication");
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG,
- "EAP-TLS: Send Commitment Message");
+ "EAP-TLS: Send protected success indication (appl data 0x00)");
plain = wpabuf_alloc(1);
if (!plain)
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index b0723a1..ad28c79 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -55,6 +55,8 @@
* tls_v13 - Whether TLS v1.3 or newer is used
*/
int tls_v13;
+
+ bool skip_prot_success; /* testing behavior only for TLS v1.3 */
};
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 5fe89c6..61b7039 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -23,6 +23,7 @@
size_t eap_req_id_text_len;
int erp_send_reauth_start;
char *erp_domain; /* a copy of this will be allocated */
+ bool eap_skip_prot_success;
/* Opaque context pointer to owner data for callback functions */
void *ctx;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 7d21f68..a203606 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -508,7 +508,7 @@
return;
}
- for (i = 0, j = 0; i < P2P_MAX_REG_CLASSES; i++) {
+ for (i = 0, j = 0; i < src->reg_classes; i++) {
if (is_6ghz_op_class(src->reg_class[i].reg_class))
continue;
os_memcpy(&dst->reg_class[j], &src->reg_class[i],
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index cf41d8d..2bf3e8e 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -20,7 +20,7 @@
#define STATE_MACHINE_DATA struct ieee802_1x_cp_sm
#define STATE_MACHINE_DEBUG_PREFIX "CP"
-static u64 default_cs_id = CS_ID_GCM_AES_128;
+static u64 cs_id[] = { CS_ID_GCM_AES_128, CS_ID_GCM_AES_256 };
/* The variable defined in clause 12 in IEEE Std 802.1X-2010 */
enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE };
@@ -210,7 +210,6 @@
sm->replay_protect = sm->kay->macsec_replay_protect;
sm->validate_frames = sm->kay->macsec_validate;
- /* NOTE: now no other than default cipher suite (AES-GCM-128) */
sm->current_cipher_suite = sm->cipher_suite;
secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
@@ -473,8 +472,8 @@
sm->orx = false;
sm->otx = false;
- sm->current_cipher_suite = default_cs_id;
- sm->cipher_suite = default_cs_id;
+ sm->current_cipher_suite = cs_id[kay->macsec_csindex];
+ sm->cipher_suite = cs_id[kay->macsec_csindex];
sm->cipher_offset = CONFIDENTIALITY_OFFSET_0;
sm->confidentiality_offset = sm->cipher_offset;
sm->transmit_delay = MKA_LIFE_TIME;
@@ -491,6 +490,7 @@
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
+ secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
SM_STEP_RUN(CP);
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 657de93..a1f8ae9 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -221,8 +221,16 @@
wpa_printf(MSG_DEBUG, "\tKey Number............: %d",
be_to_host32(body->kn));
- /* TODO: Other than GCM-AES-128 case: MACsec Cipher Suite */
- wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", body->sak, 24);
+ if (body_len == 28) {
+ wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:",
+ body->sak, 24);
+ } else if (body_len > CS_ID_LEN - sizeof(body->kn)) {
+ wpa_hexdump(MSG_DEBUG, "\tMACsec Cipher Suite...:",
+ body->sak, CS_ID_LEN);
+ wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:",
+ body->sak + CS_ID_LEN,
+ body_len - CS_ID_LEN - sizeof(body->kn));
+ }
}
@@ -3456,7 +3464,8 @@
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
- u16 port, u8 priority, const char *ifname, const u8 *addr)
+ u16 port, u8 priority, u32 macsec_csindex,
+ const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
@@ -3493,7 +3502,7 @@
kay->dist_time = 0;
kay->pn_exhaustion = PENDING_PN_EXHAUSTION;
- kay->macsec_csindex = DEFAULT_CS_INDEX;
+ kay->macsec_csindex = macsec_csindex;
kay->mka_algindex = DEFAULT_MKA_ALG_INDEX;
kay->mka_version = MKA_VERSION_ID;
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 1d3c2ac..11cf7b7 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -240,7 +240,8 @@
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
- u16 port, u8 priority, const char *ifname, const u8 *addr);
+ u16 port, u8 priority, u32 macsec_csindex,
+ const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
struct ieee802_1x_mka_participant *
diff --git a/src/radius/radius.c b/src/radius/radius.c
index be16e27..a642280 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -159,7 +159,8 @@
struct radius_attr_type {
- u8 type;
+ u16 type; /* 0..255 for basic types;
+ * (241 << 8) | <ext-type> for extended types */
char *name;
enum {
RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
@@ -260,11 +261,31 @@
RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher",
RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_EXT_TYPE_1, "Extended-Type-1", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_TYPE_2, "Extended-Type-2", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_TYPE_3, "Extended-Type-3", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_TYPE_4, "Extended-Type-4", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_LONG_EXT_TYPE_1, "Long-Extended-Type-1",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_LONG_EXT_TYPE_2, "Long-Extended-Type-2",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1, "Extended-Vendor-Specific-1",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2, "Extended-Vendor-Specific-2",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3, "Extended-Vendor-Specific-3",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4, "Extended-Vendor-Specific-4",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, "Extended-Vendor-Specific-5",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6, "Extended-Vendor-Specific-6",
+ RADIUS_ATTR_UNDIST },
};
#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
-static const struct radius_attr_type *radius_get_attr_type(u8 type)
+static const struct radius_attr_type * radius_get_attr_type(u16 type)
{
size_t i;
@@ -277,23 +298,60 @@
}
+static bool radius_is_long_ext_type(u8 type)
+{
+ return type == RADIUS_ATTR_LONG_EXT_TYPE_1 ||
+ type == RADIUS_ATTR_LONG_EXT_TYPE_2;
+}
+
+
+static bool radius_is_ext_type(u8 type)
+{
+ return type >= RADIUS_ATTR_EXT_TYPE_1 &&
+ type <= RADIUS_ATTR_LONG_EXT_TYPE_2;
+}
+
+
static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
{
+ struct radius_attr_hdr_ext *ext = NULL;
const struct radius_attr_type *attr;
int len;
unsigned char *pos;
char buf[1000];
- attr = radius_get_attr_type(hdr->type);
-
- wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
- hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
-
- if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
+ if (hdr->length < sizeof(struct radius_attr_hdr))
return;
- len = hdr->length - sizeof(struct radius_attr_hdr);
- pos = (unsigned char *) (hdr + 1);
+ if (radius_is_ext_type(hdr->type)) {
+ if (hdr->length < 4) {
+ wpa_printf(MSG_INFO,
+ " Invalid attribute %d (too short for extended type)",
+ hdr->type);
+ return;
+ }
+
+ ext = (struct radius_attr_hdr_ext *) hdr;
+ }
+
+ if (ext) {
+ attr = radius_get_attr_type((ext->type << 8) | ext->ext_type);
+ wpa_printf(MSG_INFO, " Attribute %d.%d (%s) length=%d",
+ ext->type, ext->ext_type,
+ attr ? attr->name : "?Unknown?", ext->length);
+ pos = (unsigned char *) (ext + 1);
+ len = ext->length - sizeof(struct radius_attr_hdr_ext);
+ } else {
+ attr = radius_get_attr_type(hdr->type);
+ wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
+ hdr->type, attr ? attr->name : "?Unknown?",
+ hdr->length);
+ pos = (unsigned char *) (hdr + 1);
+ len = hdr->length - sizeof(struct radius_attr_hdr);
+ }
+
+ if (!attr)
+ return;
switch (attr->data_type) {
case RADIUS_ATTR_TEXT:
@@ -627,22 +685,54 @@
}
-struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
- const u8 *data, size_t data_len)
+struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type,
+ const u8 *data, size_t data_len)
{
- size_t buf_needed;
- struct radius_attr_hdr *attr;
+ size_t buf_needed, max_len;
+ struct radius_attr_hdr *attr = NULL;
+ struct radius_attr_hdr_ext *ext;
+ u8 ext_type = 0;
if (TEST_FAIL())
return NULL;
- if (data_len > RADIUS_MAX_ATTR_LEN) {
- wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
- (unsigned long) data_len);
- return NULL;
+ if (type > 255) {
+ if (!radius_is_ext_type(type >> 8)) {
+ wpa_printf(MSG_ERROR,
+ "%s: Undefined extended type %d.%d",
+ __func__, type >> 8, type & 0xff);
+ return NULL;
+ }
+ ext_type = type & 0xff;
+ type >>= 8;
+ } else if (radius_is_ext_type(type)) {
+ wpa_printf(MSG_ERROR, "%s: Unexpected extended type use for %d",
+ __func__, type);
}
- buf_needed = sizeof(*attr) + data_len;
+ if (radius_is_long_ext_type(type)) {
+ size_t hdr_len = sizeof(struct radius_attr_hdr_ext) + 1;
+ size_t plen = 255 - hdr_len;
+ size_t num;
+
+ max_len = 4096;
+ num = (data_len + plen - 1) / plen;
+ if (num == 0)
+ num = 1;
+ buf_needed = num * hdr_len + data_len;
+ } else if (radius_is_ext_type(type)) {
+ max_len = RADIUS_MAX_EXT_ATTR_LEN;
+ buf_needed = sizeof(struct radius_attr_hdr_ext) + data_len;
+ } else {
+ max_len = RADIUS_MAX_ATTR_LEN;
+ buf_needed = sizeof(*attr) + data_len;
+ }
+ if (data_len > max_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: too long attribute (%zu > %zu bytes)",
+ __func__, data_len, max_len);
+ return NULL;
+ }
if (wpabuf_tailroom(msg->buf) < buf_needed) {
/* allocate more space for message buffer */
@@ -651,13 +741,44 @@
msg->hdr = wpabuf_mhead(msg->buf);
}
- attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
- attr->type = type;
- attr->length = sizeof(*attr) + data_len;
- wpabuf_put_data(msg->buf, data, data_len);
+ if (radius_is_long_ext_type(type)) {
+ size_t plen = 255 - sizeof(struct radius_attr_hdr_ext) - 1;
+ size_t alen;
- if (radius_msg_add_attr_to_array(msg, attr))
- return NULL;
+ do {
+ alen = data_len > plen ? plen : data_len;
+ ext = wpabuf_put(msg->buf,
+ sizeof(struct radius_attr_hdr_ext));
+ if (!attr)
+ attr = (struct radius_attr_hdr *) ext;
+ ext->type = type;
+ ext->length = sizeof(*ext) + 1 + alen;
+ ext->ext_type = ext_type;
+ wpabuf_put_u8(msg->buf, data_len > alen ? 0x80 : 0);
+ wpabuf_put_data(msg->buf, data, data_len);
+ data += alen;
+ data_len -= alen;
+ if (radius_msg_add_attr_to_array(
+ msg, (struct radius_attr_hdr *) ext))
+ return NULL;
+ } while (data_len > 0);
+ } else if (radius_is_ext_type(type)) {
+ ext = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr_ext));
+ attr = (struct radius_attr_hdr *) ext;
+ ext->type = type;
+ ext->length = sizeof(*ext) + data_len;
+ ext->ext_type = ext_type;
+ wpabuf_put_data(msg->buf, data, data_len);
+ if (radius_msg_add_attr_to_array(msg, attr))
+ return NULL;
+ } else {
+ attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
+ attr->type = type;
+ attr->length = sizeof(*attr) + data_len;
+ wpabuf_put_data(msg->buf, data, data_len);
+ if (radius_msg_add_attr_to_array(msg, attr))
+ return NULL;
+ }
return attr;
}
@@ -1285,6 +1406,28 @@
}
+int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id,
+ u8 vendor_type, const u8 *data, size_t len)
+{
+ struct radius_attr_hdr *attr;
+ u8 *buf, *pos;
+ size_t alen;
+
+ alen = 4 + 1 + len;
+ buf = os_malloc(alen);
+ if (!buf)
+ return 0;
+ pos = buf;
+ WPA_PUT_BE32(pos, vendor_id);
+ pos += 4;
+ *pos++ = vendor_type;
+ os_memcpy(pos, data, len);
+ attr = radius_msg_add_attr(msg, type, buf, alen);
+ os_free(buf);
+ return attr != NULL;
+}
+
+
int radius_user_password_hide(struct radius_msg *msg,
const u8 *data, size_t data_len,
const u8 *secret, size_t secret_len,
diff --git a/src/radius/radius.h b/src/radius/radius.h
index fb81481..177c64a 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, 2014-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -46,7 +46,15 @@
/* followed by length-2 octets of attribute value */
} STRUCT_PACKED;
+struct radius_attr_hdr_ext {
+ u8 type;
+ u8 length; /* including this header */
+ u8 ext_type;
+ /* followed by length-3 octets of attribute value */
+} STRUCT_PACKED;
+
#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr))
+#define RADIUS_MAX_EXT_ATTR_LEN (255 - sizeof(struct radius_attr_hdr_ext))
enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_USER_PASSWORD = 2,
@@ -113,6 +121,18 @@
RADIUS_ATTR_WLAN_GROUP_CIPHER = 187,
RADIUS_ATTR_WLAN_AKM_SUITE = 188,
RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER = 189,
+ RADIUS_ATTR_EXT_TYPE_1 = 241,
+ RADIUS_ATTR_EXT_TYPE_2 = 242,
+ RADIUS_ATTR_EXT_TYPE_3 = 243,
+ RADIUS_ATTR_EXT_TYPE_4 = 244,
+ RADIUS_ATTR_LONG_EXT_TYPE_1 = 245,
+ RADIUS_ATTR_LONG_EXT_TYPE_2 = 246,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1 = (241 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2 = (242 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3 = (243 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4 = (244 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5 = (245 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6 = (246 << 8) | 26,
};
@@ -188,6 +208,13 @@
RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
};
+/* FreeRADIUS vendor-specific attributes */
+#define RADIUS_VENDOR_ID_FREERADIUS 11344
+/* Extended-Vendor-Specific-5 (245.26; long extended header) */
+enum {
+ RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE = 1,
+ RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG = 2,
+};
/* Hotspot 2.0 - WFA Vendor-specific RADIUS Attributes */
#define RADIUS_VENDOR_ID_WFA 40808
@@ -257,7 +284,7 @@
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len,
int require_message_authenticator);
-struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
+struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type,
const u8 *data, size_t data_len);
struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
int radius_msg_add_eap(struct radius_msg *msg, const u8 *data,
@@ -284,6 +311,8 @@
const u8 *recv_key, size_t recv_key_len);
int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
size_t len);
+int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id,
+ u8 vendor_type, const u8 *data, size_t len);
int radius_user_password_hide(struct radius_msg *msg,
const u8 *data, size_t data_len,
const u8 *secret, size_t secret_len,
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 5ff11bd..00b7e84 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -2024,6 +2024,13 @@
u8 *rbuf, *key_mic;
size_t kde_len = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->disable_eapol_g2_tx) {
+ wpa_printf(MSG_INFO, "TEST: Disable sending EAPOL-Key 2/2");
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm))
kde_len = OCV_OCI_KDE_LEN;
@@ -3381,6 +3388,9 @@
case WPA_PARAM_OCI_FREQ_FILS_ASSOC:
sm->oci_freq_override_fils_assoc = value;
break;
+ case WPA_PARAM_DISABLE_EAPOL_G2_TX:
+ sm->disable_eapol_g2_tx = value;
+ break;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_DPP2
case WPA_PARAM_DPP_PFS:
@@ -3897,7 +3907,7 @@
pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0, true);
}
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
void wpa_sm_install_pmk(struct wpa_sm *sm)
{
/* In case the driver wants to handle re-assocs, pass it down the PMK. */
@@ -3936,7 +3946,8 @@
"WPA: Updated KCK and KEK after FT reassoc");
}
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+
#ifdef CONFIG_WNM
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 3d5e883..00fa0bc 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -118,6 +118,7 @@
WPA_PARAM_OCI_FREQ_EAPOL_G2,
WPA_PARAM_OCI_FREQ_FT_ASSOC,
WPA_PARAM_OCI_FREQ_FILS_ASSOC,
+ WPA_PARAM_DISABLE_EAPOL_G2_TX,
};
struct rsn_supp_config {
@@ -211,10 +212,10 @@
int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
void wpa_sm_install_pmk(struct wpa_sm *sm);
void wpa_sm_notify_brcm_ft_reassoc(struct wpa_sm *sm, const u8 *bssid);
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter);
void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
@@ -454,9 +455,10 @@
size_t ies_len, const u8 *src_addr);
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
const u8 *mdie);
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
int wpa_ft_is_ft_protocol(struct wpa_sm *sm);
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+
#ifdef CONFIG_PASN
int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *r1kh_id,
@@ -496,12 +498,12 @@
return 0;
}
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
static inline int wpa_ft_is_ft_protocol(struct wpa_sm *sm)
{
return 0;
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
static inline void wpa_reset_ft_completed(struct wpa_sm *sm)
{
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 2b172b7..9d3b538 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -743,7 +743,7 @@
return sm->ft_completed;
}
-#ifdef CONFIG_DRIVER_NL80211_BRCM
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
int wpa_ft_is_ft_protocol(struct wpa_sm *sm)
{
if (sm == NULL)
@@ -754,7 +754,7 @@
return sm->ft_protocol;
}
-#endif /* CONFIG_DRIVER_NL80211_BRCM */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
void wpa_reset_ft_completed(struct wpa_sm *sm)
{
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 6cdce32..579616f 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -185,6 +185,7 @@
unsigned int oci_freq_override_eapol_g2;
unsigned int oci_freq_override_ft_assoc;
unsigned int oci_freq_override_fils_assoc;
+ unsigned int disable_eapol_g2_tx;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FILS
diff --git a/src/utils/common.c b/src/utils/common.c
index 2c12751..6acfcbd 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -13,7 +13,7 @@
#include "common.h"
-static int hex2num(char c)
+int hex2num(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
diff --git a/src/utils/common.h b/src/utils/common.h
index 45f72bb..435a9a8 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -477,6 +477,7 @@
int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
int hwaddr_compact_aton(const char *txt, u8 *addr);
int hwaddr_aton2(const char *txt, u8 *addr);
+int hex2num(char c);
int hex2byte(const char *hex);
int hexstr2bin(const char *hex, u8 *buf, size_t len);
void inc_byte_array(u8 *counter, size_t len);
diff --git a/src/utils/http-utils.h b/src/utils/http-utils.h
index d9fc925..23e9ecd 100644
--- a/src/utils/http-utils.h
+++ b/src/utils/http-utils.h
@@ -33,6 +33,7 @@
size_t num_othername;
struct http_logo *logo;
size_t num_logo;
+ const char *url;
};
int soap_init_client(struct http_ctx *ctx, const char *address,
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index a1e88bc..77d5b35 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -64,6 +64,7 @@
X509 *peer_issuer_issuer;
const char *last_err;
+ const char *url;
};
@@ -848,6 +849,7 @@
X509 *cert, GENERAL_NAMES **names)
{
os_memset(hcert, 0, sizeof(*hcert));
+ hcert->url = ctx->url ? ctx->url : ctx->svc_address;
*names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
if (*names)
@@ -1594,23 +1596,23 @@
const char *fname, const char *ca_fname)
{
CURL *curl;
- FILE *f;
+ FILE *f = NULL;
CURLcode res;
long http = 0;
+ int ret = -1;
ctx->last_err = NULL;
+ ctx->url = url;
wpa_printf(MSG_DEBUG, "curl: Download file from %s to %s (ca=%s)",
url, fname, ca_fname);
curl = curl_easy_init();
if (curl == NULL)
- return -1;
+ goto fail;
f = fopen(fname, "wb");
- if (f == NULL) {
- curl_easy_cleanup(curl);
- return -1;
- }
+ if (!f)
+ goto fail;
curl_easy_setopt(curl, CURLOPT_URL, url);
if (ca_fname) {
@@ -1632,9 +1634,7 @@
ctx->last_err = curl_easy_strerror(res);
wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s",
ctx->last_err);
- curl_easy_cleanup(curl);
- fclose(f);
- return -1;
+ goto fail;
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http);
@@ -1642,15 +1642,19 @@
if (http != 200) {
ctx->last_err = "HTTP download failed";
wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http);
- curl_easy_cleanup(curl);
- fclose(f);
- return -1;
+ goto fail;
}
- curl_easy_cleanup(curl);
- fclose(f);
+ ret = 0;
- return 0;
+fail:
+ ctx->url = NULL;
+ if (curl)
+ curl_easy_cleanup(curl);
+ if (f)
+ fclose(f);
+
+ return ret;
}
@@ -1663,16 +1667,17 @@
{
long http = 0;
CURLcode res;
- char *ret;
+ char *ret = NULL;
CURL *curl;
struct curl_slist *curl_hdr = NULL;
ctx->last_err = NULL;
+ ctx->url = url;
wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url);
curl = setup_curl_post(ctx, url, ca_fname, username, password,
client_cert, client_key);
if (curl == NULL)
- return NULL;
+ goto fail;
if (content_type) {
char ct[200];
@@ -1692,8 +1697,7 @@
ctx->last_err = curl_easy_strerror(res);
wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s",
ctx->last_err);
- free_curl_buf(ctx);
- return NULL;
+ goto fail;
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http);
@@ -1701,12 +1705,11 @@
if (http != 200) {
ctx->last_err = "HTTP POST failed";
wpa_printf(MSG_INFO, "HTTP POST failed - code %ld", http);
- free_curl_buf(ctx);
- return NULL;
+ goto fail;
}
if (ctx->curl_buf == NULL)
- return NULL;
+ goto fail;
ret = ctx->curl_buf;
if (resp_len)
@@ -1716,6 +1719,9 @@
wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ret);
+fail:
+ free_curl_buf(ctx);
+ ctx->url = NULL;
return ret;
}
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index e660fb8..25b5b31 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -330,7 +330,6 @@
"src/common/sae_pk.c",
"src/common/wpa_common.c",
"src/crypto/aes-ctr.c",
- "src/crypto/aes-omac1.c",
"src/crypto/aes-siv.c",
"src/crypto/crypto_openssl.c",
"src/crypto/dh_groups.c",
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index cdf8943..d1436e2 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -119,7 +119,6 @@
ifdef CONFIG_FIPS
CONFIG_NO_RANDOM_POOL=
-CONFIG_OPENSSL_CMAC=y
endif
OBJS = config.c
@@ -515,6 +514,9 @@
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_TLSV1_3
+L_CFLAGS += -DEAP_TLSV1_3
+endif
endif
ifdef CONFIG_EAP_UNAUTH_TLS
@@ -775,6 +777,7 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_ECC=y
NEED_DRAGONFLY=y
+MS_FUNCS=y
endif
ifdef CONFIG_EAP_EKE
@@ -945,6 +948,9 @@
ifdef CONFIG_IEEE80211AX
OBJS += src/ap/ieee802_11_he.c
endif
+ifdef CONFIG_IEEE80211BE
+OBJS += src/ap/ieee802_11_eht.c
+endif
ifdef CONFIG_WNM_AP
L_CFLAGS += -DCONFIG_WNM_AP
OBJS += src/ap/wnm_ap.c
@@ -967,6 +973,10 @@
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BE
+CONFIG_IEEE80211AX=y
+L_CFLAGS += -DCONFIG_IEEE80211BE
+endif
ifdef CONFIG_IEEE80211AX
L_CFLAGS += -DCONFIG_IEEE80211AX
endif
@@ -1099,6 +1109,7 @@
endif
ifeq ($(CONFIG_TLS), openssl)
+L_CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
ifdef TLS_FUNCS
L_CFLAGS += -DEAP_TLS_OPENSSL
OBJS += src/crypto/tls_openssl.c
@@ -1303,9 +1314,7 @@
AESOBJS += src/crypto/aes-encblock.c
endif
NEED_AES_ENC=y
-ifdef CONFIG_OPENSSL_CMAC
-L_CFLAGS += -DCONFIG_OPENSSL_CMAC
-else
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += src/crypto/aes-omac1.c
endif
ifdef NEED_AES_WRAP
@@ -1399,6 +1408,17 @@
endif
endif
+ifdef CONFIG_SAE
+ifdef NEED_SHA384
+# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled.
+NEED_HMAC_SHA384_KDF=y
+endif
+ifdef NEED_SHA512
+# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled.
+NEED_HMAC_SHA512_KDF=y
+endif
+endif
+
SHA256OBJS = # none by default
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 18ffbcb..1c6911b 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1,24 +1,29 @@
BINALL=wpa_supplicant wpa_cli
-ifndef CONFIG_NO_WPA_PASSPHRASE
-BINALL += wpa_passphrase
-endif
-
ALL = $(BINALL)
ALL += systemd/wpa_supplicant.service
ALL += systemd/wpa_supplicant@.service
ALL += systemd/wpa_supplicant-nl80211@.service
ALL += systemd/wpa_supplicant-wired@.service
ALL += dbus/fi.w1.wpa_supplicant1.service
-ifdef CONFIG_BUILD_WPA_CLIENT_SO
-ALL += libwpa_client.so
-endif
EXTRA_TARGETS=dynamic_eap_methods
CONFIG_FILE=.config
include ../src/build.rules
+ifdef CONFIG_BUILD_WPA_CLIENT_SO
+# add the dependency this way to allow CONFIG_BUILD_WPA_CLIENT_SO
+# being set in the config which is read by build.rules
+_all: libwpa_client.so
+endif
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+# add the dependency this way to allow CONFIG_NO_WPA_PASSPHRASE
+# being set in the config which is read by build.rules
+_all: wpa_passphrase
+endif
+
ifdef LIBS
# If LIBS is set with some global build system defaults, clone those for
# LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well.
@@ -68,6 +73,9 @@
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL))
$(MAKE) -C ../src install
+ifndef CONFIG_NO_WPA_PASSPHRASE
+ install -D wpa_passphrase $(DESTDIR)/$(BINDIR)/wpa_passphrase
+endif
ifdef CONFIG_BUILD_WPA_CLIENT_SO
install -m 0644 -D libwpa_client.so $(DESTDIR)/$(LIBDIR)/libwpa_client.so
install -m 0644 -D ../src/common/wpa_ctrl.h $(DESTDIR)/$(INCDIR)/wpa_ctrl.h
@@ -79,7 +87,6 @@
ifdef CONFIG_FIPS
CONFIG_NO_RANDOM_POOL=
-CONFIG_OPENSSL_CMAC=y
endif
OBJS = config.o
@@ -484,6 +491,9 @@
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_TLSV1_3
+CFLAGS += -DEAP_TLSV1_3
+endif
endif
ifdef CONFIG_EAP_UNAUTH_TLS
@@ -750,6 +760,7 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_ECC=y
NEED_DRAGONFLY=y
+MS_FUNCS=y
endif
ifdef CONFIG_EAP_EKE
@@ -939,6 +950,9 @@
ifdef CONFIG_IEEE80211AX
OBJS += ../src/ap/ieee802_11_he.o
endif
+ifdef CONFIG_IEEE80211BE
+OBJS += ../src/ap/ieee802_11_eht.o
+endif
ifdef CONFIG_WNM_AP
CFLAGS += -DCONFIG_WNM_AP
OBJS += ../src/ap/wnm_ap.o
@@ -961,6 +975,10 @@
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BE
+CONFIG_IEEE80211AX=y
+CFLAGS += -DCONFIG_IEEE80211BE
+endif
ifdef CONFIG_IEEE80211AX
CFLAGS += -DCONFIG_IEEE80211AX
endif
@@ -1107,6 +1125,7 @@
endif
ifeq ($(CONFIG_TLS), openssl)
+CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
ifdef TLS_FUNCS
CFLAGS += -DEAP_TLS_OPENSSL
OBJS += ../src/crypto/tls_openssl.o
@@ -1358,9 +1377,7 @@
AESOBJS += ../src/crypto/aes-encblock.o
endif
NEED_AES_ENC=y
-ifdef CONFIG_OPENSSL_CMAC
-CFLAGS += -DCONFIG_OPENSSL_CMAC
-else
+ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-omac1.o
@@ -1474,6 +1491,17 @@
endif
endif
+ifdef CONFIG_SAE
+ifdef NEED_SHA384
+# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled.
+NEED_HMAC_SHA384_KDF=y
+endif
+ifdef NEED_SHA512
+# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled.
+NEED_HMAC_SHA512_KDF=y
+endif
+endif
+
SHA256OBJS = # none by default
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
@@ -2076,3 +2104,4 @@
rm -f libwpa_client.a
rm -f libwpa_client.so
rm -f libwpa_test1 libwpa_test2
+ rm -f wpa_passphrase
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index b076621..a099a85 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -168,6 +168,12 @@
# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
# format
#
+# imsi_privacy_key: IMSI privacy key (PEM encoded X.509v3 certificate)
+# This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
+# identity (IMSI) to improve privacy. The X.509v3 certificate needs to
+# include a 2048-bit RSA public key and this is from the operator who
+# authenticates the SIM/USIM.
+#
# domain_suffix_match: Constraint for server domain name
# If set, this FQDN is used as a suffix match requirement for the AAA
# server certificate in SubjectAltName dNSName element(s). If a
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index b884f67..e902cc8 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -24,8 +24,8 @@
environments that require secure network access without chance for
allowing outsiders to gain access during the setup phase.
-WPS uses following terms to describe the entities participating in the
-network setup:
+WPS uses the following terms to describe the entities participating
+in the network setup:
- access point: the WLAN access point
- Registrar: a device that control a network and can authorize
addition of new devices); this may be either in the AP ("internal
@@ -55,22 +55,22 @@
WPS is an optional component that needs to be enabled in
wpa_supplicant build configuration (.config). Here is an example
-configuration that includes WPS support and Linux nl80211 -based
+configuration that includes WPS support and Linux nl80211-based
driver interface:
CONFIG_DRIVER_NL80211=y
CONFIG_WPS=y
If you want to enable WPS external registrar (ER) functionality, you
-will also need to add following line:
+will also need to add the following line:
CONFIG_WPS_ER=y
-Following parameter can be used to enable support for NFC config method:
+The following parameter can be used to enable support for NFC config
+method:
CONFIG_WPS_NFC=y
-
WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
the device. This is configured in the runtime configuration for
wpa_supplicant (if not set, UUID will be generated based on local MAC
@@ -91,7 +91,6 @@
update_config=1
-
External operations
-------------------
@@ -118,7 +117,6 @@
the client will be enrolled with credentials needed to connect to the
AP to access the network.
-
If the client device does not have a display that could show the
random PIN, a hardcoded PIN that is printed on a label can be
used. wpa_supplicant is notified this with a control interface
@@ -135,7 +133,6 @@
wpa_cli wps_pin any 12345670 300
-
If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
can be used to generate a new PIN without starting WPS negotiation.
This random PIN can then be passed as an argument to another wps_pin
@@ -154,7 +151,6 @@
negotiation which will generate a new WPA PSK in the same way as the
PIN method described above.
-
If the client wants to operate in the Registrar role to learn the
current AP configuration and optionally, to configure an AP,
wpa_supplicant is notified over the control interface, e.g., with
@@ -218,7 +214,8 @@
processing the credential attributes and updating wpa_supplicant
configuration based on them.
-Following control interface messages are sent out for external programs:
+The following control interface messages are sent out for external
+programs:
WPS-CRED-RECEIVED <hexdump of Credential attribute(s)>
For example:
@@ -236,7 +233,7 @@
Separate wpa_supplicant process can be started for WPS ER
operations. A special "none" driver can be used in such a case to
indicate that no local network interface is actually controlled. For
-example, following command could be used to start the ER:
+example, the following command could be used to start the ER:
wpa_supplicant -Dnone -c er.conf -ieth0
@@ -245,7 +242,6 @@
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
device_name=WPS External Registrar
-
wpa_cli commands for ER functionality:
wps_er_start [IP address]
@@ -275,7 +271,6 @@
<auth> must be one of the following: OPEN WPAPSK WPA2PSK
<encr> must be one of the following: NONE WEP TKIP CCMP
-
wps_er_pbc <Enrollee UUID|MAC address>
- accept an Enrollee PBC using External Registrar
@@ -285,7 +280,6 @@
- if the MAC address of the enrollee is known, it should be configured
to allow the AP to advertise list of authorized enrollees
-
WPS ER events:
WPS_EVENT_ER_AP_ADD
diff --git a/wpa_supplicant/aidl/sta_network.cpp b/wpa_supplicant/aidl/sta_network.cpp
index fe4a760..61c71a1 100644
--- a/wpa_supplicant/aidl/sta_network.cpp
+++ b/wpa_supplicant/aidl/sta_network.cpp
@@ -2142,6 +2142,7 @@
return ndk::ScopedAStatus::ok();
}
+ new_entry->external = true;
wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, new_entry);
return ndk::ScopedAStatus::ok();
@@ -2160,6 +2161,7 @@
if (key_mgmt_mask & WPA_KEY_MGMT_OWE) {
// Do not allow to connect to Open network when OWE is selected
wpa_ssid->owe_only = 1;
+ wpa_ssid->owe_ptk_workaround = 1;
}
wpa_ssid->key_mgmt = key_mgmt_mask;
wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", wpa_ssid->key_mgmt);
@@ -2488,6 +2490,26 @@
key_mgmt_mask |= WPA_KEY_MGMT_FT_SAE;
}
#endif
+#ifdef CONFIG_FILS
+ if ((key_mgmt_mask & WPA_KEY_MGMT_FILS_SHA256) &&
+ (capa.key_mgmt_iftype[WPA_IF_STATION] &
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256)) {
+ key_mgmt_mask |= WPA_KEY_MGMT_FT_FILS_SHA256;
+ }
+
+ if ((key_mgmt_mask & WPA_KEY_MGMT_FILS_SHA384) &&
+ (capa.key_mgmt_iftype[WPA_IF_STATION] &
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384)) {
+ key_mgmt_mask |= WPA_KEY_MGMT_FT_FILS_SHA384;
+ }
+#endif
+#ifdef CONFIG_SUITEB192
+ if ((key_mgmt_mask & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) &&
+ (capa.key_mgmt_iftype[WPA_IF_STATION] &
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384)) {
+ key_mgmt_mask |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+ }
+#endif
#endif
}
@@ -2512,6 +2534,20 @@
key_mgmt_mask &= ~WPA_KEY_MGMT_FT_SAE;
}
#endif
+#ifdef CONFIG_FILS
+ if (key_mgmt_mask & WPA_KEY_MGMT_FILS_SHA256) {
+ key_mgmt_mask &= ~WPA_KEY_MGMT_FT_FILS_SHA256;
+ }
+
+ if (key_mgmt_mask & WPA_KEY_MGMT_FILS_SHA384) {
+ key_mgmt_mask &= ~WPA_KEY_MGMT_FT_FILS_SHA384;
+ }
+#endif
+#ifdef CONFIG_SUITEB192
+ if (key_mgmt_mask & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ key_mgmt_mask &= ~WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+ }
+#endif
#endif
}
diff --git a/wpa_supplicant/aidl/supplicant.cpp b/wpa_supplicant/aidl/supplicant.cpp
index ee6f809..799790b 100644
--- a/wpa_supplicant/aidl/supplicant.cpp
+++ b/wpa_supplicant/aidl/supplicant.cpp
@@ -303,12 +303,38 @@
wpa_printf(MSG_DEBUG, "%s,NULL wpa_s for wlan0", __FUNCTION__);
return createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN);
}
- if (wpas_p2p_add_p2pdev_interface(
- wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
+
+ const u8 *if_addr = NULL;
+ char force_name[100] = {'\0'};
+ wpa_s->pending_interface_type = WPA_IF_P2P_DEVICE;
+ if (wpa_s->conf->p2p_device_random_mac_addr == 2 &&
+ !is_zero_ether_addr(wpa_s->conf->p2p_device_persistent_mac_addr))
+ if_addr = wpa_s->conf->p2p_device_persistent_mac_addr;
+
+ int ret = wpa_drv_if_add(wpa_s, WPA_IF_P2P_DEVICE, iface_params.ifname, if_addr, NULL,
+ force_name, wpa_s->pending_interface_addr, NULL);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to create P2P Device interface");
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+
+ os_strlcpy(wpa_s->pending_interface_name, iface_params.ifname,
+ sizeof(wpa_s->pending_interface_name));
+ iface_params.p2p_mgmt = 1;
+ iface_params.driver_param = wpa_s->conf->driver_param;
+ iface_params.ctrl_interface = NULL;
+
+ struct wpa_supplicant *p2pdev_wpa_s = wpa_supplicant_add_iface(
+ wpa_s->global, &iface_params, wpa_s);
+
+ if (!p2pdev_wpa_s) {
wpa_printf(MSG_INFO,
"Failed to enable P2P Device");
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
+ p2pdev_wpa_s->p2pdev = p2pdev_wpa_s;
+ wpa_s->pending_interface_name[0] = '\0';
+
return ndk::ScopedAStatus::ok();
}
@@ -321,6 +347,13 @@
if (name.empty()) {
return {nullptr, createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
}
+ if (strncmp(name.c_str(), P2P_MGMT_DEVICE_PREFIX, strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+ struct wpa_supplicant* wpa_s = wpa_supplicant_get_iface(wpa_global_, name.c_str());
+ if (wpa_s) {
+ wpa_printf(MSG_DEBUG, "Remove existing p2p dev interface");
+ wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0);
+ }
+ }
// Try to get the wpa_supplicant record for this iface, return
// the iface object with the appropriate status code if it exists.
ndk::ScopedAStatus status;
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 0559822..94f0f83 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -175,6 +175,10 @@
hostapd_set_oper_centr_freq_seg0_idx(
conf, conf->channel + conf->secondary_channel * 2);
hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT);
+ ieee80211_freq_to_channel_ext(ssid->frequency, 0,
+ conf->vht_oper_chwidth,
+ &conf->op_class,
+ &conf->channel);
}
@@ -1028,6 +1032,7 @@
hapd_iface->extended_capa = wpa_s->extended_capa;
hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
hapd_iface->extended_capa_len = wpa_s->extended_capa_len;
+ hapd_iface->drv_max_acl_mac_addrs = wpa_s->drv_max_acl_mac_addrs;
wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
if (conf == NULL) {
@@ -1105,6 +1110,11 @@
hapd_iface->bss[i]->ext_eapol_frame_io =
wpa_s->ext_eapol_frame_io;
#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_WNM_AP
+ if (ssid->mode == WPAS_MODE_AP)
+ hapd_iface->bss[i]->conf->bss_transition = 1;
+#endif /* CONFIG_WNM_AP */
}
os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
@@ -1564,6 +1574,183 @@
return pos - buf;
}
+
+#ifdef CONFIG_WNM_AP
+
+int ap_ctrl_iface_disassoc_imminent(struct wpa_supplicant *wpa_s,
+ const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+ return hostapd_ctrl_iface_disassoc_imminent(hapd, buf);
+}
+
+
+int ap_ctrl_iface_ess_disassoc(struct wpa_supplicant *wpa_s, const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+ return hostapd_ctrl_iface_ess_disassoc(hapd, buf);
+}
+
+
+int ap_ctrl_iface_bss_tm_req(struct wpa_supplicant *wpa_s, const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+ return hostapd_ctrl_iface_bss_tm_req(hapd, buf);
+}
+
+#endif /* CONFIG_WNM_AP */
+
+
+int ap_ctrl_iface_acl_add_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type,
+ const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ hapd->conf->macaddr_acl = acl_type;
+
+ if (acl_type == ACCEPT_UNLESS_DENIED)
+ return hostapd_ctrl_iface_acl_add_mac(&hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac,
+ buf);
+ if (acl_type == DENY_UNLESS_ACCEPTED)
+ return hostapd_ctrl_iface_acl_add_mac(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac, buf);
+
+ return -1;
+}
+
+
+int ap_ctrl_iface_acl_del_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type,
+ const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ hapd->conf->macaddr_acl = acl_type;
+
+ if (acl_type == ACCEPT_UNLESS_DENIED)
+ return hostapd_ctrl_iface_acl_del_mac(&hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac,
+ buf);
+ if (acl_type == DENY_UNLESS_ACCEPTED)
+ return hostapd_ctrl_iface_acl_del_mac(
+ &hapd->conf->accept_mac, &hapd->conf->num_accept_mac,
+ buf);
+
+ return -1;
+}
+
+
+int ap_ctrl_iface_acl_show_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type, char *buf,
+ size_t buflen)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ if (acl_type == ACCEPT_UNLESS_DENIED)
+ return hostapd_ctrl_iface_acl_show_mac(hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac,
+ buf, buflen);
+ if (acl_type == DENY_UNLESS_ACCEPTED)
+ return hostapd_ctrl_iface_acl_show_mac(
+ hapd->conf->accept_mac, hapd->conf->num_accept_mac,
+ buf, buflen);
+
+ return -1;
+}
+
+
+void ap_ctrl_iface_acl_clear_list(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return;
+
+ hapd->conf->macaddr_acl = acl_type;
+
+ if (acl_type == ACCEPT_UNLESS_DENIED)
+ hostapd_ctrl_iface_acl_clear_list(&hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac);
+ else if (acl_type == DENY_UNLESS_ACCEPTED)
+ hostapd_ctrl_iface_acl_clear_list(&hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac);
+}
+
+
+int ap_ctrl_iface_disassoc_deny_mac(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ return hostapd_disassoc_deny_mac(hapd);
+}
+
+
+int ap_ctrl_iface_disassoc_accept_mac(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ return hostapd_disassoc_accept_mac(hapd);
+}
+
+
+int ap_ctrl_iface_set_acl(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ return hostapd_set_acl(hapd);
+}
+
#endif /* CONFIG_CTRL_IFACE */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 7bc1b78..ccd3e7b 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -10,6 +10,8 @@
#ifndef AP_H
#define AP_H
+enum macaddr_acl;
+
int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
@@ -38,6 +40,22 @@
const char *txtaddr);
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose);
+int ap_ctrl_iface_disassoc_imminent(struct wpa_supplicant *wpa_s,
+ const char *buf);
+int ap_ctrl_iface_ess_disassoc(struct wpa_supplicant *wpa_s, const char *buf);
+int ap_ctrl_iface_bss_tm_req(struct wpa_supplicant *wpa_s, const char *buf);
+int ap_ctrl_iface_acl_add_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type, const char *buf);
+int ap_ctrl_iface_acl_del_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type, const char *buf);
+int ap_ctrl_iface_acl_show_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type, char *buf,
+ size_t buflen);
+void ap_ctrl_iface_acl_clear_list(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type);
+int ap_ctrl_iface_disassoc_deny_mac(struct wpa_supplicant *wpa_s);
+int ap_ctrl_iface_disassoc_accept_mac(struct wpa_supplicant *wpa_s);
+int ap_ctrl_iface_set_acl(struct wpa_supplicant *wpa_s);
void ap_tx_status(void *ctx, const u8 *addr,
const u8 *buf, size_t len, int ack);
void ap_eapol_tx_status(void *ctx, const u8 *dst,
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index e13783c..429c6e7 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -291,6 +291,7 @@
dst->noise = src->noise;
dst->level = src->level;
dst->tsf = src->tsf;
+ dst->beacon_newer = src->beacon_newer;
dst->est_throughput = src->est_throughput;
dst->snr = src->snr;
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 4078b9b..146aaee 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -108,6 +108,8 @@
int level;
/** Timestamp of last Beacon/Probe Response frame */
u64 tsf;
+ /** Whether the Beacon frame data is known to be newer */
+ bool beacon_newer;
/** Time of the last update (i.e., Beacon or Probe Response RX) */
struct os_reltime last_update;
/** Estimated throughput in kbps */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index f344e1d..c8844bb 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2451,7 +2451,6 @@
{ STRe(client_cert, cert.client_cert) },
{ STRe(private_key, cert.private_key) },
{ STR_KEYe(private_key_passwd, cert.private_key_passwd) },
- { STRe(dh_file, cert.dh_file) },
{ STRe(subject_match, cert.subject_match) },
{ STRe(check_cert_subject, cert.check_cert_subject) },
{ STRe(altsubject_match, cert.altsubject_match) },
@@ -2462,7 +2461,6 @@
{ STRe(client_cert2, phase2_cert.client_cert) },
{ STRe(private_key2, phase2_cert.private_key) },
{ STR_KEYe(private_key2_passwd, phase2_cert.private_key_passwd) },
- { STRe(dh_file2, phase2_cert.dh_file) },
{ STRe(subject_match2, phase2_cert.subject_match) },
{ STRe(check_cert_subject2, phase2_cert.check_cert_subject) },
{ STRe(altsubject_match2, phase2_cert.altsubject_match) },
@@ -2490,7 +2488,6 @@
{ STRe(machine_private_key, machine_cert.private_key) },
{ STR_KEYe(machine_private_key_passwd,
machine_cert.private_key_passwd) },
- { STRe(machine_dh_file, machine_cert.dh_file) },
{ STRe(machine_subject_match, machine_cert.subject_match) },
{ STRe(machine_check_cert_subject, machine_cert.check_cert_subject) },
{ STRe(machine_altsubject_match, machine_cert.altsubject_match) },
@@ -2506,6 +2503,7 @@
{ INTe(machine_ocsp, machine_cert.ocsp) },
{ INT(eapol_flags) },
{ INTe(sim_num, sim_num) },
+ { STRe(imsi_privacy_key, imsi_privacy_key) },
{ STRe(openssl_ciphers, openssl_ciphers) },
{ INTe(erp, erp) },
#endif /* IEEE8021X_EAPOL */
@@ -2612,6 +2610,7 @@
{ INT(macsec_replay_window) },
{ INT_RANGE(macsec_port, 1, 65534) },
{ INT_RANGE(mka_priority, 0, 255) },
+ { INT_RANGE(macsec_csindex, 0, 1) },
{ FUNC_KEY(mka_cak) },
{ FUNC_KEY(mka_ckn) },
#endif /* CONFIG_MACSEC */
@@ -2753,7 +2752,6 @@
os_free(cert->client_cert);
os_free(cert->private_key);
str_clear_free(cert->private_key_passwd);
- os_free(cert->dh_file);
os_free(cert->subject_match);
os_free(cert->check_cert_subject);
os_free(cert->altsubject_match);
@@ -2773,6 +2771,7 @@
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
os_free(eap->imsi_identity);
+ os_free(eap->imsi_privacy_key);
os_free(eap->machine_identity);
bin_clear_free(eap->password, eap->password_len);
bin_clear_free(eap->machine_password, eap->machine_password_len);
@@ -2876,6 +2875,7 @@
os_free(cred->req_conn_capab_port[i]);
os_free(cred->req_conn_capab_port);
os_free(cred->req_conn_capab_proto);
+ os_free(cred->imsi_privacy_key);
os_free(cred);
}
@@ -3155,6 +3155,26 @@
}
+static const char *removed_fields[] = {
+ "dh_file",
+ "dh_file2",
+ "machine_dh_file",
+ NULL
+};
+
+static bool removed_field(const char *field)
+{
+ int i;
+
+ for (i = 0; removed_fields[i]; i++) {
+ if (os_strcmp(field, removed_fields[i]) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+
/**
* wpa_config_set - Set a variable in network configuration
* @ssid: Pointer to network configuration data
@@ -3203,6 +3223,12 @@
break;
}
if (i == NUM_SSID_FIELDS) {
+ if (removed_field(var)) {
+ wpa_printf(MSG_INFO,
+ "Line %d: Ignore removed configuration field '%s'",
+ line, var);
+ return ret;
+ }
if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown network field "
"'%s'.", line, var);
@@ -3400,8 +3426,11 @@
void wpa_config_update_psk(struct wpa_ssid *ssid)
{
#ifndef CONFIG_NO_PBKDF2
- pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
- ssid->psk, PMK_LEN);
+ if (pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
+ ssid->psk, PMK_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()");
+ return;
+ }
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
ssid->psk, PMK_LEN);
ssid->psk_set = 1;
@@ -3882,6 +3911,12 @@
return 0;
}
+ if (os_strcmp(var, "imsi_privacy_key") == 0) {
+ os_free(cred->imsi_privacy_key);
+ cred->imsi_privacy_key = val;
+ return 0;
+ }
+
if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
line, var);
@@ -4032,6 +4067,9 @@
if (os_strcmp(var, "imsi") == 0)
return alloc_strdup(cred->imsi);
+ if (os_strcmp(var, "imsi_privacy_key") == 0)
+ return alloc_strdup(cred->imsi_privacy_key);
+
if (os_strcmp(var, "milenage") == 0) {
if (!(cred->milenage))
return NULL;
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 696fb38..77d6ab5 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -182,6 +182,16 @@
char *milenage;
/**
+ * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate)
+ *
+ * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
+ * identity (IMSI) to improve privacy. The X.509v3 certificate needs to
+ * include a 2048-bit RSA public key and this is from the operator who
+ * authenticates the SIM/USIM.
+ */
+ char *imsi_privacy_key;
+
+ /**
* engine - Use an engine for private key operations
*/
int engine;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 778da45..978cc6a 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -297,8 +297,8 @@
struct wpa_ssid *ssid, *tail, *head;
struct wpa_cred *cred, *cred_tail, *cred_head;
struct wpa_config *config;
- int id = 0;
- int cred_id = 0;
+ static int id = 0;
+ static int cred_id = 0;
if (name == NULL)
return NULL;
@@ -699,7 +699,6 @@
STR(client_cert);
STR(private_key);
STR(private_key_passwd);
- STR(dh_file);
STR(subject_match);
STR(check_cert_subject);
STR(altsubject_match);
@@ -710,7 +709,6 @@
STR(client_cert2);
STR(private_key2);
STR(private_key2_passwd);
- STR(dh_file2);
STR(subject_match2);
STR(check_cert_subject2);
STR(altsubject_match2);
@@ -721,7 +719,6 @@
STR(machine_client_cert);
STR(machine_private_key);
STR(machine_private_key_passwd);
- STR(machine_dh_file);
STR(machine_subject_match);
STR(machine_check_cert_subject);
STR(machine_altsubject_match);
@@ -810,6 +807,7 @@
INT(macsec_replay_window);
INT(macsec_port);
INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER);
+ INT(macsec_csindex);
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
INT(update_identifier);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index dd8b1d9..4d3d114 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -911,6 +911,13 @@
int mka_priority;
/**
+ * macsec_csindex - Cipher suite index for MACsec
+ *
+ * Range: 0-1 (default: 0)
+ */
+ int macsec_csindex;
+
+ /**
* mka_ckn - MKA pre-shared CKN
*/
#define MACSEC_CKN_MAX_LEN 32
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 1b7f96e..b27c6cf 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -905,7 +905,6 @@
STR(client_cert);
STR(private_key);
STR(private_key_passwd);
- STR(dh_file);
STR(subject_match);
STR(check_cert_subject);
STR(altsubject_match);
@@ -914,7 +913,6 @@
STR(client_cert2);
STR(private_key2);
STR(private_key2_passwd);
- STR(dh_file2);
STR(subject_match2);
STR(check_cert_subject2);
STR(altsubject_match2);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index dc6c772..e8a8118 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -674,6 +674,9 @@
} else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
os_free(wpa_s->dpp_configurator_params);
wpa_s->dpp_configurator_params = os_strdup(value);
+#ifdef CONFIG_DPP2
+ dpp_controller_set_params(wpa_s->dpp, value);
+#endif /* CONFIG_DPP2 */
} else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
wpa_s->dpp_init_max_tries = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
@@ -836,6 +839,11 @@
wpa_s->disable_scs_support = !!atoi(value);
} else if (os_strcasecmp(cmd, "disable_mscs_support") == 0) {
wpa_s->disable_mscs_support = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "disable_eapol_g2_tx") == 0) {
+ wpa_s->disable_eapol_g2_tx = !!atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX,
+ wpa_s->disable_eapol_g2_tx);
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(wpa_s->dpp_config_obj_override);
@@ -2306,11 +2314,12 @@
if (wpa_s->connection_set &&
(wpa_s->connection_ht || wpa_s->connection_vht ||
- wpa_s->connection_he)) {
+ wpa_s->connection_he || wpa_s->connection_eht)) {
ret = os_snprintf(pos, end - pos,
"wifi_generation=%u\n",
- wpa_s->connection_he ? 6 :
- (wpa_s->connection_vht ? 5 : 4));
+ wpa_s->connection_eht ? 7 :
+ (wpa_s->connection_he ? 6 :
+ (wpa_s->connection_vht ? 5 : 4)));
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -8539,6 +8548,7 @@
wpa_s->oci_freq_override_ft_assoc = 0;
wpa_s->oci_freq_override_fils_assoc = 0;
wpa_s->oci_freq_override_wnm_sleep = 0;
+ wpa_s->disable_eapol_g2_tx = 0;
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
wpa_s->dpp_config_obj_override = NULL;
@@ -8592,6 +8602,8 @@
if (wpa_s->mac_addr_changed && wpa_s->conf->mac_addr == 0)
wpas_restore_permanent_mac_addr(wpa_s);
+
+ wpa_s->conf->ignore_old_scan_res = 0;
}
@@ -9984,8 +9996,9 @@
int flow_id = 0;
bool protection = false;
u8 twt_channel = 0;
- u8 control = BIT(4); /* Control field (IEEE P802.11ax/D8.0 Figure
- * 9-687): B4 = TWT Information Frame Disabled */
+ u8 control = BIT(4); /* Control field (IEEE Std 802.11ax-2021,
+ * Figure 9-687 - Control field format):
+ * B4 = TWT Information Frame Disabled */
const char *tok_s;
tok_s = os_strstr(cmd, " dialog=");
@@ -10687,7 +10700,7 @@
#endif /* CONFIG_FILS */
-static int wpas_ctrl_cmd_debug_level(const char *cmd)
+int wpas_ctrl_cmd_debug_level(const char *cmd)
{
if (os_strcmp(cmd, "PING") == 0 ||
os_strncmp(cmd, "BSS ", 4) == 0 ||
@@ -12019,6 +12032,58 @@
} else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
if (wpas_ap_update_beacon(wpa_s))
reply_len = -1;
+ } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
+ if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
+ if (ap_ctrl_iface_acl_add_mac(wpa_s,
+ DENY_UNLESS_ACCEPTED,
+ buf + 19) ||
+ ap_ctrl_iface_set_acl(wpa_s))
+ reply_len = -1;
+ } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
+ if (ap_ctrl_iface_acl_del_mac(wpa_s,
+ DENY_UNLESS_ACCEPTED,
+ buf + 19) ||
+ ap_ctrl_iface_set_acl(wpa_s) ||
+ ap_ctrl_iface_disassoc_accept_mac(wpa_s))
+ reply_len = -1;
+ } else if (os_strcmp(buf + 11, "SHOW") == 0) {
+ reply_len = ap_ctrl_iface_acl_show_mac(
+ wpa_s, DENY_UNLESS_ACCEPTED,
+ reply, reply_size);
+ } else if (os_strcmp(buf + 11, "CLEAR") == 0) {
+ ap_ctrl_iface_acl_clear_list(wpa_s,
+ DENY_UNLESS_ACCEPTED);
+ if (ap_ctrl_iface_set_acl(wpa_s) ||
+ ap_ctrl_iface_disassoc_accept_mac(wpa_s))
+ reply_len = -1;
+ } else {
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
+ if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
+ if (ap_ctrl_iface_acl_add_mac(wpa_s,
+ ACCEPT_UNLESS_DENIED,
+ buf + 17) ||
+ ap_ctrl_iface_set_acl(wpa_s) ||
+ ap_ctrl_iface_disassoc_deny_mac(wpa_s))
+ reply_len = -1;
+ } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
+ if (ap_ctrl_iface_acl_del_mac(wpa_s,
+ ACCEPT_UNLESS_DENIED,
+ buf + 17) ||
+ ap_ctrl_iface_set_acl(wpa_s))
+ reply_len = -1;
+ } else if (os_strcmp(buf + 9, "SHOW") == 0) {
+ reply_len = ap_ctrl_iface_acl_show_mac(
+ wpa_s, ACCEPT_UNLESS_DENIED, reply, reply_size);
+ } else if (os_strcmp(buf + 9, "CLEAR") == 0) {
+ ap_ctrl_iface_acl_clear_list(wpa_s,
+ ACCEPT_UNLESS_DENIED);
+ if (ap_ctrl_iface_set_acl(wpa_s))
+ reply_len = -1;
+ } else {
+ reply_len = -1;
+ }
#endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
@@ -12114,6 +12179,17 @@
if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18))
reply_len = -1;
#endif /* CONFIG_WNM */
+#ifdef CONFIG_WNM_AP
+ } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
+ if (ap_ctrl_iface_disassoc_imminent(wpa_s, buf + 18))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
+ if (ap_ctrl_iface_ess_disassoc(wpa_s, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
+ if (ap_ctrl_iface_bss_tm_req(wpa_s, buf + 11))
+ reply_len = -1;
+#endif /* CONFIG_WNM_AP */
} else if (os_strcmp(buf, "FLUSH") == 0) {
wpa_supplicant_ctrl_iface_flush(wpa_s);
} else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
@@ -12312,6 +12388,9 @@
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) {
+ if (dpp_configurator_set(wpa_s->dpp, buf + 20) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
if (dpp_configurator_remove(wpa_s->dpp, buf + 24) < 0)
reply_len = -1;
diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h
index dfbd25a..9842ea1 100644
--- a/wpa_supplicant/ctrl_iface.h
+++ b/wpa_supplicant/ctrl_iface.h
@@ -122,6 +122,8 @@
void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s);
+int wpas_ctrl_cmd_debug_level(const char *cmd);
+
#else /* CONFIG_CTRL_IFACE */
static inline struct ctrl_iface_priv *
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 1cbf7fa..1178f40 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -337,6 +337,9 @@
else
reply_len = 2;
} else {
+ sockaddr_print(wpas_ctrl_cmd_debug_level(buf),
+ "Control interface recv command from:",
+ &from, fromlen);
reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
&reply_len);
}
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 639573d..2052873 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -178,6 +178,9 @@
else
reply_len = 2;
} else {
+ sockaddr_print(wpas_ctrl_cmd_debug_level(buf),
+ "Control interface recv command from:",
+ &from, fromlen);
reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
&reply_len);
reply = reply_buf;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 959a68b..0b1002b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1121,7 +1121,7 @@
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[13];
+ const char *capabilities[14];
size_t num_items = 0;
struct wpa_global *global = user_data;
struct wpa_supplicant *wpa_s;
@@ -1177,6 +1177,9 @@
#endif /* CONFIG_SUITEB192 */
if (ext_key_id_supported)
capabilities[num_items++] = "extended_key_id";
+#ifndef CONFIG_WEP
+ capabilities[num_items++] = "wep_disabled";
+#endif /* !CONFIG_WEP */
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -3951,7 +3954,7 @@
const char *auth_mode;
char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
- if (wpa_s->wpa_state != WPA_COMPLETED) {
+ if (wpa_s->wpa_state <= WPA_SCANNING) {
auth_mode = "INACTIVE";
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
diff --git