aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/dbus.doxygen2
-rw-r--r--hostapd/Android.mk10
-rw-r--r--hostapd/Makefile10
-rw-r--r--hostapd/config_file.c103
-rw-r--r--hostapd/ctrl_iface.c132
-rw-r--r--hostapd/defconfig7
-rw-r--r--hostapd/hostapd.conf99
-rw-r--r--hostapd/hostapd_cli.c30
-rw-r--r--src/ap/ap_config.c84
-rw-r--r--src/ap/ap_config.h37
-rw-r--r--src/ap/ap_drv_ops.c8
-rw-r--r--src/ap/ap_drv_ops.h15
-rw-r--r--src/ap/beacon.c309
-rw-r--r--src/ap/beacon.h2
-rw-r--r--src/ap/ctrl_iface_ap.c6
-rw-r--r--src/ap/dfs.c35
-rw-r--r--src/ap/dpp_hostapd.c49
-rw-r--r--src/ap/drv_callbacks.c14
-rw-r--r--src/ap/hostapd.c43
-rw-r--r--src/ap/hostapd.h11
-rw-r--r--src/ap/hs20.c4
-rw-r--r--src/ap/hw_features.c77
-rw-r--r--src/ap/hw_features.h6
-rw-r--r--src/ap/ieee802_11.c1379
-rw-r--r--src/ap/ieee802_11_he.c20
-rw-r--r--src/ap/ieee802_11_shared.c55
-rw-r--r--src/ap/ieee802_11_vht.c112
-rw-r--r--src/ap/ieee802_1x.c3
-rw-r--r--src/ap/neighbor_db.c2
-rw-r--r--src/ap/sta_info.c35
-rw-r--r--src/ap/sta_info.h45
-rw-r--r--src/ap/wnm_ap.c7
-rw-r--r--src/ap/wpa_auth.c56
-rw-r--r--src/ap/wpa_auth.h24
-rw-r--r--src/ap/wpa_auth_ft.c29
-rw-r--r--src/ap/wpa_auth_glue.c57
-rw-r--r--src/ap/wpa_auth_ie.c189
-rw-r--r--src/ap/wps_hostapd.c105
-rw-r--r--src/common/Makefile2
-rw-r--r--src/common/common_module_tests.c173
-rw-r--r--src/common/defs.h12
-rw-r--r--src/common/dpp.h1
-rw-r--r--src/common/dpp_auth.c1
-rw-r--r--src/common/dpp_tcp.c2
-rw-r--r--src/common/gas_server.c15
-rw-r--r--src/common/gas_server.h1
-rw-r--r--src/common/hw_features_common.c42
-rw-r--r--src/common/hw_features_common.h3
-rw-r--r--src/common/ieee802_11_common.c99
-rw-r--r--src/common/ieee802_11_common.h9
-rw-r--r--src/common/ieee802_11_defs.h68
-rw-r--r--src/common/ptksa_cache.c321
-rw-r--r--src/common/ptksa_cache.h79
-rw-r--r--src/common/qca-vendor.h533
-rw-r--r--src/common/wpa_common.c802
-rw-r--r--src/common/wpa_common.h84
-rw-r--r--src/common/wpa_ctrl.h8
-rw-r--r--src/crypto/tls_openssl.c18
-rw-r--r--src/crypto/tls_wolfssl.c14
-rw-r--r--src/drivers/driver.h92
-rw-r--r--src/drivers/driver_bsd.c113
-rw-r--r--src/drivers/driver_nl80211.c310
-rw-r--r--src/drivers/driver_nl80211.h14
-rw-r--r--src/drivers/driver_nl80211_capa.c21
-rw-r--r--src/drivers/driver_nl80211_event.c80
-rw-r--r--src/drivers/nl80211_copy.h127
-rw-r--r--src/eap_peer/eap_aka.c34
-rw-r--r--src/eap_peer/eap_peap.c27
-rw-r--r--src/eap_peer/eap_tls.c12
-rw-r--r--src/eap_peer/eap_tls_common.c4
-rw-r--r--src/eap_peer/eap_ttls.c33
-rw-r--r--src/eap_server/eap_server_peap.c72
-rw-r--r--src/eap_server/eap_server_tls.c33
-rw-r--r--src/eap_server/eap_server_tls_common.c54
-rw-r--r--src/eap_server/eap_server_ttls.c30
-rw-r--r--src/p2p/p2p.c15
-rw-r--r--src/p2p/p2p.h3
-rw-r--r--src/p2p/p2p_pd.c12
-rw-r--r--src/radius/radius.h3
-rw-r--r--src/radius/radius_client.c17
-rw-r--r--src/radius/radius_server.c5
-rw-r--r--src/rsn_supp/tdls.c41
-rw-r--r--src/rsn_supp/wpa.c74
-rw-r--r--src/rsn_supp/wpa.h36
-rw-r--r--src/rsn_supp/wpa_ft.c125
-rw-r--r--src/rsn_supp/wpa_i.h42
-rw-r--r--src/rsn_supp/wpa_ie.c41
-rw-r--r--src/utils/Makefile1
-rw-r--r--src/utils/config.c97
-rw-r--r--src/utils/config.h29
-rw-r--r--src/utils/ext_password.c3
-rw-r--r--src/utils/ext_password_file.c136
-rw-r--r--src/utils/ext_password_i.h4
-rw-r--r--src/utils/list.h4
-rw-r--r--src/utils/os_unix.c2
-rw-r--r--src/utils/platform.h23
-rw-r--r--src/utils/radiotap.c12
-rw-r--r--src/utils/radiotap.h407
-rw-r--r--src/wps/wps.h5
-rw-r--r--src/wps/wps_registrar.c29
-rw-r--r--tests/fuzzing/p2p/p2p.c2
-rw-r--r--tests/fuzzing/wnm/Makefile2
-rw-r--r--tests/fuzzing/wnm/wnm.c2
-rwxr-xr-xtests/hwsim/build.sh13
-rw-r--r--tests/hwsim/example-hostapd.config1
-rw-r--r--tests/hwsim/example-wpa_supplicant.config2
-rw-r--r--tests/hwsim/hostapd.py17
-rw-r--r--tests/hwsim/remotehost.py109
-rwxr-xr-xtests/hwsim/rfkill.py2
-rw-r--r--tests/hwsim/test_ap_acs.py40
-rw-r--r--tests/hwsim/test_ap_ciphers.py29
-rw-r--r--tests/hwsim/test_ap_dynamic.py38
-rw-r--r--tests/hwsim/test_ap_eap.py49
-rw-r--r--tests/hwsim/test_ap_ft.py30
-rw-r--r--tests/hwsim/test_ap_open.py46
-rw-r--r--tests/hwsim/test_ap_params.py49
-rw-r--r--tests/hwsim/test_ap_psk.py34
-rw-r--r--tests/hwsim/test_ap_roam.py26
-rw-r--r--tests/hwsim/test_ap_tdls.py2
-rw-r--r--tests/hwsim/test_dfs.py113
-rw-r--r--tests/hwsim/test_dpp.py29
-rw-r--r--tests/hwsim/test_eap_proto.py3
-rw-r--r--tests/hwsim/test_ext_password.py31
-rw-r--r--tests/hwsim/test_fils.py34
-rw-r--r--tests/hwsim/test_he.py47
-rw-r--r--tests/hwsim/test_multi_ap.py120
-rw-r--r--tests/hwsim/test_p2p_channel.py10
-rw-r--r--tests/hwsim/test_p2p_discovery.py42
-rw-r--r--tests/hwsim/test_pasn.py638
-rw-r--r--tests/hwsim/test_scan.py37
-rw-r--r--tests/hwsim/test_sigma_dut.py23
-rw-r--r--tests/hwsim/test_wpas_ctrl.py76
-rw-r--r--tests/hwsim/test_wpas_mesh.py57
-rw-r--r--tests/hwsim/tshark.py6
-rw-r--r--tests/hwsim/wlantest.py4
-rw-r--r--tests/hwsim/wpasupplicant.py22
-rw-r--r--tests/remote/monitor.py4
-rwxr-xr-xtests/remote/run-tests.py12
-rw-r--r--tests/remote/rutils.py22
-rw-r--r--wlantest/Makefile1
-rw-r--r--wlantest/bss.c24
-rw-r--r--wlantest/inject.c3
-rw-r--r--wlantest/rx_data.c13
-rw-r--r--wlantest/rx_eapol.c4
-rw-r--r--wlantest/rx_ip.c35
-rw-r--r--wlantest/rx_mgmt.c267
-rw-r--r--wlantest/sta.c16
-rw-r--r--wlantest/wlantest.c13
-rw-r--r--wlantest/wlantest.h2
-rw-r--r--wpa_supplicant/Android.mk24
-rw-r--r--wpa_supplicant/Makefile20
-rw-r--r--wpa_supplicant/ap.c12
-rw-r--r--wpa_supplicant/blacklist.h33
-rw-r--r--wpa_supplicant/bss.c18
-rw-r--r--wpa_supplicant/bss.h16
-rw-r--r--wpa_supplicant/bssid_ignore.c (renamed from wpa_supplicant/blacklist.c)112
-rw-r--r--wpa_supplicant/bssid_ignore.h33
-rw-r--r--wpa_supplicant/config.c116
-rw-r--r--wpa_supplicant/config.h68
-rw-r--r--wpa_supplicant/config_file.c121
-rw-r--r--wpa_supplicant/config_ssid.h12
-rw-r--r--wpa_supplicant/ctrl_iface.c191
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c22
-rw-r--r--wpa_supplicant/defconfig8
-rw-r--r--wpa_supplicant/doc/docbook/eapol_test.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml4
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.sgml4
-rw-r--r--wpa_supplicant/dpp_supplicant.c103
-rw-r--r--wpa_supplicant/driver_i.h4
-rw-r--r--wpa_supplicant/events.c117
-rw-r--r--wpa_supplicant/hs20_supplicant.c6
-rw-r--r--wpa_supplicant/interworking.c16
-rw-r--r--wpa_supplicant/mesh.c179
-rw-r--r--wpa_supplicant/mesh.h6
-rw-r--r--wpa_supplicant/nmake.mak2
-rw-r--r--wpa_supplicant/notify.c5
-rw-r--r--wpa_supplicant/op_classes.c25
-rw-r--r--wpa_supplicant/p2p_supplicant.c100
-rw-r--r--wpa_supplicant/pasn_supplicant.c1509
-rw-r--r--wpa_supplicant/robust_av.c7
-rw-r--r--wpa_supplicant/rrm.c6
-rw-r--r--wpa_supplicant/scan.c75
-rw-r--r--wpa_supplicant/scan.h4
-rw-r--r--wpa_supplicant/sme.c8
-rwxr-xr-xwpa_supplicant/vs2005/eapol_test/eapol_test.vcproj6
-rwxr-xr-xwpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj6
-rwxr-xr-xwpa_supplicant/vs2005/wpasvc/wpasvc.vcproj6
-rw-r--r--wpa_supplicant/wnm_sta.c2
-rw-r--r--wpa_supplicant/wpa_cli.c84
-rw-r--r--wpa_supplicant/wpa_supplicant.c141
-rw-r--r--wpa_supplicant/wpa_supplicant.conf26
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h92
-rw-r--r--wpa_supplicant/wpas_glue.c43
-rw-r--r--wpa_supplicant/wpas_module_tests.c90
-rw-r--r--wpa_supplicant/wps_supplicant.c17
200 files changed, 11740 insertions, 1704 deletions
diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
index 06e53b9..8231aac 100644
--- a/doc/dbus.doxygen
+++ b/doc/dbus.doxygen
@@ -669,7 +669,7 @@ fi.w1.wpa_supplicant1.CreateInterface.
<tr><td>Pairwise</td><td>as</td><td>Possible array elements: "ccmp-256", "gcmp-256", "ccmp", "gcmp", "tkip", "none"</td>
<tr><td>Group</td><td>as</td><td>Possible array elements: "ccmp-256", "gcmp-256", "ccmp", "gcmp", "tkip", "wep104", "wep40"</td>
<tr><td>GroupMgmt</td><td>as</td><td>Possible array elements: "aes-128-cmac", "bip-gmac-128", "bip-gmac-256", "bip-cmac-256"</td>
- <tr><td>KeyMgmt</td><td>as</td><td>Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "sae", "ieee8021x", "wpa-none", "wps", "none"</td>
+ <tr><td>KeyMgmt</td><td>as</td><td>Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "sae", "owe", "ieee8021x", "wpa-none", "wps", "none"</td>
<tr><td>Protocol</td><td>as</td><td>Possible array elements: "rsn", "wpa"</td>
<tr><td>AuthAlg</td><td>as</td><td>Possible array elements: "open", "shared", "leap"</td>
<tr><td>Scan</td><td>as</td><td>Possible array elements: "active", "passive", "ssid"</td>
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 6c95617..b3af968 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -565,6 +565,16 @@ L_CFLAGS += -DCONFIG_DPP2
endif
endif
+ifdef CONFIG_PASN
+L_CFLAGS += -DCONFIG_PASN
+L_CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += src/common/ptksa_cache.c
+endif
+
ifdef CONFIG_EAP_IKEV2
L_CFLAGS += -DEAP_SERVER_IKEV2
OBJS += src/eap_server/eap_server_ikev2.c src/eap_server/ikev2.c
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 456fb18..ac085fd 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -595,6 +595,16 @@ CFLAGS += -DCONFIG_DPP2
endif
endif
+ifdef CONFIG_PASN
+CFLAGS += -DCONFIG_PASN
+CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += ../src/common/ptksa_cache.o
+endif
+
ifdef CONFIG_EAP_IKEV2
CFLAGS += -DEAP_SERVER_IKEV2
OBJS += ../src/eap_server/eap_server_ikev2.o ../src/eap_server/ikev2.o
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index ce32f3c..64704fb 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -754,6 +754,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
else if (os_strcmp(start, "OSEN") == 0)
val |= WPA_KEY_MGMT_OSEN;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_PASN
+ else if (os_strcmp(start, "PASN") == 0)
+ val |= WPA_KEY_MGMT_PASN;
+#endif /* CONFIG_PASN */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -1216,6 +1220,32 @@ static u8 set_he_cap(int val, u8 mask)
return (u8) (mask & (val << find_bit_offset(mask)));
}
+
+static int hostapd_parse_he_srg_bitmap(u8 *bitmap, char *val)
+{
+ int bitpos;
+ char *pos, *end;
+
+ os_memset(bitmap, 0, 8);
+ pos = val;
+ while (*pos != '\0') {
+ end = os_strchr(pos, ' ');
+ if (end)
+ *end = '\0';
+
+ bitpos = atoi(pos);
+ if (bitpos < 0 || bitpos > 64)
+ return -1;
+
+ bitmap[bitpos / 8] |= BIT(bitpos % 8);
+ if (!end)
+ break;
+ pos = end + 1;
+ }
+
+ return 0;
+}
+
#endif /* CONFIG_IEEE80211AX */
@@ -3259,6 +3289,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
conf->rate_type = BEACON_RATE_VHT;
conf->beacon_rate = val;
+ } else if (os_strncmp(pos, "he:", 3) == 0) {
+ val = atoi(pos + 3);
+ if (val < 0 || val > 11) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid beacon_rate HE-MCS %d",
+ line, val);
+ return 1;
+ }
+ conf->rate_type = BEACON_RATE_HE;
+ conf->beacon_rate = val;
} else {
val = atoi(pos);
if (val < 10 || val > 10000) {
@@ -3540,19 +3580,53 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] =
atoi(pos) & 0xff;
} else if (os_strcmp(buf, "he_spr_sr_control") == 0) {
- conf->spr.sr_control = atoi(pos) & 0xff;
+ conf->spr.sr_control = atoi(pos) & 0x1f;
} else if (os_strcmp(buf, "he_spr_non_srg_obss_pd_max_offset") == 0) {
conf->spr.non_srg_obss_pd_max_offset = atoi(pos);
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_min_offset") == 0) {
conf->spr.srg_obss_pd_min_offset = atoi(pos);
} else if (os_strcmp(buf, "he_spr_srg_obss_pd_max_offset") == 0) {
conf->spr.srg_obss_pd_max_offset = atoi(pos);
+ } else if (os_strcmp(buf, "he_spr_srg_bss_colors") == 0) {
+ if (hostapd_parse_he_srg_bitmap(
+ conf->spr.srg_bss_color_bitmap, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid srg bss colors list '%s'",
+ line, pos);
+ return 1;
+ }
+ } else if (os_strcmp(buf, "he_spr_srg_partial_bssid") == 0) {
+ if (hostapd_parse_he_srg_bitmap(
+ conf->spr.srg_partial_bssid_bitmap, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid srg partial bssid list '%s'",
+ line, pos);
+ return 1;
+ }
} 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) {
conf->he_oper_centr_freq_seg0_idx = atoi(pos);
} else if (os_strcmp(buf, "he_oper_centr_freq_seg1_idx") == 0) {
conf->he_oper_centr_freq_seg1_idx = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_max_mpdu") == 0) {
+ conf->he_6ghz_max_mpdu = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_max_ampdu_len_exp") == 0) {
+ conf->he_6ghz_max_ampdu_len_exp = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_rx_ant_pat") == 0) {
+ conf->he_6ghz_rx_ant_pat = atoi(pos);
+ } else if (os_strcmp(buf, "he_6ghz_tx_ant_pat") == 0) {
+ conf->he_6ghz_tx_ant_pat = atoi(pos);
+ } else if (os_strcmp(buf, "unsol_bcast_probe_resp_interval") == 0) {
+ int val = atoi(pos);
+
+ if (val < 0 || val > 20) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid unsol_bcast_probe_resp_interval value",
+ line);
+ return 1;
+ }
+ bss->unsol_bcast_probe_resp_interval = val;
#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -4359,11 +4433,17 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->dhcp_server_port = atoi(pos);
} else if (os_strcmp(buf, "dhcp_relay_port") == 0) {
bss->dhcp_relay_port = atoi(pos);
+ } else if (os_strcmp(buf, "fils_discovery_min_interval") == 0) {
+ bss->fils_discovery_min_int = atoi(pos);
+ } else if (os_strcmp(buf, "fils_discovery_max_interval") == 0) {
+ bss->fils_discovery_max_int = atoi(pos);
#endif /* CONFIG_FILS */
} else if (os_strcmp(buf, "multicast_to_unicast") == 0) {
bss->multicast_to_unicast = atoi(pos);
} else if (os_strcmp(buf, "broadcast_deauth") == 0) {
bss->broadcast_deauth = atoi(pos);
+ } else if (os_strcmp(buf, "notify_mgmt_frames") == 0) {
+ bss->notify_mgmt_frames = atoi(pos);
#ifdef CONFIG_DPP
} else if (os_strcmp(buf, "dpp_name") == 0) {
os_free(bss->dpp_name);
@@ -4450,6 +4530,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->rssi_reject_assoc_rssi = atoi(pos);
} else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) {
conf->rssi_reject_assoc_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "rssi_ignore_probe_request") == 0) {
+ conf->rssi_ignore_probe_request = atoi(pos);
} else if (os_strcmp(buf, "pbss") == 0) {
bss->pbss = atoi(pos);
} else if (os_strcmp(buf, "transition_disable") == 0) {
@@ -4569,6 +4651,25 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
bss->mka_psk_set |= MKA_PSK_SET_CKN;
#endif /* CONFIG_MACSEC */
+ } else if (os_strcmp(buf, "disable_11n") == 0) {
+ bss->disable_11n = !!atoi(pos);
+ } else if (os_strcmp(buf, "disable_11ac") == 0) {
+ bss->disable_11ac = !!atoi(pos);
+ } else if (os_strcmp(buf, "disable_11ax") == 0) {
+ bss->disable_11ax = !!atoi(pos);
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcmp(buf, "force_kdk_derivation") == 0) {
+ bss->force_kdk_derivation = atoi(pos);
+#endif /* CONFIG_TESTING_OPTIONS */
+ } else if (os_strcmp(buf, "pasn_groups") == 0) {
+ if (hostapd_parse_intlist(&bss->pasn_groups, pos)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid pasn_groups value '%s'",
+ line, pos);
+ return 1;
+ }
+#endif /* CONFIG_PASN */
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index e2ae0ad..05d6be6 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -37,6 +37,7 @@
#include "common/dpp.h"
#endif /* CONFIG_DPP */
#include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
#include "eapol_auth/eapol_auth_sm.h"
@@ -1222,6 +1223,52 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
return pos - buf;
pos += ret;
}
+
+ if (hapd->conf->multi_ap) {
+ struct hostapd_ssid *ssid = &hapd->conf->multi_ap_backhaul_ssid;
+
+ ret = os_snprintf(pos, end - pos, "multi_ap=%d\n",
+ hapd->conf->multi_ap);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ if (ssid->ssid_len) {
+ ret = os_snprintf(pos, end - pos,
+ "multi_ap_backhaul_ssid=%s\n",
+ wpa_ssid_txt(ssid->ssid,
+ ssid->ssid_len));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (hapd->conf->wps_state && hapd->conf->wpa &&
+ ssid->wpa_passphrase) {
+ ret = os_snprintf(pos, end - pos,
+ "multi_ap_backhaul_wpa_passphrase=%s\n",
+ ssid->wpa_passphrase);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (hapd->conf->wps_state && hapd->conf->wpa &&
+ ssid->wpa_psk &&
+ ssid->wpa_psk->group) {
+ char hex[PMK_LEN * 2 + 1];
+
+ wpa_snprintf_hex(hex, sizeof(hex), ssid->wpa_psk->psk,
+ PMK_LEN);
+ ret = os_snprintf(pos, end - pos,
+ "multi_ap_backhaul_wpa_psk=%s\n",
+ hex);
+ forced_memzero(hex, sizeof(hex));
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ }
#endif /* CONFIG_WPS */
if (hapd->conf->wpa) {
@@ -1347,21 +1394,29 @@ static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
- const char *band)
+ const char *bands)
{
union wpa_event_data event;
- enum set_band setband;
-
- if (os_strcmp(band, "AUTO") == 0)
- setband = WPA_SETBAND_AUTO;
- else if (os_strcmp(band, "5G") == 0)
- setband = WPA_SETBAND_5G;
- else if (os_strcmp(band, "2G") == 0)
- setband = WPA_SETBAND_2G;
- else
- return -1;
+ u32 setband_mask = WPA_SETBAND_AUTO;
- if (hostapd_drv_set_band(hapd, setband) == 0) {
+ /*
+ * For example:
+ * SET setband 2G,6G
+ * SET setband 5G
+ * SET setband AUTO
+ */
+ if (!os_strstr(bands, "AUTO")) {
+ if (os_strstr(bands, "5G"))
+ setband_mask |= WPA_SETBAND_5G;
+ if (os_strstr(bands, "6G"))
+ setband_mask |= WPA_SETBAND_6G;
+ if (os_strstr(bands, "2G"))
+ setband_mask |= WPA_SETBAND_2G;
+ if (setband_mask == WPA_SETBAND_AUTO)
+ return -1;
+ }
+
+ if (hostapd_drv_set_band(hapd, setband_mask) == 0) {
os_memset(&event, 0, sizeof(event));
event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
@@ -2671,9 +2726,9 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
for (i = 0; i < iface->num_bss; i++) {
- /* Save CHAN_SWITCH VHT config */
- hostapd_chan_switch_vht_config(
- iface->bss[i], settings.freq_params.vht_enabled);
+ /* Save CHAN_SWITCH VHT and HE config */
+ hostapd_chan_switch_config(iface->bss[i],
+ &settings.freq_params);
ret = hostapd_switch_channel(iface->bss[i], &settings);
if (ret) {
@@ -3309,6 +3364,23 @@ static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
}
+#ifdef ANDROID
+static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd,
+ char *buf, size_t buflen)
+{
+ int ret;
+
+ ret = hostapd_drv_driver_cmd(hapd, cmd, buf, buflen);
+ if (ret == 0) {
+ ret = os_snprintf(buf, buflen, "%s\n", "OK");
+ if (os_snprintf_error(buflen, ret))
+ ret = -1;
+ }
+ return ret;
+}
+#endif /* ANDROID */
+
+
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply,
int reply_size,
@@ -3626,16 +3698,17 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
eloop_terminate();
} else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
- if (!hostapd_ctrl_iface_acl_add_mac(
+ if (hostapd_ctrl_iface_acl_add_mac(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac, buf + 19))
+ reply_len = -1;
+ } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
+ if (!hostapd_ctrl_iface_acl_del_mac(
&hapd->conf->accept_mac,
&hapd->conf->num_accept_mac, buf + 19))
hostapd_disassoc_accept_mac(hapd);
else
reply_len = -1;
- } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
- hostapd_ctrl_iface_acl_del_mac(
- &hapd->conf->accept_mac,
- &hapd->conf->num_accept_mac, buf + 19);
} else if (os_strcmp(buf + 11, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
hapd->conf->accept_mac,
@@ -3644,6 +3717,7 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
hostapd_ctrl_iface_acl_clear_list(
&hapd->conf->accept_mac,
&hapd->conf->num_accept_mac);
+ hostapd_disassoc_accept_mac(hapd);
}
} else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
@@ -3651,10 +3725,13 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
&hapd->conf->deny_mac,
&hapd->conf->num_deny_mac, buf + 17))
hostapd_disassoc_deny_mac(hapd);
+ else
+ reply_len = -1;
} else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
- hostapd_ctrl_iface_acl_del_mac(
- &hapd->conf->deny_mac,
- &hapd->conf->num_deny_mac, buf + 17);
+ if (hostapd_ctrl_iface_acl_del_mac(
+ &hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac, buf + 17))
+ reply_len = -1;
} else if (os_strcmp(buf + 9, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
hapd->conf->deny_mac,
@@ -3802,6 +3879,15 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
reply_len = hostapd_ctrl_iface_get_capability(
hapd, buf + 15, reply, reply_size);
+#ifdef CONFIG_PASN
+ } else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) {
+ reply_len = ptksa_cache_list(hapd->ptksa, reply, reply_size);
+#endif /* CONFIG_PASN */
+#ifdef ANDROID
+ } else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
+ reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply,
+ reply_size);
+#endif /* ANDROID */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/hostapd/defconfig b/hostapd/defconfig
index e9f5de7..cbdd2a5 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -395,3 +395,10 @@ CONFIG_IPV6=y
# build includes this to allow mixed mode WPA+WPA2 networks to be enabled, but
# that functionality is subject to be removed in the future.
#CONFIG_NO_TKIP=y
+
+# Pre-Association Security Negotiation (PASN)
+# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol
+# design is still subject to change. As such, this should not yet be enabled in
+# production use.
+# This requires CONFIG_IEEE80211W=y to be enabled, too.
+#CONFIG_PASN=y
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index bf89fbc..a3d28ef 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -279,6 +279,8 @@ fragm_threshold=-1
# beacon_rate=ht:<HT MCS>
# VHT:
# beacon_rate=vht:<VHT MCS>
+# HE:
+# beacon_rate=he:<HE MCS>
#
# For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM).
#beacon_rate=10
@@ -571,6 +573,10 @@ wmm_ac_vo_acm=0
# Default: 1 (enabled)
#broadcast_deauth=1
+# Get notifications for received Management frames on control interface
+# Default: 0 (disabled)
+#notify_mgmt_frames=0
+
##### IEEE 802.11n related configuration ######################################
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
@@ -580,6 +586,9 @@ wmm_ac_vo_acm=0
# Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band.
#ieee80211n=1
+# disable_11n: Boolean (0/1) to disable HT for a specific BSS
+#disable_11n=0
+
# ht_capab: HT capabilities (list of flags)
# LDPC coding capability: [LDPC] = supported
# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
@@ -632,6 +641,9 @@ wmm_ac_vo_acm=0
# Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
#ieee80211ac=1
+# disable_11ac: Boolean (0/1) to disable VHT for a specific BSS
+#disable_11ac=0
+
# vht_capab: VHT capabilities (list of flags)
#
# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
@@ -786,6 +798,9 @@ wmm_ac_vo_acm=0
# 1 = enabled
#ieee80211ax=1
+# disable_11ax: Boolean (0/1) to disable HE for a specific BSS
+#disable_11ax=0
+
#he_su_beamformer: HE single user beamformer support
# 0 = not supported (default)
# 1 = supported
@@ -866,6 +881,65 @@ wmm_ac_vo_acm=0
#he_spr_non_srg_obss_pd_max_offset
#he_spr_srg_obss_pd_min_offset
#he_spr_srg_obss_pd_max_offset
+#
+# SPR SRG BSS Color
+# This config represents SRG BSS Color Bitmap field of Spatial Reuse Parameter
+# Set element that indicates the BSS color values used by members of the
+# SRG of which the transmitting STA is a member. The value is in range of 0-63.
+#he_spr_srg_bss_colors=1 2 10 63
+#
+# SPR SRG Partial BSSID
+# This config represents SRG Partial BSSID Bitmap field of Spatial Reuse
+# Parameter Set element that indicates the Partial BSSID values used by members
+# of the SRG of which the transmitting STA is a member. The value range
+# corresponds to one of the 64 possible values of BSSID[39:44], where the lowest
+# numbered bit corresponds to Partial BSSID value 0 and the highest numbered bit
+# corresponds to Partial BSSID value 63.
+#he_spr_srg_partial_bssid=0 1 3 63
+#
+#he_6ghz_max_mpdu: Maximum MPDU Length of HE 6 GHz band capabilities.
+# Indicates maximum MPDU length
+# 0 = 3895 octets
+# 1 = 7991 octets
+# 2 = 11454 octets (default)
+#he_6ghz_max_mpdu=2
+#
+#he_6ghz_max_ampdu_len_exp: Maximum A-MPDU Length Exponent of HE 6 GHz band
+# capabilities. Indicates the maximum length of A-MPDU pre-EOF padding that
+# the STA can receive. This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
+# 0 = AMPDU length of 8k
+# 1 = AMPDU length of 16k
+# 2 = AMPDU length of 32k
+# 3 = AMPDU length of 65k
+# 4 = AMPDU length of 131k
+# 5 = AMPDU length of 262k
+# 6 = AMPDU length of 524k
+# 7 = AMPDU length of 1048k (default)
+#he_6ghz_max_ampdu_len_exp=7
+#
+#he_6ghz_rx_ant_pat: Rx Antenna Pattern Consistency of HE 6 GHz capability.
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+# (default)
+#he_6ghz_rx_ant_pat=1
+#
+#he_6ghz_tx_ant_pat: Tx Antenna Pattern Consistency of HE 6 GHz capability.
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+# (default)
+#he_6ghz_tx_ant_pat=1
+
+# 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
+# transmitted for in-band discovery. Refer to
+# IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning.
+# Valid range: 0..20 TUs; default is 0 (disabled)
+#unsol_bcast_probe_resp_interval=0
##### IEEE 802.1X-2004 related configuration ##################################
@@ -1712,7 +1786,8 @@ own_ip_addr=127.0.0.1
#group_mgmt_cipher=AES-128-CMAC
# Beacon Protection (management frame protection for Beacon frames)
-# This depends on management frame protection being enabled (ieee80211w != 0).
+# This depends on management frame protection being enabled (ieee80211w != 0)
+# and beacon protection support indication from the driver.
# 0 = disabled (default)
# 1 = enabled
#beacon_prot=0
@@ -1729,6 +1804,9 @@ own_ip_addr=127.0.0.1
# ocv: Operating Channel Validation
# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# Enabling this depends on the driver's support for OCV when the driver SME is
+# used. If hostapd SME is used, this will be enabled just based on this
+# configuration.
# Enabling this automatically also enables ieee80211w, if not yet enabled.
# 0 = disabled (default)
# 1 = enabled
@@ -1921,6 +1999,13 @@ own_ip_addr=127.0.0.1
# default: 30 TUs (= 30.72 milliseconds)
#fils_hlp_wait_time=30
+# FILS Discovery frame transmission minimum and maximum interval settings.
+# If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery
+# frame transmission. These values use TUs as the unit and have allowed range
+# of 0-10000. fils_discovery_min_interval defaults to 20.
+#fils_discovery_min_interval=20
+#fils_discovery_max_interval=0
+
# Transition Disable indication
# The AP can notify authenticated stations to disable transition mode in their
# network profiles when the network has completed transition steps, i.e., once
@@ -1938,6 +2023,14 @@ own_ip_addr=127.0.0.1
# (default: 0 = do not include Transition Disable KDE)
#transition_disable=0x01
+# PASN ECDH groups
+# PASN implementations are required to support group 19 (NIST P-256). If this
+# parameter is not set, only group 19 is supported by default. This
+# configuration parameter can be used to specify a limited set of allowed
+# groups. The group values are listed in the IANA registry:
+# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10
+#pasn_groups=19 20 21
+
##### IEEE 802.11r configuration ##############################################
# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
@@ -2726,6 +2819,10 @@ own_ip_addr=127.0.0.1
# threshold (range: 0..255, default=30).
#rssi_reject_assoc_timeout=30
+# Ignore Probe Request frames if RSSI is below given threshold (in dBm)
+# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled)
+#rssi_ignore_probe_request=-75
+
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index dac00e0..eaa628a 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1475,6 +1475,20 @@ static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc,
#ifdef CONFIG_DPP2
+static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv);
+}
+
+
+static int hostapd_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP");
+}
+
+
static int hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1527,6 +1541,14 @@ static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc,
}
+#ifdef ANDROID
+static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "DRIVER", 1, argc, argv);
+}
+#endif /* ANDROID */
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -1698,6 +1720,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL,
"*|<id> = remove DPP pkex information" },
#ifdef CONFIG_DPP2
+ { "dpp_controller_start", hostapd_cli_cmd_dpp_controller_start, NULL,
+ "[tcp_port=<port>] [role=..] = start DPP controller" },
+ { "dpp_controller_stop", hostapd_cli_cmd_dpp_controller_stop, NULL,
+ "= stop DPP controller" },
{ "dpp_chirp", hostapd_cli_cmd_dpp_chirp, NULL,
"own=<BI ID> iter=<count> = start DPP chirp" },
{ "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL,
@@ -1714,6 +1740,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
"<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" },
{ "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL,
"= reload wpa_psk_file only" },
+#ifdef ANDROID
+ { "driver", hostapd_cli_cmd_driver, NULL,
+ "<driver sub command> [<hex formatted data>] = send driver command data" },
+#endif /* ANDROID */
{ NULL, NULL, NULL, NULL }
};
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 04535a1..419bf7c 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -131,6 +131,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
bss->fils_hlp_wait_time = 30;
bss->dhcp_server_port = DHCP_SERVER_PORT;
bss->dhcp_relay_port = DHCP_SERVER_PORT;
+ bss->fils_discovery_min_int = 20;
#endif /* CONFIG_FILS */
bss->broadcast_deauth = 1;
@@ -268,6 +269,10 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->he_op.he_bss_color_disabled = 1;
conf->he_op.he_bss_color_partial = 0;
conf->he_op.he_bss_color = 1;
+ conf->he_6ghz_max_mpdu = 2;
+ conf->he_6ghz_max_ampdu_len_exp = 7;
+ conf->he_6ghz_rx_ant_pat = 1;
+ conf->he_6ghz_tx_ant_pat = 1;
#endif /* CONFIG_IEEE80211AX */
/* The third octet of the country string uses an ASCII space character
@@ -955,6 +960,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
}
#endif /* CONFIG_AIRTIME_POLICY */
+#ifdef CONFIG_PASN
+ os_free(conf->pasn_groups);
+#endif /* CONFIG_PASN */
+
os_free(conf);
}
@@ -1150,10 +1159,54 @@ static bool hostapd_sae_pk_password_without_pk(struct hostapd_bss_config *bss)
#endif /* CONFIG_SAE_PK */
+static bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss)
+{
+ if (bss->wpa != WPA_PROTO_RSN) {
+ wpa_printf(MSG_ERROR,
+ "Pre-RSNA security methods are not allowed in 6 GHz");
+ return false;
+ }
+
+ if (bss->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_printf(MSG_ERROR,
+ "Management frame protection is required in 6 GHz");
+ return false;
+ }
+
+ if (bss->wpa_key_mgmt & (WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256)) {
+ wpa_printf(MSG_ERROR, "Invalid AKM suite for 6 GHz");
+ return false;
+ }
+
+ if (bss->rsn_pairwise & (WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104 |
+ WPA_CIPHER_TKIP)) {
+ wpa_printf(MSG_ERROR,
+ "Invalid pairwise cipher suite for 6 GHz");
+ return false;
+ }
+
+ if (bss->wpa_group & (WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104 |
+ WPA_CIPHER_TKIP)) {
+ wpa_printf(MSG_ERROR, "Invalid group cipher suite for 6 GHz");
+ return false;
+ }
+
+ return true;
+}
+
+
static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
struct hostapd_config *conf,
int full_config)
{
+ if (full_config && is_6ghz_op_class(conf->op_class) &&
+ !hostapd_config_check_bss_6g(bss))
+ return -1;
+
if (full_config && bss->ieee802_1x && !bss->eap_server &&
!bss->radius->auth_servers) {
wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
@@ -1229,7 +1282,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
if (full_config && conf->ieee80211n &&
conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
- bss->disable_11n = 1;
+ bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
"allowed, disabling HT capabilities");
}
@@ -1237,7 +1290,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
#ifdef CONFIG_WEP
if (full_config && conf->ieee80211n &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
- bss->disable_11n = 1;
+ bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
"allowed, disabling HT capabilities");
}
@@ -1248,7 +1301,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{
- bss->disable_11n = 1;
+ bss->disable_11n = true;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
"requires CCMP/GCMP to be enabled, disabling HT "
"capabilities");
@@ -1258,7 +1311,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
#ifdef CONFIG_WEP
if (full_config && conf->ieee80211ac &&
bss->ssid.security_policy == SECURITY_STATIC_WEP) {
- bss->disable_11ac = 1;
+ bss->disable_11ac = true;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities");
}
@@ -1269,12 +1322,33 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
{
- bss->disable_11ac = 1;
+ bss->disable_11ac = true;
wpa_printf(MSG_ERROR,
"VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities");
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+#ifdef CONFIG_WEP
+ if (full_config && conf->ieee80211ax &&
+ bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+ bss->disable_11ax = true;
+ wpa_printf(MSG_ERROR,
+ "HE (IEEE 802.11ax) with WEP is not allowed, disabling HE capabilities");
+ }
+#endif /* CONFIG_WEP */
+
+ if (full_config && conf->ieee80211ax && bss->wpa &&
+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP |
+ WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256)))
+ {
+ bss->disable_11ax = true;
+ wpa_printf(MSG_ERROR,
+ "HE (IEEE 802.11ax) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling HE capabilities");
+ }
+#endif /* CONFIG_IEEE80211AX */
+
#ifdef CONFIG_WPS
if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) {
wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index bada04c..88200c6 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -531,8 +531,9 @@ struct hostapd_bss_config {
#define TDLS_PROHIBIT BIT(0)
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls;
- int disable_11n;
- int disable_11ac;
+ bool disable_11n;
+ bool disable_11ac;
+ bool disable_11ax;
/* IEEE 802.11v */
int time_advertisement;
@@ -729,12 +730,16 @@ struct hostapd_bss_config {
unsigned int fils_hlp_wait_time;
u16 dhcp_server_port;
u16 dhcp_relay_port;
+ u32 fils_discovery_min_int;
+ u32 fils_discovery_max_int;
#endif /* CONFIG_FILS */
int multicast_to_unicast;
int broadcast_deauth;
+ int notify_mgmt_frames;
+
#ifdef CONFIG_DPP
char *dpp_name;
char *dpp_mud_url;
@@ -861,6 +866,20 @@ struct hostapd_bss_config {
*/
u8 mka_psk_set;
#endif /* CONFIG_MACSEC */
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ /*
+ * Normally, KDK should be derived if and only if both sides support
+ * secure LTF. Allow forcing KDK derivation for testing purposes.
+ */
+ int force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ int *pasn_groups;
+#endif /* CONFIG_PASN */
+
+ unsigned int unsol_bcast_probe_resp_interval;
};
/**
@@ -893,8 +912,8 @@ struct spatial_reuse {
u8 non_srg_obss_pd_max_offset;
u8 srg_obss_pd_min_offset;
u8 srg_obss_pd_max_offset;
- u8 srg_obss_color_bitmap;
- u8 srg_obss_color_partial_bitmap;
+ u8 srg_bss_color_bitmap[8];
+ u8 srg_partial_bssid_bitmap[8];
};
/**
@@ -1029,6 +1048,10 @@ struct hostapd_config {
u8 he_oper_chwidth;
u8 he_oper_centr_freq_seg0_idx;
u8 he_oper_centr_freq_seg1_idx;
+ u8 he_6ghz_max_mpdu;
+ u8 he_6ghz_max_ampdu_len_exp;
+ u8 he_6ghz_rx_ant_pat;
+ u8 he_6ghz_tx_ant_pat;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@@ -1036,8 +1059,14 @@ struct hostapd_config {
#define CH_SWITCH_VHT_DISABLED BIT(1)
unsigned int ch_switch_vht_config;
+ /* HE enable/disable config from CHAN_SWITCH */
+#define CH_SWITCH_HE_ENABLED BIT(0)
+#define CH_SWITCH_HE_DISABLED BIT(1)
+ unsigned int ch_switch_he_config;
+
int rssi_reject_assoc_rssi;
int rssi_reject_assoc_timeout;
+ int rssi_ignore_probe_request;
#ifdef CONFIG_AIRTIME_POLICY
enum {
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index f157659..d1642d7 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -988,3 +988,11 @@ int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
ie, ielen);
}
+
+
+int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable)
+{
+ if (!hapd->driver || !hapd->driver->dpp_listen || !hapd->drv_priv)
+ return 0;
+ return hapd->driver->dpp_listen(hapd->drv_priv, enable);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index cc7ea07..a420701 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -134,6 +134,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
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);
+int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable);
#include "drivers/driver.h"
@@ -385,11 +386,21 @@ hostapd_drv_send_external_auth_status(struct hostapd_data *hapd,
}
static inline int
-hostapd_drv_set_band(struct hostapd_data *hapd, enum set_band band)
+hostapd_drv_set_band(struct hostapd_data *hapd, u32 band_mask)
{
if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band)
return -1;
- return hapd->driver->set_band(hapd->drv_priv, band);
+ return hapd->driver->set_band(hapd->drv_priv, band_mask);
}
+#ifdef ANDROID
+static inline int hostapd_drv_driver_cmd(struct hostapd_data *hapd,
+ char *cmd, char *buf, size_t buf_len)
+{
+ if (!hapd->driver->driver_cmd)
+ return -1;
+ return hapd->driver->driver_cmd(hapd->drv_priv, cmd, buf, buf_len);
+}
+#endif /* ANDROID */
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 6d5bb71..7d9e8b9 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -266,7 +266,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
}
-static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
+const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid)
{
const u8 *ies;
size_t ies_len;
@@ -458,7 +458,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
}
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
buflen += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
@@ -563,15 +563,21 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
+ is_6ghz_op_class(hapd->iconf->op_class))
+ pos = hostapd_eid_txpower_envelope(hapd, pos);
+#endif /* CONFIG_IEEE80211AX */
+
if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
- hapd->iconf->ieee80211ax)
+ (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
pos = hostapd_eid_fils_indic(hapd, pos, 0);
pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_he_operation(hapd, pos);
pos = hostapd_eid_spatial_reuse(hapd, pos);
@@ -818,6 +824,10 @@ void handle_probe_req(struct hostapd_data *hapd,
size_t csa_offs_len;
struct radius_sta rad_info;
+ if (hapd->iconf->rssi_ignore_probe_request && ssi_signal &&
+ ssi_signal < hapd->iconf->rssi_ignore_probe_request)
+ return;
+
if (len < IEEE80211_HDRLEN)
return;
ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
@@ -1114,6 +1124,23 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
#endif /* NEED_AP_MLME */
+#ifdef CONFIG_IEEE80211AX
+/* Unsolicited broadcast Probe Response transmission, 6 GHz only */
+static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params)
+{
+ if (!is_6ghz_op_class(hapd->iconf->op_class))
+ return NULL;
+
+ params->unsol_bcast_probe_resp_interval =
+ hapd->conf->unsol_bcast_probe_resp_interval;
+
+ return hostapd_gen_probe_resp(hapd, NULL, 0,
+ &params->unsol_bcast_probe_resp_tmpl_len);
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
void sta_track_del(struct hostapd_sta_info *info)
{
#ifdef CONFIG_TAXONOMY
@@ -1124,6 +1151,243 @@ void sta_track_del(struct hostapd_sta_info *info)
}
+#ifdef CONFIG_FILS
+
+static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd)
+{
+ u16 cap_info, phy_index = 0;
+ u8 chwidth = FD_CAP_BSS_CHWIDTH_20, mcs_nss_size = 4;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
+
+ cap_info = FD_CAP_ESS;
+ if (hapd->conf->wpa)
+ cap_info |= FD_CAP_PRIVACY;
+
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ phy_index = FD_CAP_PHY_INDEX_HE;
+
+ switch (hapd->iconf->op_class) {
+ case 135:
+ mcs_nss_size += 4;
+ /* fallthrough */
+ case 134:
+ mcs_nss_size += 4;
+ chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
+ break;
+ case 133:
+ chwidth = FD_CAP_BSS_CHWIDTH_80;
+ break;
+ case 132:
+ chwidth = FD_CAP_BSS_CHWIDTH_40;
+ break;
+ }
+ } else {
+ switch (hostapd_get_oper_chwidth(hapd->iconf)) {
+ case CHANWIDTH_80P80MHZ:
+ mcs_nss_size += 4;
+ /* fallthrough */
+ case CHANWIDTH_160MHZ:
+ mcs_nss_size += 4;
+ chwidth = FD_CAP_BSS_CHWIDTH_160_80_80;
+ break;
+ case CHANWIDTH_80MHZ:
+ chwidth = FD_CAP_BSS_CHWIDTH_80;
+ break;
+ case CHANWIDTH_USE_HT:
+ if (hapd->iconf->secondary_channel)
+ chwidth = FD_CAP_BSS_CHWIDTH_40;
+ else
+ chwidth = FD_CAP_BSS_CHWIDTH_20;
+ break;
+ }
+
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)
+ phy_index = FD_CAP_PHY_INDEX_HE;
+#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211AC
+ if (!phy_index &&
+ hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)
+ phy_index = FD_CAP_PHY_INDEX_VHT;
+#endif /* CONFIG_IEEE80211AC */
+ if (!phy_index &&
+ hapd->iconf->ieee80211n && !hapd->conf->disable_11n)
+ phy_index = FD_CAP_PHY_INDEX_HT;
+ }
+
+ cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT;
+ cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT;
+
+ if (mode) {
+ u16 *mcs = (u16 *) mode->he_capab[IEEE80211_MODE_AP].mcs;
+ int i;
+ u16 nss = 0;
+
+ for (i = 0; i < HE_NSS_MAX_STREAMS; i++) {
+ u16 nss_mask = 0x3 << (i * 2);
+
+ if (mcs_nss_size == 4 &&
+ (((mcs[0] & nss_mask) == nss_mask) ||
+ ((mcs[1] & nss_mask) == nss_mask)))
+ continue;
+
+ if (mcs_nss_size == 8 &&
+ (((mcs[2] & nss_mask) == nss_mask) ||
+ ((mcs[3] & nss_mask) == nss_mask)))
+ continue;
+
+ if (mcs_nss_size == 12 &&
+ (((mcs[4] & nss_mask) == nss_mask) ||
+ ((mcs[5] & nss_mask) == nss_mask)))
+ continue;
+
+ nss++;
+ }
+
+ if (nss > 4)
+ cap_info |= FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT;
+ else if (nss)
+ cap_info |= (nss - 1) << FD_CAP_NSS_SHIFT;
+ }
+
+ return cap_info;
+}
+
+
+static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
+{
+ struct ieee80211_mgmt *head;
+ const u8 *mobility_domain;
+ u8 *pos, *length_pos, buf[200];
+ u16 ctl = 0;
+ u8 fd_rsn_info[5];
+ size_t total_len, buf_len;
+
+ total_len = 24 + 2 + 12;
+
+ /* FILS Discovery Frame Control */
+ ctl = (sizeof(hapd->conf->ssid.short_ssid) - 1) |
+ FD_FRAME_CTL_SHORT_SSID_PRESENT |
+ FD_FRAME_CTL_LENGTH_PRESENT |
+ FD_FRAME_CTL_CAP_PRESENT;
+ total_len += 4 + 1 + 2;
+
+ /* Check for optional subfields and calculate length */
+ if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) {
+ ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT;
+ total_len += sizeof(fd_rsn_info);
+ }
+
+ mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN);
+ if (mobility_domain) {
+ ctl |= FD_FRAME_CTL_MD_PRESENT;
+ total_len += 3;
+ }
+
+ pos = hostapd_eid_fils_indic(hapd, buf, 0);
+ buf_len = pos - buf;
+ total_len += buf_len;
+
+ head = os_zalloc(total_len);
+ if (!head)
+ return NULL;
+
+ head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memset(head->da, 0xff, ETH_ALEN);
+ os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
+
+ head->u.action.category = WLAN_ACTION_PUBLIC;
+ head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY;
+
+ pos = &head->u.action.u.public_action.variable[0];
+
+ /* FILS Discovery Information field */
+
+ /* FILS Discovery Frame Control */
+ WPA_PUT_LE16(pos, ctl);
+ pos += 2;
+
+ /* Hardware or low-level driver will fill in the Timestamp value */
+ pos += 8;
+
+ /* Beacon Interval */
+ WPA_PUT_LE16(pos, hapd->iconf->beacon_int);
+ pos += 2;
+
+ /* Short SSID */
+ WPA_PUT_LE32(pos, hapd->conf->ssid.short_ssid);
+ pos += sizeof(hapd->conf->ssid.short_ssid);
+
+ /* Store position of FILS discovery information element Length field */
+ length_pos = pos++;
+
+ /* FD Capability */
+ WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd));
+ pos += 2;
+
+ /* Operating Class - not present */
+
+ /* Primary Channel - not present */
+
+ /* AP Configuration Sequence Number - not present */
+
+ /* Access Network Options - not present */
+
+ /* FD RSN Information */
+ if (ctl & FD_FRAME_CTL_RSN_INFO_PRESENT) {
+ os_memcpy(pos, fd_rsn_info, sizeof(fd_rsn_info));
+ pos += sizeof(fd_rsn_info);
+ }
+
+ /* Channel Center Frequency Segment 1 - not present */
+
+ /* Mobility Domain */
+ if (ctl & FD_FRAME_CTL_MD_PRESENT) {
+ os_memcpy(pos, &mobility_domain[2], 3);
+ pos += 3;
+ }
+
+ /* Fill in the Length field value */
+ *length_pos = pos - (length_pos + 1);
+
+ /* FILS Indication element */
+ if (buf_len) {
+ os_memcpy(pos, buf, buf_len);
+ pos += buf_len;
+ }
+
+ *len = pos - (u8 *) head;
+ wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
+ head, pos - (u8 *) head);
+ return (u8 *) head;
+}
+
+
+/* Configure FILS Discovery frame transmission parameters */
+static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
+ struct wpa_driver_ap_params *params)
+{
+ params->fd_max_int = hapd->conf->fils_discovery_max_int;
+ if (is_6ghz_op_class(hapd->iconf->op_class) &&
+ params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
+ params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
+
+ params->fd_min_int = hapd->conf->fils_discovery_min_int;
+ if (params->fd_min_int > params->fd_max_int)
+ params->fd_min_int = params->fd_max_int;
+
+ if (params->fd_max_int)
+ return hostapd_gen_fils_discovery(hapd,
+ &params->fd_frame_tmpl_len);
+
+ return NULL;
+}
+
+#endif /* CONFIG_FILS */
+
+
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params)
{
@@ -1163,7 +1427,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
tail_len += 3 + sizeof(struct ieee80211_he_capabilities) +
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
@@ -1280,22 +1544,29 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0);
tailpos = hostapd_eid_vht_operation(hapd, tailpos);
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax &&
+ is_6ghz_op_class(hapd->iconf->op_class))
+ tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
+#endif /* CONFIG_IEEE80211AX */
+
if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) ||
- hapd->iconf->ieee80211ax)
+ (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
tailpos = hostapd_eid_he_capab(hapd, tailpos,
IEEE80211_MODE_AP);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
@@ -1461,6 +1732,14 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
params->head = NULL;
os_free(params->proberesp);
params->proberesp = NULL;
+#ifdef CONFIG_FILS
+ os_free(params->fd_frame_tmpl);
+ params->fd_frame_tmpl = NULL;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211AX
+ os_free(params->unsol_bcast_probe_resp_tmpl);
+ params->unsol_bcast_probe_resp_tmpl = NULL;
+#endif /* CONFIG_IEEE80211AX */
}
@@ -1493,11 +1772,17 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
params.assocresp_ies = assocresp;
params.reenable = hapd->reenable_beacon;
#ifdef CONFIG_IEEE80211AX
- params.he_spr = !!hapd->iface->conf->spr.sr_control;
+ params.he_spr_ctrl = hapd->iface->conf->spr.sr_control;
+ params.he_spr_non_srg_obss_pd_max_offset =
+ hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
params.he_spr_srg_obss_pd_min_offset =
hapd->iface->conf->spr.srg_obss_pd_min_offset;
params.he_spr_srg_obss_pd_max_offset =
hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ os_memcpy(params.he_spr_bss_color_bitmap,
+ hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
+ os_memcpy(params.he_spr_partial_bssid_bitmap,
+ hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
params.he_bss_color_disabled =
hapd->iface->conf->he_op.he_bss_color_disabled;
params.he_bss_color_partial =
@@ -1505,12 +1790,18 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
params.he_bss_color = hapd->iface->conf->he_op.he_bss_color;
params.twt_responder = hostapd_get_he_twt_responder(hapd,
IEEE80211_MODE_AP);
+ params.unsol_bcast_probe_resp_tmpl =
+ hostapd_unsol_bcast_probe_resp(hapd, &params);
#endif /* CONFIG_IEEE80211AX */
hapd->reenable_beacon = 0;
#ifdef CONFIG_SAE
params.sae_pwe = hapd->conf->sae_pwe;
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ params.fd_frame_tmpl = hostapd_fils_discovery(hapd, &params);
+#endif /* CONFIG_FILS */
+
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
iconf->channel, iconf->enable_edmg,
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index a26e308..c320825 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -30,4 +30,6 @@ sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr,
struct wpabuf **probe_ie_taxonomy);
+const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid);
+
#endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index ef53a82..28e40ba 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -748,7 +748,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
iface->conf->ieee80211n && !hapd->conf->disable_11n,
iface->conf->ieee80211ac &&
!hapd->conf->disable_11ac,
- iface->conf->ieee80211ax,
+ iface->conf->ieee80211ax &&
+ !hapd->conf->disable_11ax,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
@@ -756,7 +757,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
len += ret;
#ifdef CONFIG_IEEE80211AX
- if (iface->conf->ieee80211ax) {
+ if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
ret = os_snprintf(buf + len, buflen - len,
"he_oper_chwidth=%d\n"
"he_oper_centr_freq_seg0_idx=%d\n"
@@ -908,6 +909,7 @@ int hostapd_parse_csa_settings(const char *pos,
SET_CSA_SETTING(sec_channel_offset);
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->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index f04a00a..b990fb3 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -81,17 +81,17 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
* We will also choose this first channel as the control one.
*/
int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
- 184, 192 };
+ 165, 173, 184, 192 };
/*
* VHT80, valid channels based on center frequency:
- * 42, 58, 106, 122, 138, 155
+ * 42, 58, 106, 122, 138, 155, 171
*/
- int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
+ int allowed_80[] = { 36, 52, 100, 116, 132, 149, 165 };
/*
* VHT160 valid channels based on center frequency:
- * 50, 114
+ * 50, 114, 163
*/
- int allowed_160[] = { 36, 100 };
+ int allowed_160[] = { 36, 100, 149 };
int *allowed = allowed_40;
unsigned int i, allowed_no = 0;
@@ -1032,6 +1032,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
int err = 1;
struct hostapd_hw_modes *cmode = iface->current_mode;
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",
@@ -1069,8 +1070,16 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
&skip_radar);
- if (!channel)
- return err;
+ if (!channel) {
+ /*
+ * Toggle interface state to enter DFS state
+ * until NOP is finished.
+ */
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+ return 0;
+ }
+
if (!skip_radar) {
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
@@ -1099,6 +1108,10 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
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,
@@ -1113,7 +1126,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
cmode->vht_capab,
- &cmode->he_capab[IEEE80211_MODE_AP]);
+ &cmode->he_capab[ieee80211_mode]);
if (err) {
wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
@@ -1335,12 +1348,16 @@ int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
if (!(chan->flag & HOSTAPD_CHAN_RADAR))
continue;
+ if ((chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
+ HOSTAPD_CHAN_DFS_AVAILABLE)
+ continue;
+
if (center_freq - chan->freq < half_width &&
chan->freq - center_freq < half_width)
res++;
}
- wpa_printf(MSG_DEBUG, "DFS: (%d, %d): in range: %s",
+ wpa_printf(MSG_DEBUG, "DFS CAC required: (%d, %d): in range: %s",
center_freq - half_width, center_freq + half_width,
res ? "yes" : "no");
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 6772a87..e1e5a3a 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -23,6 +23,8 @@
static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx);
+static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx);
static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator);
static void hostapd_dpp_init_timeout(void *eloop_ctx, void *timeout_ctx);
static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
@@ -246,6 +248,8 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout,
+ hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL);
#ifdef CONFIG_DPP2
@@ -277,6 +281,17 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
}
}
+ if (auth->waiting_auth_conf &&
+ auth->auth_resp_status == DPP_STATUS_OK) {
+ /* Make sure we do not get stuck waiting for Auth Confirm
+ * indefinitely after successfully transmitted Auth Response to
+ * allow new authentication exchanges to be started. */
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd,
+ NULL);
+ eloop_register_timeout(1, 0, hostapd_dpp_auth_conf_wait_timeout,
+ hapd, NULL);
+ }
+
if (!is_broadcast_ether_addr(dst) && auth->waiting_auth_resp && ok) {
/* Allow timeout handling to stop iteration if no response is
* received from a peer that has ACKed a request. */
@@ -377,6 +392,25 @@ static void hostapd_dpp_reply_wait_timeout(void *eloop_ctx, void *timeout_ctx)
}
+static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_auth_conf)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Terminate authentication exchange due to Auth Confirm timeout");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+ "No Auth Confirm received");
+ hostapd_drv_send_action_cancel_wait(hapd);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
struct dpp_authentication *auth)
{
@@ -461,7 +495,9 @@ static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd)
freq = auth->freq[auth->freq_idx++];
auth->curr_freq = freq;
- if (is_zero_ether_addr(auth->peer_bi->mac_addr))
+ if (!is_zero_ether_addr(auth->peer_mac_addr))
+ dst = auth->peer_mac_addr;
+ else if (is_zero_ether_addr(auth->peer_bi->mac_addr))
dst = broadcast;
else
dst = auth->peer_bi->mac_addr;
@@ -594,6 +630,8 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd)
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout,
hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout,
+ hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd,
NULL);
#ifdef CONFIG_DPP2
@@ -661,12 +699,14 @@ int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd)
return -1;
}
+ hostapd_drv_dpp_listen(hapd, true);
return 0;
}
void hostapd_dpp_listen_stop(struct hostapd_data *hapd)
{
+ hostapd_drv_dpp_listen(hapd, false);
/* TODO: Stop listen operation on non-operating channel */
}
@@ -1261,8 +1301,9 @@ hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src,
auth->neg_freq = freq;
- if (!is_zero_ether_addr(peer_bi->mac_addr))
- os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN);
+ /* The source address of the Presence Announcement frame overrides any
+ * MAC address information from the bootstrapping information. */
+ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
hapd->dpp_auth = auth;
if (hostapd_dpp_auth_init_next(hapd) < 0) {
@@ -1962,6 +2003,7 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
@@ -2207,6 +2249,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
if (!hapd->dpp_init_done)
return;
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 9af5445..53082f5 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -870,9 +870,10 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver %s channel switch: freq=%d, ht=%d, vht_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, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
finished ? "had" : "starting",
- freq, ht, hapd->iconf->ch_switch_vht_config, offset,
+ freq, ht, hapd->iconf->ch_switch_vht_config,
+ hapd->iconf->ch_switch_he_config, offset,
width, channel_width_to_string(width), cf1, cf2);
if (!hapd->iface->current_mode) {
@@ -944,8 +945,17 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
else if (hapd->iconf->ch_switch_vht_config &
CH_SWITCH_VHT_DISABLED)
hapd->iconf->ieee80211ac = 0;
+ } else if (hapd->iconf->ch_switch_he_config) {
+ /* CHAN_SWITCH HE config */
+ if (hapd->iconf->ch_switch_he_config &
+ CH_SWITCH_HE_ENABLED)
+ hapd->iconf->ieee80211ax = 1;
+ else if (hapd->iconf->ch_switch_he_config &
+ CH_SWITCH_HE_DISABLED)
+ hapd->iconf->ieee80211ax = 0;
}
hapd->iconf->ch_switch_vht_config = 0;
+ hapd->iconf->ch_switch_he_config = 0;
hapd->iconf->secondary_channel = offset;
hostapd_set_oper_chwidth(hapd->iconf, chwidth);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index b37f49f..e257174 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -354,7 +354,7 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
#endif /* CONFIG_WEP */
-static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
os_free(hapd->probereq_cb);
hapd->probereq_cb = NULL;
@@ -434,6 +434,8 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_MESH
wpabuf_free(hapd->mesh_pending_auth);
hapd->mesh_pending_auth = NULL;
+ /* handling setup failure is already done */
+ hapd->setup_complete_cb = NULL;
#endif /* CONFIG_MESH */
hostapd_clean_rrm(hapd);
@@ -496,7 +498,7 @@ static void sta_track_deinit(struct hostapd_iface *iface)
}
-static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
#ifdef NEED_AP_MLME
@@ -624,7 +626,7 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
}
-static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd)
{
hostapd_free_stas(hapd);
hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
@@ -1701,6 +1703,9 @@ static int setup_interface2(struct hostapd_iface *iface)
ret = hostapd_check_edmg_capab(iface);
if (ret < 0)
goto fail;
+ ret = hostapd_check_he_6ghz_capab(iface);
+ if (ret < 0)
+ goto fail;
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
goto fail;
@@ -2156,6 +2161,13 @@ dfs_offload:
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
+#ifdef CONFIG_MESH
+ if (delay_apply_cfg && !iface->mconf) {
+ wpa_printf(MSG_ERROR, "Error while completing mesh init");
+ goto fail;
+ }
+#endif /* CONFIG_MESH */
+
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
iface->bss[0]->conf->iface);
if (iface->interfaces && iface->interfaces->terminate_on_error > 0)
@@ -2299,7 +2311,7 @@ int hostapd_setup_interface(struct hostapd_iface *iface)
ret = setup_interface(iface);
if (ret) {
wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
- iface->bss[0]->conf->iface);
+ iface->conf ? iface->conf->bss[0]->iface : "N/A");
return -1;
}
@@ -2681,6 +2693,12 @@ int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
{
size_t j;
+ if (!hapd_iface)
+ return -1;
+
+ if (hapd_iface->enable_iface_cb)
+ return hapd_iface->enable_iface_cb(hapd_iface);
+
if (hapd_iface->bss[0]->drv_priv != NULL) {
wpa_printf(MSG_ERROR, "Interface %s already enabled",
hapd_iface->conf->bss[0]->iface);
@@ -2742,6 +2760,9 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
if (hapd_iface == NULL)
return -1;
+ if (hapd_iface->disable_iface_cb)
+ return hapd_iface->disable_iface_cb(hapd_iface);
+
if (hapd_iface->bss[0]->drv_priv == NULL) {
wpa_printf(MSG_INFO, "Interface %s already disabled",
hapd_iface->conf->bss[0]->iface);
@@ -3539,15 +3560,23 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
}
-void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled)
+void hostapd_chan_switch_config(struct hostapd_data *hapd,
+ struct hostapd_freq_params *freq_params)
{
- if (vht_enabled)
+ if (freq_params->he_enabled)
+ hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED;
+ else
+ hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_DISABLED;
+
+ if (freq_params->vht_enabled)
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_ENABLED;
else
hapd->iconf->ch_switch_vht_config |= CH_SWITCH_VHT_DISABLED;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "CHAN_SWITCH VHT CONFIG 0x%x",
+ HOSTAPD_LEVEL_INFO,
+ "CHAN_SWITCH HE config 0x%x VHT config 0x%x",
+ hapd->iconf->ch_switch_he_config,
hapd->iconf->ch_switch_vht_config);
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index b70d13f..0736f45 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -370,6 +370,8 @@ struct hostapd_data {
int dhcp_sock; /* UDP socket used with the DHCP server */
+ struct ptksa_cache *ptksa;
+
#ifdef CONFIG_DPP
int dpp_init_done;
struct dpp_authentication *dpp_auth;
@@ -589,6 +591,9 @@ struct hostapd_iface {
/* Previous WMM element information */
struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM];
+
+ int (*enable_iface_cb)(struct hostapd_iface *iface);
+ int (*disable_iface_cb)(struct hostapd_iface *iface);
};
/* hostapd.c */
@@ -617,13 +622,17 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface);
int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+void hostapd_bss_deinit_no_free(struct hostapd_data *hapd);
+void hostapd_free_hapd_data(struct hostapd_data *hapd);
+void hostapd_cleanup_iface_partial(struct hostapd_iface *iface);
int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator);
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
int hostapd_csa_in_progress(struct hostapd_iface *iface);
-void hostapd_chan_switch_vht_config(struct hostapd_data *hapd, int vht_enabled);
+void hostapd_chan_switch_config(struct hostapd_data *hapd,
+ struct hostapd_freq_params *freq_params);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
void
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index 543fa33..05e9b9d 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -86,7 +86,9 @@ u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
capab |= WPA_CAPABILITY_MFPR;
}
#ifdef CONFIG_OCV
- if (hapd->conf->ocv)
+ if (hapd->conf->ocv &&
+ (hapd->iface->drv_flags2 &
+ (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
capab |= WPA_CAPABILITY_OCVC;
#endif /* CONFIG_OCV */
WPA_PUT_LE16(eid, capab);
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index f6e6903..7849be1 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -313,7 +313,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
{
struct wpa_scan_results *scan_res;
int oper40;
- int res;
+ int res = 0;
/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
* allowed per IEEE Std 802.11-2012, 10.15.3.2 */
@@ -349,7 +349,24 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
}
}
- res = ieee80211n_allowed_ht40_channel_pair(iface);
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->secondary_channel &&
+ iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ iface->conf->ieee80211ax) {
+ struct he_capabilities *he_cap;
+
+ he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
+ if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
+ wpa_printf(MSG_DEBUG,
+ "HE: 40 MHz channel width is not supported in 2.4 GHz; clear secondary channel configuration");
+ iface->conf->secondary_channel = 0;
+ }
+ }
+#endif /* CONFIG_IEEE80211AX */
+
+ if (iface->conf->secondary_channel)
+ res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0);
@@ -732,6 +749,51 @@ int hostapd_check_edmg_capab(struct hostapd_iface *iface)
}
+int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
+{
+#ifdef CONFIG_IEEE80211AX
+ struct he_capabilities *he_cap;
+ u16 hw;
+
+ if (!iface->current_mode || !is_6ghz_freq(iface->freq))
+ return 0;
+
+ he_cap = &iface->current_mode->he_capab[IEEE80211_MODE_AP];
+ hw = he_cap->he_6ghz_capa;
+ if (iface->conf->he_6ghz_max_mpdu >
+ ((hw & HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK) >>
+ HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Max MPDU length");
+ return -1;
+ }
+
+ if (iface->conf->he_6ghz_max_ampdu_len_exp >
+ ((hw & HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK) >>
+ HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Max AMPDU Length Exponent");
+ return -1;
+ }
+
+ if (iface->conf->he_6ghz_rx_ant_pat &&
+ !(hw & HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Rx Antenna Pattern");
+ return -1;
+ }
+
+ if (iface->conf->he_6ghz_tx_ant_pat &&
+ !(hw & HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS)) {
+ wpa_printf(MSG_ERROR,
+ "The driver does not support the configured HE 6 GHz Tx Antenna Pattern");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211AX */
+ return 0;
+}
+
+
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int frequency, int primary)
{
@@ -949,9 +1011,9 @@ static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
- "Configured channel (%d) or frequency (%d) not found from the channel list of the current mode (%d) %s",
+ "Configured channel (%d) or frequency (%d) (secondary_channel=%d) not found from the channel list of the current mode (%d) %s",
iface->conf->channel,
- iface->freq,
+ iface->freq, iface->conf->secondary_channel,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
@@ -1029,12 +1091,13 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
+ int chan;
+
if (mode->mode == iface->conf->hw_mode) {
if (iface->freq > 0 &&
- !hw_get_chan(mode->mode, iface->freq,
- iface->hw_features,
- iface->num_hw_features))
+ !hw_mode_get_channel(mode, iface->freq, &chan))
continue;
+
iface->current_mode = mode;
break;
}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index dd24f95..ad0ddf7 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -22,6 +22,7 @@ int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_check_edmg_capab(struct hostapd_iface *iface);
+int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
@@ -85,6 +86,11 @@ static inline int hostapd_hw_skip_mode(struct hostapd_iface *iface,
return 0;
}
+static inline int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface)
+{
+ return 0;
+}
+
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index de715a0..40d4a33 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -25,6 +25,7 @@
#include "common/ocv.h"
#include "common/wpa_common.h"
#include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -65,6 +66,23 @@ prepare_auth_resp_fils(struct hostapd_data *hapd,
const u8 *msk, size_t msk_len,
int *is_pub);
#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_PASN
+
+static int handle_auth_pasn_resp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct rsn_pmksa_cache_entry *pmksa,
+ u16 status);
+#ifdef CONFIG_FILS
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len);
+
+#endif /* CONFIG_FILS */
+#endif /* CONFIG_PASN */
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi, int from_queue);
@@ -469,6 +487,49 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state,
}
+static const char * sae_get_password(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const char *rx_id,
+ struct sae_password_entry **pw_entry,
+ struct sae_pt **s_pt,
+ const struct sae_pk **s_pk)
+{
+ const char *password = NULL;
+ struct sae_password_entry *pw;
+ struct sae_pt *pt = NULL;
+ const struct sae_pk *pk = NULL;
+
+ for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
+ if (!is_broadcast_ether_addr(pw->peer_addr) &&
+ os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
+ continue;
+ if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
+ continue;
+ if (rx_id && pw->identifier &&
+ os_strcmp(rx_id, pw->identifier) != 0)
+ continue;
+ password = pw->password;
+ pt = pw->pt;
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ pk = pw->pk;
+ break;
+ }
+ if (!password) {
+ password = hapd->conf->ssid.wpa_passphrase;
+ pt = hapd->conf->ssid.pt;
+ }
+
+ if (pw_entry)
+ *pw_entry = pw;
+ if (s_pt)
+ *s_pt = pt;
+ if (s_pk)
+ *s_pk = pk;
+
+ return password;
+}
+
+
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
struct sta_info *sta, int update,
int status_code)
@@ -498,25 +559,7 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
status_code == WLAN_STATUS_SAE_PK)
use_pt = 1;
- for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
- if (!is_broadcast_ether_addr(pw->peer_addr) &&
- os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
- continue;
- if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
- continue;
- if (rx_id && pw->identifier &&
- os_strcmp(rx_id, pw->identifier) != 0)
- continue;
- password = pw->password;
- pt = pw->pt;
- if (!(hapd->conf->mesh & MESH_ENABLED))
- pk = pw->pk;
- break;
- }
- if (!password) {
- password = hapd->conf->ssid.wpa_passphrase;
- pt = hapd->conf->ssid.pt;
- }
+ password = sae_get_password(hapd, sta, rx_id, &pw, &pt, &pk);
if (!password || (use_pt && !pt)) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
return NULL;
@@ -1234,6 +1277,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
int default_groups[] = { 19, 0 };
const u8 *pos, *end;
int sta_removed = 0;
+ bool success_status;
if (!groups)
groups = default_groups;
@@ -1519,9 +1563,12 @@ reply:
}
remove_sta:
+ if (auth_transaction == 1)
+ success_status = sae_status_success(hapd, status_code);
+ else
+ success_status = status_code == WLAN_STATUS_SUCCESS;
if (!sta_removed && sta->added_unassoc &&
- (resp != WLAN_STATUS_SUCCESS ||
- status_code != WLAN_STATUS_SUCCESS)) {
+ (resp != WLAN_STATUS_SUCCESS || !success_status)) {
hostapd_drv_sta_remove(hapd, sta->addr);
sta->added_unassoc = 0;
}
@@ -2185,23 +2232,35 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
struct wpabuf *erp_resp,
const u8 *msk, size_t msk_len)
{
- struct wpabuf *data;
- int pub = 0;
u16 resp;
+ u32 flags = sta->flags;
- sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
+ sta->flags &= ~(WLAN_STA_PENDING_FILS_ERP |
+ WLAN_STA_PENDING_PASN_FILS_ERP);
- if (!sta->fils_pending_cb)
- return;
resp = success ? WLAN_STATUS_SUCCESS : WLAN_STATUS_UNSPECIFIED_FAILURE;
- data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
- msk, msk_len, &pub);
- if (!data) {
- wpa_printf(MSG_DEBUG,
- "%s: prepare_auth_resp_fils() returned failure",
- __func__);
+
+ if (flags & WLAN_STA_PENDING_FILS_ERP) {
+ struct wpabuf *data;
+ int pub = 0;
+
+ if (!sta->fils_pending_cb)
+ return;
+
+ data = prepare_auth_resp_fils(hapd, sta, &resp, NULL, erp_resp,
+ msk, msk_len, &pub);
+ if (!data) {
+ wpa_printf(MSG_DEBUG,
+ "%s: prepare_auth_resp_fils() failure",
+ __func__);
+ }
+ sta->fils_pending_cb(hapd, sta, resp, data, pub);
+#ifdef CONFIG_PASN
+ } else if (flags & WLAN_STA_PENDING_PASN_FILS_ERP) {
+ pasn_fils_auth_resp(hapd, sta, resp, erp_resp,
+ msk, msk_len);
+#endif /* CONFIG_PASN */
}
- sta->fils_pending_cb(hapd, sta, resp, data, pub);
}
#endif /* CONFIG_FILS */
@@ -2296,6 +2355,1065 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
}
+#ifdef CONFIG_PASN
+#ifdef CONFIG_SAE
+
+static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct wpabuf *wd)
+{
+ struct pasn_data *pasn = sta->pasn;
+ const char *password = NULL;
+ const u8 *data;
+ size_t buf_len;
+ u16 res, alg, seq, status;
+ int groups[] = { pasn->group, 0 };
+ int ret;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE commit: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ /* TODO: SAE H2E */
+ if (alg != WLAN_AUTH_SAE || seq != 1 || status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit");
+ return -1;
+ }
+
+ sae_clear_data(&pasn->sae);
+ pasn->sae.state = SAE_NOTHING;
+
+ ret = sae_set_group(&pasn->sae, pasn->group);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
+ return -1;
+ }
+
+ password = sae_get_password(hapd, sta, NULL, NULL, NULL, NULL);
+ if (!password) {
+ wpa_printf(MSG_DEBUG, "PASN: No SAE password found");
+ return -1;
+ }
+
+ ret = sae_prepare_commit(hapd->own_addr, sta->addr,
+ (const u8 *) password, os_strlen(password), 0,
+ &pasn->sae);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
+ return -1;
+ }
+
+ res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
+ groups, 0);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
+ return -1;
+ }
+
+ /* Process the commit message and derive the PMK */
+ ret = sae_process_commit(&pasn->sae);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
+ return -1;
+ }
+
+ pasn->sae.state = SAE_COMMITTED;
+
+ return 0;
+}
+
+
+static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct wpabuf *wd)
+{
+ struct pasn_data *pasn = sta->pasn;
+ const u8 *data;
+ size_t buf_len;
+ u16 res, alg, seq, status;
+
+ if (!wd)
+ return -1;
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
+ return -1;
+ }
+
+ res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6);
+ if (res != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
+ return -1;
+ }
+
+ pasn->sae.state = SAE_ACCEPTED;
+
+ /*
+ * TODO: Based on on IEEE P802.11az/D2.6, the PMKSA derived with
+ * PASN/SAE should only be allowed with future PASN only. For now do not
+ * restrict this only for PASN.
+ */
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+ pasn->sae.pmk, pasn->sae.pmkid);
+ return 0;
+}
+
+
+static struct wpabuf * pasn_get_sae_wd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct wpabuf *buf = NULL;
+ u8 *len_ptr;
+ size_t len;
+
+ /* Need to add the entire Authentication frame body */
+ buf = wpabuf_alloc(8 + SAE_COMMIT_MAX_LEN + 8 + SAE_CONFIRM_MAX_LEN);
+ if (!buf) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
+ return NULL;
+ }
+
+ /* Need to add the entire authentication frame body for the commit */
+ len_ptr = wpabuf_put(buf, 2);
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 1);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* Write the actual commit and update the length accordingly */
+ sae_write_commit(&pasn->sae, buf, NULL, 0);
+ len = wpabuf_len(buf);
+ WPA_PUT_LE16(len_ptr, len - 2);
+
+ /* Need to add the entire Authentication frame body for the confirm */
+ len_ptr = wpabuf_put(buf, 2);
+ wpabuf_put_le16(buf, WLAN_AUTH_SAE);
+ wpabuf_put_le16(buf, 2);
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ sae_write_confirm(&pasn->sae, buf);
+ WPA_PUT_LE16(len_ptr, wpabuf_len(buf) - len - 2);
+
+ pasn->sae.state = SAE_CONFIRMED;
+
+ return buf;
+}
+
+#endif /* CONFIG_SAE */
+
+
+#ifdef CONFIG_FILS
+
+static struct wpabuf * pasn_get_fils_wd(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ struct wpabuf *buf = NULL;
+
+ if (!fils->erp_resp) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing erp_resp");
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ return NULL;
+
+ /* Add the authentication algorithm */
+ wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
+
+ /* Authentication Transaction seq# */
+ wpabuf_put_le16(buf, 2);
+
+ /* Status Code */
+ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+
+ /* Own RSNE */
+ wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
+
+ /* FILS Nonce */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
+ wpabuf_put_data(buf, fils->anonce, FILS_NONCE_LEN);
+
+ /* FILS Session */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
+ wpabuf_put_data(buf, fils->session, FILS_SESSION_LEN);
+
+ /* Wrapped Data */
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(fils->erp_resp));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+ wpabuf_put_buf(buf, fils->erp_resp);
+
+ return buf;
+}
+
+
+static void pasn_fils_auth_resp(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 status,
+ struct wpabuf *erp_resp,
+ const u8 *msk, size_t msk_len)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ u8 pmk[PMK_LEN_MAX];
+ size_t pmk_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u",
+ status);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ goto fail;
+
+ if (!pasn->secret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret");
+ goto fail;
+ }
+
+ if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce");
+ goto fail;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce",
+ fils->anonce, FILS_NONCE_LEN);
+
+ ret = fils_rmsk_to_pmk(pasn->akmp, msk, msk_len, fils->nonce,
+ fils->anonce, NULL, 0, pmk, &pmk_len);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
+ goto fail;
+ }
+
+ ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
+ wpabuf_head(pasn->secret),
+ wpabuf_len(pasn->secret),
+ &sta->pasn->ptk, sta->pasn->akmp,
+ sta->pasn->cipher, WPA_KDK_MAX_LEN);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
+
+ wpabuf_free(pasn->secret);
+ pasn->secret = NULL;
+
+ fils->erp_resp = erp_resp;
+ ret = handle_auth_pasn_resp(hapd, sta, NULL, WLAN_STATUS_SUCCESS);
+ fils->erp_resp = NULL;
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response");
+ goto fail;
+ }
+
+ fils->state = PASN_FILS_STATE_COMPLETE;
+ return;
+fail:
+ ap_free_sta(hapd, sta);
+}
+
+
+static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
+ struct wpabuf *wd)
+{
+ struct pasn_data *pasn = sta->pasn;
+ struct pasn_fils_data *fils = &pasn->fils;
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsne_data;
+ struct wpabuf *fils_wd;
+ const u8 *data;
+ size_t buf_len;
+ u16 alg, seq, status;
+ int ret;
+
+ if (fils->state != PASN_FILS_STATE_NONE) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Not expecting wrapped data");
+ return -1;
+ }
+
+ if (!wd) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: No wrapped data");
+ return -1;
+ }
+
+ data = wpabuf_head_u8(wd);
+ buf_len = wpabuf_len(wd);
+
+ if (buf_len < 6) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%lu",
+ buf_len);
+ return -1;
+ }
+
+ alg = WPA_GET_LE16(data);
+ seq = WPA_GET_LE16(data + 2);
+ status = WPA_GET_LE16(data + 4);
+
+ wpa_printf(MSG_DEBUG, "PASN: FILS: alg=%u, seq=%u, status=%u",
+ alg, seq, status);
+
+ if (alg != WLAN_AUTH_FILS_SK || seq != 1 ||
+ status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Dropping peer authentication");
+ return -1;
+ }
+
+ data += 6;
+ buf_len -= 6;
+
+ if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
+ return -1;
+ }
+
+ if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
+ !elems.wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
+ return -1;
+ }
+
+ ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
+ return -1;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsne_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
+ return -1;
+ }
+
+ if (rsne_data.num_pmkid) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Not expecting PMKID in RSNE");
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce,
+ FILS_NONCE_LEN);
+ os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN);
+
+ wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session,
+ FILS_SESSION_LEN);
+ os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN);
+
+#ifdef CONFIG_NO_RADIUS
+ wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail");
+ return -1;
+#endif /* CONFIG_NO_RADIUS */
+
+ fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!fils_wd) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data");
+ return -1;
+ }
+
+ if (!sta->eapol_sm)
+ sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Forward EAP-Initiate/Re-auth to AS");
+
+ ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd),
+ wpabuf_len(fils_wd));
+
+ sta->flags |= WLAN_STA_PENDING_PASN_FILS_ERP;
+
+ fils->state = PASN_FILS_STATE_PENDING_AS;
+
+ /*
+ * Calculate pending PMKID here so that we do not need to maintain a
+ * copy of the EAP-Initiate/Reautt message.
+ */
+ fils_pmkid_erp(pasn->akmp, wpabuf_head(fils_wd), wpabuf_len(fils_wd),
+ fils->erp_pmkid);
+
+ wpabuf_free(fils_wd);
+ return 0;
+}
+
+#endif /* CONFIG_FILS */
+
+
+static struct wpabuf * pasn_get_wrapped_data(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ switch (sta->pasn->akmp) {
+ case WPA_KEY_MGMT_PASN:
+ /* no wrapped data */
+ return NULL;
+ case WPA_KEY_MGMT_SAE:
+#ifdef CONFIG_SAE
+ return pasn_get_sae_wd(hapd, sta);
+#else /* CONFIG_SAE */
+ wpa_printf(MSG_ERROR,
+ "PASN: SAE: Cannot derive wrapped data");
+ return NULL;
+#endif /* CONFIG_SAE */
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+#ifdef CONFIG_FILS
+ return pasn_get_fils_wd(hapd, sta);
+#endif /* CONFIG_FILS */
+ /* fall through */
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ default:
+ wpa_printf(MSG_ERROR,
+ "PASN: TODO: Wrapped data for akmp=0x%x",
+ sta->pasn->akmp);
+ return NULL;
+ }
+}
+
+
+static int
+pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *cached_pmk, size_t cached_pmk_len,
+ struct wpa_pasn_params_data *pasn_data,
+ struct wpabuf *wrapped_data,
+ struct wpabuf *secret)
+{
+ static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
+ u8 pmk[PMK_LEN_MAX];
+ u8 pmk_len;
+ int ret;
+
+ os_memset(pmk, 0, sizeof(pmk));
+ pmk_len = 0;
+
+ if (!cached_pmk || !cached_pmk_len)
+ wpa_printf(MSG_DEBUG, "PASN: No valid PMKSA entry");
+
+ if (sta->pasn->akmp == WPA_KEY_MGMT_PASN) {
+ wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
+
+ pmk_len = WPA_PASN_PMK_LEN;
+ os_memcpy(pmk, pasn_default_pmk, sizeof(pasn_default_pmk));
+ } else if (cached_pmk && cached_pmk_len) {
+ wpa_printf(MSG_DEBUG, "PASN: Using PMKSA entry");
+
+ pmk_len = cached_pmk_len;
+ os_memcpy(pmk, cached_pmk, cached_pmk_len);
+ } else {
+ switch (sta->pasn->akmp) {
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ if (sta->pasn->sae.state == SAE_COMMITTED) {
+ pmk_len = PMK_LEN;
+ os_memcpy(pmk, sta->pasn->sae.pmk, PMK_LEN);
+ break;
+ }
+#endif /* CONFIG_SAE */
+ /* fall through */
+ default:
+ /* TODO: Derive PMK based on wrapped data */
+ wpa_printf(MSG_DEBUG,
+ "PASN: Missing PMK derivation");
+ return -1;
+ }
+ }
+
+ ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr,
+ wpabuf_head(secret), wpabuf_len(secret),
+ &sta->pasn->ptk, sta->pasn->akmp,
+ sta->pasn->cipher, WPA_KDK_MAX_LEN);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived");
+ return 0;
+}
+
+
+static int handle_auth_pasn_resp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct rsn_pmksa_cache_entry *pmksa,
+ u16 status)
+{
+ struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len, frame_len, data_len;
+ u8 *ptr;
+ const u8 *frame, *data, *rsn_ie, *rsnxe_ie;
+ u8 *data_buf = NULL;
+ size_t rsn_ie_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "PASN: Building frame 2: status=%u", status);
+
+ buf = wpabuf_alloc(1500);
+ if (!buf)
+ goto fail;
+
+ wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr,
+ sta->addr, 2, status);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ goto done;
+
+ if (wpa_pasn_add_rsne(buf, pmksa ? pmksa->pmkid : NULL,
+ sta->pasn->akmp, sta->pasn->cipher) < 0)
+ goto fail;
+
+ /* No need to derive PMK if PMKSA is given */
+ if (!pmksa)
+ wrapped_data_buf = pasn_get_wrapped_data(hapd, sta);
+ else
+ sta->pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO;
+
+ /* Get public key */
+ pubkey = crypto_ecdh_get_pubkey(sta->pasn->ecdh, 0);
+ pubkey = wpabuf_zeropad(pubkey,
+ crypto_ecdh_prime_len(sta->pasn->ecdh));
+ if (!pubkey) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
+ goto fail;
+ }
+
+ wpa_pasn_add_parameter_ie(buf, sta->pasn->group,
+ sta->pasn->wrapped_data_format,
+ pubkey, NULL, 0);
+
+ if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
+ goto fail;
+
+ wpabuf_free(wrapped_data_buf);
+ wrapped_data_buf = NULL;
+ wpabuf_free(pubkey);
+ pubkey = NULL;
+
+ /* Add RSNXE if needed */
+ rsnxe_ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX);
+ if (rsnxe_ie)
+ wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
+
+ /* Add the mic */
+ mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
+ wpabuf_put_u8(buf, WLAN_EID_MIC);
+ wpabuf_put_u8(buf, mic_len);
+ ptr = wpabuf_put(buf, mic_len);
+
+ os_memset(ptr, 0, mic_len);
+
+ frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
+ frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
+
+ rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &rsn_ie_len);
+ if (!rsn_ie || !rsn_ie_len)
+ goto fail;
+
+ /*
+ * Note: wpa_auth_get_wpa_ie() might return not only the RSNE but also
+ * MDE, etc. Thus, do not use the returned length but instead use the
+ * length specified in the IE header.
+ */
+ data_len = rsn_ie[1] + 2;
+ if (rsnxe_ie) {
+ data_buf = os_zalloc(rsn_ie[1] + 2 + rsnxe_ie[1] + 2);
+ if (!data_buf)
+ goto fail;
+
+ os_memcpy(data_buf, rsn_ie, rsn_ie[1] + 2);
+ os_memcpy(data_buf + rsn_ie[1] + 2, rsnxe_ie, rsnxe_ie[1] + 2);
+ data_len += rsnxe_ie[1] + 2;
+ data = data_buf;
+ } else {
+ data = rsn_ie;
+ }
+
+ ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
+ hapd->own_addr, sta->addr, data, data_len,
+ frame, frame_len, mic);
+ os_free(data_buf);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Frame 3: Failed MIC calculation");
+ goto fail;
+ }
+
+ os_memcpy(ptr, mic, mic_len);
+
+done:
+ wpa_printf(MSG_DEBUG,
+ "PASN: Building frame 2: success; resp STA=" MACSTR,
+ MAC2STR(sta->addr));
+
+ ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0,
+ NULL, 0, 0);
+ if (ret)
+ wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
+
+ wpabuf_free(buf);
+ return ret;
+fail:
+ wpabuf_free(wrapped_data_buf);
+ wpabuf_free(pubkey);
+ wpabuf_free(buf);
+ return -1;
+}
+
+
+static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee802_11_elems elems;
+ struct wpa_ie_data rsn_data;
+ struct wpa_pasn_params_data pasn_params;
+ struct rsn_pmksa_cache_entry *pmksa = NULL;
+ const u8 *cached_pmk = NULL;
+ size_t cached_pmk_len = 0;
+#ifdef CONFIG_IEEE80211R_AP
+ u8 pmk_r1[PMK_LEN_MAX];
+ size_t pmk_r1_len;
+#endif /* CONFIG_IEEE80211R_AP */
+ struct wpabuf *wrapped_data = NULL, *secret = NULL;
+ const int *groups = hapd->conf->pasn_groups;
+ static const int default_groups[] = { 19, 0 };
+ u16 status = WLAN_STATUS_SUCCESS;
+ int ret;
+ bool derive_keys;
+ u32 i;
+
+ if (!groups)
+ groups = default_groups;
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ ret = wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ &rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto send_resp;
+ }
+
+ ret = wpa_pasn_validate_rsne(&rsn_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto send_resp;
+ }
+
+ if (!(rsn_data.key_mgmt & hapd->conf->wpa_key_mgmt) ||
+ !(rsn_data.pairwise_cipher & hapd->conf->rsn_pairwise)) {
+ wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto send_resp;
+ }
+
+ sta->pasn->akmp = rsn_data.key_mgmt;
+ sta->pasn->cipher = rsn_data.pairwise_cipher;
+
+ if (!elems.pasn_params || !elems.pasn_params_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: No PASN Parameters element found");
+ status = WLAN_STATUS_INVALID_PARAMETERS;
+ goto send_resp;
+ }
+
+ ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+ elems.pasn_params_len + 3,
+ false, &pasn_params);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed validation of PASN Parameters IE");
+ status = WLAN_STATUS_INVALID_PARAMETERS;
+ goto send_resp;
+ }
+
+ for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++)
+ ;
+
+ if (!pasn_params.group || groups[i] != pasn_params.group) {
+ wpa_printf(MSG_DEBUG, "PASN: Requested group=%hu not allowed",
+ pasn_params.group);
+ status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ goto send_resp;
+ }
+
+ if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group);
+ if (!sta->pasn->ecdh) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ sta->pasn->group = pasn_params.group;
+
+ secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, 0,
+ pasn_params.pubkey,
+ pasn_params.pubkey_len);
+ if (!secret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ derive_keys = true;
+ if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+ wrapped_data = ieee802_11_defrag(&elems,
+ WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+ if (!wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+#ifdef CONFIG_SAE
+ if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+ ret = pasn_wd_handle_sae_commit(hapd, sta,
+ wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing SAE commit");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ ret = pasn_wd_handle_fils(hapd, sta, wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing FILS wrapped data");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Pending AS response");
+
+ /*
+ * With PASN/FILS, keys can be derived only after a
+ * response from the AS is processed.
+ */
+ derive_keys = false;
+ }
+#endif /* CONFIG_FILS */
+ }
+
+ sta->pasn->wrapped_data_format = pasn_params.wrapped_data_format;
+
+ ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
+ ((const u8 *) mgmt) + IEEE80211_HDRLEN,
+ len - IEEE80211_HDRLEN, sta->pasn->hash);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ if (!derive_keys) {
+ wpa_printf(MSG_DEBUG, "PASN: Storing secret");
+ sta->pasn->secret = secret;
+ wpabuf_free(wrapped_data);
+ return;
+ }
+
+ if (rsn_data.num_pmkid) {
+ if (wpa_key_mgmt_ft(sta->pasn->akmp)) {
+#ifdef CONFIG_IEEE80211R_AP
+ wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1");
+
+ ret = wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr,
+ rsn_data.pmkid,
+ pmk_r1, &pmk_r1_len, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Failed getting PMK-R1");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+ cached_pmk = pmk_r1;
+ cached_pmk_len = pmk_r1_len;
+#else /* CONFIG_IEEE80211R_AP */
+ wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+#endif /* CONFIG_IEEE80211R_AP */
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: Try to find PMKSA entry");
+
+ pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr,
+ rsn_data.pmkid);
+ if (pmksa) {
+ cached_pmk = pmksa->pmk;
+ cached_pmk_len = pmksa->pmk_len;
+ }
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: No PMKID specified");
+ }
+
+ ret = pasn_derive_keys(hapd, sta, cached_pmk, cached_pmk_len,
+ &pasn_params, wrapped_data, secret);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
+ ret = pasn_auth_frame_hash(sta->pasn->akmp, sta->pasn->cipher,
+ ((const u8 *) mgmt) + IEEE80211_HDRLEN,
+ len - IEEE80211_HDRLEN, sta->pasn->hash);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+send_resp:
+ ret = handle_auth_pasn_resp(hapd, sta, pmksa, status);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to send response");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Success handling transaction == 1");
+ }
+
+ wpabuf_free(secret);
+ wpabuf_free(wrapped_data);
+
+ if (status != WLAN_STATUS_SUCCESS)
+ ap_free_sta(hapd, sta);
+}
+
+
+static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct ieee802_11_elems elems;
+ struct wpa_pasn_params_data pasn_params;
+ struct wpabuf *wrapped_data = NULL;
+ u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
+ u8 mic_len;
+ int ret;
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ goto fail;
+ }
+
+ /* Check that the MIC IE exists. Save it and zero out the memory. */
+ mic_len = pasn_mic_len(sta->pasn->akmp, sta->pasn->cipher);
+ if (!elems.mic || elems.mic_len != mic_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid MIC. Expecting len=%u", mic_len);
+ goto fail;
+ } else {
+ os_memcpy(mic, elems.mic, mic_len);
+ /* TODO: Clean this up.. Should not modify received frame
+ * buffer. */
+ os_memset((u8 *) elems.mic, 0, mic_len);
+ }
+
+ if (!elems.pasn_params || !elems.pasn_params_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: No PASN Parameters element found");
+ goto fail;
+ }
+
+ ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
+ elems.pasn_params_len + 3,
+ false, &pasn_params);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed validation of PASN Parameters IE");
+ goto fail;
+ }
+
+ if (pasn_params.pubkey || pasn_params.pubkey_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Public key should not be included");
+ goto fail;
+ }
+
+ /* Verify the MIC */
+ ret = pasn_mic(sta->pasn->ptk.kck, sta->pasn->akmp, sta->pasn->cipher,
+ sta->addr, hapd->own_addr,
+ sta->pasn->hash, mic_len * 2,
+ (u8 *) &mgmt->u.auth,
+ len - offsetof(struct ieee80211_mgmt, u.auth),
+ out_mic);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
+ if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
+ goto fail;
+ }
+
+ if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
+ wrapped_data = ieee802_11_defrag(&elems,
+ WLAN_EID_EXTENSION,
+ WLAN_EID_EXT_WRAPPED_DATA);
+
+ if (!wrapped_data) {
+ wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
+ goto fail;
+ }
+
+#ifdef CONFIG_SAE
+ if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) {
+ ret = pasn_wd_handle_sae_confirm(hapd, sta,
+ wrapped_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed processing SAE confirm");
+ wpabuf_free(wrapped_data);
+ goto fail;
+ }
+ }
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ if (wrapped_data) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS: Ignore wrapped data");
+ }
+ }
+#endif /* CONFIG_FILS */
+ wpabuf_free(wrapped_data);
+ }
+
+ wpa_printf(MSG_INFO,
+ "PASN: Success handling transaction == 3. Store PTK");
+
+ ptksa_cache_add(hapd->ptksa, sta->addr, sta->pasn->cipher, 43200,
+ &sta->pasn->ptk);
+fail:
+ ap_free_sta(hapd, sta);
+}
+
+
+static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ u16 trans_seq, u16 status)
+{
+ if (hapd->conf->wpa != WPA_PROTO_RSN) {
+ wpa_printf(MSG_INFO, "PASN: RSN is not configured");
+ return;
+ }
+
+ wpa_printf(MSG_INFO, "PASN authentication: sta=" MACSTR,
+ MAC2STR(sta->addr));
+
+ if (trans_seq == 1) {
+ if (sta->pasn) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Not expecting transaction == 1");
+ return;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failure status in transaction == 1");
+ return;
+ }
+
+ sta->pasn = os_zalloc(sizeof(*sta->pasn));
+ if (!sta->pasn) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed to allocate PASN context");
+ return;
+ }
+
+ handle_auth_pasn_1(hapd, sta, mgmt, len);
+ } else if (trans_seq == 3) {
+ if (!sta->pasn) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Not expecting transaction == 3");
+ return;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failure status in transaction == 3");
+ ap_free_sta_pasn(hapd, sta);
+ return;
+ }
+
+ handle_auth_pasn_3(hapd, sta, mgmt, len);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid transaction %u - ignore", trans_seq);
+ }
+}
+
+#endif /* CONFIG_PASN */
+
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int rssi, int from_queue)
@@ -2382,6 +3500,11 @@ static void handle_auth(struct hostapd_data *hapd,
hapd->conf->fils_dh_group &&
auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
#endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+ (hapd->conf->wpa &&
+ (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) &&
+ auth_alg == WLAN_AUTH_PASN) ||
+#endif /* CONFIG_PASN */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
wpa_printf(MSG_INFO, "Unsupported authentication algorithm (%d)",
@@ -2391,6 +3514,9 @@ static void handle_auth(struct hostapd_data *hapd,
}
if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
+#ifdef CONFIG_PASN
+ (auth_alg == WLAN_AUTH_PASN && auth_transaction == 3) ||
+#endif /* CONFIG_PASN */
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
wpa_printf(MSG_INFO, "Unknown authentication transaction number (%d)",
auth_transaction);
@@ -2512,6 +3638,15 @@ static void handle_auth(struct hostapd_data *hapd,
return;
}
#endif /* CONFIG_MESH */
+#ifdef CONFIG_PASN
+ if (auth_alg == WLAN_AUTH_PASN &&
+ (sta->flags & WLAN_STA_ASSOC)) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: auth: Existing station: " MACSTR,
+ MAC2STR(sta->addr));
+ return;
+ }
+#endif /* CONFIG_PASN */
} else {
#ifdef CONFIG_MESH
if (hapd->conf->mesh & MESH_ENABLED) {
@@ -2572,11 +3707,14 @@ static void handle_auth(struct hostapd_data *hapd,
* to allow the original connection work until the attempt can complete
* (re)association, so that unprotected Authentication frame cannot be
* used to bypass PMF protection.
+ *
+ * PASN authentication does not require adding/removing station to the
+ * driver so skip this flow in case of PASN authentication.
*/
if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
(!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
!(hapd->conf->mesh & MESH_ENABLED) &&
- !(sta->added_unassoc)) {
+ !(sta->added_unassoc) && auth_alg != WLAN_AUTH_PASN) {
if (ap_sta_re_add(hapd, sta) < 0) {
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail;
@@ -2663,6 +3801,12 @@ static void handle_auth(struct hostapd_data *hapd,
handle_auth_fils_finish);
return;
#endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+ case WLAN_AUTH_PASN:
+ handle_auth_pasn(hapd, sta, mgmt, len, auth_transaction,
+ status_code);
+ return;
+#endif /* CONFIG_PASN */
}
fail:
@@ -3254,7 +4398,7 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
resp = copy_sta_he_capab(hapd, sta, IEEE80211_MODE_AP,
elems.he_capabilities,
elems.he_capabilities_len);
@@ -3870,7 +5014,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax) {
+ 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_spatial_reuse(hapd, p);
@@ -4884,6 +6028,31 @@ static int handle_action(struct hostapd_data *hapd,
/**
+ * notify_mgmt_frame - Notify of Management frames on the control interface
+ * @hapd: hostapd BSS data structure (the BSS to which the Management frame was
+ * sent to)
+ * @buf: Management frame data (starting from the IEEE 802.11 header)
+ * @len: Length of frame data in octets
+ *
+ * Notify the control interface of any received Management frame.
+ */
+static void notify_mgmt_frame(struct hostapd_data *hapd, const u8 *buf,
+ size_t len)
+{
+
+ int hex_len = len * 2 + 1;
+ char *hex = os_malloc(hex_len);
+
+ if (hex) {
+ wpa_snprintf_hex(hex, hex_len, buf, len);
+ wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO,
+ AP_MGMT_FRAME_RECEIVED "buf=%s", hex);
+ os_free(hex);
+ }
+}
+
+
+/**
* ieee802_11_mgmt - process incoming IEEE 802.11 management frames
* @hapd: hostapd BSS data structure (the BSS to which the management frame was
* sent to)
@@ -4973,6 +6142,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
if (hapd->iconf->track_sta_max_num)
sta_track_add(hapd->iface, mgmt->sa, ssi_signal);
+ if (hapd->conf->notify_mgmt_frames)
+ notify_mgmt_frame(hapd, buf, len);
+
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
@@ -5020,6 +6192,7 @@ static void handle_auth_cb(struct hostapd_data *hapd,
{
u16 auth_alg, auth_transaction, status_code;
struct sta_info *sta;
+ bool success_status;
sta = ap_get_sta(hapd, mgmt->da);
if (!sta) {
@@ -5029,6 +6202,15 @@ static void handle_auth_cb(struct hostapd_data *hapd,
return;
}
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+ wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
+ (unsigned long) len);
+ auth_alg = 0;
+ auth_transaction = 0;
+ status_code = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
status_code = le_to_host16(mgmt->u.auth.status_code);
@@ -5040,12 +6222,6 @@ static void handle_auth_cb(struct hostapd_data *hapd,
goto fail;
}
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
- wpa_printf(MSG_INFO, "handle_auth_cb - too short payload (len=%lu)",
- (unsigned long) len);
- goto fail;
- }
-
if (status_code == WLAN_STATUS_SUCCESS &&
((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
(auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
@@ -5058,7 +6234,12 @@ static void handle_auth_cb(struct hostapd_data *hapd,
}
fail:
- if (status_code != WLAN_STATUS_SUCCESS && sta->added_unassoc) {
+ success_status = status_code == WLAN_STATUS_SUCCESS;
+#ifdef CONFIG_SAE
+ if (auth_alg == WLAN_AUTH_SAE && auth_transaction == 1)
+ success_status = sae_status_success(hapd, status_code);
+#endif /* CONFIG_SAE */
+ if (!success_status && sta->added_unassoc) {
hostapd_drv_sta_remove(hapd, sta->addr);
sta->added_unassoc = 0;
}
@@ -5588,6 +6769,118 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
}
+u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_config *iconf = iface->conf;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ struct hostapd_channel_data *chan;
+ int dfs, i;
+ u8 channel, tx_pwr_count, local_pwr_constraint;
+ int max_tx_power;
+ u8 tx_pwr;
+
+ if (!mode)
+ return eid;
+
+ if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
+ return eid;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ if (mode->channels[i].freq == iface->freq)
+ break;
+ }
+ if (i == mode->num_channels)
+ return eid;
+
+ switch (hostapd_get_oper_chwidth(iconf)) {
+ case CHANWIDTH_USE_HT:
+ if (iconf->secondary_channel == 0) {
+ /* Max Transmit Power count = 0 (20 MHz) */
+ tx_pwr_count = 0;
+ } else {
+ /* Max Transmit Power count = 1 (20, 40 MHz) */
+ tx_pwr_count = 1;
+ }
+ break;
+ case CHANWIDTH_80MHZ:
+ /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
+ tx_pwr_count = 2;
+ break;
+ case CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_160MHZ:
+ /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
+ tx_pwr_count = 3;
+ break;
+ default:
+ return eid;
+ }
+
+ /*
+ * Below local_pwr_constraint logic is referred from
+ * hostapd_eid_pwr_constraint.
+ *
+ * Check if DFS is required by regulatory.
+ */
+ dfs = hostapd_is_dfs_required(hapd->iface);
+ if (dfs < 0)
+ dfs = 0;
+
+ /*
+ * In order to meet regulations when TPC is not implemented using
+ * a transmit power that is below the legal maximum (including any
+ * mitigation factor) should help. In this case, indicate 3 dB below
+ * maximum allowed transmit power.
+ */
+ if (hapd->iconf->local_pwr_constraint == -1)
+ local_pwr_constraint = (dfs == 0) ? 0 : 3;
+ else
+ local_pwr_constraint = hapd->iconf->local_pwr_constraint;
+
+ /*
+ * A STA that is not an AP shall use a transmit power less than or
+ * equal to the local maximum transmit power level for the channel.
+ * The local maximum transmit power can be calculated from the formula:
+ * local max TX pwr = max TX pwr - local pwr constraint
+ * Where max TX pwr is maximum transmit power level specified for
+ * channel in Country element and local pwr constraint is specified
+ * for channel in this Power Constraint element.
+ */
+ chan = &mode->channels[i];
+ max_tx_power = chan->max_tx_power - local_pwr_constraint;
+
+ /*
+ * Local Maximum Transmit power is encoded as two's complement
+ * with a 0.5 dB step.
+ */
+ max_tx_power *= 2; /* in 0.5 dB steps */
+ if (max_tx_power > 127) {
+ /* 63.5 has special meaning of 63.5 dBm or higher */
+ max_tx_power = 127;
+ }
+ if (max_tx_power < -128)
+ max_tx_power = -128;
+ if (max_tx_power < 0)
+ tx_pwr = 0x80 + max_tx_power + 128;
+ 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;
+}
+
+
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
{
u8 bw, chan1, chan2 = 0;
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 85b7140..c27bb1f 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -304,6 +304,11 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
+ os_memcpy(spr_param,
+ hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
+ spr_param += 8;
+ os_memcpy(spr_param,
+ hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
pos += 18;
}
@@ -313,6 +318,7 @@ u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
{
+ struct hostapd_config *conf = hapd->iface->conf;
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
struct he_capabilities *he_cap;
struct ieee80211_he_6ghz_band_cap *cap;
@@ -324,8 +330,18 @@ u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
return eid;
he_cap = &mode->he_capab[IEEE80211_MODE_AP];
- capab = he_cap->he_6ghz_capa;
+ capab = he_cap->he_6ghz_capa & HE_6GHZ_BAND_CAP_MIN_MPDU_START;
+ capab |= (conf->he_6ghz_max_ampdu_len_exp <<
+ HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT) &
+ HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK;
+ capab |= (conf->he_6ghz_max_mpdu <<
+ HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT) &
+ HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK;
capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
+ if (conf->he_6ghz_rx_ant_pat)
+ capab |= HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS;
+ if (conf->he_6ghz_tx_ant_pat)
+ capab |= HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS;
pos = eid;
*pos++ = WLAN_EID_EXTENSION;
@@ -419,6 +435,7 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
size_t he_capab_len)
{
if (!he_capab || !hapd->iconf->ieee80211ax ||
+ hapd->conf->disable_11ax ||
!check_valid_he_mcs(hapd, he_capab, opmode) ||
ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
@@ -448,6 +465,7 @@ u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *he_6ghz_capab)
{
if (!he_6ghz_capab || !hapd->iconf->ieee80211ax ||
+ hapd->conf->disable_11ax ||
!is_6ghz_op_class(hapd->iconf->op_class)) {
sta->flags &= ~WLAN_STA_6GHZ;
os_free(sta->he_6ghz_capab);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 17003d5..a429b5d 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -425,7 +425,9 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx)
* Identifiers Used Exclusively */
}
#endif /* CONFIG_SAE */
- if (hapd->conf->beacon_prot)
+ if (hapd->conf->beacon_prot &&
+ (hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_BEACON_PROTECTION))
*pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */
break;
case 11: /* Bits 88-95 */
@@ -494,7 +496,8 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
hostapd_sae_pw_id_in_use(hapd->conf))
len = 11;
#endif /* CONFIG_SAE */
- if (len < 11 && hapd->conf->beacon_prot)
+ if (len < 11 && hapd->conf->beacon_prot &&
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
len = 11;
#ifdef CONFIG_SAE_PK
if (len < 12 && hapd->conf->wpa &&
@@ -1097,29 +1100,45 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
{
u8 *pos = eid;
bool sae_pk = false;
+ u16 capab = 0;
+ size_t flen;
+
+ if (!(hapd->conf->wpa & WPA_PROTO_RSN))
+ return eid;
#ifdef CONFIG_SAE_PK
sae_pk = hostapd_sae_pk_in_use(hapd->conf);
#endif /* CONFIG_SAE_PK */
- if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
- !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) ||
- (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 &&
- !hostapd_sae_pw_id_in_use(hapd->conf) && !sae_pk) ||
- hapd->conf->sae_pwe == 3 ||
- len < 3)
- return pos;
-
- *pos++ = WLAN_EID_RSNX;
- *pos++ = 1;
- /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
- * used for now */
- *pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ (hapd->conf->sae_pwe == 1 || hapd->conf->sae_pwe == 2 ||
+ hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk) &&
+ hapd->conf->sae_pwe != 3) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
#ifdef CONFIG_SAE_PK
- if (sae_pk)
- *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+ if (sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
#endif /* CONFIG_SAE_PK */
- pos++;
+ }
+
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (len < 2 + flen || !capab)
+ return eid; /* no supported extended RSN capabilities */
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = flen;
+ *pos++ = capab & 0x00ff;
+ capab >>= 8;
+ if (capab)
+ *pos++ = capab;
return pos;
}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index c925bf1..d037022 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -167,118 +167,6 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
}
-u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
-{
- struct hostapd_iface *iface = hapd->iface;
- struct hostapd_config *iconf = iface->conf;
- struct hostapd_hw_modes *mode = iface->current_mode;
- struct hostapd_channel_data *chan;
- int dfs, i;
- u8 channel, tx_pwr_count, local_pwr_constraint;
- int max_tx_power;
- u8 tx_pwr;
-
- if (!mode)
- return eid;
-
- if (ieee80211_freq_to_chan(iface->freq, &channel) == NUM_HOSTAPD_MODES)
- return eid;
-
- for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].freq == iface->freq)
- break;
- }
- if (i == mode->num_channels)
- return eid;
-
- switch (iface->conf->vht_oper_chwidth) {
- case CHANWIDTH_USE_HT:
- if (iconf->secondary_channel == 0) {
- /* Max Transmit Power count = 0 (20 MHz) */
- tx_pwr_count = 0;
- } else {
- /* Max Transmit Power count = 1 (20, 40 MHz) */
- tx_pwr_count = 1;
- }
- break;
- case CHANWIDTH_80MHZ:
- /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */
- tx_pwr_count = 2;
- break;
- case CHANWIDTH_80P80MHZ:
- case CHANWIDTH_160MHZ:
- /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */
- tx_pwr_count = 3;
- break;
- default:
- return eid;
- }
-
- /*
- * Below local_pwr_constraint logic is referred from
- * hostapd_eid_pwr_constraint.
- *
- * Check if DFS is required by regulatory.
- */
- dfs = hostapd_is_dfs_required(hapd->iface);
- if (dfs < 0)
- dfs = 0;
-
- /*
- * In order to meet regulations when TPC is not implemented using
- * a transmit power that is below the legal maximum (including any
- * mitigation factor) should help. In this case, indicate 3 dB below
- * maximum allowed transmit power.
- */
- if (hapd->iconf->local_pwr_constraint == -1)
- local_pwr_constraint = (dfs == 0) ? 0 : 3;
- else
- local_pwr_constraint = hapd->iconf->local_pwr_constraint;
-
- /*
- * A STA that is not an AP shall use a transmit power less than or
- * equal to the local maximum transmit power level for the channel.
- * The local maximum transmit power can be calculated from the formula:
- * local max TX pwr = max TX pwr - local pwr constraint
- * Where max TX pwr is maximum transmit power level specified for
- * channel in Country element and local pwr constraint is specified
- * for channel in this Power Constraint element.
- */
- chan = &mode->channels[i];
- max_tx_power = chan->max_tx_power - local_pwr_constraint;
-
- /*
- * Local Maximum Transmit power is encoded as two's complement
- * with a 0.5 dB step.
- */
- max_tx_power *= 2; /* in 0.5 dB steps */
- if (max_tx_power > 127) {
- /* 63.5 has special meaning of 63.5 dBm or higher */
- max_tx_power = 127;
- }
- if (max_tx_power < -128)
- max_tx_power = -128;
- if (max_tx_power < 0)
- tx_pwr = 0x80 + max_tx_power + 128;
- else
- tx_pwr = max_tx_power;
-
- *eid++ = WLAN_EID_VHT_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;
-}
-
-
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab)
{
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index ee095f6..753c883 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -2067,7 +2067,8 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
#ifdef CONFIG_FILS
#ifdef NEED_AP_MLME
- if (sta->flags & WLAN_STA_PENDING_FILS_ERP) {
+ if (sta->flags &
+ (WLAN_STA_PENDING_FILS_ERP | WLAN_STA_PENDING_PASN_FILS_ERP)) {
/* TODO: Add a PMKSA entry on success? */
ieee802_11_finish_fils_auth(
hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT,
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 01bf886..2bbe318 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -220,7 +220,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
u16 capab = hostapd_own_capab_info(hapd);
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
- int he = hapd->iconf->ieee80211ax;
+ int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 67b5e98..ccd1ed9 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -156,6 +156,37 @@ void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
}
+#ifdef CONFIG_PASN
+
+void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ if (sta->pasn) {
+ wpa_printf(MSG_DEBUG, "PASN: Free PASN context: " MACSTR,
+ MAC2STR(sta->addr));
+
+ if (sta->pasn->ecdh)
+ crypto_ecdh_deinit(sta->pasn->ecdh);
+
+ wpabuf_free(sta->pasn->secret);
+ sta->pasn->secret = NULL;
+
+#ifdef CONFIG_SAE
+ sae_clear_data(&sta->pasn->sae);
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ /* In practice this pointer should be NULL */
+ wpabuf_free(sta->pasn->fils.erp_resp);
+ sta->pasn->fils.erp_resp = NULL;
+#endif /* CONFIG_FILS */
+
+ bin_clear_free(sta->pasn, sizeof(*sta->pasn));
+ sta->pasn = NULL;
+ }
+}
+
+#endif /* CONFIG_PASN */
+
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
@@ -371,6 +402,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ap_sta_reset_steer_flag_timer, hapd, sta);
#endif /* CONFIG_WNM_AP */
+#ifdef CONFIG_PASN
+ ap_free_sta_pasn(hapd, sta);
+#endif /* CONFIG_PASN */
+
os_free(sta->ifname_wds);
#ifdef CONFIG_TESTING_OPTIONS
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index ef48561..efa48e7 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -14,6 +14,8 @@
#include "vlan.h"
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
+#include "common/sae.h"
+#include "crypto/sha384.h"
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
@@ -39,6 +41,7 @@
#define WLAN_STA_MULTI_AP BIT(23)
#define WLAN_STA_HE BIT(24)
#define WLAN_STA_6GHZ BIT(25)
+#define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -63,6 +66,42 @@ struct pending_eapol_rx {
struct os_reltime rx_time;
};
+enum pasn_fils_state {
+ PASN_FILS_STATE_NONE = 0,
+ PASN_FILS_STATE_PENDING_AS,
+ PASN_FILS_STATE_COMPLETE
+};
+
+struct pasn_fils_data {
+ u8 state;
+ u8 nonce[FILS_NONCE_LEN];
+ u8 anonce[FILS_NONCE_LEN];
+ u8 session[FILS_SESSION_LEN];
+ u8 erp_pmkid[PMKID_LEN];
+
+ struct wpabuf *erp_resp;
+};
+
+struct pasn_data {
+ int akmp;
+ int cipher;
+ u16 group;
+ u8 trans_seq;
+ u8 wrapped_data_format;
+
+ u8 hash[SHA384_MAC_LEN];
+ struct wpa_ptk ptk;
+ struct crypto_ecdh *ecdh;
+
+ struct wpabuf *secret;
+#ifdef CONFIG_SAE
+ struct sae_data sae;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ struct pasn_fils_data fils;
+#endif /* CONFIG_FILS */
+};
+
struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
@@ -286,6 +325,10 @@ struct sta_info {
unsigned int airtime_weight;
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
+
+#ifdef CONFIG_PASN
+ struct pasn_data *pasn;
+#endif /* CONFIG_PASN */
};
@@ -363,4 +406,6 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta);
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta);
+
#endif /* STA_INFO_H */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index be81797..d32967e 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -169,7 +169,9 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
(int) igtk_elem_len);
- if (hapd->conf->beacon_prot) {
+ if (hapd->conf->beacon_prot &&
+ (hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_BEACON_PROTECTION)) {
res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
if (res < 0)
goto fail;
@@ -537,7 +539,8 @@ static void wnm_beacon_protection_failure(struct hostapd_data *hapd,
{
struct sta_info *sta;
- if (!hapd->conf->beacon_prot)
+ if (!hapd->conf->beacon_prot ||
+ !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
return;
sta = ap_get_sta(hapd, addr);
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 82a9746..7c53797 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -224,6 +224,23 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
}
+void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ if (wpa_auth->cb->store_ptksa)
+ wpa_auth->cb->store_ptksa(wpa_auth->cb_ctx, addr, cipher,
+ life_time, ptk);
+}
+
+
+void wpa_auth_remove_ptksa(struct wpa_authenticator *wpa_auth,
+ const u8 *addr, int cipher)
+{
+ if (wpa_auth->cb->clear_ptksa)
+ wpa_auth->cb->clear_ptksa(wpa_auth->cb_ctx, addr, cipher);
+}
+
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt)
{
@@ -1739,6 +1756,9 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
{
sm->PTK_valid = false;
os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+
+ wpa_auth_remove_ptksa(sm->wpa_auth, sm->addr, sm->pairwise);
+
if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
0, KEY_FLAG_PAIRWISE))
wpa_printf(MSG_DEBUG,
@@ -2258,9 +2278,17 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
struct wpa_ptk *ptk, int force_sha256)
{
const u8 *z = NULL;
- size_t z_len = 0;
+ size_t z_len = 0, kdk_len;
int akmp;
+ if (sm->wpa_auth->conf.force_kdk_derivation ||
+ (sm->wpa_auth->conf.secure_ltf &&
+ sm->rsnxe && sm->rsnxe_len >= 4 &&
+ sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
if (sm->ft_completed) {
@@ -2272,7 +2300,8 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
sm->pmk_r1_name,
ptk, ptk_name,
sm->wpa_key_mgmt,
- sm->pairwise);
+ sm->pairwise,
+ kdk_len);
}
return wpa_auth_derive_ptk_ft(sm, ptk);
}
@@ -2290,7 +2319,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
akmp |= WPA_KEY_MGMT_PSK_SHA256;
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- ptk, akmp, sm->pairwise, z, z_len);
+ ptk, akmp, sm->pairwise, z, z_len, kdk_len);
}
@@ -2305,13 +2334,21 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
size_t ick_len;
int res;
u8 fils_ft[FILS_FT_MAX_LEN];
- size_t fils_ft_len = 0;
+ size_t fils_ft_len = 0, kdk_len;
+
+ if (sm->wpa_auth->conf.force_kdk_derivation ||
+ (sm->wpa_auth->conf.secure_ltf &&
+ sm->rsnxe && sm->rsnxe_len >= 4 &&
+ sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
res = fils_pmk_to_ptk(pmk, pmk_len, sm->addr, sm->wpa_auth->addr,
snonce, anonce, dhss, dhss_len,
&sm->PTK, ick, &ick_len,
sm->wpa_key_mgmt, sm->pairwise,
- fils_ft, &fils_ft_len);
+ fils_ft, &fils_ft_len, kdk_len);
if (res < 0)
return res;
sm->PTK_valid = true;
@@ -2819,6 +2856,9 @@ int fils_set_tk(struct wpa_state_machine *sm)
}
sm->tk_already_set = true;
+ wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
+ dot11RSNAConfigPMKLifetime, &sm->PTK);
+
return 0;
}
@@ -3353,6 +3393,8 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
/* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ if (wpa_ie[0] == WLAN_EID_RSNX)
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
@@ -3607,6 +3649,8 @@ SM_STATE(WPA_PTK, PTKINITDONE)
sm->pairwise_set = true;
wpa_auth_set_ptk_rekey_timer(sm);
+ wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise,
+ dot11RSNAConfigPMKLifetime, &sm->PTK);
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
@@ -5355,6 +5399,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
/* WPA-only STA, remove RSN IE and possible MDIE */
wpa_ie = wpa_ie + wpa_ie[1] + 2;
+ if (wpa_ie[0] == WLAN_EID_RSNX)
+ wpa_ie = wpa_ie + wpa_ie[1] + 2;
if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 5f9df9c..eaa2caf 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -257,11 +257,22 @@ struct wpa_auth_config {
#endif /* CONFIG_FILS */
int sae_pwe;
bool sae_pk;
+
+ unsigned int secure_ltf:1;
+ unsigned int secure_rtt:1;
+ unsigned int prot_range_neg:1;
+
int owe_ptk_workaround;
u8 transition_disable;
#ifdef CONFIG_DPP2
int dpp_pfs;
#endif /* CONFIG_DPP2 */
+
+ /*
+ * If set Key Derivation Key should be derived as part of PMK to
+ * PTK derivation regardless of advertised capabilities.
+ */
+ bool force_kdk_derivation;
};
typedef enum {
@@ -306,6 +317,9 @@ struct wpa_auth_callbacks {
int (*get_sta_tx_params)(void *ctx, const u8 *addr,
int ap_max_chanwidth, int ap_seg1_idx,
int *bandwidth, int *seg1_idx);
+ 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);
#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);
@@ -459,6 +473,14 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
void wpa_ft_deinit(struct wpa_authenticator *wpa_auth);
void wpa_ft_sta_deinit(struct wpa_state_machine *sm);
+int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r1_name,
+ u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui, size_t *radius_cui_len,
+ int *session_timeout);
+
#endif /* CONFIG_IEEE80211R_AP */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
@@ -515,6 +537,8 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len);
+bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
+ u8 *fd_rsn_info);
void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg);
void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z);
void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth,
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 5aa363e..32b7456 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1473,13 +1473,13 @@ static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
}
-static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
- const u8 *spa, const u8 *pmk_r1_name,
- u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
- struct vlan_description *vlan,
- const u8 **identity, size_t *identity_len,
- const u8 **radius_cui, size_t *radius_cui_len,
- int *session_timeout)
+int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+ const u8 *spa, const u8 *pmk_r1_name,
+ u8 *pmk_r1, size_t *pmk_r1_len, int *pairwise,
+ struct vlan_description *vlan,
+ const u8 **identity, size_t *identity_len,
+ const u8 **radius_cui, size_t *radius_cui_len,
+ int *session_timeout)
{
struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
struct wpa_ft_pmk_r1_sa *r1;
@@ -2147,7 +2147,8 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk)
return wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
sm->addr, sm->wpa_auth->addr, sm->pmk_r1_name,
- ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
+ ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise,
+ 0);
}
@@ -3065,7 +3066,7 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
const u8 *identity, *radius_cui;
size_t identity_len = 0, radius_cui_len = 0;
int use_sha384;
- size_t pmk_r1_len;
+ size_t pmk_r1_len, kdk_len;
*resp_ies = NULL;
*resp_ies_len = 0;
@@ -3195,10 +3196,18 @@ pmk_r1_derived:
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
+ if (sm->wpa_auth->conf.force_kdk_derivation ||
+ (sm->wpa_auth->conf.secure_ltf &&
+ sm->rsnxe && sm->rsnxe_len >= 4 &&
+ sm->rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
if (wpa_pmk_r1_to_ptk(pmk_r1, pmk_r1_len, sm->SNonce, sm->ANonce,
sm->addr, sm->wpa_auth->addr, pmk_r1_name,
&sm->PTK, ptk_name, sm->wpa_key_mgmt,
- pairwise) < 0)
+ pairwise, kdk_len) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
sm->pairwise = pairwise;
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index c01654f..c3b2e81 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -14,6 +14,7 @@
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "common/wpa_ctrl.h"
+#include "common/ptksa_cache.h"
#include "crypto/sha1.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
@@ -208,6 +209,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#ifdef CONFIG_DPP2
wconf->dpp_pfs = conf->dpp_pfs;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ wconf->force_kdk_derivation = conf->force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
}
@@ -912,6 +918,27 @@ static int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci)
}
+#ifdef CONFIG_PASN
+
+static void hostapd_store_ptksa(void *ctx, const u8 *addr,int cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ struct hostapd_data *hapd = ctx;
+
+ ptksa_cache_add(hapd->ptksa, addr, cipher, life_time, ptk);
+}
+
+
+static void hostapd_clear_ptksa(void *ctx, const u8 *addr, int cipher)
+{
+ struct hostapd_data *hapd = ctx;
+
+ ptksa_cache_flush(hapd->ptksa, addr, cipher);
+}
+
+#endif /* CONFIG_PASN */
+
+
static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id)
{
#ifndef CONFIG_NO_VLAN
@@ -1437,6 +1464,11 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
.send_oui = hostapd_wpa_auth_send_oui,
.channel_info = hostapd_channel_info,
.update_vlan = hostapd_wpa_auth_update_vlan,
+#ifdef CONFIG_PASN
+ .store_ptksa = hostapd_store_ptksa,
+ .clear_ptksa = hostapd_clear_ptksa,
+#endif /* CONFIG_PASN */
+
#ifdef CONFIG_OCV
.get_sta_tx_params = hostapd_get_sta_tx_params,
#endif /* CONFIG_OCV */
@@ -1480,6 +1512,22 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
else
_conf.extended_key_id = 0;
+ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION))
+ _conf.beacon_prot = 0;
+
+#ifdef CONFIG_OCV
+ if (!(hapd->iface->drv_flags2 &
+ (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
+ _conf.ocv = 0;
+#endif /* CONFIG_OCV */
+
+ _conf.secure_ltf =
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF);
+ _conf.secure_rtt =
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT);
+ _conf.prot_range_neg =
+ !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG);
+
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
@@ -1505,6 +1553,12 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
return -1;
}
+ hapd->ptksa = ptksa_cache_init();
+ if (!hapd->ptksa) {
+ wpa_printf(MSG_ERROR, "Failed to allocate PTKSA cache");
+ return -1;
+ }
+
#ifdef CONFIG_IEEE80211R_AP
if (!hostapd_drv_none(hapd) &&
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
@@ -1544,6 +1598,9 @@ void hostapd_reconfig_wpa(struct hostapd_data *hapd)
void hostapd_deinit_wpa(struct hostapd_data *hapd)
{
ieee80211_tkip_countermeasures_deinit(hapd);
+ ptksa_cache_deinit(hapd->ptksa);
+ hapd->ptksa = NULL;
+
rsn_preauth_iface_deinit(hapd);
if (hapd->wpa_auth) {
wpa_deinit(hapd->wpa_auth);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 3704fc0..d471031 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -88,13 +88,42 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
}
+static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf)
+{
+ u16 capab = 0;
+
+ if (conf->rsn_preauth)
+ capab |= WPA_CAPABILITY_PREAUTH;
+ if (conf->wmm_enabled) {
+ /* 4 PTKSA replay counters when using WMM */
+ capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+ }
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ capab |= WPA_CAPABILITY_MFPC;
+ if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+ capab |= WPA_CAPABILITY_MFPR;
+ }
+#ifdef CONFIG_OCV
+ if (conf->ocv)
+ capab |= WPA_CAPABILITY_OCVC;
+#endif /* CONFIG_OCV */
+#ifdef CONFIG_RSN_TESTING
+ if (rsn_testing)
+ capab |= BIT(8) | BIT(15);
+#endif /* CONFIG_RSN_TESTING */
+ if (conf->extended_key_id)
+ capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
+
+ return capab;
+}
+
+
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid)
{
struct rsn_ie_hdr *hdr;
int num_suites, res;
u8 *pos, *count;
- u16 capab;
u32 suite;
hdr = (struct rsn_ie_hdr *) buf;
@@ -260,6 +289,13 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
num_suites++;
}
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_PASN
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+#endif /* CONFIG_PASN */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -277,29 +313,7 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
WPA_PUT_LE16(count, num_suites);
/* RSN Capabilities */
- capab = 0;
- if (conf->rsn_preauth)
- capab |= WPA_CAPABILITY_PREAUTH;
- if (conf->wmm_enabled) {
- /* 4 PTKSA replay counters when using WMM */
- capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
- }
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- capab |= WPA_CAPABILITY_MFPC;
- if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
- capab |= WPA_CAPABILITY_MFPR;
- }
-#ifdef CONFIG_OCV
- if (conf->ocv)
- capab |= WPA_CAPABILITY_OCVC;
-#endif /* CONFIG_OCV */
-#ifdef CONFIG_RSN_TESTING
- if (rsn_testing)
- capab |= BIT(8) | BIT(15);
-#endif /* CONFIG_RSN_TESTING */
- if (conf->extended_key_id)
- capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
- WPA_PUT_LE16(pos, capab);
+ WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
pos += 2;
if (pmkid) {
@@ -377,23 +391,38 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
u8 *pos = buf;
+ u16 capab = 0;
+ size_t flen;
- if (conf->sae_pwe != 1 && conf->sae_pwe != 2 && !conf->sae_pk)
- return 0; /* no supported extended RSN capabilities */
+ if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
+ (conf->sae_pwe == 1 || conf->sae_pwe == 2 || conf->sae_pk)) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (conf->sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ }
+
+ if (conf->secure_ltf)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (conf->secure_rtt)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (conf->prot_range_neg)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
- if (len < 3)
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (!capab)
+ return 0; /* no supported extended RSN capabilities */
+ if (len < 2 + flen)
return -1;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
*pos++ = WLAN_EID_RSNX;
- *pos++ = 1;
- /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
- * used for now */
- *pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
-#ifdef CONFIG_SAE_PK
- if (conf->sae_pk)
- *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
-#endif /* CONFIG_SAE_PK */
- pos++;
+ *pos++ = flen;
+ *pos++ = capab & 0x00ff;
+ capab >>= 8;
+ if (capab)
+ *pos++ = capab;
return pos - buf;
}
@@ -1096,6 +1125,7 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
#ifdef CONFIG_FILS
+
u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
u8 *pos, size_t max_len,
const u8 *req_ies, size_t req_ies_len)
@@ -1112,4 +1142,91 @@ u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
return pos;
return pos + res;
}
+
+
+bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
+ u8 *fd_rsn_info)
+{
+ struct wpa_auth_config *conf;
+ u32 selectors = 0;
+ u8 *pos = fd_rsn_info;
+ int i, res;
+ u32 cipher, suite, selector, mask;
+ u8 tmp[10 * RSN_SELECTOR_LEN];
+
+ if (!wpa_auth)
+ return false;
+ conf = &wpa_auth->conf;
+
+ if (!(conf->wpa & WPA_PROTO_RSN))
+ return false;
+
+ /* RSN Capability (B0..B15) */
+ WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
+ pos += 2;
+
+ /* Group Data Cipher Suite Selector (B16..B21) */
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+ if (suite == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
+ cipher = 63; /* No cipher suite selected */
+ if ((suite >> 8) == 0x000fac && ((suite & 0xff) <= 13))
+ cipher = suite & 0xff;
+ else
+ cipher = 62; /* vendor specific */
+ selectors |= cipher;
+
+ /* Group Management Cipher Suite Selector (B22..B27) */
+ cipher = 63; /* Default to no cipher suite selected */
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ switch (conf->group_mgmt_cipher) {
+ case WPA_CIPHER_AES_128_CMAC:
+ cipher = RSN_CIPHER_SUITE_AES_128_CMAC & 0xff;
+ break;
+ case WPA_CIPHER_BIP_GMAC_128:
+ cipher = RSN_CIPHER_SUITE_BIP_GMAC_128 & 0xff;
+ break;
+ case WPA_CIPHER_BIP_GMAC_256:
+ cipher = RSN_CIPHER_SUITE_BIP_GMAC_256 & 0xff;
+ break;
+ case WPA_CIPHER_BIP_CMAC_256:
+ cipher = RSN_CIPHER_SUITE_BIP_CMAC_256 & 0xff;
+ break;
+ }
+ }
+ selectors |= cipher << 6;
+
+ /* Pairwise Cipher Suite Selector (B28..B33) */
+ cipher = 63; /* Default to no cipher suite selected */
+ res = rsn_cipher_put_suites(tmp, conf->rsn_pairwise);
+ if (res == 1 && tmp[0] == 0x00 && tmp[1] == 0x0f && tmp[2] == 0xac &&
+ tmp[3] <= 13)
+ cipher = tmp[3];
+ selectors |= cipher << 12;
+
+ /* AKM Suite Selector (B34..B39) */
+ selector = 0; /* default to AKM from RSNE in Beacon/Probe Response */
+ mask = WPA_KEY_MGMT_FILS_SHA256 | WPA_KEY_MGMT_FILS_SHA384 |
+ WPA_KEY_MGMT_FT_FILS_SHA384;
+ if ((conf->wpa_key_mgmt & mask) && (conf->wpa_key_mgmt & ~mask) == 0) {
+ suite = conf->wpa_key_mgmt & mask;
+ if (suite == WPA_KEY_MGMT_FILS_SHA256)
+ selector = 1; /* 00-0f-ac:14 */
+ else if (suite == WPA_KEY_MGMT_FILS_SHA384)
+ selector = 2; /* 00-0f-ac:15 */
+ else if (suite == (WPA_KEY_MGMT_FILS_SHA256 |
+ WPA_KEY_MGMT_FILS_SHA384))
+ selector = 3; /* 00-0f-ac:14 or 00-0f-ac:15 */
+ else if (suite == WPA_KEY_MGMT_FT_FILS_SHA384)
+ selector = 4; /* 00-0f-ac:17 */
+ }
+ selectors |= selector << 18;
+
+ for (i = 0; i < 3; i++) {
+ *pos++ = selectors & 0xff;
+ selectors >>= 8;
+ }
+
+ return true;
+}
+
#endif /* CONFIG_FILS */
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index dc8aa8f..e97dbf9 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1376,6 +1376,48 @@ static void hostapd_wps_nfc_clear(struct wps_context *wps)
}
+static int hostapd_wps_update_multi_ap(struct hostapd_data *hapd,
+ struct wps_registrar *reg)
+{
+ struct hostapd_bss_config *conf = hapd->conf;
+ u8 *multi_ap_backhaul_network_key = NULL;
+ size_t multi_ap_backhaul_network_key_len = 0;
+ int ret;
+
+ if (!(conf->multi_ap & FRONTHAUL_BSS) ||
+ !conf->multi_ap_backhaul_ssid.ssid_len)
+ return 0;
+
+ if (conf->multi_ap_backhaul_ssid.wpa_passphrase) {
+ multi_ap_backhaul_network_key =
+ (u8 *) os_strdup(
+ conf->multi_ap_backhaul_ssid.wpa_passphrase);
+ if (!multi_ap_backhaul_network_key)
+ return -1;
+ multi_ap_backhaul_network_key_len =
+ os_strlen(conf->multi_ap_backhaul_ssid.wpa_passphrase);
+ } else if (conf->multi_ap_backhaul_ssid.wpa_psk) {
+ multi_ap_backhaul_network_key = os_malloc(2 * PMK_LEN + 1);
+ if (!multi_ap_backhaul_network_key)
+ return -1;
+ wpa_snprintf_hex((char *) multi_ap_backhaul_network_key,
+ 2 * PMK_LEN + 1,
+ conf->multi_ap_backhaul_ssid.wpa_psk->psk,
+ PMK_LEN);
+ multi_ap_backhaul_network_key_len = 2 * PMK_LEN;
+ }
+
+ ret = wps_registrar_update_multi_ap(
+ reg, conf->multi_ap_backhaul_ssid.ssid,
+ conf->multi_ap_backhaul_ssid.ssid_len,
+ multi_ap_backhaul_network_key,
+ multi_ap_backhaul_network_key_len);
+ os_free(multi_ap_backhaul_network_key);
+
+ return ret;
+}
+
+
void hostapd_deinit_wps(struct hostapd_data *hapd)
{
eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
@@ -1398,22 +1440,65 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
void hostapd_update_wps(struct hostapd_data *hapd)
{
- if (hapd->wps == NULL)
+ struct wps_context *wps = hapd->wps;
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ if (!wps)
return;
#ifdef CONFIG_WPS_UPNP
- hapd->wps->friendly_name = hapd->conf->friendly_name;
- hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
- hapd->wps->model_description = hapd->conf->model_description;
- hapd->wps->model_url = hapd->conf->model_url;
- hapd->wps->upc = hapd->conf->upc;
+ wps->friendly_name = conf->friendly_name;
+ wps->manufacturer_url = conf->manufacturer_url;
+ wps->model_description = conf->model_description;
+ wps->model_url = conf->model_url;
+ wps->upc = conf->upc;
#endif /* CONFIG_WPS_UPNP */
- hostapd_wps_set_vendor_ext(hapd, hapd->wps);
- hostapd_wps_set_application_ext(hapd, hapd->wps);
+ os_memcpy(wps->ssid, conf->ssid.ssid, conf->ssid.ssid_len);
+ wps->ssid_len = conf->ssid.ssid_len;
- if (hapd->conf->wps_state)
- wps_registrar_update_ie(hapd->wps->registrar);
+ /* Clear WPS settings, then fill them again */
+ os_free(wps->network_key);
+ wps->network_key = NULL;
+ wps->network_key_len = 0;
+ wps->psk_set = 0;
+ if (conf->ssid.wpa_psk_file) {
+ /* Use per-device PSKs */
+ } else if (conf->ssid.wpa_passphrase) {
+ wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
+ if (!wps->network_key)
+ return;
+ wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
+ } else if (conf->ssid.wpa_psk) {
+ wps->network_key = os_malloc(2 * PMK_LEN + 1);
+ if (!wps->network_key)
+ return;
+ wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
+ conf->ssid.wpa_psk->psk, PMK_LEN);
+ wps->network_key_len = 2 * PMK_LEN;
+#ifdef CONFIG_WEP
+ } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
+ wps->network_key = os_malloc(conf->ssid.wep.len[0]);
+ if (!wps->network_key)
+ return;
+ os_memcpy(wps->network_key, conf->ssid.wep.key[0],
+ conf->ssid.wep.len[0]);
+ wps->network_key_len = conf->ssid.wep.len[0];
+#endif /* CONFIG_WEP */
+ }
+
+ if (conf->ssid.wpa_psk) {
+ os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
+ wps->psk_set = 1;
+ }
+
+ hostapd_wps_update_multi_ap(hapd, wps->registrar);
+
+ hostapd_wps_set_vendor_ext(hapd, wps);
+ hostapd_wps_set_application_ext(hapd, wps);
+
+ if (conf->wps_state)
+ wps_registrar_update_ie(wps->registrar);
else
hostapd_deinit_wps(hapd);
}
diff --git a/src/common/Makefile b/src/common/Makefile
index 59ba6c5..e2c5f03 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -3,12 +3,14 @@ CFLAGS += -DCONFIG_HS20
CFLAGS += -DCONFIG_SAE
CFLAGS += -DCONFIG_SUITE
CFLAGS += -DCONFIG_SUITEB
+CFLAGS += -DCONFIG_PTKSA_CACHE
LIB_OBJS= \
gas.o \
hw_features_common.o \
ieee802_11_common.o \
sae.o \
+ ptksa_cache.o \
wpa_common.o
include ../lib.rules
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 00308d4..50ce192 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -637,6 +637,178 @@ static int sae_pk_tests(void)
}
+#ifdef CONFIG_PASN
+
+static int pasn_test_pasn_auth(void)
+{
+ /* Test vector taken from IEEE P802.11az/D2.6, J.12 */
+ const u8 pmk[] = {
+ 0xde, 0xf4, 0x3e, 0x55, 0x67, 0xe0, 0x1c, 0xa6,
+ 0x64, 0x92, 0x65, 0xf1, 0x9a, 0x29, 0x0e, 0xef,
+ 0xf8, 0xbd, 0x88, 0x8f, 0x6c, 0x1d, 0x9c, 0xc9,
+ 0xd1, 0x0f, 0x04, 0xbd, 0x37, 0x8f, 0x3c, 0xad
+ };
+
+ const u8 spa_addr[] = {
+ 0x00, 0x90, 0x4c, 0x01, 0xc1, 0x07
+ };
+ const u8 bssid[] = {
+ 0xc0, 0xff, 0xd4, 0xa8, 0xdb, 0xc1
+ };
+ const u8 dhss[] = {
+ 0xf8, 0x7b, 0x20, 0x8e, 0x7e, 0xd2, 0xb7, 0x37,
+ 0xaf, 0xdb, 0xc2, 0xe1, 0x3e, 0xae, 0x78, 0xda,
+ 0x30, 0x01, 0x23, 0xd4, 0xd8, 0x4b, 0xa8, 0xb0,
+ 0xea, 0xfe, 0x90, 0xc4, 0x8c, 0xdf, 0x1f, 0x93
+ };
+ const u8 kck[] = {
+ 0x7b, 0xb8, 0x21, 0xac, 0x0a, 0xa5, 0x90, 0x9d,
+ 0xd6, 0x54, 0xa5, 0x60, 0x65, 0xad, 0x7c, 0x77,
+ 0xeb, 0x88, 0x9c, 0xbe, 0x29, 0x05, 0xbb, 0xf0,
+ 0x5a, 0xbb, 0x1e, 0xea, 0xc8, 0x8b, 0xa3, 0x06
+ };
+ const u8 tk[] = {
+ 0x67, 0x3e, 0xab, 0x46, 0xb8, 0x32, 0xd5, 0xa8,
+ 0x0c, 0xbc, 0x02, 0x43, 0x01, 0x6e, 0x20, 0x7e
+ };
+ const u8 kdk[] = {
+ 0x2d, 0x0f, 0x0e, 0x82, 0xc7, 0x0d, 0xd2, 0x6b,
+ 0x79, 0x06, 0x1a, 0x46, 0x81, 0xe8, 0xdb, 0xb2,
+ 0xea, 0x83, 0xbe, 0xa3, 0x99, 0x84, 0x4b, 0xd5,
+ 0x89, 0x4e, 0xb3, 0x20, 0xf6, 0x9d, 0x7d, 0xd6
+ };
+ struct wpa_ptk ptk;
+ int ret;
+
+ ret = pasn_pmk_to_ptk(pmk, sizeof(pmk),
+ spa_addr, bssid,
+ dhss, sizeof(dhss),
+ &ptk, WPA_KEY_MGMT_PASN, WPA_CIPHER_CCMP,
+ WPA_KDK_MAX_LEN);
+
+ if (ret)
+ return ret;
+
+ if (ptk.kck_len != sizeof(kck) ||
+ os_memcmp(kck, ptk.kck, sizeof(kck)) != 0) {
+ wpa_printf(MSG_ERROR, "PASN: Mismatched KCK");
+ return -1;
+ }
+
+ if (ptk.tk_len != sizeof(tk) ||
+ os_memcmp(tk, ptk.tk, sizeof(tk)) != 0) {
+ wpa_printf(MSG_ERROR, "PASN: Mismatched TK");
+ return -1;
+ }
+
+ if (ptk.kdk_len != sizeof(kdk) ||
+ os_memcmp(kdk, ptk.kdk, sizeof(kdk)) != 0) {
+ wpa_printf(MSG_ERROR, "PASN: Mismatched KDK");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int pasn_test_no_pasn_auth(void)
+{
+ /* Test vector taken from IEEE P802.11az/D2.6, J.13 */
+ const u8 pmk[] = {
+ 0xde, 0xf4, 0x3e, 0x55, 0x67, 0xe0, 0x1c, 0xa6,
+ 0x64, 0x92, 0x65, 0xf1, 0x9a, 0x29, 0x0e, 0xef,
+ 0xf8, 0xbd, 0x88, 0x8f, 0x6c, 0x1d, 0x9c, 0xc9,
+ 0xd1, 0x0f, 0x04, 0xbd, 0x37, 0x8f, 0x3c, 0xad
+ };
+ const u8 aa[] = {
+ 0xc0, 0xff, 0xd4, 0xa8, 0xdb, 0xc1
+ };
+ const u8 spa[] = {
+ 0x00, 0x90, 0x4c, 0x01, 0xc1, 0x07
+ };
+ const u8 anonce[] = {
+ 0xbe, 0x7a, 0x1c, 0xa2, 0x84, 0x34, 0x7b, 0x5b,
+ 0xd6, 0x7d, 0xbd, 0x2d, 0xfd, 0xb4, 0xd9, 0x9f,
+ 0x1a, 0xfa, 0xe0, 0xb8, 0x8b, 0xa1, 0x8e, 0x00,
+ 0x87, 0x18, 0x41, 0x7e, 0x4b, 0x27, 0xef, 0x5f
+ };
+ const u8 snonce[] = {
+ 0x40, 0x4b, 0x01, 0x2f, 0xfb, 0x43, 0xed, 0x0f,
+ 0xb4, 0x3e, 0xa1, 0xf2, 0x87, 0xc9, 0x1f, 0x25,
+ 0x06, 0xd2, 0x1b, 0x4a, 0x92, 0xd7, 0x4b, 0x5e,
+ 0xa5, 0x0c, 0x94, 0x33, 0x50, 0xce, 0x86, 0x71
+ };
+ const u8 kck[] = {
+ 0xcd, 0x7b, 0x9e, 0x75, 0x55, 0x36, 0x2d, 0xf0,
+ 0xb6, 0x35, 0x68, 0x48, 0x4a, 0x81, 0x12, 0xf5
+ };
+ const u8 kek[] = {
+ 0x99, 0xca, 0xd3, 0x58, 0x8d, 0xa0, 0xf1, 0xe6,
+ 0x3f, 0xd1, 0x90, 0x19, 0x10, 0x39, 0xbb, 0x4b
+ };
+ const u8 tk[] = {
+ 0x9e, 0x2e, 0x93, 0x77, 0xe7, 0x53, 0x2e, 0x73,
+ 0x7a, 0x1b, 0xc2, 0x50, 0xfe, 0x19, 0x4a, 0x03
+ };
+ const u8 kdk[] = {
+ 0x6c, 0x7f, 0xb9, 0x7c, 0xeb, 0x55, 0xb0, 0x1a,
+ 0xcf, 0xf0, 0x0f, 0x07, 0x09, 0x42, 0xbd, 0xf5,
+ 0x29, 0x1f, 0xeb, 0x4b, 0xee, 0x38, 0xe0, 0x36,
+ 0x5b, 0x25, 0xa2, 0x50, 0xbb, 0x2a, 0xc9, 0xff
+ };
+ struct wpa_ptk ptk;
+ int ret;
+
+ ret = wpa_pmk_to_ptk(pmk, sizeof(pmk),
+ "Pairwise key expansion",
+ spa, aa, snonce, anonce,
+ &ptk, WPA_KEY_MGMT_SAE, WPA_CIPHER_CCMP,
+ NULL, 0, WPA_KDK_MAX_LEN);
+
+ if (ret)
+ return ret;
+
+ if (ptk.kck_len != sizeof(kck) ||
+ os_memcmp(kck, ptk.kck, sizeof(kck)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched KCK");
+ return -1;
+ }
+
+ if (ptk.kek_len != sizeof(kek) ||
+ os_memcmp(kek, ptk.kek, sizeof(kek)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched KEK");
+ return -1;
+ }
+
+ if (ptk.tk_len != sizeof(tk) ||
+ os_memcmp(tk, ptk.tk, sizeof(tk)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched TK");
+ return -1;
+ }
+
+ if (ptk.kdk_len != sizeof(kdk) ||
+ os_memcmp(kdk, ptk.kdk, sizeof(kdk)) != 0) {
+ wpa_printf(MSG_ERROR, "KDK no PASN auth: Mismatched KDK");
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_PASN */
+
+
+static int pasn_tests(void)
+{
+#ifdef CONFIG_PASN
+ if (pasn_test_pasn_auth() ||
+ pasn_test_no_pasn_auth())
+ return -1;
+#endif /* CONFIG_PASN */
+ return 0;
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -647,6 +819,7 @@ int common_module_tests(void)
gas_tests() < 0 ||
sae_tests() < 0 ||
sae_pk_tests() < 0 ||
+ pasn_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/src/common/defs.h b/src/common/defs.h
index bbe3120..f43bdb5 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -49,6 +49,8 @@
#define WPA_KEY_MGMT_OWE BIT(22)
#define WPA_KEY_MGMT_DPP BIT(23)
#define WPA_KEY_MGMT_FT_IEEE8021X_SHA384 BIT(24)
+#define WPA_KEY_MGMT_PASN BIT(25)
+
#define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \
WPA_KEY_MGMT_FT_IEEE8021X | \
@@ -388,9 +390,10 @@ enum mesh_plink_state {
};
enum set_band {
- WPA_SETBAND_AUTO,
- WPA_SETBAND_5G,
- WPA_SETBAND_2G
+ WPA_SETBAND_AUTO = 0,
+ WPA_SETBAND_5G = BIT(0),
+ WPA_SETBAND_2G = BIT(1),
+ WPA_SETBAND_6G = BIT(2),
};
enum wpa_radio_work_band {
@@ -402,7 +405,8 @@ enum wpa_radio_work_band {
enum beacon_rate_type {
BEACON_RATE_LEGACY,
BEACON_RATE_HT,
- BEACON_RATE_VHT
+ BEACON_RATE_VHT,
+ BEACON_RATE_HE
};
enum eap_proxy_sim_state {
diff --git a/src/common/dpp.h b/src/common/dpp.h
index 2fd331b..65ee905 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -348,6 +348,7 @@ struct dpp_authentication {
struct wpabuf *cacert;
struct wpabuf *certbag;
void *cert_resp_ctx;
+ void *gas_server_ctx;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
diff --git a/src/common/dpp_auth.c b/src/common/dpp_auth.c
index f79cfef..0cabd64 100644
--- a/src/common/dpp_auth.c
+++ b/src/common/dpp_auth.c
@@ -251,6 +251,7 @@ static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth,
u8 *attr_start, *attr_end, *pos;
auth->waiting_auth_conf = 1;
+ auth->auth_resp_status = status;
auth->auth_resp_tries = 0;
/* Build DPP Authentication Response frame attributes */
diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c
index 7e330d6..609c243 100644
--- a/src/common/dpp_tcp.c
+++ b/src/common/dpp_tcp.c
@@ -1279,7 +1279,7 @@ static int dpp_rx_gas_resp(struct dpp_connection *conn, const u8 *msg,
const u8 *pos, *end, *next, *adv_proto;
u16 status, slen, comeback_delay;
- if (len < 5 + 2 + (comeback ? 1 : 0))
+ if (len < (size_t) (5 + 2 + (comeback ? 1 : 0)))
return -1;
wpa_printf(MSG_DEBUG,
diff --git a/src/common/gas_server.c b/src/common/gas_server.c
index c000aeb..5f44ffe 100644
--- a/src/common/gas_server.c
+++ b/src/common/gas_server.c
@@ -489,6 +489,21 @@ int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
}
+bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx)
+{
+ struct gas_server_response *tmp;
+
+ dl_list_for_each(tmp, &gas->responses, struct gas_server_response,
+ list) {
+ if (tmp == resp_ctx)
+ return tmp->resp &&
+ tmp->offset == wpabuf_len(tmp->resp);
+ }
+
+ return false;
+}
+
+
struct gas_server * gas_server_init(void *ctx,
void (*tx)(void *ctx, int freq,
const u8 *da,
diff --git a/src/common/gas_server.h b/src/common/gas_server.h
index 2611dde..db00f87 100644
--- a/src/common/gas_server.h
+++ b/src/common/gas_server.h
@@ -36,6 +36,7 @@ void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data,
size_t data_len, int ack);
int gas_server_set_resp(struct gas_server *gas, void *resp_ctx,
struct wpabuf *resp);
+bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx);
#else /* CONFIG_GAS_SERVER */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 511e68f..b8b886f 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -41,10 +41,30 @@ struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan)
+{
+ int i;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *ch = &mode->channels[i];
+
+ if (ch->freq == freq) {
+ if (chan)
+ *chan = ch->chan;
+ return ch;
+ }
+ }
+
+ return NULL;
+}
+
+
+struct hostapd_channel_data *
hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
struct hostapd_hw_modes *hw_features, int num_hw_features)
{
- int i, j;
+ struct hostapd_channel_data *chan_data;
+ int i;
if (chan)
*chan = 0;
@@ -52,21 +72,15 @@ hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
if (!hw_features)
return NULL;
- for (j = 0; j < num_hw_features; j++) {
- struct hostapd_hw_modes *curr_mode = &hw_features[j];
+ for (i = 0; i < num_hw_features; i++) {
+ struct hostapd_hw_modes *curr_mode = &hw_features[i];
if (curr_mode->mode != mode)
continue;
- for (i = 0; i < curr_mode->num_channels; i++) {
- struct hostapd_channel_data *ch =
- &curr_mode->channels[i];
-
- if (ch->freq == freq) {
- if (chan)
- *chan = ch->chan;
- return ch;
- }
- }
+
+ chan_data = hw_mode_get_channel(curr_mode, freq, chan);
+ if (chan_data)
+ return chan_data;
}
return NULL;
@@ -580,6 +594,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 = 138;
else if (channel <= 161)
center_segment0 = 155;
+ else if (channel <= 177)
+ center_segment0 = 171;
data->center_freq1 = 5000 + center_segment0 * 5;
} else {
/*
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index e57a8d6..ddde36b 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -15,6 +15,9 @@
struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
int chan, int *freq);
struct hostapd_channel_data *
+hw_mode_get_channel(struct hostapd_hw_modes *mode, int freq, int *chan);
+
+struct hostapd_channel_data *
hw_get_channel_freq(enum hostapd_hw_mode mode, int freq, int *chan,
struct hostapd_hw_modes *hw_features, int num_hw_features);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 8bdeeb5..ec17456 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -303,6 +303,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen,
break;
elems->he_6ghz_band_cap = pos;
break;
+ case WLAN_EID_EXT_PASN_PARAMS:
+ elems->pasn_params = pos;
+ elems->pasn_params_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -566,6 +570,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->dils = pos;
elems->dils_len = elen;
break;
+ case WLAN_EID_S1G_CAPABILITIES:
+ if (elen < 15)
+ break;
+ elems->s1g_capab = pos;
+ break;
case WLAN_EID_FRAGMENT:
ieee802_11_parse_fragment(&elems->frag_ies, pos, elen);
break;
@@ -870,7 +879,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
/**
* ieee80211_freq_to_channel_ext - Convert frequency into channel info
- * for HT40 and VHT. DFS channels are not covered.
+ * for HT40, VHT, and HE. DFS channels are not covered.
* @freq: Frequency (MHz) to convert
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
* @chanwidth: VHT/EDMG channel width (CHANWIDTH_*)
@@ -981,8 +990,8 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
- /* 5 GHz, channels 149..169 */
- if (freq >= 5745 && freq <= 5845) {
+ /* 5 GHz, channels 149..177 */
+ if (freq >= 5745 && freq <= 5885) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
@@ -1412,22 +1421,22 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
return -1;
return 5000 + 5 * chan;
case 124: /* channels 149,153,157,161 */
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
if (chan < 149 || chan > 161)
return -1;
return 5000 + 5 * chan;
- case 125: /* channels 149,153,157,161,165,169 */
- if (chan < 149 || chan > 169)
+ case 125: /* channels 149,153,157,161,165,169,173,177 */
+ case 126: /* channels 149,157,165,173; 40 MHz */
+ case 127: /* channels 153,161,169,177; 40 MHz */
+ if (chan < 149 || chan > 177)
return -1;
return 5000 + 5 * chan;
- case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
- case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
- if (chan < 36 || chan > 161)
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
+ if (chan < 36 || chan > 177)
return -1;
return 5000 + 5 * chan;
- case 129: /* center freqs 50, 114; 160 MHz */
- if (chan < 36 || chan > 128)
+ case 129: /* center freqs 50, 114, 163; 160 MHz */
+ if (chan < 36 || chan > 177)
return -1;
return 5000 + 5 * chan;
case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
@@ -1871,20 +1880,20 @@ const struct oper_class_map global_op_class[] = {
{ HOSTAPD_MODE_IEEE80211A, 122, 100, 132, 8, BW40PLUS, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 123, 104, 136, 8, BW40MINUS, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 125, 149, 169, 4, BW20, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP },
/*
- * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
- * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
- * 80 MHz, but currently use the following definition for simplicity
+ * IEEE P802.11ax/D8.0 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
- * wpas_p2p_allow_channel() fail). wpas_p2p_verify_80mhz() should take
+ * wpas_p2p_verify_channel() fail). wpas_p2p_verify_80mhz() should take
* care of removing invalid channels.
*/
- { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP },
@@ -1906,7 +1915,7 @@ const struct oper_class_map global_op_class[] = {
* the OneHundredAndThirty Delimiter value used in the Supported
* Operating Classes element to indicate the end of the Operating
* Classes field. */
- { HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP },
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
};
@@ -2240,44 +2249,44 @@ int center_idx_to_bw_6ghz(u8 idx)
}
-int is_6ghz_freq(int freq)
+bool is_6ghz_freq(int freq)
{
if (freq < 5935 || freq > 7115)
- return 0;
+ return false;
if (freq == 5935)
- return 1;
+ return true;
if (center_idx_to_bw_6ghz((freq - 5950) / 5) < 0)
- return 0;
+ return false;
- return 1;
+ return true;
}
-int is_6ghz_op_class(u8 op_class)
+bool is_6ghz_op_class(u8 op_class)
{
return op_class >= 131 && op_class <= 136;
}
-int is_6ghz_psc_frequency(int freq)
+bool is_6ghz_psc_frequency(int freq)
{
int i;
if (!is_6ghz_freq(freq) || freq == 5935)
- return 0;
+ return false;
if ((((freq - 5950) / 5) & 0x3) != 0x1)
- return 0;
+ return false;
i = (freq - 5950 + 55) % 80;
if (i == 0)
i = (freq - 5950 + 55) / 80;
if (i >= 1 && i <= 15)
- return 1;
+ return true;
- return 0;
+ return false;
}
@@ -2488,16 +2497,16 @@ int op_class_to_bandwidth(u8 op_class)
case 123: /* channels 104-136; 40 MHz */
return 40;
case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
+ case 125: /* channels 149,153,157,161,165,169,173,177 */
return 20;
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
+ case 126: /* channels 149,157,161,165,169,173; 40 MHz */
+ case 127: /* channels 153..177; 40 MHz */
return 40;
- case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
return 80;
- case 129: /* center freqs 50, 114; 160 MHz */
+ case 129: /* center freqs 50, 114, 163; 160 MHz */
return 160;
- case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80+80 MHz */
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
return 80;
case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
return 20;
@@ -2549,16 +2558,16 @@ int op_class_to_ch_width(u8 op_class)
case 123: /* channels 104-136; 40 MHz */
return CHANWIDTH_USE_HT;
case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
+ case 125: /* channels 149,153,157,161,165,169,171 */
return CHANWIDTH_USE_HT;
- case 126: /* channels 149,157; 40 MHz */
- case 127: /* channels 153,161; 40 MHz */
+ case 126: /* channels 149,157,165, 173; 40 MHz */
+ case 127: /* channels 153,161,169,177; 40 MHz */
return CHANWIDTH_USE_HT;
- case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */
return CHANWIDTH_80MHZ;
- case 129: /* center freqs 50, 114; 160 MHz */
+ case 129: /* center freqs 50, 114, 163; 160 MHz */
return CHANWIDTH_160MHZ;
- case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80+80 MHz */
+ case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */
return CHANWIDTH_80P80MHZ;
case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
return CHANWIDTH_USE_HT;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 0ae0fa4..8a16f16 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -115,6 +115,8 @@ struct ieee802_11_elems {
const u8 *short_ssid_list;
const u8 *he_6ghz_band_cap;
const u8 *sae_pk;
+ const u8 *s1g_capab;
+ const u8 *pasn_params;
u8 ssid_len;
u8 supp_rates_len;
@@ -168,6 +170,7 @@ struct ieee802_11_elems {
u8 he_operation_len;
u8 short_ssid_list_len;
u8 sae_pk_len;
+ u8 pasn_params_len;
struct mb_ies_info mb_ies;
struct frag_ies_info frag_ies;
@@ -258,9 +261,9 @@ u8 country_to_global_op_class(const char *country, u8 op_class);
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
int oper_class_bw_to_int(const struct oper_class_map *map);
int center_idx_to_bw_6ghz(u8 idx);
-int is_6ghz_freq(int freq);
-int is_6ghz_op_class(u8 op_class);
-int is_6ghz_psc_frequency(int freq);
+bool is_6ghz_freq(int freq);
+bool is_6ghz_op_class(u8 op_class);
+bool is_6ghz_psc_frequency(int freq);
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 86d71c1..9518545 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -50,6 +50,7 @@
#define WLAN_FC_STYPE_AUTH 11
#define WLAN_FC_STYPE_DEAUTH 12
#define WLAN_FC_STYPE_ACTION 13
+#define WLAN_FC_STYPE_ACTION_NO_ACK 14
/* control */
#define WLAN_FC_STYPE_PSPOLL 10
@@ -84,6 +85,7 @@
#define WLAN_AUTH_FILS_SK 4
#define WLAN_AUTH_FILS_SK_PFS 5
#define WLAN_AUTH_FILS_PK 6
+#define WLAN_AUTH_PASN 7
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
@@ -432,7 +434,7 @@
#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
#define WLAN_EID_VHT_WIDE_BW_CHSWITCH 194
-#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195
+#define WLAN_EID_TRANSMIT_POWER_ENVELOPE 195
#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
#define WLAN_EID_VHT_AID 197
#define WLAN_EID_VHT_QUIET_CHANNEL 198
@@ -443,7 +445,10 @@
#define WLAN_EID_DEVICE_LOCATION 204
#define WLAN_EID_WHITE_SPACE_MAP 205
#define WLAN_EID_FTM_PARAMETERS 206
+#define WLAN_EID_S1G_BCN_COMPAT 213
+#define WLAN_EID_S1G_CAPABILITIES 217
#define WLAN_EID_VENDOR_SPECIFIC 221
+#define WLAN_EID_S1G_OPERATION 232
#define WLAN_EID_CAG_NUMBER 237
#define WLAN_EID_AP_CSN 239
#define WLAN_EID_FILS_INDICATION 240
@@ -482,6 +487,7 @@
#define WLAN_EID_EXT_TCLAS_MASK 89
#define WLAN_EID_EXT_REJECTED_GROUPS 92
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
+#define WLAN_EID_EXT_PASN_PARAMS 100
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -525,7 +531,6 @@
#define WLAN_EXT_CAPAB_TDLS_PROHIBITED 38
#define WLAN_EXT_CAPAB_TDLS_CHANNEL_SWITCH_PROHIBITED 39
#define WLAN_EXT_CAPAB_REJECT_UNADMITTED_FRAME 40
-#define WLAN_EXT_CAPAB_
/* 41-43 - Service Interval Granularity */
#define WLAN_EXT_CAPAB_IDENTIFIER_LOCATION 44
#define WLAN_EXT_CAPAB_U_APSD_COEX 45
@@ -546,7 +551,6 @@
#define WLAN_EXT_CAPAB_PROT_QLOAD_REPORT 60
#define WLAN_EXT_CAPAB_TDLS_WIDER_BW 61
#define WLAN_EXT_CAPAB_OPMODE_NOTIF 62
-#define WLAN_EXT_CAPAB_
/* 63-64 - Max Number of MSDUs In A-MSDU */
#define WLAN_EXT_CAPAB_CHANNEL_SCHEDULE_MGMT 65
#define WLAN_EXT_CAPAB_GEODB_INBAND_ENABLING_SIGNAL 66
@@ -572,6 +576,9 @@
#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
#define WLAN_RSNX_CAPAB_SAE_H2E 5
#define WLAN_RSNX_CAPAB_SAE_PK 6
+#define WLAN_RSNX_CAPAB_SECURE_LTF 8
+#define WLAN_RSNX_CAPAB_SECURE_RTT 9
+#define WLAN_RSNX_CAPAB_PROT_RANGE_NEG 10
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
@@ -597,6 +604,7 @@
#define WLAN_ACTION_UNPROTECTED_DMG 20
#define WLAN_ACTION_VHT 21
#define WLAN_ACTION_FILS 26
+#define WLAN_ACTION_PROTECTED_FTM 34
#define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126
#define WLAN_ACTION_VENDOR_SPECIFIC 127
/* Note: 128-255 used to report errors by setting category | 0x80 */
@@ -637,6 +645,7 @@
#define WLAN_PA_FTM_REQUEST 32
#define WLAN_PA_FTM 33
#define WLAN_PA_FILS_DISCOVERY 34
+#define WLAN_PA_LOCATION_MEASUREMENT_REPORT 47
/* Protected Dual of Public Action frames (IEEE Std 802.11-2016, 9.6.11,
* Table 9-332) */
@@ -694,6 +703,11 @@
#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
+/* Protected Fine Timing Frame Action Field value */
+#define WLAN_PROT_FTM_REQUEST 1
+#define WLAN_PROT_FTM 2
+#define WLAN_PROT_FTM_REPORT 3
+
/* Radio Measurement capabilities (from RM Enabled Capabilities element)
* IEEE Std 802.11-2016, 9.4.2.45, Table 9-157 */
/* byte 1 (out of 5) */
@@ -2150,6 +2164,7 @@ struct ieee80211_he_capabilities {
* and optional variable length PPE Thresholds field. */
u8 optional[37];
} STRUCT_PACKED;
+#define IEEE80211_HE_CAPAB_MIN_LEN (6 + 11)
struct ieee80211_he_operation {
le32 he_oper_params; /* HE Operation Parameters[3] and
@@ -2364,4 +2379,51 @@ enum mscs_description_subelem {
MCSC_SUBELEM_STATUS = 1,
};
+/*
+ * IEEE Std 802.11ai-2016, 9.6.8.36 FILS Discovery frame format,
+ * Figure 9-687b - FILS Discovery Frame Control subfield format
+ */
+#define FD_FRAME_CTL_CAP_PRESENT ((u16) BIT(5))
+#define FD_FRAME_CTL_SHORT_SSID_PRESENT ((u16) BIT(6))
+#define FD_FRAME_CTL_AP_CSN_PRESENT ((u16) BIT(7))
+#define FD_FRAME_CTL_ANO_PRESENT ((u16) BIT(8))
+#define FD_FRAME_CTL_FREQ_SEG1_PRESENT ((u16) BIT(9))
+#define FD_FRAME_CTL_PRI_CHAN_PRESENT ((u16) BIT(10))
+#define FD_FRAME_CTL_RSN_INFO_PRESENT ((u16) BIT(11))
+#define FD_FRAME_CTL_LENGTH_PRESENT ((u16) BIT(12))
+#define FD_FRAME_CTL_MD_PRESENT ((u16) BIT(13))
+
+/*
+ * IEEE Std 802.11ai-2016, 9.6.8.36 FILS Discovery frame format,
+ * Figure 9-687c - FD Capability subfield format
+ */
+#define FD_CAP_ESS BIT(0)
+#define FD_CAP_PRIVACY BIT(1)
+#define FD_CAP_MULTI_BSSID_PRESENT BIT(9)
+
+#define FD_CAP_BSS_CHWIDTH_20 0
+#define FD_CAP_BSS_CHWIDTH_40 1
+#define FD_CAP_BSS_CHWIDTH_80 2
+#define FD_CAP_BSS_CHWIDTH_160_80_80 3
+#define FD_CAP_BSS_CHWIDTH_SHIFT 2
+
+#define FD_CAP_NSS_1 0
+#define FD_CAP_NSS_2 1
+#define FD_CAP_NSS_3 2
+#define FD_CAP_NSS_4 3
+#define FD_CAP_NSS_5_8 4
+#define FD_CAP_NSS_SHIFT 5
+
+#define FD_CAP_PHY_INDEX_HR_DSSS 0
+#define FD_CAP_PHY_INDEX_ERP_OFDM 1
+#define FD_CAP_PHY_INDEX_HT 2
+#define FD_CAP_PHY_INDEX_VHT 3
+#define FD_CAP_PHY_INDEX_HE 4 /* P802.11ax */
+#define FD_CAP_PHY_INDEX_SHIFT 10
+
+/*
+ * IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning
+ */
+#define FD_MAX_INTERVAL_6GHZ 20 /* TUs */
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/ptksa_cache.c b/src/common/ptksa_cache.c
new file mode 100644
index 0000000..6a053d6
--- /dev/null
+++ b/src/common/ptksa_cache.c
@@ -0,0 +1,321 @@
+/*
+ * RSN PTKSA cache implementation
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include "utils/common.h"
+#include "eloop.h"
+#include "common/ptksa_cache.h"
+
+#define PTKSA_CACHE_MAX_ENTRIES 16
+
+struct ptksa_cache {
+ struct dl_list ptksa;
+ unsigned int n_ptksa;
+};
+
+static void ptksa_cache_set_expiration(struct ptksa_cache *ptksa);
+
+
+static void ptksa_cache_free_entry(struct ptksa_cache *ptksa,
+ struct ptksa_cache_entry *entry)
+{
+ ptksa->n_ptksa--;
+
+ dl_list_del(&entry->list);
+ bin_clear_free(entry, sizeof(*entry));
+}
+
+
+static void ptksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+{
+ struct ptksa_cache *ptksa = eloop_ctx;
+ struct ptksa_cache_entry *e, *next;
+ struct os_reltime now;
+
+ if (!ptksa)
+ return;
+
+ os_get_reltime(&now);
+
+ dl_list_for_each_safe(e, next, &ptksa->ptksa,
+ struct ptksa_cache_entry, list) {
+ if (e->expiration > now.sec)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "Expired PTKSA cache entry for " MACSTR,
+ MAC2STR(e->addr));
+
+ ptksa_cache_free_entry(ptksa, e);
+ }
+
+ ptksa_cache_set_expiration(ptksa);
+}
+
+
+static void ptksa_cache_set_expiration(struct ptksa_cache *ptksa)
+{
+ struct ptksa_cache_entry *e;
+ int sec;
+ struct os_reltime now;
+
+ eloop_cancel_timeout(ptksa_cache_expire, ptksa, NULL);
+
+ if (!ptksa || !ptksa->n_ptksa)
+ return;
+
+ e = dl_list_first(&ptksa->ptksa, struct ptksa_cache_entry, list);
+ if (!e)
+ return;
+
+ os_get_reltime(&now);
+ sec = e->expiration - now.sec;
+ if (sec < 0)
+ sec = 0;
+
+ eloop_register_timeout(sec + 1, 0, ptksa_cache_expire, ptksa, NULL);
+}
+
+
+/*
+ * ptksa_cache_init - Initialize PTKSA cache
+ *
+ * Returns: Pointer to PTKSA cache data or %NULL on failure
+ */
+struct ptksa_cache * ptksa_cache_init(void)
+{
+ struct ptksa_cache *ptksa = os_zalloc(sizeof(struct ptksa_cache));
+
+ wpa_printf(MSG_DEBUG, "PTKSA: Initializing");
+
+ if (ptksa)
+ dl_list_init(&ptksa->ptksa);
+
+ return ptksa;
+}
+
+
+/*
+ * ptksa_cache_deinit - Free all entries in PTKSA cache
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ */
+void ptksa_cache_deinit(struct ptksa_cache *ptksa)
+{
+ struct ptksa_cache_entry *e, *next;
+
+ if (!ptksa)
+ return;
+
+ wpa_printf(MSG_DEBUG, "PTKSA: Deinit. n_ptksa=%u", ptksa->n_ptksa);
+
+ dl_list_for_each_safe(e, next, &ptksa->ptksa,
+ struct ptksa_cache_entry, list)
+ ptksa_cache_free_entry(ptksa, e);
+
+ eloop_cancel_timeout(ptksa_cache_expire, ptksa, NULL);
+ os_free(ptksa);
+}
+
+
+/*
+ * ptksa_cache_get - Fetch a PTKSA cache entry
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @addr: Peer address or %NULL to match any
+ * @cipher: Specific cipher suite to search for or WPA_CIPHER_NONE for any
+ * Returns: Pointer to PTKSA cache entry or %NULL if no match was found
+ */
+struct ptksa_cache_entry * ptksa_cache_get(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher)
+{
+ struct ptksa_cache_entry *e;
+
+ if (!ptksa)
+ return NULL;
+
+ dl_list_for_each(e, &ptksa->ptksa, struct ptksa_cache_entry, list) {
+ if ((!addr || os_memcmp(e->addr, addr, ETH_ALEN) == 0) &&
+ (cipher == WPA_CIPHER_NONE || cipher == e->cipher))
+ return e;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * ptksa_cache_list - Dump text list of entries in PTKSA cache
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PTKSA cache contents for the ctrl_iface PTKSA command.
+ */
+int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len)
+{
+ struct ptksa_cache_entry *e;
+ int i = 0, ret;
+ char *pos = buf;
+ struct os_reltime now;
+
+ if (!ptksa)
+ return 0;
+
+ os_get_reltime(&now);
+
+ ret = os_snprintf(pos, buf + len - pos,
+ "Index / ADDR / Cipher / expiration (secs) / TK / KDK\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ dl_list_for_each(e, &ptksa->ptksa, struct ptksa_cache_entry, list) {
+ ret = os_snprintf(pos, buf + len - pos, "%u " MACSTR,
+ i, MAC2STR(e->addr));
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, buf + len - pos, " %s %lu ",
+ wpa_cipher_txt(e->cipher),
+ e->expiration - now.sec);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = wpa_snprintf_hex(pos, buf + len - pos, e->ptk.tk,
+ e->ptk.tk_len);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, buf + len - pos, " ");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = wpa_snprintf_hex(pos, buf + len - pos, e->ptk.kdk,
+ e->ptk.kdk_len);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ ret = os_snprintf(pos, buf + len - pos, "\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ i++;
+ }
+
+ return pos - buf;
+}
+
+
+/*
+ * ptksa_cache_flush - Flush PTKSA cache entries
+ *
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @addr: Peer address or %NULL to match any
+ * @cipher: Specific cipher suite to search for or WPA_CIPHER_NONE for any
+ */
+void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher)
+{
+ struct ptksa_cache_entry *e, *next;
+ bool removed = false;
+
+ if (!ptksa)
+ return;
+
+ dl_list_for_each_safe(e, next, &ptksa->ptksa, struct ptksa_cache_entry,
+ list) {
+ if ((!addr || os_memcmp(e->addr, addr, ETH_ALEN) == 0) &&
+ (cipher == WPA_CIPHER_NONE || cipher == e->cipher)) {
+ wpa_printf(MSG_DEBUG,
+ "Flush PTKSA cache entry for " MACSTR,
+ MAC2STR(e->addr));
+
+ ptksa_cache_free_entry(ptksa, e);
+ removed = true;
+ }
+ }
+
+ if (removed)
+ ptksa_cache_set_expiration(ptksa);
+}
+
+
+/*
+ * ptksa_cache_add - Add a PTKSA cache entry
+ * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init()
+ * @addr: Peer address
+ * @cipher: The cipher used
+ * @life_time: The PTK life time in seconds
+ * @ptk: The PTK
+ * Returns: Pointer to the added PTKSA cache entry or %NULL on error
+ *
+ * This function creates a PTKSA entry and adds it to the PTKSA cache.
+ * If an old entry is already in the cache for the same peer and cipher
+ * this entry will be replaced with the new entry.
+ */
+struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher,
+ u32 life_time,
+ const struct wpa_ptk *ptk)
+{
+ struct ptksa_cache_entry *entry, *tmp;
+ struct os_reltime now;
+
+ if (!ptksa || !ptk || !addr || !life_time || cipher == WPA_CIPHER_NONE)
+ return NULL;
+
+ /* remove a previous entry if present */
+ ptksa_cache_flush(ptksa, addr, cipher);
+
+ /* no place to add another entry */
+ if (ptksa->n_ptksa >= PTKSA_CACHE_MAX_ENTRIES)
+ return NULL;
+
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ return NULL;
+
+ dl_list_init(&entry->list);
+ os_memcpy(entry->addr, addr, ETH_ALEN);
+ entry->cipher = cipher;
+
+ os_memcpy(&entry->ptk, ptk, sizeof(entry->ptk));
+
+ os_get_reltime(&now);
+ entry->expiration = now.sec + life_time;
+
+ dl_list_for_each(tmp, &ptksa->ptksa, struct ptksa_cache_entry, list) {
+ if (tmp->expiration > entry->expiration)
+ break;
+ }
+
+ /*
+ * If the list was empty add to the head; otherwise if the expiration is
+ * later then all other entries, add it to the end of the list;
+ * otherwise add it before the relevant entry.
+ */
+ if (!tmp)
+ dl_list_add(&ptksa->ptksa, &entry->list);
+ else if (tmp->expiration < entry->expiration)
+ dl_list_add(&tmp->list, &entry->list);
+ else
+ dl_list_add_tail(&tmp->list, &entry->list);
+
+ ptksa->n_ptksa++;
+ wpa_printf(MSG_DEBUG,
+ "Added PTKSA cache entry addr=" MACSTR " cipher=%u",
+ MAC2STR(addr), cipher);
+
+ return entry;
+}
diff --git a/src/common/ptksa_cache.h b/src/common/ptksa_cache.h
new file mode 100644
index 0000000..28ef291
--- /dev/null
+++ b/src/common/ptksa_cache.h
@@ -0,0 +1,79 @@
+/*
+ * RSN PTKSA cache interface
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PTKSA_CACHE_H
+#define PTKSA_CACHE_H
+
+#include "wpa_common.h"
+#include "defs.h"
+#include "list.h"
+
+/**
+ * struct ptksa_cache_entry - PTKSA cache entry
+ */
+struct ptksa_cache_entry {
+ struct dl_list list;
+ struct wpa_ptk ptk;
+ os_time_t expiration;
+ u32 cipher;
+ u8 addr[ETH_ALEN];
+};
+
+#ifdef CONFIG_PTKSA_CACHE
+
+struct ptksa_cache;
+
+struct ptksa_cache * ptksa_cache_init(void);
+void ptksa_cache_deinit(struct ptksa_cache *ptksa);
+struct ptksa_cache_entry * ptksa_cache_get(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher);
+int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len);
+struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher,
+ u32 life_time,
+ const struct wpa_ptk *ptk);
+void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher);
+
+#else /* CONFIG_PTKSA_CACHE */
+
+static inline struct ptksa_cache * ptksa_cache_init(void)
+{
+ return (struct ptksa_cache *) 1;
+}
+
+static inline void ptksa_cache_deinit(struct ptksa_cache *ptksa)
+{
+}
+
+static inline struct ptksa_cache_entry *
+ptksa_cache_get(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher)
+{
+ return NULL;
+}
+
+static inline int ptksa_cache_list(struct ptksa_cache *ptksa,
+ char *buf, size_t len)
+{
+ return -1;
+}
+
+static inline struct ptksa_cache_entry *
+ptksa_cache_add(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher,
+ u32 life_time, const struct wpa_ptk *ptk)
+{
+ return NULL;
+}
+
+static inline void ptksa_cache_flush(struct ptksa_cache *ptksa,
+ const u8 *addr, u32 cipher)
+{
+}
+
+#endif /* CONFIG_PTKSA_CACHE */
+#endif /* PTKSA_CACHE_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index d4c1da7..f7e5571 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1458,6 +1458,12 @@ enum qca_wlan_vendor_acs_hw_mode {
* concurrent network sessions on different Wi-Fi bands. This feature
* capability is attributed to the hardware's capability to support
* the same (e.g., DBS).
+ * @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT: Flag indicating whether the
+ * responses for the respective TWT operations are asynchronous (separate
+ * event message) from the driver. If not specified, the responses are
+ * 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.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1475,6 +1481,7 @@ enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG = 11,
QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R = 12,
QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS = 13,
+ QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT = 14,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -2300,6 +2307,10 @@ enum qca_wlan_vendor_attr_config {
* frame. The updated NSS value after the connection shall not be
* greater than the one negotiated during the connection. Any such
* higher value configuration shall be returned with a failure.
+ * Only symmetric NSS configuration (such as 2X2 or 1X1) can be done
+ * using this attribute. QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS and
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS attributes shall be used to
+ * configure the asymmetric NSS configuration (such as 1X2).
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_NSS = 70,
/* 8-bit unsigned value to trigger Optimized Power Management:
@@ -2348,6 +2359,46 @@ enum qca_wlan_vendor_attr_config {
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_LEVEL = 76,
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of spatial streams used for transmitting the data. When
+ * configured in the disconnected state, the configured value will
+ * be considered for the following connection attempt.
+ * If the NSS is updated after the connection, the updated NSS value
+ * is notified to the peer using the Operating Mode Notification/Spatial
+ * Multiplexing Power Save frame.
+ * The TX NSS value configured after the connection shall not be greater
+ * than the value negotiated during the connection. Any such higher
+ * value configuration shall be treated as invalid configuration by
+ * the driver. This attribute shall be configured along with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS attribute to define the symmetric
+ * configuration (such as 2X2 or 1X1) or the asymmetric
+ * configuration (such as 1X2).
+ * If QCA_WLAN_VENDOR_ATTR_CONFIG_NSS attribute is also provided along
+ * with this QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS attribute the driver
+ * will update the TX NSS based on QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS = 77,
+
+ /* 8-bit unsigned value. This attribute is used to dynamically configure
+ * the number of spatial streams used for receiving the data. When
+ * configured in the disconnected state, the configured value will
+ * be considered for the following connection attempt.
+ * If the NSS is updated after the connection, the updated NSS value
+ * is notified to the peer using the Operating Mode Notification/Spatial
+ * Multiplexing Power Save frame.
+ * The RX NSS value configured after the connection shall not be greater
+ * than the value negotiated during the connection. Any such higher
+ * value configuration shall be treated as invalid configuration by
+ * the driver. This attribute shall be configured along with
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS attribute to define the symmetric
+ * configuration (such as 2X2 or 1X1) or the asymmetric
+ * configuration (such as 1X2).
+ * If QCA_WLAN_VENDOR_ATTR_CONFIG_NSS attribute is also provided along
+ * with this QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS attribute the driver
+ * will update the RX NSS based on QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS = 78,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -4192,6 +4243,139 @@ enum qca_vendor_roam_triggers {
QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN = 1 << 12,
};
+/*
+ * enum qca_vendor_roam_fail_reasons: Defines the various roam
+ * fail reasons. This enum value is used in
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON attribute.
+ *
+ * @QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED: Roam module in the firmware is not
+ * able to trigger the scan.
+ * @QCA_ROAM_FAIL_REASON_NO_AP_FOUND: No roamable APs found during roam scan.
+ * @QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND: No candidate APs found during roam
+ * scan.
+ * @QCA_ROAM_FAIL_REASON_HOST: Roam fail due to disconnect issued from host.
+ * @QCA_ROAM_FAIL_REASON_AUTH_SEND: Unable to send Authentication frame.
+ * @QCA_ROAM_FAIL_REASON_AUTH_RECV: Received Authentication frame with error
+ * status code.
+ * @QCA_ROAM_FAIL_REASON_NO_AUTH_RESP: Authentication frame not received.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_SEND: Unable to send Reassociation Request
+ * frame.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_RECV: Received Reassociation Response frame
+ * with error status code.
+ * @QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP: Reassociation Response frame not
+ * received.
+ * @QCA_ROAM_FAIL_REASON_SCAN_FAIL: Scan module not able to start scan.
+ * @QCA_ROAM_FAIL_REASON_AUTH_NO_ACK: No ACK is received for Authentication
+ * frame.
+ * @QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP: Authentication frame is dropped
+ * internally before transmission.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK: No ACK is received for Reassociation
+ * Request frame.
+ * @QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP: Reassociation Request frame is
+ * dropped internally.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT: EAPOL-Key M1 is not received and
+ * times out.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND: Unable to send EAPOL-Key M2 frame.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP: EAPOL-Key M2 frame dropped
+ * internally.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK: No ACK is received for EAPOL-Key
+ * M2 frame.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT: EAPOL-Key M3 frame is not received.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND: Unable to send EAPOL-Key M4 frame.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP: EAPOL-Key M4 frame dropped
+ * internally.
+ * @QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK: No ACK is received for EAPOL-Key M4
+ * frame.
+ * @QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS: Roam scan is not
+ * started for final beacon miss case.
+ * @QCA_ROAM_FAIL_REASON_DISCONNECT: Deauthentication or Disassociation frame
+ * received from the AP during roaming handoff.
+ * @QCA_ROAM_FAIL_REASON_RESUME_ABORT: Firmware roams to the AP when the Apps
+ * or host is suspended and gives the indication of the last roamed AP only
+ * when the Apps is resumed. If the Apps is resumed while the roaming is in
+ * progress, this ongoing roaming is aborted and the last roamed AP is
+ * indicated to host.
+ * @QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID: WPA3-SAE invalid PMKID.
+ * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT: WPA3-SAE pre-authentication times
+ * out.
+ * @QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL: WPA3-SAE pre-authentication fails.
+ */
+enum qca_vendor_roam_fail_reasons {
+ QCA_ROAM_FAIL_REASON_NONE = 0,
+ QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED = 1,
+ QCA_ROAM_FAIL_REASON_NO_AP_FOUND = 2,
+ QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND = 3,
+ QCA_ROAM_FAIL_REASON_HOST = 4,
+ QCA_ROAM_FAIL_REASON_AUTH_SEND = 5,
+ QCA_ROAM_FAIL_REASON_AUTH_RECV = 6,
+ QCA_ROAM_FAIL_REASON_NO_AUTH_RESP = 7,
+ QCA_ROAM_FAIL_REASON_REASSOC_SEND = 8,
+ QCA_ROAM_FAIL_REASON_REASSOC_RECV = 9,
+ QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP = 10,
+ QCA_ROAM_FAIL_REASON_SCAN_FAIL = 11,
+ QCA_ROAM_FAIL_REASON_AUTH_NO_ACK = 12,
+ QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP = 13,
+ QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK = 14,
+ QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP = 15,
+ QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT = 16,
+ QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND = 17,
+ QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP = 18,
+ QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK = 19,
+ QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT = 20,
+ QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND = 21,
+ QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP = 22,
+ QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK = 23,
+ QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS = 24,
+ QCA_ROAM_FAIL_REASON_DISCONNECT = 25,
+ QCA_ROAM_FAIL_REASON_RESUME_ABORT = 26,
+ QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID = 27,
+ QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT = 28,
+ QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL = 29,
+};
+
+/*
+ * enum qca_vendor_roam_invoke_fail_reasons: Defines the various roam
+ * invoke fail reasons. This enum value is used in
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON attribute.
+ *
+ * @QCA_ROAM_INVOKE_STATUS_IFACE_INVALID: Invalid interface ID is passed
+ * in roam invoke command.
+ * @QCA_ROAM_INVOKE_STATUS_OFFLOAD_DISABLE: Roam offload in firmware is not
+ * enabled.
+ * @QCA_ROAM_INVOKE_STATUS_AP_SSID_LENGTH_INVALID: Connected AP profile SSID
+ * length is invalid.
+ * @QCA_ROAM_INVOKE_STATUS_ROAM_DISALLOW: Firmware internal roaming is already
+ * in progress.
+ * @QCA_ROAM_INVOKE_STATUS_NON_ROAMABLE_AP: Host sends the Beacon/Probe Response
+ * of the AP in the roam invoke command to firmware. This reason is sent by the
+ * firmware when the given AP is configured to be ignored or SSID/security
+ * does not match.
+ * @QCA_ROAM_INVOKE_STATUS_ROAM_INTERNAL_FAIL: Roam handoff failed because of
+ * firmware internal reasons.
+ * @QCA_ROAM_INVOKE_STATUS_DISALLOW: Roam invoke trigger is not enabled.
+ * @QCA_ROAM_INVOKE_STATUS_SCAN_FAIL: Scan start fail for roam invoke.
+ * @QCA_ROAM_INVOKE_STATUS_START_ROAM_FAIL: Roam handoff start fail.
+ * @QCA_ROAM_INVOKE_STATUS_INVALID_PARAMS: Roam invoke parameters are invalid.
+ * @QCA_ROAM_INVOKE_STATUS_NO_CAND_AP: No candidate AP found to roam to.
+ * @QCA_ROAM_INVOKE_STATUS_ROAM_FAIL: Roam handoff failed.
+ */
+enum qca_vendor_roam_invoke_fail_reasons {
+ QCA_ROAM_INVOKE_STATUS_NONE = 0,
+ QCA_ROAM_INVOKE_STATUS_IFACE_INVALID = 1,
+ QCA_ROAM_INVOKE_STATUS_OFFLOAD_DISABLE = 2,
+ QCA_ROAM_INVOKE_STATUS_AP_SSID_LENGTH_INVALID = 3,
+ QCA_ROAM_INVOKE_STATUS_ROAM_DISALLOW = 4,
+ QCA_ROAM_INVOKE_STATUS_NON_ROAMABLE_AP = 5,
+ QCA_ROAM_INVOKE_STATUS_ROAM_INTERNAL_FAIL = 6,
+ QCA_ROAM_INVOKE_STATUS_DISALLOW = 7,
+ QCA_ROAM_INVOKE_STATUS_SCAN_FAIL = 8,
+ QCA_ROAM_INVOKE_STATUS_START_ROAM_FAIL = 9,
+ QCA_ROAM_INVOKE_STATUS_INVALID_PARAMS = 10,
+ QCA_ROAM_INVOKE_STATUS_NO_CAND_AP = 11,
+ QCA_ROAM_INVOKE_STATUS_ROAM_FAIL = 12,
+
+};
+
/**
* enum qca_vendor_attr_roam_candidate_selection_criteria:
*
@@ -7774,6 +7958,37 @@ enum qca_wlan_vendor_attr_wifi_test_config {
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FULL_BW_UL_MU_MIMO = 45,
+ /* 16-bit unsigned value to configure the driver with a specific BSS
+ * max idle period to advertise in the BSS Max Idle Period element
+ * (IEEE Std 802.11-2016, 9.4.2.79) in (Re)Association Request frames.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD = 46,
+
+ /* 8-bit unsigned value to configure the driver to use only RU 242 tone
+ * for data transmission.
+ * 0 - Default behavior, 1 - Configure RU 242 tone for data Tx.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RU_242_TONE_TX = 47,
+
+ /* 8-bit unsigned value to configure the driver to disable data and
+ * management response frame transmission to test the BSS max idle
+ * feature.
+ * 0 - Default behavior, 1 - Disable data and management response Tx.
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISABLE_DATA_MGMT_RSP_TX = 48,
+
+ /* 8-bit unsigned value to configure the driver/firmware to enable or
+ * disable Punctured Preamble Rx subfield in the HE PHY capabilities
+ * information field.
+ * 0 - Disable Punctured Preamble Rx subfield
+ * 1 - Enable Punctured Preamble Rx subfield
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PUNCTURED_PREAMBLE_RX = 49,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -7783,32 +7998,69 @@ enum qca_wlan_vendor_attr_wifi_test_config {
/**
* enum qca_wlan_twt_operation - Operation of the config TWT request
* Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION.
+ * The response for the respective operations can be either synchronous or
+ * asynchronous (wherever specified). If synchronous, the response to this
+ * operation is obtained in the corresponding vendor command reply to the user
+ * space. For the asynchronous case the response is obtained as an event with
+ * the same operation type.
+ *
+ * Drivers shall support either of these modes but not both simultaneously.
+ * This support for asynchronous mode is advertised through the flag
+ * QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT. If this flag is not advertised,
+ * the driver shall support synchronous mode.
*
* @QCA_WLAN_TWT_SET: Setup a TWT session. Required parameters are configured
* through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
- * qca_wlan_vendor_attr_twt_setup.
+ * qca_wlan_vendor_attr_twt_setup. Depending upon the
+ * @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT capability, this is either a
+ * synchronous or asynchronous operation.
*
* @QCA_WLAN_TWT_GET: Get the configured TWT parameters. Required parameters are
* obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
- * qca_wlan_vendor_attr_twt_setup.
+ * qca_wlan_vendor_attr_twt_setup. This is a synchronous operation.
*
* @QCA_WLAN_TWT_TERMINATE: Terminate the TWT session. Required parameters are
* obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
* qca_wlan_vendor_attr_twt_setup. Valid only after the TWT session is setup.
+ * This terminate can either get triggered by the user space or can as well be
+ * a notification from the firmware if it initiates a terminate.
+ * Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT capability,
+ * the request from user space can either be a synchronous or asynchronous
+ * operation.
*
* @QCA_WLAN_TWT_SUSPEND: Suspend the TWT session. Required parameters are
* obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
* qca_wlan_vendor_attr_twt_setup. Valid only after the TWT session is setup.
+ * Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT capability,
+ * this is either a synchronous or asynchronous operation.
*
* @QCA_WLAN_TWT_RESUME: Resume the TWT session. Required parameters are
* configured through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the enum
* qca_wlan_vendor_attr_twt_resume. Valid only after the TWT session is setup.
+ * This can as well be a notification from the firmware on a QCA_WLAN_TWT_NUDGE
+ * request. Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT
+ * capability, this is either a synchronous or asynchronous operation.
*
* @QCA_WLAN_TWT_NUDGE: Suspend and resume the TWT session. TWT nudge is a
* combination of suspend and resume in a single request. Required parameters
* are configured through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refers the
* enum qca_wlan_vendor_attr_twt_nudge. Valid only after the TWT session is
- * setup.
+ * setup. Depending upon the @QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT
+ * capability, this is either a synchronous or asynchronous operation.
+ *
+ * @QCA_WLAN_TWT_GET_STATS: Get the TWT session traffic statistics information.
+ * Refers the enum qca_wlan_vendor_attr_twt_stats. Valid only after the TWT
+ * session is setup. It's a synchronous operation.
+ *
+ * @QCA_WLAN_TWT_CLEAR_STATS: Clear TWT session traffic statistics information.
+ * Valid only after the TWT session is setup. It's a synchronous operation.
+ *
+ * @QCA_WLAN_TWT_GET_CAPABILITIES: Get TWT capabilities of this device and its
+ * 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
+ * ready for a new TWT session setup after it issued a TWT teardown.
*/
enum qca_wlan_twt_operation {
QCA_WLAN_TWT_SET = 0,
@@ -7817,6 +8069,10 @@ enum qca_wlan_twt_operation {
QCA_WLAN_TWT_SUSPEND = 3,
QCA_WLAN_TWT_RESUME = 4,
QCA_WLAN_TWT_NUDGE = 5,
+ QCA_WLAN_TWT_GET_STATS = 6,
+ QCA_WLAN_TWT_CLEAR_STATS = 7,
+ QCA_WLAN_TWT_GET_CAPABILITIES = 8,
+ QCA_WLAN_TWT_SETUP_READY_NOTIFY = 9,
};
/**
@@ -7830,8 +8086,8 @@ enum qca_wlan_twt_operation {
*
* @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS: Nested attribute representing the
* parameters configured for TWT. These parameters are represented by
- * enum qca_wlan_vendor_attr_twt_setup or enum qca_wlan_vendor_attr_twt_resume
- * based on the operation.
+ * enum qca_wlan_vendor_attr_twt_setup, enum qca_wlan_vendor_attr_twt_resume,
+ * or enum qca_wlan_vendor_attr_twt_stats based on the operation.
*/
enum qca_wlan_vendor_attr_config_twt {
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_INVALID = 0,
@@ -7992,6 +8248,19 @@ enum qca_wlan_vendor_attr_nan_params {
};
/**
+ * qca_wlan_twt_setup_state: Represents the TWT session states.
+ *
+ * QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED: TWT session not established.
+ * QCA_WLAN_TWT_SETUP_STATE_ACTIVE: TWT session is active.
+ * QCA_WLAN_TWT_SETUP_STATE_SUSPEND: TWT session is in suspended state.
+ */
+enum qca_wlan_twt_setup_state {
+ QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED = 0,
+ QCA_WLAN_TWT_SETUP_STATE_ACTIVE = 1,
+ QCA_WLAN_TWT_SETUP_STATE_SUSPEND = 2,
+};
+
+/**
* enum qca_wlan_vendor_attr_twt_setup: Represents attributes for
* TWT (Target Wake Time) setup request. These attributes are sent as part of
* %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP and
@@ -8041,6 +8310,14 @@ enum qca_wlan_vendor_attr_nan_params {
* 2. TWT GET Request and Response
* 3. TWT TERMINATE Request and Response
* 4. TWT SUSPEND Request and Response
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions for the following
+ * 1. TWT TERMINATE Request and Response
+ * 2. TWT SUSPEND Request and Response
+ * 4. TWT CLEAR STATISTICS request
+ * 5. TWT GET STATISTICS request and response
+ * If an invalid dialog ID is provided, status
+ * QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST will be returned.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP: Required (u8)
* This attribute (exp) is used along with the mantissa to derive the
@@ -8128,6 +8405,23 @@ enum qca_wlan_vendor_attr_nan_params {
* 4. TWT SUSPEND Request
* In STA mode, this is an optional parameter in request and response for
* the above four TWT operations.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL: Optional (u32)
+ * Minimum tolerance limit of wake interval parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL: Optional (u32)
+ * Maximum tolerance limit of wake interval parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION: Optional (u32)
+ * Minimum tolerance limit of wake duration parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION: Optional (u32)
+ * Maximum tolerance limit of wake duration parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE: Optional (u32)
+ * TWT state for the given dialog id. The values for this are represented
+ * by enum qca_wlan_twt_setup_state.
+ * This is obtained through TWT GET operation.
*/
enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
@@ -8149,6 +8443,11 @@ enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED = 14,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR = 15,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL = 16,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL = 17,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION = 18,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION = 19,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE = 20,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
@@ -8178,6 +8477,16 @@ enum qca_wlan_vendor_attr_twt_setup {
* unknown reason
* @QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED: TWT session already in
* suspend state
+ * @QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID: FW has dropped the frame due to
+ * invalid IE in the received TWT frame
+ * @QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE: Parameters received from
+ * the responder are not in the specified range
+ * @QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE: FW terminated the TWT
+ * session due to request from the responder. Used on the TWT_TERMINATE
+ * notification from the firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE: FW terminated the TWT
+ * session due to roaming. Used on the TWT_TERMINATE notification from the
+ * firmware.
*/
enum qca_wlan_vendor_twt_status {
QCA_WLAN_VENDOR_TWT_STATUS_OK = 0,
@@ -8194,6 +8503,10 @@ enum qca_wlan_vendor_twt_status {
QCA_WLAN_VENDOR_TWT_STATUS_DENIED = 11,
QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR = 12,
QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED = 13,
+ QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID = 14,
+ QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE = 15,
+ QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE = 16,
+ QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE = 17,
};
/**
@@ -8220,6 +8533,10 @@ enum qca_wlan_vendor_twt_status {
* @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID: Required (u8).
* Flow ID is the unique identifier for each TWT session. This attribute
* represents the respective TWT session to resume.
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions.
+ * If an invalid dialog id is provided, status
+ * QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST will be returned.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR: 6-byte MAC address
* Represents the MAC address of the peer to which TWT Resume is
@@ -8250,6 +8567,11 @@ enum qca_wlan_vendor_attr_twt_resume {
* @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID: Required (u8)
* Flow ID is the unique identifier for each TWT session. This attribute
* represents the respective TWT session to suspend and resume.
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions in TWT NUDGE request
+ * and response.
+ * If an invalid dialog id is provided, status
+ * QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST will be returned.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME: Required (u32)
* This attribute is used as the SP offset which is the offset from
@@ -8265,6 +8587,10 @@ enum qca_wlan_vendor_attr_twt_resume {
* being sent. This is used in AP mode to represent the respective
* client and is a required parameter. In STA mode, this is an optional
* parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF: Optional (u64)
+ * This field contains absolute TSF value of the time at which the TWT
+ * session will be resumed.
*/
enum qca_wlan_vendor_attr_twt_nudge {
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_INVALID = 0,
@@ -8272,6 +8598,7 @@ enum qca_wlan_vendor_attr_twt_nudge {
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME = 2,
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE = 3,
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF = 5,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_AFTER_LAST,
@@ -8280,6 +8607,162 @@ enum qca_wlan_vendor_attr_twt_nudge {
};
/**
+ * enum qca_wlan_vendor_attr_twt_stats: Represents attributes for
+ * TWT (Target Wake Time) get statistics and clear statistics request.
+ * These attributes are sent as part of
+ * %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID: Required (u8)
+ * Flow ID is the unique identifier for each TWT session. This attribute
+ * represents the respective TWT session for get and clear TWT statistics.
+ * Flow ID values from 0 to 254 represent a single TWT session
+ * Flow ID value of 255 represents all TWT sessions in
+ * 1) TWT GET STATISTICS request and response
+ * 2) TWT CLEAR STATISTICS request
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer for which TWT Statistics
+ * is required.
+ * In AP mode this is used to represent the respective
+ * client and is a required parameter for
+ * 1) TWT GET STATISTICS request and response
+ * 2) TWT CLEAR STATISTICS request and response
+ * In STA mode, this is an optional parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION: Required (u32)
+ * This is the duration of the service period in microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION: Required (u32)
+ * Average of the actual wake duration observed so far. Unit is microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS: Required (u32)
+ * The number of TWT service periods elapsed so far.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION: Required (u32)
+ * This is the minimum value of the wake duration observed across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS. Unit is
+ * microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION: Required (u32)
+ * This is the maximum value of wake duration observed across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS. Unit is
+ * microseconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU: Required (u32)
+ * Average number of MPDUs transmitted successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU: Required (u32)
+ * Average number of MPDUs received successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE: Required (u32)
+ * Average number of bytes transmitted successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE: Required (u32)
+ * Average number of bytes received successfully across
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS: Required (u32)
+ * Status of the TWT GET STATISTICS request.
+ * This contains status values in enum qca_wlan_vendor_twt_status
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ */
+enum qca_wlan_vendor_attr_twt_stats {
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS = 5,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION = 6,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION = 7,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU = 8,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU = 9,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE = 10,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE = 11,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS = 12,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_twt_get_capa - Represents the bitmap of TWT capabilities
+ * supported by the device and the peer.
+ * Values for %QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_GET_CAPABILITIES
+ *
+ * @QCA_WLAN_TWT_CAPA_REQUESTOR: TWT requestor support is advertised by
+ * TWT non-scheduling STA. This capability is advertised in the HE
+ * Capability/Extended Capabilities information element in the
+ * Association Request frame by the device.
+ *
+ * @QCA_WLAN_TWT_CAPA_RESPONDER: TWT responder support is advertised by
+ * the TWT scheduling AP. This capability is advertised in the Extended
+ * Capabilities/HE Capabilities information element.
+ *
+ * @QCA_WLAN_TWT_CAPA_BROADCAST: On the requestor side, this indicates support
+ * for the broadcast TWT functionality. On the responder side, this indicates
+ * support for the role of broadcast TWT scheduling functionality. This
+ * capability is advertised in the HE Capabilities information element.
+ *
+ * @QCA_WLAN_TWT_CAPA_TWT_FLEXIBLE: The device supports flexible TWT schedule.
+ * This capability is advertised in the HE Capabilities information element.
+ *
+ * @QCA_WLAN_TWT_CAPA_REQUIRED: The TWT Required is advertised by AP to indicate
+ * that it mandates the associated HE STAs to support TWT. This capability is
+ * advertised by AP in the HE Operation Parameters field of the HE Operation
+ * information element.
+ */
+enum qca_wlan_twt_capa {
+ QCA_WLAN_TWT_CAPA_REQUESTOR = BIT(0),
+ QCA_WLAN_TWT_CAPA_RESPONDER = BIT(1),
+ QCA_WLAN_TWT_CAPA_BROADCAST = BIT(2),
+ QCA_WLAN_TWT_CAPA_FLEXIBLE = BIT(3),
+ QCA_WLAN_TWT_CAPA_REQUIRED = BIT(4),
+};
+
+/**
+ * enum qca_wlan_vendor_attr_twt_capability - Represents attributes for TWT
+ * get capabilities request type. Used by QCA_WLAN_TWT_GET_CAPABILITIES TWT
+ * operation.
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAC_ADDR: 6-byte MAC address
+ * Represents the MAC address of the peer for which the TWT capabilities
+ * are being queried. This is used in AP mode to represent the respective
+ * client. In STA mode, this is an optional parameter.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF: (u16).
+ * Self TWT capabilities. Carries a bitmap of TWT capabilities specified in
+ * enum qca_wlan_twt_capa.
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER: (u16).
+ * Peer TWT capabilities. Carries a bitmap of TWT capabilities specified in
+ * enum qca_wlan_twt_capa.
+ */
+enum qca_wlan_vendor_attr_twt_capability {
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAC_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF = 2,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_AFTER_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_twt_setup_resp_type - Represents the response type by
* the TWT responder
*
@@ -9623,6 +10106,40 @@ enum qca_vendor_wlan_sta_guard_interval {
* include this attribute in response to the
* QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO command if there is no connection
* failure observed in the last attempted connection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_RATE: u32, latest TX rate (Kbps)
+ * used by the station in its last TX frame while communicating to the AP in the
+ * connected state. When queried in the disconnected state, this represents the
+ * rate used by the STA in the last TX frame to the AP when it was connected.
+ * This attribute is used for STA mode only.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_RIX: u32, used in STA mode only.
+ * This represents the rate index used by the STA for the last TX frame to the
+ * AP. When queried in the disconnected state, this gives the last RIX used by
+ * the STA in the last TX frame to the AP when it was connected.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TSF_OUT_OF_SYNC_COUNT: u32, used in STA
+ * mode only. This represents the number of times the STA TSF goes out of sync
+ * from the AP after the connection. If queried in the disconnected state, this
+ * gives the count of TSF out of sync for the last connection.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_TRIGGER_REASON: u32, used in STA
+ * mode only. This represents the roam trigger reason for the last roaming
+ * attempted by the firmware. This can be queried either in connected state or
+ * disconnected state. Each bit of this attribute represents the different
+ * roam trigger reason code which are defined in enum qca_vendor_roam_triggers.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON: u32, used in STA mode
+ * only. This represents the roam fail reason for the last failed roaming
+ * attempt by the firmware. Different roam failure reason codes are specified
+ * in enum qca_vendor_roam_fail_reasons. This can be queried either in
+ * connected state or disconnected state.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON: u32, used in
+ * STA mode only. This represents the roam invoke fail reason for the last
+ * failed roam invoke. Different roam invoke failure reason codes
+ * are specified in enum qca_vendor_roam_invoke_fail_reasons. This can be
+ * queried either in connected state or disconnected state.
*/
enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0,
@@ -9669,6 +10186,12 @@ enum qca_wlan_vendor_attr_get_sta_info {
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_MIC_ERROR_COUNT = 41,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_REPLAY_COUNT = 42,
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE = 43,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_RATE = 44,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_RIX = 45,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TSF_OUT_OF_SYNC_COUNT = 46,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_TRIGGER_REASON = 47,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON = 48,
+ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON = 49,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST,
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 82a5a17..04d49ee 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -333,6 +333,7 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
* @ptk: Buffer for pairwise transient key
* @akmp: Negotiated AKM
* @cipher: Negotiated pairwise cipher
+ * @kdk_len: The length in octets that should be derived for KDK
* Returns: 0 on success, -1 on failure
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
@@ -348,12 +349,13 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
struct wpa_ptk *ptk, int akmp, int cipher,
- const u8 *z, size_t z_len)
+ const u8 *z, size_t z_len, size_t kdk_len)
{
#define MAX_Z_LEN 66 /* with NIST P-521 */
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN + MAX_Z_LEN];
size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN;
- u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
+ WPA_KDK_MAX_LEN];
size_t ptk_len;
#ifdef CONFIG_OWE
int owe_ptk_workaround = 0;
@@ -395,16 +397,24 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
data_len += z_len;
}
+ if (kdk_len > WPA_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR,
+ "WPA: KDK len=%zu exceeds max supported len",
+ kdk_len);
+ return -1;
+ }
+
ptk->kck_len = wpa_kck_len(akmp, pmk_len);
ptk->kek_len = wpa_kek_len(akmp, pmk_len);
ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk->kdk_len = kdk_len;
if (ptk->tk_len == 0) {
wpa_printf(MSG_ERROR,
"WPA: Unsupported cipher (0x%x) used in PTK derivation",
cipher);
return -1;
}
- ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len + ptk->kdk_len;
if (wpa_key_mgmt_sha384(akmp)) {
#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
@@ -488,6 +498,12 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
+ if (kdk_len) {
+ os_memcpy(ptk->kdk, tmp + ptk->kck_len + ptk->kek_len +
+ ptk->tk_len, ptk->kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KDK", ptk->kdk, ptk->kdk_len);
+ }
+
ptk->kek2_len = 0;
ptk->kck2_len = 0;
@@ -576,15 +592,16 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
const u8 *snonce, const u8 *anonce, const u8 *dhss,
size_t dhss_len, struct wpa_ptk *ptk,
u8 *ick, size_t *ick_len, int akmp, int cipher,
- u8 *fils_ft, size_t *fils_ft_len)
+ u8 *fils_ft, size_t *fils_ft_len, size_t kdk_len)
{
u8 *data, *pos;
size_t data_len;
u8 tmp[FILS_ICK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
- FILS_FT_MAX_LEN];
+ FILS_FT_MAX_LEN + WPA_KDK_MAX_LEN];
size_t key_data_len;
const char *label = "FILS PTK Derivation";
int ret = -1;
+ size_t offset;
/*
* FILS-Key-Data = PRF-X(PMK, "FILS PTK Derivation",
@@ -595,6 +612,9 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
* If doing FT initial mobility domain association:
* FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits,
* FILS-FT_bits)
+ * When a KDK is derived:
+ * KDK = L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits + FILS-FT_bits,
+ * KDK_bits)
*/
data_len = 2 * ETH_ALEN + 2 * FILS_NONCE_LEN + dhss_len;
data = os_malloc(data_len);
@@ -623,6 +643,19 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
goto err;
key_data_len = *ick_len + ptk->kek_len + ptk->tk_len;
+ if (kdk_len) {
+ if (kdk_len > WPA_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR, "FILS: KDK len=%zu too big",
+ kdk_len);
+ goto err;
+ }
+
+ ptk->kdk_len = kdk_len;
+ key_data_len += kdk_len;
+ } else {
+ ptk->kdk_len = 0;
+ }
+
if (fils_ft && fils_ft_len) {
if (akmp == WPA_KEY_MGMT_FT_FILS_SHA256) {
*fils_ft_len = 32;
@@ -657,19 +690,27 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-Key-Data", tmp, key_data_len);
os_memcpy(ick, tmp, *ick_len);
+ offset = *ick_len;
wpa_hexdump_key(MSG_DEBUG, "FILS: ICK", ick, *ick_len);
- os_memcpy(ptk->kek, tmp + *ick_len, ptk->kek_len);
+ os_memcpy(ptk->kek, tmp + offset, ptk->kek_len);
wpa_hexdump_key(MSG_DEBUG, "FILS: KEK", ptk->kek, ptk->kek_len);
+ offset += ptk->kek_len;
- os_memcpy(ptk->tk, tmp + *ick_len + ptk->kek_len, ptk->tk_len);
+ os_memcpy(ptk->tk, tmp + offset, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "FILS: TK", ptk->tk, ptk->tk_len);
+ offset += ptk->tk_len;
if (fils_ft && fils_ft_len) {
- os_memcpy(fils_ft, tmp + *ick_len + ptk->kek_len + ptk->tk_len,
- *fils_ft_len);
+ os_memcpy(fils_ft, tmp + offset, *fils_ft_len);
wpa_hexdump_key(MSG_DEBUG, "FILS: FILS-FT",
fils_ft, *fils_ft_len);
+ offset += *fils_ft_len;
+ }
+
+ if (ptk->kdk_len) {
+ os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "FILS: KDK", ptk->kdk, ptk->kdk_len);
}
ptk->kek2_len = 0;
@@ -1127,6 +1168,266 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_PASN
+
+/*
+ * pasn_use_sha384 - Should SHA384 be used or SHA256
+ *
+ * @akmp: Authentication and key management protocol
+ * @cipher: The cipher suite
+ *
+ * According to IEEE P802.11az/D2.7, 12.12.7, the hash algorithm to use is the
+ * hash algorithm defined for the Base AKM (see Table 9-151 (AKM suite
+ * selectors)). When there is no Base AKM, the hash algorithm is selected based
+ * on the pairwise cipher suite provided in the RSNE by the AP in the second
+ * PASN frame. SHA-256 is used as the hash algorithm, except for the ciphers
+ * 00-0F-AC:9 and 00-0F-AC:10 for which SHA-384 is used.
+ */
+static bool pasn_use_sha384(int akmp, int cipher)
+{
+ return (akmp == WPA_KEY_MGMT_PASN && (cipher == WPA_CIPHER_CCMP_256 ||
+ cipher == WPA_CIPHER_GCMP_256)) ||
+ wpa_key_mgmt_sha384(akmp);
+}
+
+
+/**
+ * pasn_pmk_to_ptk - Calculate PASN PTK from PMK, addresses, etc.
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of PMK
+ * @spa: Suppplicant address
+ * @bssid: AP BSSID
+ * @dhss: Is the shared secret (DHss) derived from the PASN ephemeral key
+ * exchange encoded as an octet string
+ * @dhss_len: The length of dhss in octets
+ * @ptk: Buffer for pairwise transient key
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * @kdk_len: the length in octets that should be derived for HTLK. Can be zero.
+ * Returns: 0 on success, -1 on failure
+ */
+int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
+ const u8 *spa, const u8 *bssid,
+ const u8 *dhss, size_t dhss_len,
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ size_t kdk_len)
+{
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_MAX_LEN];
+ u8 *data;
+ size_t data_len, ptk_len;
+ int ret = -1;
+ const char *label = "PASN PTK Derivation";
+
+ if (!pmk || !pmk_len) {
+ wpa_printf(MSG_ERROR, "PASN: No PMK set for PTK derivation");
+ return -1;
+ }
+
+ if (!dhss || !dhss_len) {
+ wpa_printf(MSG_ERROR, "PASN: No DHss set for PTK derivation");
+ return -1;
+ }
+
+ /*
+ * PASN-PTK = KDF(PMK, “PASN PTK Derivation”, SPA || BSSID || DHss)
+ *
+ * KCK = L(PASN-PTK, 0, 256)
+ * TK = L(PASN-PTK, 256, TK_bits)
+ * KDK = L(PASN-PTK, 256 + TK_bits, kdk_len * 8)
+ */
+ data_len = 2 * ETH_ALEN + dhss_len;
+ data = os_zalloc(data_len);
+ if (!data)
+ return -1;
+
+ os_memcpy(data, spa, ETH_ALEN);
+ os_memcpy(data + ETH_ALEN, bssid, ETH_ALEN);
+ os_memcpy(data + 2 * ETH_ALEN, dhss, dhss_len);
+
+ ptk->kck_len = WPA_PASN_KCK_LEN;
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk->kdk_len = kdk_len;
+ ptk->kek_len = 0;
+ ptk->kek2_len = 0;
+ ptk->kck2_len = 0;
+
+ if (ptk->tk_len == 0) {
+ wpa_printf(MSG_ERROR,
+ "PASN: Unsupported cipher (0x%x) used in PTK derivation",
+ cipher);
+ goto err;
+ }
+
+ ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len;
+ if (ptk_len > sizeof(tmp))
+ goto err;
+
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA384");
+
+ if (sha384_prf(pmk, pmk_len, label, data, data_len, tmp,
+ ptk_len) < 0)
+ goto err;
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: PTK derivation using SHA256");
+
+ if (sha256_prf(pmk, pmk_len, label, data, data_len, tmp,
+ ptk_len) < 0)
+ goto err;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "PASN: PTK derivation: SPA=" MACSTR " BSSID=" MACSTR,
+ MAC2STR(spa), MAC2STR(bssid));
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: DHss", dhss, dhss_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: PMK", pmk, pmk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: PASN-PTK", tmp, ptk_len);
+
+ os_memcpy(ptk->kck, tmp, WPA_PASN_KCK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: KCK:", ptk->kck, WPA_PASN_KCK_LEN);
+
+ os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN, ptk->tk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: TK:", ptk->tk, ptk->tk_len);
+
+ if (kdk_len) {
+ os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->tk_len,
+ ptk->kdk_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:",
+ ptk->kdk, ptk->kdk_len);
+ }
+
+ forced_memzero(tmp, sizeof(tmp));
+ ret = 0;
+err:
+ bin_clear_free(data, data_len);
+ return ret;
+}
+
+
+/*
+ * pasn_mic_len - Returns the MIC length for PASN authentication
+ */
+u8 pasn_mic_len(int akmp, int cipher)
+{
+ if (pasn_use_sha384(akmp, cipher))
+ return 24;
+
+ return 16;
+}
+
+
+/**
+ * pasn_mic - Calculate PASN MIC
+ * @kck: The key confirmation key for the PASN PTKSA
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * @addr1: For the 2nd PASN frame supplicant address; for the 3rd frame the
+ * BSSID
+ * @addr2: For the 2nd PASN frame the BSSID; for the 3rd frame the supplicant
+ * address
+ * @data: For calculating the MIC for the 2nd PASN frame, this should hold the
+ * Beacon frame RSNE + RSNXE. For calculating the MIC for the 3rd PASN
+ * frame, this should hold the hash of the body of the PASN 1st frame.
+ * @data_len: The length of data
+ * @frame: The body of the PASN frame including the MIC element with the octets
+ * in the MIC field of the MIC element set to 0.
+ * @frame_len: The length of frame
+ * @mic: Buffer to hold the MIC on success. Should be big enough to handle the
+ * maximal MIC length
+ * Returns: 0 on success, -1 on failure
+ */
+int pasn_mic(const u8 *kck, int akmp, int cipher,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *data, size_t data_len,
+ const u8 *frame, size_t frame_len, u8 *mic)
+{
+ u8 *buf;
+ u8 hash[SHA384_MAC_LEN];
+ size_t buf_len = 2 * ETH_ALEN + data_len + frame_len;
+ int ret = -1;
+
+ if (!kck) {
+ wpa_printf(MSG_ERROR, "PASN: No KCK for MIC calculation");
+ return -1;
+ }
+
+ if (!data || !data_len) {
+ wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation");
+ return -1;
+ }
+
+ if (!frame || !frame_len) {
+ wpa_printf(MSG_ERROR, "PASN: invalid data for MIC calculation");
+ return -1;
+ }
+
+ buf = os_zalloc(buf_len);
+ if (!buf)
+ return -1;
+
+ os_memcpy(buf, addr1, ETH_ALEN);
+ os_memcpy(buf + ETH_ALEN, addr2, ETH_ALEN);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: data", data, data_len);
+ os_memcpy(buf + 2 * ETH_ALEN, data, data_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: frame", frame, frame_len);
+ os_memcpy(buf + 2 * ETH_ALEN + data_len, frame, frame_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: KCK", kck, WPA_PASN_KCK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: buf", buf, buf_len);
+
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA384");
+
+ if (hmac_sha384(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash))
+ goto err;
+
+ os_memcpy(mic, hash, 24);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 24);
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: MIC using HMAC-SHA256");
+
+ if (hmac_sha256(kck, WPA_PASN_KCK_LEN, buf, buf_len, hash))
+ goto err;
+
+ os_memcpy(mic, hash, 16);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: MIC: mic: ", mic, 16);
+ }
+
+ ret = 0;
+err:
+ bin_clear_free(buf, buf_len);
+ return ret;
+}
+
+
+/**
+ * pasn_auth_frame_hash - Computes a hash of an Authentication frame body
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * @data: Pointer to the Authentication frame body
+ * @len: Length of the Authentication frame body
+ * @hash: On return would hold the computed hash. Should be big enough to handle
+ * SHA384.
+ * Returns: 0 on success, -1 on failure
+ */
+int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len,
+ u8 *hash)
+{
+ if (pasn_use_sha384(akmp, cipher)) {
+ wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-384");
+ return sha384_vector(1, &data, &len, hash);
+ } else {
+ wpa_printf(MSG_DEBUG, "PASN: Frame hash using SHA-256");
+ return sha256_vector(1, &data, &len, hash);
+ }
+}
+
+#endif /* CONFIG_PASN */
+
+
static int rsn_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
@@ -1203,6 +1504,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
#endif /* CONFIG_DPP */
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
return WPA_KEY_MGMT_OSEN;
+#ifdef CONFIG_PASN
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PASN)
+ return WPA_KEY_MGMT_PASN;
+#endif /* CONFIG_PASN */
return 0;
}
@@ -1216,7 +1521,8 @@ int wpa_cipher_valid_group(int cipher)
int wpa_cipher_valid_mgmt_group(int cipher)
{
- return cipher == WPA_CIPHER_AES_128_CMAC ||
+ return cipher == WPA_CIPHER_GTK_NOT_USED ||
+ cipher == WPA_CIPHER_AES_128_CMAC ||
cipher == WPA_CIPHER_BIP_GMAC_128 ||
cipher == WPA_CIPHER_BIP_GMAC_256 ||
cipher == WPA_CIPHER_BIP_CMAC_256;
@@ -1733,16 +2039,25 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
- struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher,
+ size_t kdk_len)
{
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
- u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ u8 tmp[2 * WPA_KCK_MAX_LEN + 2 * WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
+ WPA_KDK_MAX_LEN];
size_t ptk_len, offset;
int use_sha384 = wpa_key_mgmt_sha384(akmp);
+ if (kdk_len > WPA_KDK_MAX_LEN) {
+ wpa_printf(MSG_ERROR,
+ "FT: KDK len=%zu exceeds max supported len",
+ kdk_len);
+ return -1;
+ }
+
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
* BSSID || STA-ADDR)
@@ -1769,8 +2084,9 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
ptk->kek_len = wpa_kek_len(akmp, PMK_LEN);
ptk->kek2_len = wpa_kek2_len(akmp);
ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk->kdk_len = kdk_len;
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len +
- ptk->kck2_len + ptk->kek2_len;
+ ptk->kck2_len + ptk->kek2_len + ptk->kdk_len;
#ifdef CONFIG_SHA384
if (use_sha384) {
@@ -1829,6 +2145,8 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
os_memcpy(ptk->kck2, tmp + offset, ptk->kck2_len);
offset += ptk->kck2_len;
os_memcpy(ptk->kek2, tmp + offset, ptk->kek2_len);
+ offset += ptk->kek2_len;
+ os_memcpy(ptk->kdk, tmp + offset, ptk->kdk_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
@@ -1838,6 +2156,9 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len,
if (ptk->kek2_len)
wpa_hexdump_key(MSG_DEBUG, "FT: KEK2",
ptk->kek2, ptk->kek2_len);
+ if (ptk->kdk_len)
+ wpa_hexdump_key(MSG_DEBUG, "FT: KDK", ptk->kdk, ptk->kdk_len);
+
wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
@@ -2071,6 +2392,8 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
return "OWE";
case WPA_KEY_MGMT_DPP:
return "DPP";
+ case WPA_KEY_MGMT_PASN:
+ return "PASN";
default:
return "UNKNOWN";
}
@@ -2903,6 +3226,11 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
pos[1] >= sizeof(struct ieee80211_vht_capabilities))
{
ie->vht_capabilities = pos + 2;
+ } else if (*pos == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 + IEEE80211_HE_CAPAB_MIN_LEN &&
+ pos[2] == WLAN_EID_EXT_HE_CAPABILITIES) {
+ ie->he_capabilities = pos + 3;
+ ie->he_capab_len = pos[1] - 1;
} else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
ie->qosinfo = pos[2];
} else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
@@ -2942,3 +3270,451 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
return ret;
}
+
+
+#ifdef CONFIG_PASN
+
+/*
+ * wpa_pasn_build_auth_header - Add the MAC header and initialize Authentication
+ * frame for PASN
+ *
+ * @buf: Buffer in which the header will be added
+ * @bssid: The BSSID of the AP
+ * @src: Source address
+ * @dst: Destination address
+ * @trans_seq: Authentication transaction sequence number
+ * @status: Authentication status
+ */
+void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid,
+ const u8 *src, const u8 *dst,
+ u8 trans_seq, u16 status)
+{
+ struct ieee80211_mgmt *auth;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add authentication header. trans_seq=%u",
+ trans_seq);
+
+ auth = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
+ u.auth.variable));
+
+ auth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_AUTH << 4));
+
+ os_memcpy(auth->da, dst, ETH_ALEN);
+ os_memcpy(auth->sa, src, ETH_ALEN);
+ os_memcpy(auth->bssid, bssid, ETH_ALEN);
+ auth->seq_ctrl = 0;
+
+ auth->u.auth.auth_alg = host_to_le16(WLAN_AUTH_PASN);
+ auth->u.auth.auth_transaction = host_to_le16(trans_seq);
+ auth->u.auth.status_code = host_to_le16(status);
+}
+
+
+/*
+ * wpa_pasn_add_rsne - Add an RSNE for PASN authentication
+ * @buf: Buffer in which the IE will be added
+ * @pmkid: Optional PMKID. Can be NULL.
+ * @akmp: Authentication and key management protocol
+ * @cipher: The cipher suite
+ */
+int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher)
+{
+ struct rsn_ie_hdr *hdr;
+ u32 suite;
+ u16 capab;
+ u8 *pos;
+ u8 rsne_len;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add RSNE");
+
+ rsne_len = sizeof(*hdr) + RSN_SELECTOR_LEN +
+ 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN +
+ 2 + RSN_SELECTOR_LEN + 2 + (pmkid ? PMKID_LEN : 0);
+
+ if (wpabuf_tailroom(buf) < rsne_len)
+ return -1;
+ hdr = wpabuf_put(buf, rsne_len);
+ hdr->elem_id = WLAN_EID_RSN;
+ hdr->len = rsne_len - 2;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+
+ /* Group addressed data is not allowed */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ pos += RSN_SELECTOR_LEN;
+
+ /* Add the pairwise cipher */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, cipher);
+ RSN_SELECTOR_PUT(pos, suite);
+ pos += RSN_SELECTOR_LEN;
+
+ /* Add the AKM suite */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+
+ switch (akmp) {
+ case WPA_KEY_MGMT_PASN:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
+ break;
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+ break;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WPA_KEY_MGMT_FILS_SHA256:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
+ break;
+ case WPA_KEY_MGMT_FILS_SHA384:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
+ break;
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ case WPA_KEY_MGMT_FT_PSK:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+ break;
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+ break;
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
+ break;
+#endif /* CONFIG_IEEE80211R */
+ default:
+ wpa_printf(MSG_ERROR, "PASN: Invalid AKMP=0x%x", akmp);
+ return -1;
+ }
+ pos += RSN_SELECTOR_LEN;
+
+ /* RSN Capabilities: PASN mandates both MFP capable and required */
+ capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
+ WPA_PUT_LE16(pos, capab);
+ pos += 2;
+
+ if (pmkid) {
+ wpa_printf(MSG_DEBUG, "PASN: Adding PMKID");
+
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ os_memcpy(pos, pmkid, PMKID_LEN);
+ pos += PMKID_LEN;
+ } else {
+ WPA_PUT_LE16(pos, 0);
+ pos += 2;
+ }
+
+ /* Group addressed management is not allowed */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+
+ return 0;
+}
+
+
+/*
+ * wpa_pasn_add_parameter_ie - Add PASN Parameters IE for PASN authentication
+ * @buf: Buffer in which the IE will be added
+ * @pasn_group: Finite Cyclic Group ID for PASN authentication
+ * @wrapped_data_format: Format of the data in the Wrapped Data IE
+ * @pubkey: A buffer holding the local public key. Can be NULL
+ * @comeback: A buffer holding the comeback token. Can be NULL
+ * @after: If comeback is set, defined the comeback time in seconds. -1 to not
+ * include the Comeback After field (frames from non-AP STA).
+ */
+void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
+ u8 wrapped_data_format,
+ struct wpabuf *pubkey,
+ struct wpabuf *comeback, int after)
+{
+ struct pasn_parameter_ie *params;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add PASN Parameters element");
+
+ params = wpabuf_put(buf, sizeof(*params));
+
+ params->id = WLAN_EID_EXTENSION;
+ params->len = sizeof(*params) - 2;
+ params->id_ext = WLAN_EID_EXT_PASN_PARAMS;
+ params->control = 0;
+ params->wrapped_data_format = wrapped_data_format;
+
+ if (comeback) {
+ wpa_printf(MSG_DEBUG, "PASN: Adding comeback data");
+
+ /*
+ * 2 octets for the 'after' field + 1 octet for the length +
+ * actual cookie data
+ */
+ if (after >= 0)
+ params->len += 2;
+ params->len += 1 + wpabuf_len(comeback);
+ params->control |= WPA_PASN_CTRL_COMEBACK_INFO_PRESENT;
+
+ if (after >= 0)
+ wpabuf_put_le16(buf, after);
+ wpabuf_put_u8(buf, wpabuf_len(comeback));
+ wpabuf_put_buf(buf, comeback);
+ }
+
+ if (pubkey) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Adding public key and group ID %u",
+ pasn_group);
+
+ /*
+ * 2 octets for the finite cyclic group + 2 octets public key
+ * length + the actual key
+ */
+ params->len += 2 + 1 + wpabuf_len(pubkey);
+ params->control |= WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT;
+
+ wpabuf_put_le16(buf, pasn_group);
+ wpabuf_put_u8(buf, wpabuf_len(pubkey));
+ wpabuf_put_buf(buf, pubkey);
+ }
+}
+
+/*
+ * wpa_pasn_add_wrapped_data - Add a Wrapped Data IE to PASN Authentication
+ * frame. If needed, the Wrapped Data IE would be fragmented.
+ *
+ * @buf: Buffer in which the IE will be added
+ * @wrapped_data_buf: Buffer holding the wrapped data
+ */
+int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
+ struct wpabuf *wrapped_data_buf)
+{
+ const u8 *data;
+ size_t data_len;
+ u8 len;
+
+ if (!wrapped_data_buf)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "PASN: Add wrapped data");
+
+ data = wpabuf_head_u8(wrapped_data_buf);
+ data_len = wpabuf_len(wrapped_data_buf);
+
+ /* nothing to add */
+ if (!data_len)
+ return 0;
+
+ if (data_len <= 254)
+ len = 1 + data_len;
+ else
+ len = 255;
+
+ if (wpabuf_tailroom(buf) < 3 + data_len)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf, len);
+ wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
+ wpabuf_put_data(buf, data, len - 1);
+
+ data += len - 1;
+ data_len -= len - 1;
+
+ while (data_len) {
+ if (wpabuf_tailroom(buf) < 1 + data_len)
+ return -1;
+ wpabuf_put_u8(buf, WLAN_EID_FRAGMENT);
+ len = data_len > 255 ? 255 : data_len;
+ wpabuf_put_u8(buf, len);
+ wpabuf_put_data(buf, data, len);
+ data += len;
+ data_len -= len;
+ }
+
+ return 0;
+}
+
+
+/*
+ * wpa_pasn_validate_rsne - Validate PSAN specific data of RSNE
+ * @data: Parsed representation of an RSNE
+ * Returns -1 for invalid data; otherwise 0
+ */
+int wpa_pasn_validate_rsne(const struct wpa_ie_data *data)
+{
+ u16 capab = WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR;
+
+ if (data->proto != WPA_PROTO_RSN)
+ return -1;
+
+ if ((data->capabilities & capab) != capab) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid RSNE capabilities");
+ return -1;
+ }
+
+ if (!data->has_group || data->group_cipher != WPA_CIPHER_GTK_NOT_USED) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid group data cipher");
+ return -1;
+ }
+
+ if (!data->has_pairwise || !data->pairwise_cipher ||
+ (data->pairwise_cipher & (data->pairwise_cipher - 1))) {
+ wpa_printf(MSG_DEBUG, "PASN: No valid pairwise suite");
+ return -1;
+ }
+
+ switch (data->key_mgmt) {
+#ifdef CONFIG_SAE
+ case WPA_KEY_MGMT_SAE:
+ /* fall through */
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ case WPA_KEY_MGMT_FILS_SHA256:
+ case WPA_KEY_MGMT_FILS_SHA384:
+ /* fall through */
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R
+ case WPA_KEY_MGMT_FT_PSK:
+ case WPA_KEY_MGMT_FT_IEEE8021X:
+ case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
+ /* fall through */
+#endif /* CONFIG_IEEE80211R */
+ case WPA_KEY_MGMT_PASN:
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "PASN: invalid key_mgmt: 0x%0x",
+ data->key_mgmt);
+ return -1;
+ }
+
+ if (data->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid group mgmt cipher");
+ return -1;
+ }
+
+ if (data->num_pmkid > 1) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid number of PMKIDs");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * wpa_pasn_parse_parameter_ie - Validates PASN Parameters IE
+ * @data: Pointer to the PASN Parameters IE (starting with the EID).
+ * @len: Length of the data in the PASN Parameters IE
+ * @from_ap: Whether this was received from an AP
+ * @pasn_params: On successful return would hold the parsed PASN parameters.
+ * Returns: -1 for invalid data; otherwise 0
+ *
+ * Note: On successful return, the pointers in &pasn_params point to the data in
+ * the IE and are not locally allocated (so they should not be freed etc.).
+ */
+int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
+ struct wpa_pasn_params_data *pasn_params)
+{
+ struct pasn_parameter_ie *params = (struct pasn_parameter_ie *) data;
+ const u8 *pos = (const u8 *) (params + 1);
+
+ if (!pasn_params) {
+ wpa_printf(MSG_DEBUG, "PASN: Invalid params");
+ return -1;
+ }
+
+ if (!params || ((size_t) (params->len + 2) < sizeof(*params)) ||
+ len < sizeof(*params) || params->len + 2 != len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid parameters IE. len=(%u, %u)",
+ params ? params->len : 0, len);
+ return -1;
+ }
+
+ os_memset(pasn_params, 0, sizeof(*pasn_params));
+
+ switch (params->wrapped_data_format) {
+ case WPA_PASN_WRAPPED_DATA_NO:
+ case WPA_PASN_WRAPPED_DATA_SAE:
+ case WPA_PASN_WRAPPED_DATA_FILS_SK:
+ case WPA_PASN_WRAPPED_DATA_FT:
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "PASN: Invalid wrapped data format");
+ return -1;
+ }
+
+ pasn_params->wrapped_data_format = params->wrapped_data_format;
+
+ len -= sizeof(*params);
+
+ if (params->control & WPA_PASN_CTRL_COMEBACK_INFO_PRESENT) {
+ if (from_ap) {
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE: Truncated Comeback After");
+ return -1;
+ }
+ pasn_params->after = WPA_GET_LE16(pos);
+ pos += 2;
+ len -= 2;
+ }
+
+ if (len < 1 || len < 1 + *pos) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE: comeback len");
+ return -1;
+ }
+
+ pasn_params->comeback_len = *pos++;
+ len--;
+ pasn_params->comeback = pos;
+ len -= pasn_params->comeback_len;
+ pos += pasn_params->comeback_len;
+ }
+
+ if (params->control & WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT) {
+ if (len < 3 || len < 3 + pos[2]) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE: group and key");
+ return -1;
+ }
+
+ pasn_params->group = WPA_GET_LE16(pos);
+ pos += 2;
+ len -= 2;
+ pasn_params->pubkey_len = *pos++;
+ len--;
+ pasn_params->pubkey = pos;
+ len -= pasn_params->pubkey_len;
+ pos += pasn_params->pubkey_len;
+ }
+
+ if (len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Invalid Parameters IE. Bytes left=%u", len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab)
+{
+ size_t flen;
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (!capab)
+ return; /* no supported extended RSN capabilities */
+ if (wpabuf_tailroom(buf) < 2 + flen)
+ return;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+ wpabuf_put_u8(buf, WLAN_EID_RSNX);
+ wpabuf_put_u8(buf, flen);
+ wpabuf_put_u8(buf, capab & 0x00ff);
+ capab >>= 8;
+ if (capab)
+ wpabuf_put_u8(buf, capab);
+}
+
+#endif /* CONFIG_PASN */
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 065dc71..0e9f252 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -19,6 +19,9 @@
#define WPA_KEY_RSC_LEN 8
#define WPA_GMK_LEN 32
#define WPA_GTK_MAX_LEN 32
+#define WPA_PASN_PMK_LEN 32
+#define WPA_PASN_MAX_MIC_LEN 24
+#define WPA_MAX_RSNXE_LEN 4
#define OWE_DH_GROUP 19
@@ -78,6 +81,9 @@ WPA_CIPHER_BIP_CMAC_256)
#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 16)
#define RSN_AUTH_KEY_MGMT_FT_FILS_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 17)
#define RSN_AUTH_KEY_MGMT_OWE RSN_SELECTOR(0x00, 0x0f, 0xac, 18)
+
+#define RSN_AUTH_KEY_MGMT_PASN RSN_SELECTOR(0x00, 0x0f, 0xac, 21)
+
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
#define RSN_AUTH_KEY_MGMT_DPP RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x02)
@@ -211,8 +217,11 @@ struct wpa_eapol_key {
#define WPA_KCK_MAX_LEN 32
#define WPA_KEK_MAX_LEN 64
#define WPA_TK_MAX_LEN 32
+#define WPA_KDK_MAX_LEN 32
#define FILS_ICK_MAX_LEN 48
#define FILS_FT_MAX_LEN 48
+#define WPA_PASN_KCK_LEN 32
+#define WPA_PASN_MIC_MAX_LEN 24
/**
* struct wpa_ptk - WPA Pairwise Transient Key
@@ -224,11 +233,13 @@ struct wpa_ptk {
u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
u8 kck2[WPA_KCK_MAX_LEN]; /* FT reasoc Key Confirmation Key (KCK2) */
u8 kek2[WPA_KEK_MAX_LEN]; /* FT reassoc Key Encryption Key (KEK2) */
+ u8 kdk[WPA_KDK_MAX_LEN]; /* Key Derivation Key */
size_t kck_len;
size_t kek_len;
size_t tk_len;
size_t kck2_len;
size_t kek2_len;
+ size_t kdk_len;
int installed; /* 1 if key has already been installed to driver */
};
@@ -378,7 +389,7 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
struct wpa_ptk *ptk, int akmp, int cipher,
- const u8 *z, size_t z_len);
+ const u8 *z, size_t z_len, size_t kdk_len);
int fils_rmsk_to_pmk(int akmp, const u8 *rmsk, size_t rmsk_len,
const u8 *snonce, const u8 *anonce, const u8 *dh_ss,
size_t dh_ss_len, u8 *pmk, size_t *pmk_len);
@@ -388,7 +399,7 @@ int fils_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const u8 *spa, const u8 *aa,
const u8 *snonce, const u8 *anonce, const u8 *dhss,
size_t dhss_len, struct wpa_ptk *ptk,
u8 *ick, size_t *ick_len, int akmp, int cipher,
- u8 *fils_ft, size_t *fils_ft_len);
+ u8 *fils_ft, size_t *fils_ft_len, size_t kdk_len);
int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
const u8 *g_sta, size_t g_sta_len,
@@ -419,7 +430,8 @@ int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len,
int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, const u8 *snonce,
const u8 *anonce, const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
- struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher,
+ size_t kdk_len);
#endif /* CONFIG_IEEE80211R */
struct wpa_ie_data {
@@ -507,6 +519,33 @@ struct wpa_ft_ies {
size_t rsnxe_len;
};
+/* IEEE P802.11az/D2.6 - 9.4.2.303 PASN Parameters element */
+#define WPA_PASN_CTRL_COMEBACK_INFO_PRESENT BIT(0)
+#define WPA_PASN_CTRL_GROUP_AND_KEY_PRESENT BIT(1)
+
+#define WPA_PASN_WRAPPED_DATA_NO 0
+#define WPA_PASN_WRAPPED_DATA_FT 1
+#define WPA_PASN_WRAPPED_DATA_FILS_SK 2
+#define WPA_PASN_WRAPPED_DATA_SAE 3
+
+struct pasn_parameter_ie {
+ u8 id;
+ u8 len;
+ u8 id_ext;
+ u8 control; /* WPA_PASN_CTRL_* */
+ u8 wrapped_data_format; /* WPA_PASN_WRAPPED_DATA_* */
+} STRUCT_PACKED;
+
+struct wpa_pasn_params_data {
+ u8 wrapped_data_format;
+ u16 after;
+ u8 comeback_len;
+ const u8 *comeback;
+ u16 group;
+ u8 pubkey_len;
+ const u8 *pubkey;
+};
+
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int use_sha384);
@@ -553,6 +592,8 @@ struct wpa_eapol_ie_parse {
size_t ext_supp_rates_len;
const u8 *ht_capabilities;
const u8 *vht_capabilities;
+ const u8 *he_capabilities;
+ size_t he_capab_len;
const u8 *supp_channels;
size_t supp_channels_len;
const u8 *supp_oper_classes;
@@ -591,4 +632,41 @@ int wpa_use_cmac(int akmp);
int wpa_use_aes_key_wrap(int akmp);
int fils_domain_name_hash(const char *domain, u8 *hash);
+int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
+ const u8 *spa, const u8 *bssid,
+ const u8 *dhss, size_t dhss_len,
+ struct wpa_ptk *ptk, int akmp, int cipher,
+ size_t kdk_len);
+
+u8 pasn_mic_len(int akmp, int cipher);
+
+int pasn_mic(const u8 *kck, int akmp, int cipher,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *data, size_t data_len,
+ const u8 *frame, size_t frame_len, u8 *mic);
+
+int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len,
+ u8 *hash);
+
+void wpa_pasn_build_auth_header(struct wpabuf *buf, const u8 *bssid,
+ const u8 *src, const u8 *dst,
+ u8 trans_seq, u16 status);
+
+int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid,
+ int akmp, int cipher);
+
+void wpa_pasn_add_parameter_ie(struct wpabuf *buf, u16 pasn_group,
+ u8 wrapped_data_format,
+ struct wpabuf *pubkey,
+ struct wpabuf *comeback, int after);
+
+int wpa_pasn_add_wrapped_data(struct wpabuf *buf,
+ struct wpabuf *wrapped_data_buf);
+
+int wpa_pasn_validate_rsne(const struct wpa_ie_data *data);
+int wpa_pasn_parse_parameter_ie(const u8 *data, u8 len, bool from_ap,
+ struct wpa_pasn_params_data *pasn_params);
+
+void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab);
+
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index acc2d6c..126a789 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -271,7 +271,7 @@ extern "C" {
#define P2P_EVENT_P2PS_PROVISION_DONE "P2PS-PROV-DONE "
#define INTERWORKING_AP "INTERWORKING-AP "
-#define INTERWORKING_BLACKLISTED "INTERWORKING-BLACKLISTED "
+#define INTERWORKING_EXCLUDED "INTERWORKING-BLACKLISTED "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED "
#define INTERWORKING_SELECTED "INTERWORKING-SELECTED "
@@ -404,10 +404,16 @@ extern "C" {
* frame=<saqueryreq/saqueryresp> error=<error string> */
#define OCV_FAILURE "OCV-FAILURE "
+/* Event triggered for received management frame */
+#define AP_MGMT_FRAME_RECEIVED "AP-MGMT-FRAME-RECEIVED "
+
#ifndef BIT
#define BIT(x) (1U << (x))
#endif
+/* PASN authentication status */
+#define PASN_AUTH_STATUS "PASN-AUTH-STATUS "
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index ef872c5..345a35e 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1045,6 +1045,8 @@ void * tls_init(const struct tls_config *conf)
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+ SSL_CTX_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+
#ifdef SSL_MODE_NO_AUTO_CHAIN
/* Number of deployed use cases assume the default OpenSSL behavior of
* auto chaining the local certificate is in use. BoringSSL removed this
@@ -4543,10 +4545,18 @@ struct wpabuf * tls_connection_decrypt(void *tls_ctx,
return NULL;
res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
if (res < 0) {
- tls_show_errors(MSG_INFO, __func__,
- "Decryption failed - SSL_read");
- wpabuf_free(buf);
- return NULL;
+ int err = SSL_get_error(conn->ssl, res);
+
+ if (err == SSL_ERROR_WANT_READ) {
+ wpa_printf(MSG_DEBUG,
+ "SSL: SSL_connect - want more data");
+ res = 0;
+ } else {
+ tls_show_errors(MSG_INFO, __func__,
+ "Decryption failed - SSL_read");
+ wpabuf_free(buf);
+ return NULL;
+ }
}
wpabuf_put(buf, res);
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index b8a7665..cf482bf 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -469,7 +469,7 @@ static int tls_connection_client_cert(struct tls_connection *conn,
if (client_cert_blob) {
if (wolfSSL_use_certificate_chain_buffer_format(
conn->ssl, client_cert_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
+ SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert DER blob failed");
return -1;
@@ -479,13 +479,13 @@ static int tls_connection_client_cert(struct tls_connection *conn,
}
if (client_cert) {
- if (wolfSSL_use_certificate_chain_file(conn->ssl,
- client_cert) < 0) {
+ if (wolfSSL_use_certificate_chain_file(
+ conn->ssl, client_cert) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert PEM file failed");
if (wolfSSL_use_certificate_chain_file_format(
conn->ssl, client_cert,
- SSL_FILETYPE_ASN1) < 0) {
+ SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert DER file failed");
return -1;
@@ -534,7 +534,7 @@ static int tls_connection_private_key(void *tls_ctx,
if (private_key_blob) {
if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
private_key_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
+ SSL_FILETYPE_ASN1) <= 0) {
wpa_printf(MSG_INFO,
"SSL: use private DER blob failed");
} else {
@@ -545,11 +545,11 @@ static int tls_connection_private_key(void *tls_ctx,
if (!ok && private_key) {
if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) < 0) {
+ SSL_FILETYPE_PEM) <= 0) {
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) <= 0)
{
wpa_printf(MSG_INFO,
"SSL: use private key DER file failed");
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 722e428..5b2c71c 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1264,14 +1264,14 @@ struct wpa_driver_ap_params {
*
* This parameter can be used to set a specific Beacon frame data rate
* for the BSS. The interpretation of this value depends on the
- * rate_type (legacy: in 100 kbps units, HT: HT-MCS, VHT: VHT-MCS). If
- * beacon_rate == 0 and rate_type == 0 (BEACON_RATE_LEGACY), the default
- * Beacon frame data rate is used.
+ * rate_type (legacy: in 100 kbps units, HT: HT-MCS, VHT: VHT-MCS,
+ * HE: HE-MCS). If beacon_rate == 0 and rate_type == 0
+ * (BEACON_RATE_LEGACY), the default Beacon frame data rate is used.
*/
unsigned int beacon_rate;
/**
- * beacon_rate_type: Beacon data rate type (legacy/HT/VHT)
+ * beacon_rate_type: Beacon data rate type (legacy/HT/VHT/HE)
*/
enum beacon_rate_type rate_type;
@@ -1483,19 +1483,36 @@ struct wpa_driver_ap_params {
const struct wpabuf *civic;
/**
- * he_spr - Whether Spatial Reuse is enabled
+ * he_spr_ctrl - Spatial Reuse control field of SPR element
*/
- int he_spr;
+ u8 he_spr_ctrl;
+
+ /**
+ * he_spr_non_srg_obss_pd_max_offset - Non-SRG Maximum TX power offset
+ */
+ u8 he_spr_non_srg_obss_pd_max_offset;
/**
* he_spr_srg_obss_pd_min_offset - Minimum TX power offset
*/
- int he_spr_srg_obss_pd_min_offset;
+ u8 he_spr_srg_obss_pd_min_offset;
/**
* he_spr_srg_obss_pd_max_offset - Maximum TX power offset
*/
- int he_spr_srg_obss_pd_max_offset;
+ u8 he_spr_srg_obss_pd_max_offset;
+
+ /**
+ * he_spr_bss_color_bitmap - BSS color values used by members of the
+ * SRG.
+ */
+ u8 he_spr_bss_color_bitmap[8];
+
+ /**
+ * he_spr_partial_bssid_bitmap - Partial BSSID values used by members
+ * of the SRG.
+ */
+ u8 he_spr_partial_bssid_bitmap[8];
/**
* he_bss_color - Whether the BSS Color is disabled
@@ -1524,6 +1541,41 @@ struct wpa_driver_ap_params {
* 2 = both hunting-and-pecking loop and hash-to-element enabled
*/
int sae_pwe;
+
+ /**
+ * FILS Discovery frame minimum interval in TUs
+ */
+ u32 fd_min_int;
+
+ /**
+ * FILS Discovery frame maximum interval in TUs (0 = FD frame disabled)
+ */
+ u32 fd_max_int;
+
+ /**
+ * FILS Discovery frame template data
+ */
+ u8 *fd_frame_tmpl;
+
+ /**
+ * FILS Discovery frame template length
+ */
+ size_t fd_frame_tmpl_len;
+
+ /**
+ * Unsolicited broadcast Probe Response interval in TUs
+ */
+ unsigned int unsol_bcast_probe_resp_interval;
+
+ /**
+ * Unsolicited broadcast Probe Response template data
+ */
+ u8 *unsol_bcast_probe_resp_tmpl;
+
+ /**
+ * Unsolicited broadcast Probe Response template length
+ */
+ size_t unsol_bcast_probe_resp_tmpl_len;
};
struct wpa_driver_mesh_bss_params {
@@ -1559,6 +1611,7 @@ struct wpa_driver_mesh_join_params {
#define WPA_DRIVER_MESH_FLAG_SAE_AUTH 0x00000004
#define WPA_DRIVER_MESH_FLAG_AMPE 0x00000008
unsigned int flags;
+ bool handle_dfs;
};
struct wpa_driver_set_key_params {
@@ -1949,6 +2002,23 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS2_CONTROL_PORT_RX 0x0000000000000001ULL
/** Driver supports TX status reports for EAPOL frames through control port */
#define WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS 0x0000000000000002ULL
+/** Driver supports secure LTF */
+#define WPA_DRIVER_FLAGS2_SEC_LTF 0x0000000000000004ULL
+/** Driver supports secure RTT measurement exchange */
+#define WPA_DRIVER_FLAGS2_SEC_RTT 0x0000000000000008ULL
+/**
+ * Driver supports protection of range negotiation and measurement management
+ * frames
+ */
+#define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG 0x0000000000000010ULL
+/** Driver supports Beacon frame TX rate configuration (HE rates) */
+#define WPA_DRIVER_FLAGS2_BEACON_RATE_HE 0x0000000000000020ULL
+/** Driver supports Beacon protection only in client mode */
+#define WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT 0x0000000000000040ULL
+/** Driver supports Operating Channel Validation */
+#define WPA_DRIVER_FLAGS2_OCV 0x0000000000000080ULL
+/** Driver expects user space implementation of SME in AP mode */
+#define WPA_DRIVER_FLAGS2_AP_SME 0x0000000000000100ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -4276,12 +4346,12 @@ struct wpa_driver_ops {
int (*do_acs)(void *priv, struct drv_acs_params *params);
/**
- * set_band - Notify driver of band selection
+ * set_band - Notify driver of band(s) selection
* @priv: Private driver interface data
- * @band: The selected band(s)
+ * @band_mask: The selected band(s) bit mask (from enum set_band)
* Returns 0 on success, -1 on failure
*/
- int (*set_band)(void *priv, enum set_band band);
+ int (*set_band)(void *priv, u32 band_mask);
/**
* get_pref_freq_list - Get preferred frequency list for an interface
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index a29d2c8..00d970a 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -16,7 +16,9 @@
#include "common/ieee802_11_defs.h"
#include "common/wpa_common.h"
+#include <ifaddrs.h>
#include <net/if.h>
+#include <net/if_dl.h>
#include <net/if_media.h>
#ifdef __NetBSD__
@@ -615,6 +617,108 @@ bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
return 0;
}
+#ifdef SO_RERROR
+static void
+bsd_route_overflow(int sock, void *ctx, struct bsd_driver_global *global)
+{
+ char event_buf[2048]; /* max size of a single route(4) msg */
+ int n;
+ struct ifaddrs *ifaddrs, *ifa;
+ struct bsd_driver_data *drv;
+ struct sockaddr_dl *sdl;
+ union wpa_event_data event;
+
+ /* We need to match the system state, so drain the route
+ * socket to avoid stale messages. */
+ do {
+ n = read(sock, event_buf, sizeof(event_buf));
+ } while (n != -1 || errno == ENOBUFS);
+
+ if (getifaddrs(&ifaddrs) == -1) {
+ wpa_printf(MSG_ERROR, "%s getifaddrs() failed: %s",
+ __func__, strerror(errno));
+ return;
+ }
+
+ /* add or update existing interfaces */
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ sdl = (struct sockaddr_dl *) (void *) ifa->ifa_addr;
+ drv = bsd_get_drvname(global, ifa->ifa_name);
+ if (drv != NULL &&
+ (drv->ifindex != sdl->sdl_index || drv->if_removed)) {
+ wpa_printf(MSG_DEBUG,
+ "RTM_IFANNOUNCE: Interface '%s' added",
+ drv->ifname);
+ drv->ifindex = sdl->sdl_index;
+ drv->if_removed = 0;
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ os_strlcpy(event.interface_status.ifname, ifa->ifa_name,
+ sizeof(event.interface_status.ifname));
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ if (!drv &&
+ (drv = bsd_get_drvindex(global, sdl->sdl_index)) != NULL) {
+ /* Driver name is invalid */
+ wpa_printf(MSG_DEBUG,
+ "RTM_IFANNOUNCE: Interface '%s' removed",
+ drv->ifname);
+ drv->if_removed = 1;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ os_strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ }
+
+ /* punt missing interfaces and update flags */
+ dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+ sdl = (struct sockaddr_dl *) (void *) ifa->ifa_addr;
+ if (os_strcmp(drv->ifname, ifa->ifa_name) == 0)
+ break;
+ }
+ if (ifa == NULL && !drv->if_removed) {
+ wpa_printf(MSG_DEBUG,
+ "RTM_IFANNOUNCE: Interface '%s' removed",
+ drv->ifname);
+ drv->if_removed = 1;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ os_strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
+ if (!ifa)
+ continue;
+
+ if ((ifa->ifa_flags & IFF_UP) == 0 &&
+ (drv->flags & IFF_UP) != 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+ NULL);
+ } else if ((ifa->ifa_flags & IFF_UP) != 0 &&
+ (drv->flags & IFF_UP) == 0) {
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+ drv->ifname);
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+ NULL);
+ }
+ drv->flags = ifa->ifa_flags;
+ }
+
+ freeifaddrs(ifaddrs);
+}
+#endif /* SO_RERROR */
+
static void
bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
{
@@ -635,6 +739,10 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
if (errno != EINTR && errno != EAGAIN)
wpa_printf(MSG_ERROR, "%s read() failed: %s",
__func__, strerror(errno));
+#ifdef SO_RERROR
+ if (errno == ENOBUFS)
+ bsd_route_overflow(sock, ctx, sock_ctx);
+#endif /* SO_RERROR */
return;
}
@@ -1568,14 +1676,15 @@ bsd_global_init(void *ctx)
global->ctx = ctx;
dl_list_init(&global->ifaces);
- global->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ global->sock = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (global->sock < 0) {
wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
strerror(errno));
goto fail1;
}
- global->route = socket(PF_ROUTE, SOCK_RAW, 0);
+ global->route = socket(PF_ROUTE,
+ SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (global->route < 0) {
wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s",
strerror(errno));
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 94bf982..8342eb8 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -467,8 +467,8 @@ static int send_and_recv(struct nl80211_global *global,
}
out:
nl_cb_put(cb);
- if (!valid_handler && valid_data == (void *) -1)
- nl80211_nlmsg_clear(msg);
+ /* Always clear the message as it can potentially contain keys */
+ nl80211_nlmsg_clear(msg);
nlmsg_free(msg);
return err;
}
@@ -675,6 +675,7 @@ struct wiphy_idx_data {
int wiphy_idx;
enum nl80211_iftype nlmode;
u8 *macaddr;
+ u8 use_4addr;
};
@@ -697,6 +698,9 @@ static int netdev_info_handler(struct nl_msg *msg, void *arg)
os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
ETH_ALEN);
+ if (tb[NL80211_ATTR_4ADDR])
+ info->use_4addr = nla_get_u8(tb[NL80211_ATTR_4ADDR]);
+
return NL_SKIP;
}
@@ -752,6 +756,21 @@ static int nl80211_get_macaddr(struct i802_bss *bss)
}
+static int nl80211_get_4addr(struct i802_bss *bss)
+{
+ struct nl_msg *msg;
+ struct wiphy_idx_data data = {
+ .use_4addr = 0,
+ };
+
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)) ||
+ send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data,
+ NULL, NULL))
+ return -1;
+ return data.use_4addr;
+}
+
+
static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
struct nl80211_wiphy_data *w)
{
@@ -2326,6 +2345,14 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
(u8 *) "\x03\x00", 2, false);
}
+#ifdef CONFIG_PASN
+ /* register for PASN Authentication frames */
+ if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ nl80211_register_frame(bss, bss->nl_mgmt, type,
+ (u8 *) "\x07\x00", 2, false))
+ ret = -1;
+#endif /* CONFIG_PASN */
+
#ifdef CONFIG_INTERWORKING
/* QoS Map Configure */
if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
@@ -2975,6 +3002,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
os_free(drv->filter_ssids);
os_free(drv->auth_ie);
+ os_free(drv->auth_data);
if (drv->in_interface_list)
dl_list_del(&drv->list);
@@ -2986,6 +3014,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
os_free(drv->iface_ext_capa[i].ext_capa_mask);
}
os_free(drv->first_bss);
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ os_free(drv->pending_roam_data);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
os_free(drv);
}
@@ -3133,7 +3164,7 @@ static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
nlmsg_free(msg);
return -1;
}
- ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
"nl80211: Key management set key failed: ret=%d (%s)",
@@ -3173,7 +3204,7 @@ static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv,
return -ENOBUFS;
}
- ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)",
ret, strerror(-ret));
@@ -3339,8 +3370,7 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss,
goto fail;
}
- ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL,
- NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
ret = 0;
if (ret)
@@ -3625,6 +3655,16 @@ static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
}
}
+ os_free(drv->auth_data);
+ drv->auth_data = NULL;
+ drv->auth_data_len = 0;
+ if (params->auth_data) {
+ drv->auth_data = os_memdup(params->auth_data,
+ params->auth_data_len);
+ if (drv->auth_data)
+ drv->auth_data_len = params->auth_data_len;
+ }
+
for (i = 0; i < 4; i++) {
if (params->wep_key[i] && params->wep_key_len[i] &&
params->wep_key_len[i] <= 16) {
@@ -3878,6 +3918,8 @@ int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
params.ie = drv->auth_ie;
params.ie_len = drv->auth_ie_len;
+ params.auth_data = drv->auth_data;
+ params.auth_data_len = drv->auth_data_len;
for (i = 0; i < 4; i++) {
if (drv->auth_wep_key_len[i]) {
@@ -3959,15 +4001,26 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
encrypt = 0;
}
- if (freq == 0 && drv->nlmode == NL80211_IFTYPE_STATION &&
- (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
- !(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+ if (is_sta_interface(drv->nlmode) &&
WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
- freq = nl80211_get_assoc_freq(drv);
- wpa_printf(MSG_DEBUG,
- "nl80211: send_mlme - Use assoc_freq=%u for external auth",
- freq);
+ if (freq == 0 &&
+ (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) &&
+ !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
+ freq = nl80211_get_assoc_freq(drv);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme - Use assoc_freq=%u for external auth",
+ freq);
+ }
+
+ /* Allow off channel for PASN authentication */
+ if (data_len >= IEEE80211_HDRLEN + 2 &&
+ WPA_GET_LE16(data + IEEE80211_HDRLEN) == WLAN_AUTH_PASN &&
+ !offchanok) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: send_mlme: allow off channel for PASN");
+ offchanok = 1;
+ }
}
if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
@@ -4163,11 +4216,12 @@ static int nl80211_set_mesh_config(void *priv,
#endif /* CONFIG_MESH */
-static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
+static int nl80211_put_beacon_rate(struct nl_msg *msg, u64 flags, u64 flags2,
struct wpa_driver_ap_params *params)
{
struct nlattr *bands, *band;
struct nl80211_txrate_vht vht_rate;
+ struct nl80211_txrate_he he_rate;
if (!params->freq ||
(params->beacon_rate == 0 &&
@@ -4184,7 +4238,10 @@ static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
band = nla_nest_start(msg, NL80211_BAND_2GHZ);
break;
case HOSTAPD_MODE_IEEE80211A:
- band = nla_nest_start(msg, NL80211_BAND_5GHZ);
+ if (is_6ghz_freq(params->freq->freq))
+ band = nla_nest_start(msg, NL80211_BAND_6GHZ);
+ else
+ band = nla_nest_start(msg, NL80211_BAND_5GHZ);
break;
case HOSTAPD_MODE_IEEE80211AD:
band = nla_nest_start(msg, NL80211_BAND_60GHZ);
@@ -4197,6 +4254,7 @@ static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
return -1;
os_memset(&vht_rate, 0, sizeof(vht_rate));
+ os_memset(&he_rate, 0, sizeof(he_rate));
switch (params->rate_type) {
case BEACON_RATE_LEGACY:
@@ -4249,6 +4307,22 @@ static int nl80211_put_beacon_rate(struct nl_msg *msg, const u64 flags,
wpa_printf(MSG_DEBUG, " * beacon_rate = VHT-MCS %u",
params->beacon_rate);
break;
+ case BEACON_RATE_HE:
+ if (!(flags2 & WPA_DRIVER_FLAGS2_BEACON_RATE_HE)) {
+ wpa_printf(MSG_INFO,
+ "nl80211: Driver does not support setting Beacon frame rate (HE)");
+ return -1;
+ }
+ he_rate.mcs[0] = BIT(params->beacon_rate);
+ if (nla_put(msg, NL80211_TXRATE_LEGACY, 0, NULL) ||
+ nla_put(msg, NL80211_TXRATE_HT, 0, NULL) ||
+ nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate),
+ &vht_rate) ||
+ nla_put(msg, NL80211_TXRATE_HE, sizeof(he_rate), &he_rate))
+ return -1;
+ wpa_printf(MSG_DEBUG, " * beacon_rate = HE-MCS %u",
+ params->beacon_rate);
+ break;
}
nla_nest_end(msg, band);
@@ -4328,6 +4402,69 @@ static int nl80211_put_sae_pwe(struct nl_msg *msg, int pwe)
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *attr;
+
+ if (!bss->drv->fils_discovery) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Driver does not support FILS Discovery frame transmission for %s",
+ bss->ifname);
+ return -1;
+ }
+
+ attr = nla_nest_start(msg, NL80211_ATTR_FILS_DISCOVERY);
+ if (!attr ||
+ nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
+ params->fd_min_int) ||
+ nla_put_u32(msg, NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
+ params->fd_max_int) ||
+ (params->fd_frame_tmpl &&
+ nla_put(msg, NL80211_FILS_DISCOVERY_ATTR_TMPL,
+ params->fd_frame_tmpl_len, params->fd_frame_tmpl)))
+ return -1;
+
+ nla_nest_end(msg, attr);
+ return 0;
+}
+#endif /* CONFIG_FILS */
+
+
+#ifdef CONFIG_IEEE80211AX
+static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss,
+ struct nl_msg *msg,
+ struct wpa_driver_ap_params *params)
+{
+ struct nlattr *attr;
+
+ if (!bss->drv->unsol_bcast_probe_resp) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Driver does not support unsolicited broadcast Probe Response frame transmission for %s",
+ bss->ifname);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Unsolicited broadcast Probe Response frame interval: %u",
+ params->unsol_bcast_probe_resp_interval);
+ attr = nla_nest_start(msg, NL80211_ATTR_UNSOL_BCAST_PROBE_RESP);
+ if (!attr ||
+ nla_put_u32(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT,
+ params->unsol_bcast_probe_resp_interval) ||
+ (params->unsol_bcast_probe_resp_tmpl &&
+ nla_put(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL,
+ params->unsol_bcast_probe_resp_tmpl_len,
+ params->unsol_bcast_probe_resp_tmpl)))
+ return -1;
+
+ nla_nest_end(msg, attr);
+ return 0;
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
static int wpa_driver_nl80211_set_ap(void *priv,
struct wpa_driver_ap_params *params)
{
@@ -4371,7 +4508,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
params->tail) ||
nl80211_put_beacon_int(msg, params->beacon_int) ||
- nl80211_put_beacon_rate(msg, drv->capa.flags, params) ||
+ nl80211_put_beacon_rate(msg, drv->capa.flags, drv->capa.flags2,
+ params) ||
nl80211_put_dtim_period(msg, params->dtim_period) ||
nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
goto fail;
@@ -4549,17 +4687,34 @@ static int wpa_driver_nl80211_set_ap(void *priv,
}
#ifdef CONFIG_IEEE80211AX
- if (params->he_spr) {
+ if (params->he_spr_ctrl) {
struct nlattr *spr;
spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD);
- wpa_printf(MSG_DEBUG, "nl80211: he_spr=%d", params->he_spr);
+ wpa_printf(MSG_DEBUG, "nl80211: he_spr_ctrl=0x%x",
+ params->he_spr_ctrl);
if (!spr ||
- nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
- params->he_spr_srg_obss_pd_min_offset) ||
- nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
- params->he_spr_srg_obss_pd_max_offset))
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_SR_CTRL,
+ params->he_spr_ctrl) ||
+ ((params->he_spr_ctrl &
+ SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) &&
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET,
+ params->he_spr_non_srg_obss_pd_max_offset)))
+ goto fail;
+
+ if ((params->he_spr_ctrl &
+ SPATIAL_REUSE_SRG_INFORMATION_PRESENT) &&
+ (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET,
+ params->he_spr_srg_obss_pd_min_offset) ||
+ nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET,
+ params->he_spr_srg_obss_pd_max_offset) ||
+ nla_put(msg, NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP,
+ sizeof(params->he_spr_bss_color_bitmap),
+ params->he_spr_bss_color_bitmap) ||
+ nla_put(msg, NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP,
+ sizeof(params->he_spr_partial_bssid_bitmap),
+ params->he_spr_partial_bssid_bitmap)))
goto fail;
nla_nest_end(msg, spr);
@@ -4586,6 +4741,10 @@ static int wpa_driver_nl80211_set_ap(void *priv,
if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER))
goto fail;
}
+
+ if (params->unsol_bcast_probe_resp_interval &&
+ nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0)
+ goto fail;
#endif /* CONFIG_IEEE80211AX */
#ifdef CONFIG_SAE
@@ -4595,6 +4754,11 @@ static int wpa_driver_nl80211_set_ap(void *priv,
goto fail;
#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ if (params->fd_max_int && nl80211_fils_discovery(bss, msg, params) < 0)
+ goto fail;
+#endif /* CONFIG_FILS */
+
ret = send_and_recv_msgs_owner(drv, msg, get_connect_handle(bss), 1,
NULL, NULL, NULL, NULL);
if (ret) {
@@ -4895,6 +5059,16 @@ static int wpa_driver_nl80211_sta_add(void *priv,
goto fail;
}
+ if (params->he_6ghz_capab) {
+ wpa_hexdump(MSG_DEBUG, " * he_6ghz_capab",
+ params->he_6ghz_capab,
+ sizeof(*params->he_6ghz_capab));
+ if (nla_put(msg, NL80211_ATTR_HE_6GHZ_CAPABILITY,
+ sizeof(*params->he_6ghz_capab),
+ params->he_6ghz_capab))
+ goto fail;
+ }
+
if (params->ext_capab) {
wpa_hexdump(MSG_DEBUG, " * ext_capab",
params->ext_capab, params->ext_capab_len);
@@ -5226,6 +5400,10 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
goto fail;
+ if ((addr && iftype == NL80211_IFTYPE_P2P_DEVICE) &&
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+ goto fail;
+
ret = send_and_recv_msgs(drv, msg, handler, arg, NULL, NULL);
msg = NULL;
if (ret) {
@@ -6181,12 +6359,15 @@ skip_auth_type:
goto fail;
ret = send_and_recv_msgs_owner(drv, msg, nl_connect, 1, NULL,
- (void *) -1, NULL, NULL);
+ NULL, NULL, NULL);
msg = NULL;
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
"(%s)", ret, strerror(-ret));
} else {
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ drv->roam_indication_done = false;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
wpa_printf(MSG_DEBUG,
"nl80211: Connect request send successfully");
}
@@ -7950,6 +8131,28 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss,
os_memset(bss->rand_addr, 0, ETH_ALEN);
}
+#ifdef CONFIG_MESH
+ if (is_mesh_interface(drv->nlmode)) {
+ struct hostapd_hw_modes *modes;
+ u16 num_modes, flags;
+ u8 dfs_domain;
+ int i;
+
+ modes = nl80211_get_hw_feature_data(bss, &num_modes,
+ &flags, &dfs_domain);
+ if (dfs_domain != HOSTAPD_DFS_REGION_ETSI &&
+ ieee80211_is_dfs(bss->freq, modes, num_modes))
+ offchanok = 0;
+ if (modes) {
+ for (i = 0; i < num_modes; i++) {
+ os_free(modes[i].channels);
+ os_free(modes[i].rates);
+ }
+ os_free(modes);
+ }
+ }
+#endif /* CONFIG_MESH */
+
if (is_ap_interface(drv->nlmode) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
(int) freq == bss->freq || drv->device_ap_sme ||
@@ -8506,7 +8709,7 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd,
return -ENOBUFS;
}
- return send_and_recv_msgs(bss->drv, msg, NULL, (void *) -1, NULL, NULL);
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL);
}
@@ -8776,7 +8979,7 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
nla_nest_end(msg, replay_nested);
- ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret == -EOPNOTSUPP) {
wpa_printf(MSG_DEBUG,
"nl80211: Driver does not support rekey offload");
@@ -10225,6 +10428,9 @@ static int nl80211_join_mesh(struct i802_bss *bss,
wpa_printf(MSG_DEBUG, " * flags=%08X", params->flags);
+ if (params->handle_dfs && nla_put_flag(msg, NL80211_ATTR_HANDLE_DFS))
+ goto fail;
+
container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
if (!container)
goto fail;
@@ -10770,38 +10976,49 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
}
-static int nl80211_set_band(void *priv, enum set_band band)
+static int nl80211_set_band(void *priv, u32 band_mask)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
struct nlattr *data;
int ret;
- enum qca_set_band qca_band;
+ enum qca_set_band qca_band_value;
+ u32 qca_band_mask = QCA_SETBAND_AUTO;
- if (!drv->setband_vendor_cmd_avail)
+ if (!drv->setband_vendor_cmd_avail ||
+ (band_mask > (WPA_SETBAND_2G | WPA_SETBAND_5G | WPA_SETBAND_6G)))
return -1;
- switch (band) {
- case WPA_SETBAND_AUTO:
- qca_band = QCA_SETBAND_AUTO;
- break;
- case WPA_SETBAND_5G:
- qca_band = QCA_SETBAND_5G;
- break;
- case WPA_SETBAND_2G:
- qca_band = QCA_SETBAND_2G;
- break;
- default:
- return -1;
- }
+ if (band_mask & WPA_SETBAND_5G)
+ qca_band_mask |= QCA_SETBAND_5G;
+ if (band_mask & WPA_SETBAND_2G)
+ qca_band_mask |= QCA_SETBAND_2G;
+ if (band_mask & WPA_SETBAND_6G)
+ qca_band_mask |= QCA_SETBAND_6G;
+
+ /*
+ * QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE is a legacy interface hence make
+ * it suite to its values (AUTO/5G/2G) for backwards compatibility.
+ */
+ qca_band_value = ((qca_band_mask & QCA_SETBAND_5G) &&
+ (qca_band_mask & QCA_SETBAND_2G)) ?
+ QCA_SETBAND_AUTO :
+ qca_band_mask & ~QCA_SETBAND_6G;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: QCA_BAND_MASK = 0x%x, QCA_BAND_VALUE = %d",
+ qca_band_mask, qca_band_value);
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
!(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
- nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) {
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE,
+ qca_band_value) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK,
+ qca_band_mask)) {
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -11432,6 +11649,10 @@ static int nl80211_configure_data_frame_filters(void *priv, u32 filter_flags)
char path[128];
int ret;
+ /* P2P-Device has no netdev that can (or should) be configured here */
+ if (nl80211_get_ifmode(bss) == NL80211_IFTYPE_P2P_DEVICE)
+ return 0;
+
wpa_printf(MSG_DEBUG, "nl80211: Data frame filter flags=0x%x",
filter_flags);
@@ -11657,6 +11878,11 @@ static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname,
ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
msg = NULL;
+ if (ret && val && nl80211_get_4addr(bss) == 1) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: 4addr mode was already enabled");
+ ret = 0;
+ }
if (!ret) {
if (bridge_ifname[0] && val &&
i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0)
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 4009545..940d82c 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -175,6 +175,8 @@ struct wpa_driver_nl80211_data {
unsigned int multicast_registrations:1;
unsigned int no_rrm:1;
unsigned int get_sta_info_vendor_cmd_avail:1;
+ unsigned int fils_discovery:1;
+ unsigned int unsol_bcast_probe_resp:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
@@ -209,6 +211,8 @@ struct wpa_driver_nl80211_data {
int auth_alg;
u8 *auth_ie;
size_t auth_ie_len;
+ u8 *auth_data;
+ size_t auth_data_len;
u8 auth_wep_key[4][16];
size_t auth_wep_key_len[4];
int auth_wep_tx_keyidx;
@@ -221,6 +225,12 @@ struct wpa_driver_nl80211_data {
* (NL80211_CMD_VENDOR). 0 if no pending scan request.
*/
int last_scan_cmd;
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ bool roam_indication_done;
+ u8 *pending_roam_data;
+ size_t pending_roam_data_len;
+ struct os_reltime pending_roam_ind_time;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
};
struct nl_msg;
@@ -289,6 +299,10 @@ int android_pno_start(struct i802_bss *bss,
int android_pno_stop(struct i802_bss *bss);
extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
size_t buf_len);
+extern int wpa_driver_nl80211_driver_event(struct wpa_driver_nl80211_data *drv,
+ u32 vendor_id, u32 subcmd,
+ u8 *data, size_t len);
+
#ifdef ANDROID_P2P
int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 6c2ab51..1b57c0e 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -559,6 +559,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
capa->flags |= WPA_DRIVER_FLAGS_BEACON_RATE_VHT;
if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_RATE_HE))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_BEACON_RATE_HE;
+
+ if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_SET_SCAN_DWELL))
capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL;
@@ -644,6 +648,22 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS))
info->drv->multicast_registrations = 1;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_FILS_DISCOVERY))
+ info->drv->fils_discovery = 1;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP))
+ info->drv->unsol_bcast_probe_resp = 1;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_OCV;
}
@@ -1370,6 +1390,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
if (!info.device_ap_sme) {
drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_AP_SME;
/*
* No AP SME is currently assumed to also indicate no AP MLME
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index f75f7b3..c971001 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -571,6 +571,13 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
event.assoc_info.fils_pmkid = nla_data(fils_pmkid);
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+
+ /* Avoid a race condition by stopping to ignore any following
+ * disconnection events now that the driver has indicated it is
+ * connected since that connection could have been triggered by a roam
+ * operation that happened in parallel with the disconnection request.
+ */
+ drv->ignore_next_local_disconnect = 0;
}
@@ -1376,7 +1383,6 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
enum nl80211_cqm_rssi_threshold_event event;
union wpa_event_data ed;
- struct wpa_signal_info sig;
int res;
if (tb[NL80211_ATTR_CQM] == NULL ||
@@ -1443,19 +1449,27 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
return;
}
- res = nl80211_get_link_signal(drv, &sig);
+ /*
+ * nl80211_get_link_signal() and nl80211_get_link_noise() set default
+ * values in case querying the driver fails.
+ */
+ res = nl80211_get_link_signal(drv, &ed.signal_change);
if (res == 0) {
- ed.signal_change.current_signal = sig.current_signal;
- ed.signal_change.current_txrate = sig.current_txrate;
wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d",
- sig.current_signal, sig.current_txrate);
+ ed.signal_change.current_signal,
+ ed.signal_change.current_txrate);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Querying the driver for signal info failed");
}
- res = nl80211_get_link_noise(drv, &sig);
+ res = nl80211_get_link_noise(drv, &ed.signal_change);
if (res == 0) {
- ed.signal_change.current_noise = sig.current_noise;
wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
- sig.current_noise);
+ ed.signal_change.current_noise);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Querying the driver for noise info failed");
}
wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
@@ -1930,7 +1944,7 @@ try_2_4_or_5:
return 2407 + 5 * chan;
if (chan == 14)
return 2484;
- if (chan >= 36 && chan <= 169)
+ if (chan >= 36 && chan <= 177)
return 5000 + 5 * chan;
return 0;
@@ -2058,6 +2072,27 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
}
+static void
+qca_nl80211_key_mgmt_auth_handler(struct wpa_driver_nl80211_data *drv,
+ const u8 *data, size_t len)
+{
+ if (!drv->roam_indication_done) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Pending roam indication, delay processing roam+auth vendor event");
+ os_get_reltime(&drv->pending_roam_ind_time);
+
+ os_free(drv->pending_roam_data);
+ drv->pending_roam_data = os_memdup(data, len);
+ if (!drv->pending_roam_data)
+ return;
+ drv->pending_roam_data_len = len;
+ return;
+ }
+ drv->roam_indication_done = false;
+ qca_nl80211_key_mgmt_auth(drv, data, len);
+}
+
+
static void qca_nl80211_dfs_offload_radar_event(
struct wpa_driver_nl80211_data *drv, u32 subcmd, u8 *msg, int length)
{
@@ -2315,7 +2350,7 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
qca_nl80211_avoid_freq(drv, data, len);
break;
case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
- qca_nl80211_key_mgmt_auth(drv, data, len);
+ qca_nl80211_key_mgmt_auth_handler(drv, data, len);
break;
case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
qca_nl80211_acs_select_ch(drv, data, len);
@@ -2380,6 +2415,12 @@ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
return;
}
+#ifdef ANDROID
+#ifdef ANDROID_LIB_EVENT
+ wpa_driver_nl80211_driver_event(drv, vendor_id, subcmd, data, len);
+#endif /* ANDROID_LIB_EVENT */
+#endif /* ANDROID */
+
switch (vendor_id) {
case OUI_QCA:
nl80211_vendor_event_qca(drv, subcmd, data, len);
@@ -2707,17 +2748,36 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
cmd, nl80211_command_to_string(cmd), bss->ifname);
+#ifdef CONFIG_DRIVER_NL80211_QCA
if (cmd == NL80211_CMD_ROAM &&
(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+ if (drv->pending_roam_data) {
+ struct os_reltime now, age;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &drv->pending_roam_ind_time, &age);
+ if (age.sec == 0 && age.usec < 100000) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Process pending roam+auth vendor event");
+ qca_nl80211_key_mgmt_auth(
+ drv, drv->pending_roam_data,
+ drv->pending_roam_data_len);
+ }
+ os_free(drv->pending_roam_data);
+ drv->pending_roam_data = NULL;
+ return;
+ }
/*
* Device will use roam+auth vendor event to indicate
* roaming, so ignore the regular roam event.
*/
+ drv->roam_indication_done = true;
wpa_printf(MSG_DEBUG,
"nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth",
cmd);
return;
}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
(cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 3e0d4a0..ac78da9 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1178,6 +1178,10 @@
* includes the contents of the frame. %NL80211_ATTR_ACK flag is included
* if the recipient acknowledged the frame.
*
+ * @NL80211_CMD_SET_SAR_SPECS: SAR power limitation configuration is
+ * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
+ * specify the wiphy index to be applied to.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1408,6 +1412,8 @@ enum nl80211_commands {
NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS,
+ NL80211_CMD_SET_SAR_SPECS,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1957,8 +1963,15 @@ enum nl80211_commands {
* @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
* probe-response frame. The DA field in the 802.11 header is zero-ed out,
* to be filled by the FW.
- * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable
- * this feature. Currently, only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_HT: Force HT capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_VHT: Force VHT capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_HE: Force HE capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
* @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the
* ATTR_HT_CAPABILITY to which attention should be paid.
* Currently, only mac80211 NICs support this feature.
@@ -2079,7 +2092,8 @@ enum nl80211_commands {
* until the channel switch event.
* @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission
* must be blocked on the current channel (before the channel switch
- * operation).
+ * operation). Also included in the channel switch started event if quiet
+ * was requested by the AP.
* @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information
* for the time while performing a channel switch.
* @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel
@@ -2534,6 +2548,15 @@ enum nl80211_commands {
* This is a u8 attribute that encapsulates one of the values from
* &enum nl80211_sae_pwe_mechanism.
*
+ * @NL80211_ATTR_SAR_SPEC: SAR power limitation specification when
+ * used with %NL80211_CMD_SET_SAR_SPECS. The message contains fields
+ * of %nl80211_sar_attrs which specifies the sar type and related
+ * sar specs. Sar specs contains array of %nl80211_sar_specs_attrs.
+ *
+ * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and
+ * disassoc events to indicate that an immediate reconnect to the AP
+ * is desired.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3025,6 +3048,12 @@ enum nl80211_attrs {
NL80211_ATTR_SAE_PWE,
+ NL80211_ATTR_RECONNECT_REQUESTED,
+
+ NL80211_ATTR_SAR_SPEC,
+
+ NL80211_ATTR_DISABLE_HE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -7156,4 +7185,96 @@ enum nl80211_sae_pwe_mechanism {
NL80211_SAE_PWE_HASH_TO_ELEMENT,
NL80211_SAE_PWE_BOTH,
};
+
+/**
+ * enum nl80211_sar_type - type of SAR specs
+ *
+ * @NL80211_SAR_TYPE_POWER: power limitation specified in 0.25dBm unit
+ *
+ */
+enum nl80211_sar_type {
+ NL80211_SAR_TYPE_POWER,
+
+ /* add new type here */
+
+ /* Keep last */
+ NUM_NL80211_SAR_TYPE,
+};
+
+/**
+ * enum nl80211_sar_attrs - Attributes for SAR spec
+ *
+ * @NL80211_SAR_ATTR_TYPE: the SAR type as defined in &enum nl80211_sar_type.
+ *
+ * @NL80211_SAR_ATTR_SPECS: Nested array of SAR power
+ * limit specifications. Each specification contains a set
+ * of %nl80211_sar_specs_attrs.
+ *
+ * For SET operation, it contains array of %NL80211_SAR_ATTR_SPECS_POWER
+ * and %NL80211_SAR_ATTR_SPECS_RANGE_INDEX.
+ *
+ * For sar_capa dump, it contains array of
+ * %NL80211_SAR_ATTR_SPECS_START_FREQ
+ * and %NL80211_SAR_ATTR_SPECS_END_FREQ.
+ *
+ * @__NL80211_SAR_ATTR_LAST: Internal
+ * @NL80211_SAR_ATTR_MAX: highest sar attribute
+ *
+ * These attributes are used with %NL80211_CMD_SET_SAR_SPEC
+ */
+enum nl80211_sar_attrs {
+ __NL80211_SAR_ATTR_INVALID,
+
+ NL80211_SAR_ATTR_TYPE,
+ NL80211_SAR_ATTR_SPECS,
+
+ __NL80211_SAR_ATTR_LAST,
+ NL80211_SAR_ATTR_MAX = __NL80211_SAR_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_sar_specs_attrs - Attributes for SAR power limit specs
+ *
+ * @NL80211_SAR_ATTR_SPECS_POWER: Required (s32)value to specify the actual
+ * power limit value in units of 0.25 dBm if type is
+ * NL80211_SAR_TYPE_POWER. (i.e., a value of 44 represents 11 dBm).
+ * 0 means userspace doesn't have SAR limitation on this associated range.
+ *
+ * @NL80211_SAR_ATTR_SPECS_RANGE_INDEX: Required (u32) value to specify the
+ * index of exported freq range table and the associated power limitation
+ * is applied to this range.
+ *
+ * Userspace isn't required to set all the ranges advertised by WLAN driver,
+ * and userspace can skip some certain ranges. These skipped ranges don't
+ * have SAR limitations, and they are same as setting the
+ * %NL80211_SAR_ATTR_SPECS_POWER to any unreasonable high value because any
+ * value higher than regulatory allowed value just means SAR power
+ * limitation is removed, but it's required to set at least one range.
+ * It's not allowed to set duplicated range in one SET operation.
+ *
+ * Every SET operation overwrites previous SET operation.
+ *
+ * @NL80211_SAR_ATTR_SPECS_START_FREQ: Required (u32) value to specify the start
+ * frequency of this range edge when registering SAR capability to wiphy.
+ * It's not a channel center frequency. The unit is kHz.
+ *
+ * @NL80211_SAR_ATTR_SPECS_END_FREQ: Required (u32) value to specify the end
+ * frequency of this range edge when registering SAR capability to wiphy.
+ * It's not a channel center frequency. The unit is kHz.
+ *
+ * @__NL80211_SAR_ATTR_SPECS_LAST: Internal
+ * @NL80211_SAR_ATTR_SPECS_MAX: highest sar specs attribute
+ */
+enum nl80211_sar_specs_attrs {
+ __NL80211_SAR_ATTR_SPECS_INVALID,
+
+ NL80211_SAR_ATTR_SPECS_POWER,
+ NL80211_SAR_ATTR_SPECS_RANGE_INDEX,
+ NL80211_SAR_ATTR_SPECS_START_FREQ,
+ NL80211_SAR_ATTR_SPECS_END_FREQ,
+
+ __NL80211_SAR_ATTR_SPECS_LAST,
+ NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index e57461a..8c475f1 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -442,19 +442,28 @@ static int eap_aka_learn_ids(struct eap_sm *sm, struct eap_aka_data *data,
static int eap_aka_add_id_msg(struct eap_aka_data *data,
- const struct wpabuf *msg)
+ const struct wpabuf *msg1,
+ const struct wpabuf *msg2)
{
- if (msg == NULL)
+ size_t len;
+
+ if (!msg1)
return -1;
+ len = wpabuf_len(msg1);
+ if (msg2)
+ len += wpabuf_len(msg2);
- if (data->id_msgs == NULL) {
- data->id_msgs = wpabuf_dup(msg);
- return data->id_msgs == NULL ? -1 : 0;
+ if (!data->id_msgs) {
+ data->id_msgs = wpabuf_alloc(len);
+ if (!data->id_msgs)
+ return -1;
+ } else if (wpabuf_resize(&data->id_msgs, len) < 0) {
+ return -1;
}
- if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
- return -1;
- wpabuf_put_buf(data->id_msgs, msg);
+ wpabuf_put_buf(data->id_msgs, msg1);
+ if (msg2)
+ wpabuf_put_buf(data->id_msgs, msg2);
return 0;
}
@@ -799,8 +808,13 @@ static struct wpabuf * eap_aka_process_identity(struct eap_sm *sm,
buf = eap_aka_response_identity(sm, data, id, attr->id_req);
if (data->prev_id != id) {
- eap_aka_add_id_msg(data, reqData);
- eap_aka_add_id_msg(data, buf);
+ if (eap_aka_add_id_msg(data, reqData, buf) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-AKA: Failed to store ID messages");
+ wpabuf_free(buf);
+ return eap_aka_client_error(
+ data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
data->prev_id = id;
}
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 7c37043..12e30df 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -803,6 +803,10 @@ static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
if (res)
return res;
+ if (wpabuf_len(in_decrypted) == 0) {
+ wpabuf_free(in_decrypted);
+ return 1;
+ }
continue_req:
wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
@@ -1081,7 +1085,11 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
}
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- char *label;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
+
wpa_printf(MSG_DEBUG,
"EAP-PEAP: TLS done, proceed to Phase 2");
eap_peap_free_key(data);
@@ -1091,16 +1099,25 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
* PEAPv1 implementations seem to be using the old
* label, "client EAP encryption", instead. Use the old
* label by default, but allow it to be configured with
- * phase1 parameter peaplabel=1. */
- if (data->force_new_label)
+ * phase1 parameter peaplabel=1.
+ *
+ * When using TLS 1.3, draft-ietf-emu-tls-eap-types
+ * defines a new set of label and context parameters.
+ */
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else if (data->force_new_label) {
label = "client PEAP encryption";
- else
+ } else {
label = "client EAP encryption";
+ }
wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
"key derivation", label);
data->key_data =
eap_peer_tls_derive_key(sm, &data->ssl, label,
- NULL, 0,
+ context, context_len,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (data->key_data) {
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index ad079a7..0d479f1 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -302,15 +302,11 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
return NULL;
}
- if (res == 2) {
- /* Application data included in the handshake message (used by
- * EAP-TLS 1.3 to indicate conclusion of the exchange). */
- wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Received Application Data",
- resp);
- wpa_hexdump_buf(MSG_DEBUG, "EAP-TLS: Remaining tls_out data",
- data->ssl.tls_out);
+ /* draft-ietf-emu-eap-tls13-13 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");
eap_peer_tls_reset_output(&data->ssl);
- /* Send an ACK to allow the server to complete exchange */
res = 1;
}
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index ab10678..c1837db 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -413,9 +413,9 @@ u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
struct tls_random keys;
u8 *out;
- if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ if (data->tls_v13) {
u8 *id, *method_id;
- const u8 context[] = { EAP_TYPE_TLS };
+ const u8 context[] = { eap_type };
/* Session-Id = <EAP-Type> || Method-Id
* Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 642d179..c401915 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -268,10 +268,22 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
static int eap_ttls_v0_derive_key(struct eap_sm *sm,
struct eap_ttls_data *data)
{
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
+
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ label = "ttls keying material";
+ }
+
eap_ttls_free_key(data);
- data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
- "ttls keying material",
- NULL, 0,
+ data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label,
+ context, context_len,
EAP_TLS_KEY_LEN +
EAP_EMSK_LEN);
if (!data->key_data) {
@@ -1441,6 +1453,7 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
if ((in_data == NULL || wpabuf_len(in_data) == 0) &&
data->phase2_start) {
+start:
return eap_ttls_phase2_start(sm, data, ret, identifier,
out_data);
}
@@ -1455,6 +1468,20 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
if (retval)
goto done;
+ if (wpabuf_len(in_decrypted) == 0) {
+ wpabuf_free(in_decrypted);
+ goto start;
+ }
+
+ /* draft-ietf-emu-eap-tls13-13 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_peer_tls_reset_output(&data->ssl);
+ wpabuf_free(in_decrypted);
+ return 1;
+ }
continue_req:
data->phase2_start = 0;
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index f234f6f..f526e8b 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -325,13 +325,27 @@ static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
u8 *tk;
u8 isk[32], imck[60];
int res;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
+
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ /* TODO: PEAPv1 - different label in some cases */
+ label = "client EAP encryption";
+ }
/*
* Tunnel key (TK) is the first 60 octets of the key generated by
* phase 1 of PEAP (based on TLS).
*/
- tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
- NULL, 0, EAP_TLS_KEY_LEN);
+ tk = eap_server_tls_derive_key(sm, &data->ssl, label,
+ context, context_len,
+ EAP_TLS_KEY_LEN);
if (tk == NULL)
return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
@@ -498,7 +512,25 @@ static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
os_free(hdr);
- return encr_req;
+ if (!data->ssl.tls_v13 ||
+ !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn)) {
+ wpabuf_free(data->ssl.tls_out);
+ data->ssl.tls_out_pos = 0;
+ return encr_req;
+ }
+
+ if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr_req)) < 0) {
+ wpa_printf(MSG_INFO,
+ "EAP-PEAP: Failed to resize output buffer");
+ wpabuf_free(encr_req);
+ return NULL;
+ }
+ wpabuf_put_buf(data->ssl.tls_out, encr_req);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-PEAP: Data appended to the message", encr_req);
+ os_free(encr_req);
+
+ return data->ssl.tls_out;
}
@@ -547,8 +579,6 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
break;
case SUCCESS_REQ:
- wpabuf_free(data->ssl.tls_out);
- data->ssl.tls_out_pos = 0;
data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
1);
break;
@@ -1300,6 +1330,10 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
u8 *eapKeyData;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
@@ -1332,9 +1366,17 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
return eapKeyData;
}
- /* TODO: PEAPv1 - different label in some cases */
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ /* TODO: PEAPv1 - different label in some cases */
+ label = "client EAP encryption";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption", NULL, 0,
+ label, context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
@@ -1353,6 +1395,10 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_peap_data *data = priv;
u8 *eapKeyData, *emsk;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
@@ -1362,9 +1408,17 @@ static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
return NULL;
}
- /* TODO: PEAPv1 - different label in some cases */
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ /* TODO: PEAPv1 - different label in some cases */
+ label = "client EAP encryption";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "client EAP encryption", NULL, 0,
+ label, context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_memdup(eapKeyData + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 769fd1f..00a496f 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -266,39 +266,6 @@ static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
eap_tls_state(data, FAILURE);
return;
}
-
- if (data->ssl.tls_v13 &&
- tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn)) {
- struct wpabuf *plain, *encr;
-
- wpa_printf(MSG_DEBUG,
- "EAP-TLS: Send empty application data to indicate end of exchange");
- /* FIX: This should be an empty application data based on
- * draft-ietf-emu-eap-tls13-05, but OpenSSL does not allow zero
- * length payload (SSL_write() documentation explicitly
- * describes this as not allowed), so work around that for now
- * by sending out a payload of one octet. Hopefully the draft
- * specification will change to allow this so that no crypto
- * library changes are needed. */
- plain = wpabuf_alloc(1);
- if (!plain)
- return;
- wpabuf_put_u8(plain, 0);
- encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
- wpabuf_free(plain);
- if (!encr)
- return;
- if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
- wpa_printf(MSG_INFO,
- "EAP-TLS: Failed to resize output buffer");
- wpabuf_free(encr);
- return;
- }
- wpabuf_put_buf(data->ssl.tls_out, encr);
- wpa_hexdump_buf(MSG_DEBUG,
- "EAP-TLS: Data appended to the message", encr);
- wpabuf_free(encr);
- }
}
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index b38f1e0..a9b53b1 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -146,10 +146,10 @@ u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
{
struct tls_random keys;
u8 *out;
- const u8 context[] = { EAP_TYPE_TLS };
- if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
+ if (data->tls_v13) {
u8 *id, *method_id;
+ const u8 context[] = { eap_type };
/* Session-Id = <EAP-Type> || Method-Id
* Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
@@ -366,6 +366,56 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
sm->serial_num = tls_connection_peer_serial_num(
sm->cfg->ssl_ctx, data->conn);
+ /*
+ * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#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
+ * even on resumption.
+ */
+ if (data->tls_v13 &&
+ tls_connection_established(sm->cfg->ssl_ctx, data->conn)) {
+ struct wpabuf *plain, *encr;
+
+ switch (sm->currentMethod) {
+ case EAP_TYPE_PEAP:
+ break;
+ default:
+ if (!tls_connection_resumed(sm->cfg->ssl_ctx,
+ data->conn))
+ break;
+ /* fallthrough */
+ case EAP_TYPE_TLS:
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Send Commitment Message");
+
+ plain = wpabuf_alloc(1);
+ if (!plain)
+ return -1;
+ wpabuf_put_u8(plain, 0);
+ encr = eap_server_tls_encrypt(sm, data, plain);
+ wpabuf_free(plain);
+ if (!encr)
+ return -1;
+ if (wpabuf_resize(&data->tls_out, wpabuf_len(encr)) < 0)
+ {
+ wpa_printf(MSG_INFO,
+ "EAP-TLS: Failed to resize output buffer");
+ wpabuf_free(encr);
+ return -1;
+ }
+ wpabuf_put_buf(data->tls_out, encr);
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-TLS: Data appended to the message",
+ encr);
+ wpabuf_free(encr);
+ }
+ }
+
return 0;
}
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 2f0c041..b893522 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -1271,13 +1271,25 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_ttls_data *data = priv;
u8 *eapKeyData;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ label = "ttls keying material";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material", NULL, 0,
- EAP_TLS_KEY_LEN);
+ label, context, context_len,
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
*len = EAP_TLS_KEY_LEN;
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
@@ -1313,12 +1325,24 @@ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_ttls_data *data = priv;
u8 *eapKeyData, *emsk;
+ const char *label;
+ const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
+ const u8 *context = NULL;
+ size_t context_len = 0;
if (data->state != SUCCESS)
return NULL;
+ if (data->ssl.tls_v13) {
+ label = "EXPORTER_EAP_TLS_Key_Material";
+ context = eap_tls13_context;
+ context_len = sizeof(eap_tls13_context);
+ } else {
+ label = "ttls keying material";
+ }
+
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
- "ttls keying material", NULL, 0,
+ label, context, context_len,
EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
if (eapKeyData) {
emsk = os_malloc(EAP_EMSK_LEN);
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 6b92a6d..81bb937 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -428,7 +428,9 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p,
oldest = dev;
}
if (count + 1 > p2p->cfg->max_peers && oldest) {
- p2p_dbg(p2p, "Remove oldest peer entry to make room for a new peer");
+ p2p_dbg(p2p,
+ "Remove oldest peer entry to make room for a new peer "
+ MACSTR, MAC2STR(oldest->info.p2p_device_addr));
dl_list_del(&oldest->list);
p2p_device_free(p2p, oldest);
}
@@ -453,6 +455,8 @@ static void p2p_copy_client_info(struct p2p_device *dev,
dev->info.config_methods = cli->config_methods;
os_memcpy(dev->info.pri_dev_type, cli->pri_dev_type, 8);
dev->info.wps_sec_dev_type_list_len = 8 * cli->num_sec_dev_types;
+ if (dev->info.wps_sec_dev_type_list_len > WPS_SEC_DEV_TYPE_MAX_LEN)
+ dev->info.wps_sec_dev_type_list_len = WPS_SEC_DEV_TYPE_MAX_LEN;
os_memcpy(dev->info.wps_sec_dev_type_list, cli->sec_dev_types,
dev->info.wps_sec_dev_type_list_len);
}
@@ -663,6 +667,8 @@ static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies,
if (wpabuf_resize(&dev->info.vendor_elems, 2 + len) < 0)
break;
wpabuf_put_data(dev->info.vendor_elems, pos - 2, 2 + len);
+ if (wpabuf_size(dev->info.vendor_elems) > 2000)
+ break;
}
}
@@ -3510,12 +3516,17 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
}
-void p2p_scan_res_handled(struct p2p_data *p2p)
+void p2p_scan_res_handled(struct p2p_data *p2p, unsigned int delay)
{
if (!p2p->p2p_scan_running) {
p2p_dbg(p2p, "p2p_scan was not running, but scan results received");
}
p2p->p2p_scan_running = 0;
+
+ /* Use this delay only when p2p_find doesn't set it */
+ if (!p2p->search_delay)
+ p2p->search_delay = delay;
+
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
if (p2p_run_after_scan(p2p))
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index ed8beab..762bd40 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1625,6 +1625,7 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
/**
* p2p_scan_res_handled - Indicate end of scan results
* @p2p: P2P module context from p2p_init()
+ * @delay: Search delay for next scan in ms
*
* This function is called to indicate that all P2P scan results from a scan
* have been reported with zero or more calls to p2p_scan_res_handler(). This
@@ -1632,7 +1633,7 @@ int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
* struct p2p_config::p2p_scan() call if none of the p2p_scan_res_handler()
* calls stopped iteration.
*/
-void p2p_scan_res_handled(struct p2p_data *p2p);
+void p2p_scan_res_handled(struct p2p_data *p2p, unsigned int delay);
enum p2p_send_action_result {
P2P_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */,
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 3994ec0..05fd593 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -595,14 +595,12 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
goto out;
}
+ dev = p2p_get_device(p2p, sa);
if (!dev) {
- dev = p2p_get_device(p2p, sa);
- if (!dev) {
- p2p_dbg(p2p,
- "Provision Discovery device not found "
- MACSTR, MAC2STR(sa));
- goto out;
- }
+ p2p_dbg(p2p,
+ "Provision Discovery device not found "
+ MACSTR, MAC2STR(sa));
+ goto out;
}
} else if (msg.wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 630c0f9..fb81481 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -225,6 +225,9 @@ struct radius_msg;
/* Default size to be allocated for attribute array */
#define RADIUS_DEFAULT_ATTR_COUNT 16
+/* Maximum message length for incoming RADIUS messages, as stated in RFC 2865
+ * Section 3 ("Packet Format").*/
+#define RADIUS_MAX_MSG_LEN 4096
/* MAC address ASCII format for IEEE 802.1X use
* (draft-congdon-radius-8021x-20.txt) */
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 2b7a604..bfcb944 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -816,7 +816,9 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
struct hostapd_radius_servers *conf = radius->conf;
RadiusType msg_type = (RadiusType) sock_ctx;
int len, roundtrip;
- unsigned char buf[3000];
+ unsigned char buf[RADIUS_MAX_MSG_LEN];
+ struct msghdr msghdr = {0};
+ struct iovec iov;
struct radius_msg *msg;
struct radius_hdr *hdr;
struct radius_rx_handler *handlers;
@@ -836,15 +838,22 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
rconf = conf->auth_server;
}
- len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
+ iov.iov_base = buf;
+ iov.iov_len = RADIUS_MAX_MSG_LEN;
+ msghdr.msg_iov = &iov;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_flags = 0;
+ len = recvmsg(sock, &msghdr, MSG_DONTWAIT);
if (len < 0) {
- wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
+ wpa_printf(MSG_INFO, "recvmsg[RADIUS]: %s", strerror(errno));
return;
}
+
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
"server", len);
- if (len == sizeof(buf)) {
+
+ if (msghdr.msg_flags & MSG_TRUNC) {
wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
return;
}
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 971fe91..e02c215 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -35,11 +35,6 @@
*/
#define RADIUS_MAX_SESSION 1000
-/**
- * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages
- */
-#define RADIUS_MAX_MSG_LEN 3000
-
static const struct eapol_callbacks radius_server_eapol_cb;
struct radius_client;
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 7c4ef19..af69268 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -136,6 +136,8 @@ struct wpa_tdls_peer {
struct ieee80211_ht_capabilities *ht_capabilities;
struct ieee80211_vht_capabilities *vht_capabilities;
+ struct ieee80211_he_capabilities *he_capabilities;
+ size_t he_capab_len;
u8 qos_info;
@@ -703,6 +705,8 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
peer->ht_capabilities = NULL;
os_free(peer->vht_capabilities);
peer->vht_capabilities = NULL;
+ os_free(peer->he_capabilities);
+ peer->he_capabilities = NULL;
os_free(peer->ext_capab);
peer->ext_capab = NULL;
os_free(peer->supp_channels);
@@ -1652,6 +1656,29 @@ static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde,
}
+static int copy_peer_he_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->he_capabilities) {
+ wpa_printf(MSG_DEBUG, "TDLS: No HE capabilities received");
+ return 0;
+ }
+
+ os_free(peer->he_capabilities);
+ peer->he_capab_len = 0;
+ peer->he_capabilities = os_memdup(kde->he_capabilities,
+ kde->he_capab_len);
+ if (!peer->he_capabilities)
+ return -1;
+
+ peer->he_capab_len = kde->he_capab_len;
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer HE capabilities",
+ peer->he_capabilities, peer->he_capab_len);
+
+ return 0;
+}
+
+
static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde,
struct wpa_tdls_peer *peer)
{
@@ -1761,6 +1788,8 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
peer->supp_rates, peer->supp_rates_len,
peer->ht_capabilities,
peer->vht_capabilities,
+ peer->he_capabilities,
+ peer->he_capab_len,
peer->qos_info, peer->wmm_capable,
peer->ext_capab, peer->ext_capab_len,
peer->supp_channels,
@@ -1896,7 +1925,8 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
if (copy_peer_ht_capab(&kde, peer) < 0)
goto error;
- if (copy_peer_vht_capab(&kde, peer) < 0)
+ if (copy_peer_vht_capab(&kde, peer) < 0 ||
+ copy_peer_he_capab(&kde, peer) < 0)
goto error;
if (copy_peer_ext_capab(&kde, peer) < 0)
@@ -1925,7 +1955,8 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
"TDLS setup - send own request");
peer->initiator = 1;
wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
- NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0);
+ NULL, NULL, 0, 0, 0, NULL, 0, NULL, 0,
+ NULL, 0);
if (wpa_tdls_send_tpk_m1(sm, peer) == -2) {
peer = NULL;
goto error;
@@ -2303,7 +2334,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
if (copy_peer_ht_capab(&kde, peer) < 0)
goto error;
- if (copy_peer_vht_capab(&kde, peer) < 0)
+ if (copy_peer_vht_capab(&kde, peer) < 0 ||
+ copy_peer_he_capab(&kde, peer) < 0)
goto error;
if (copy_peer_ext_capab(&kde, peer) < 0)
@@ -2690,7 +2722,8 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
/* add the peer to the driver as a "setup in progress" peer */
if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
- NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0)) {
+ NULL, NULL, 0, 0, 0, NULL, 0, NULL, 0,
+ NULL, 0)) {
wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index e07527b..9a5ba7b 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -579,7 +579,7 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
const u8 *z = NULL;
- size_t z_len = 0;
+ size_t z_len = 0, kdk_len;
int akmp;
#ifdef CONFIG_IEEE80211R
@@ -603,10 +603,19 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
akmp |= WPA_KEY_MGMT_PSK_SHA256;
}
#endif /* CONFIG_OWE */
+
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 &&
+ sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
sm->own_addr, sm->bssid, sm->snonce,
key->key_nonce, ptk, akmp,
- sm->pairwise_cipher, z, z_len);
+ sm->pairwise_cipher, z, z_len,
+ kdk_len);
}
@@ -948,6 +957,9 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
return -1;
}
+ wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
+
/* TK is not needed anymore in supplicant */
os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
sm->ptk.tk_len = 0;
@@ -1306,7 +1318,8 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
{
size_t len;
- if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
+ if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) ||
+ sm->mgmt_group_cipher == WPA_CIPHER_GTK_NOT_USED)
return 0;
if (ie->igtk) {
@@ -1559,11 +1572,12 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
return -1;
}
- if ((sm->ap_rsnxe && !ie->rsnxe) ||
- (!sm->ap_rsnxe && ie->rsnxe) ||
- (sm->ap_rsnxe && ie->rsnxe &&
- (sm->ap_rsnxe_len != ie->rsnxe_len ||
- os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0))) {
+ if (sm->proto == WPA_PROTO_RSN &&
+ ((sm->ap_rsnxe && !ie->rsnxe) ||
+ (!sm->ap_rsnxe && ie->rsnxe) ||
+ (sm->ap_rsnxe && ie->rsnxe &&
+ (sm->ap_rsnxe_len != ie->rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0)))) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp",
@@ -1665,6 +1679,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
if (ie.igtk &&
+ sm->mgmt_group_cipher != WPA_CIPHER_GTK_NOT_USED &&
wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
ie.igtk_len != WPA_IGTK_KDE_PREFIX_LEN +
(unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) {
@@ -3182,6 +3197,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->p2p = config->p2p;
sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation;
sm->owe_ptk_workaround = config->owe_ptk_workaround;
+ sm->force_kdk_derivation = config->force_kdk_derivation;
#ifdef CONFIG_FILS
if (config->fils_cache_id) {
sm->fils_cache_id_set = 1;
@@ -3204,6 +3220,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->wpa_rsc_relaxation = 0;
sm->owe_ptk_workaround = 0;
sm->beacon_prot = 0;
+ sm->force_kdk_derivation = false;
}
}
@@ -3781,6 +3798,16 @@ int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
}
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,
+ const u8 *aa,
+ const u8 *pmkid,
+ const void *network_ctx,
+ int akmp)
+{
+ return pmksa_cache_get(sm->pmksa, aa, pmkid, network_ctx, akmp);
+}
+
+
void wpa_sm_drop_sa(struct wpa_sm *sm)
{
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
@@ -3801,6 +3828,11 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
sm->pmk_r0_len = 0;
os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
sm->pmk_r1_len = 0;
+#ifdef CONFIG_PASN
+ os_free(sm->pasn_r1kh);
+ sm->pasn_r1kh = NULL;
+ sm->n_pasn_r1kh = 0;
+#endif /* CONFIG_PASN */
#endif /* CONFIG_IEEE80211R */
}
@@ -4111,7 +4143,7 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
const u8 *g_sta = NULL;
size_t g_sta_len = 0;
const u8 *g_ap = NULL;
- size_t g_ap_len = 0;
+ size_t g_ap_len = 0, kdk_len;
struct wpabuf *pub = NULL;
os_memcpy(sm->bssid, bssid, ETH_ALEN);
@@ -4339,13 +4371,21 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data,
goto fail;
}
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 &&
+ sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
if (fils_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, sm->bssid,
sm->fils_nonce, sm->fils_anonce,
dh_ss ? wpabuf_head(dh_ss) : NULL,
dh_ss ? wpabuf_len(dh_ss) : 0,
&sm->ptk, ick, &ick_len,
sm->key_mgmt, sm->pairwise_cipher,
- sm->fils_ft, &sm->fils_ft_len) < 0) {
+ sm->fils_ft, &sm->fils_ft_len,
+ kdk_len) < 0) {
wpa_printf(MSG_DEBUG, "FILS: Failed to derive PTK");
goto fail;
}
@@ -4900,6 +4940,9 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
goto fail;
}
+ wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
+
/* TODO: TK could be cleared after auth frame exchange now that driver
* takes care of association frame encryption/decryption. */
/* TK is not needed anymore in supplicant */
@@ -5172,3 +5215,14 @@ void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z)
}
}
#endif /* CONFIG_DPP2 */
+
+
+#ifdef CONFIG_PASN
+void wpa_pasn_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid, const u8 *bssid, int key_mgmt)
+{
+ sm->cur_pmksa = pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0,
+ bssid, sm->own_addr, NULL,
+ key_mgmt, 0);
+}
+#endif /* CONFIG_PASN */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 2142772..f377acb 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -69,6 +69,8 @@ struct wpa_sm_ctx {
size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
+ const struct ieee80211_he_capabilities *he_capab,
+ size_t he_capab_len,
u8 qosinfo, int wmm, const u8 *ext_capab,
size_t ext_capab_len, const u8 *supp_channels,
size_t supp_channels_len,
@@ -87,6 +89,8 @@ struct wpa_sm_ctx {
const u8 *pkt, size_t pkt_len);
int (*channel_info)(void *ctx, struct wpa_channel_info *ci);
void (*transition_disable)(void *ctx, u8 bitmap);
+ void (*store_ptk)(void *ctx, u8 *addr, int cipher,
+ u32 life_time, const struct wpa_ptk *ptk);
};
@@ -130,6 +134,7 @@ struct rsn_supp_config {
int owe_ptk_workaround;
const u8 *fils_cache_id;
int beacon_prot;
+ bool force_kdk_derivation;
};
#ifndef CONFIG_NO_WPA
@@ -189,6 +194,11 @@ void wpa_sm_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid,
const void *network_ctx);
void wpa_sm_drop_sa(struct wpa_sm *sm);
+struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm,
+ const u8 *aa,
+ const u8 *pmkid,
+ const void *network_ctx,
+ int akmp);
int wpa_sm_has_ptk(struct wpa_sm *sm);
int wpa_sm_has_ptk_installed(struct wpa_sm *sm);
@@ -365,6 +375,13 @@ static inline void wpa_sm_drop_sa(struct wpa_sm *sm)
{
}
+static inline struct rsn_pmksa_cache_entry *
+wpa_sm_pmksa_cache_get(struct wpa_sm *sm, const u8 *aa, const u8 *pmkid,
+ const void *network_ctx, int akmp)
+{
+ return NULL;
+}
+
static inline int wpa_sm_has_ptk(struct wpa_sm *sm)
{
return 0;
@@ -415,6 +432,13 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
const u8 *mdie);
+#ifdef CONFIG_PASN
+
+int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *r1kh_id,
+ u8 *pmk_r1, size_t *pmk_r1_len, u8 *pmk_r1_name);
+
+#endif /* CONFIG_PASN */
+
#else /* CONFIG_IEEE80211R */
static inline int
@@ -458,6 +482,16 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
return -1;
}
+#ifdef CONFIG_PASN
+
+int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *r1kh_id,
+ u8 *pmk_r1, size_t *pmk_r1_len, u8 *pmk_r1_name)
+{
+ return -1;
+}
+
+#endif /* CONFIG_PASN */
+
#endif /* CONFIG_IEEE80211R */
@@ -506,5 +540,7 @@ int owe_process_assoc_resp(struct wpa_sm *sm, const u8 *bssid,
void wpa_sm_set_reset_fils_completed(struct wpa_sm *sm, int set);
void wpa_sm_set_fils_cache_id(struct wpa_sm *sm, const u8 *fils_cache_id);
void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z);
+void wpa_pasn_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid, const u8 *bssid, int key_mgmt);
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index bf73376..c26f1a5 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -24,6 +24,15 @@
#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_PASN
+static void wpa_ft_pasn_store_r1kh(struct wpa_sm *sm, const u8 *bssid);
+#else /* CONFIG_PASN */
+static void wpa_ft_pasn_store_r1kh(struct wpa_sm *sm, const u8 *bssid)
+{
+}
+#endif /* CONFIG_PASN */
+
+
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
@@ -31,7 +40,7 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const u8 *anonce = key->key_nonce;
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *mpmk;
- size_t mpmk_len;
+ size_t mpmk_len, kdk_len;
if (sm->xxkey_len > 0) {
mpmk = sm->xxkey;
@@ -56,9 +65,20 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
sm->r1kh_id, sm->own_addr, sm->pmk_r1,
sm->pmk_r1_name) < 0)
return -1;
+
+ wpa_ft_pasn_store_r1kh(sm, src_addr);
+
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 &&
+ sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce,
sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk,
- ptk_name, sm->key_mgmt, sm->pairwise_cipher);
+ ptk_name, sm->key_mgmt, sm->pairwise_cipher,
+ kdk_len);
}
@@ -448,6 +468,8 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
return -1;
}
+ wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
+ sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
return 0;
}
@@ -524,7 +546,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ret;
const u8 *bssid;
const u8 *kck;
- size_t kck_len;
+ size_t kck_len, kdk_len;
int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt);
const u8 *anonce, *snonce;
@@ -646,10 +668,21 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_len = sm->pmk_r0_len;
bssid = target_ap;
+
+ wpa_ft_pasn_store_r1kh(sm, bssid);
+
+ if (sm->force_kdk_derivation ||
+ (sm->secure_ltf && sm->ap_rsnxe && sm->ap_rsnxe_len >= 4 &&
+ sm->ap_rsnxe[3] & BIT(WLAN_RSNX_CAPAB_SECURE_LTF - 8)))
+ kdk_len = WPA_KDK_MAX_LEN;
+ else
+ kdk_len = 0;
+
if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce,
anonce, sm->own_addr, bssid,
sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt,
- sm->pairwise_cipher) < 0)
+ sm->pairwise_cipher,
+ kdk_len) < 0)
return -1;
if (wpa_key_mgmt_fils(sm->key_mgmt)) {
@@ -1238,4 +1271,88 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
return 0;
}
+
+#ifdef CONFIG_PASN
+
+static struct pasn_ft_r1kh * wpa_ft_pasn_get_r1kh(struct wpa_sm *sm,
+ const u8 *bssid)
+{
+ size_t i;
+
+ for (i = 0; i < sm->n_pasn_r1kh; i++)
+ if (os_memcmp(sm->pasn_r1kh[i].bssid, bssid, ETH_ALEN) == 0)
+ return &sm->pasn_r1kh[i];
+
+ return NULL;
+}
+
+
+static void wpa_ft_pasn_store_r1kh(struct wpa_sm *sm, const u8 *bssid)
+{
+ struct pasn_ft_r1kh *tmp = wpa_ft_pasn_get_r1kh(sm, bssid);
+
+ if (tmp)
+ return;
+
+ tmp = os_realloc_array(sm->pasn_r1kh, sm->n_pasn_r1kh + 1,
+ sizeof(*tmp));
+ if (!tmp) {
+ wpa_printf(MSG_DEBUG, "PASN: FT: Failed to store R1KH");
+ return;
+ }
+
+ sm->pasn_r1kh = tmp;
+ tmp = &sm->pasn_r1kh[sm->n_pasn_r1kh];
+
+ wpa_printf(MSG_DEBUG, "PASN: FT: Store R1KH for " MACSTR,
+ MAC2STR(bssid));
+
+ os_memcpy(tmp->bssid, bssid, ETH_ALEN);
+ os_memcpy(tmp->r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN);
+
+ sm->n_pasn_r1kh++;
+}
+
+
+int wpa_pasn_ft_derive_pmk_r1(struct wpa_sm *sm, int akmp, const u8 *bssid,
+ u8 *pmk_r1, size_t *pmk_r1_len, u8 *pmk_r1_name)
+{
+ struct pasn_ft_r1kh *r1kh_entry;
+
+ if (sm->key_mgmt != (unsigned int) akmp) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Key management mismatch: %u != %u",
+ sm->key_mgmt, akmp);
+ return -1;
+ }
+
+ r1kh_entry = wpa_ft_pasn_get_r1kh(sm, bssid);
+ if (!r1kh_entry) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Cannot find R1KH-ID for " MACSTR,
+ MAC2STR(bssid));
+ return -1;
+ }
+
+ /*
+ * Note: PMK R0 etc. were already derived and are maintained by the
+ * state machine, and as the same key hierarchy is used, there is no
+ * need to derive them again, so only derive PMK R1 etc.
+ */
+ if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name,
+ r1kh_entry->r1kh_id, sm->own_addr, pmk_r1,
+ pmk_r1_name) < 0)
+ return -1;
+
+ *pmk_r1_len = sm->pmk_r0_len;
+
+ wpa_hexdump_key(MSG_DEBUG, "PASN: FT: PMK-R1", pmk_r1, sm->pmk_r0_len);
+ wpa_hexdump(MSG_DEBUG, "PASN: FT: PMKR1Name", pmk_r1_name,
+ WPA_PMK_NAME_LEN);
+
+ return 0;
+}
+
+#endif /* CONFIG_PASN */
+
#endif /* CONFIG_IEEE80211R */
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 96b07fc..e7281bf 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -14,6 +14,11 @@
struct wpa_tdls_peer;
struct wpa_eapol_key;
+struct pasn_ft_r1kh {
+ u8 bssid[ETH_ALEN];
+ u8 r1kh_id[FT_R1KH_ID_LEN];
+};
+
/**
* struct wpa_sm - Internal WPA state machine data
*/
@@ -73,6 +78,12 @@ struct wpa_sm {
* to be used */
int keyidx_active; /* Key ID for the active TK */
+ /*
+ * If set Key Derivation Key should be derived as part of PMK to
+ * PTK derivation regardless of advertised capabilities.
+ */
+ bool force_kdk_derivation;
+
u8 own_addr[ETH_ALEN];
const char *ifname;
const char *bridge_ifname;
@@ -95,7 +106,11 @@ struct wpa_sm {
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
int ocv; /* Operating Channel Validation */
int sae_pwe; /* SAE PWE generation options */
- int sae_pk; /* whether SAE-PK is used */
+
+ unsigned int sae_pk:1; /* whether SAE-PK is used */
+ unsigned int secure_ltf:1;
+ unsigned int secure_rtt:1;
+ unsigned int prot_range_neg:1;
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
@@ -146,6 +161,17 @@ struct wpa_sm {
u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */
u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
size_t assoc_resp_ies_len;
+#ifdef CONFIG_PASN
+ /*
+ * Currently, the WPA state machine stores the PMK-R1, PMK-R1-Name and
+ * R1KH-ID only for the current association. As PMK-R1 is required to
+ * perform PASN authentication with FT, store the R1KH-ID for previous
+ * associations, which would later be used to derive the PMK-R1 as part
+ * of the PASN authentication flow.
+ */
+ struct pasn_ft_r1kh *pasn_r1kh;
+ unsigned int n_pasn_r1kh;
+#endif /* CONFIG_PASN */
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_P2P
@@ -372,6 +398,8 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
size_t supp_rates_len,
const struct ieee80211_ht_capabilities *ht_capab,
const struct ieee80211_vht_capabilities *vht_capab,
+ const struct ieee80211_he_capabilities *he_capab,
+ size_t he_capab_len,
u8 qosinfo, int wmm, const u8 *ext_capab,
size_t ext_capab_len, const u8 *supp_channels,
size_t supp_channels_len, const u8 *supp_oper_classes,
@@ -381,7 +409,9 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
aid, capability, supp_rates,
supp_rates_len, ht_capab,
- vht_capab, qosinfo, wmm,
+ vht_capab,
+ he_capab, he_capab_len,
+ qosinfo, wmm,
ext_capab, ext_capab_len,
supp_channels,
supp_channels_len,
@@ -441,6 +471,14 @@ static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap)
sm->ctx->transition_disable(sm->ctx->ctx, bitmap);
}
+static inline void wpa_sm_store_ptk(struct wpa_sm *sm,
+ u8 *addr, int cipher,
+ u32 life_time, struct wpa_ptk *ptk)
+{
+ if (sm->ctx->store_ptk)
+ sm->ctx->store_ptk(sm->ctx->ctx, addr, cipher, life_time,
+ ptk);
+}
int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 20fdd69..3ba722f 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -354,25 +354,38 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
{
u8 *pos = rsnxe;
+ u16 capab = 0;
+ size_t flen;
- if (!wpa_key_mgmt_sae(sm->key_mgmt))
- return 0; /* SAE not in use */
- if (sm->sae_pwe != 1 && sm->sae_pwe != 2 && !sm->sae_pk)
- return 0; /* no supported extended RSN capabilities */
+ if (wpa_key_mgmt_sae(sm->key_mgmt) &&
+ (sm->sae_pwe == 1 || sm->sae_pwe == 2 || sm->sae_pk)) {
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+#ifdef CONFIG_SAE_PK
+ if (sm->sae_pk)
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
+#endif /* CONFIG_SAE_PK */
+ }
- if (rsnxe_len < 3)
+ if (sm->secure_ltf)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (sm->secure_rtt)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (sm->prot_range_neg)
+ capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
+
+ flen = (capab & 0xff00) ? 2 : 1;
+ if (!capab)
+ return 0; /* no supported extended RSN capabilities */
+ if (rsnxe_len < 2 + flen)
return -1;
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
*pos++ = WLAN_EID_RSNX;
- *pos++ = 1;
- /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
- * used for now */
- *pos = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
-#ifdef CONFIG_SAE_PK
- if (sm->sae_pk)
- *pos |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
-#endif /* CONFIG_SAE_PK */
- pos++;
+ *pos++ = flen;
+ *pos++ = capab & 0x00ff;
+ capab >>= 8;
+ if (capab)
+ *pos++ = capab;
return pos - rsnxe;
}
diff --git a/src/utils/Makefile b/src/utils/Makefile
index e8ad997..d995b81 100644
--- a/src/utils/Makefile
+++ b/src/utils/Makefile
@@ -6,6 +6,7 @@ LIB_OBJS= \
base64.o \
bitfield.o \
common.o \
+ config.o \
crc32.o \
ip_addr.o \
json.o \
diff --git a/src/utils/config.c b/src/utils/config.c
new file mode 100644
index 0000000..22aa221
--- /dev/null
+++ b/src/utils/config.c
@@ -0,0 +1,97 @@
+/*
+ * Configuration parsing
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/config.h"
+#include "common.h"
+
+
+static int newline_terminated(const char *buf, size_t buflen)
+{
+ size_t len = os_strlen(buf);
+ if (len == 0)
+ return 0;
+ if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
+ buf[len - 1] != '\n')
+ return 0;
+ return 1;
+}
+
+
+static void skip_line_end(FILE *stream)
+{
+ char buf[100];
+ while (fgets(buf, sizeof(buf), stream)) {
+ buf[sizeof(buf) - 1] = '\0';
+ if (newline_terminated(buf, sizeof(buf)))
+ return;
+ }
+}
+
+
+char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
+ char **_pos)
+{
+ char *pos, *end, *sstart;
+
+ while (fgets(s, size, stream)) {
+ (*line)++;
+ s[size - 1] = '\0';
+ if (!newline_terminated(s, size)) {
+ /*
+ * The line was truncated - skip rest of it to avoid
+ * confusing error messages.
+ */
+ wpa_printf(MSG_INFO, "Long line in configuration file "
+ "truncated");
+ skip_line_end(stream);
+ }
+ pos = s;
+
+ /* Skip white space from the beginning of line. */
+ while (*pos == ' ' || *pos == '\t' || *pos == '\r')
+ pos++;
+
+ /* Skip comment lines and empty lines */
+ if (*pos == '#' || *pos == '\n' || *pos == '\0')
+ continue;
+
+ /*
+ * Remove # comments unless they are within a double quoted
+ * string.
+ */
+ sstart = os_strchr(pos, '"');
+ if (sstart)
+ sstart = os_strrchr(sstart + 1, '"');
+ if (!sstart)
+ sstart = pos;
+ end = os_strchr(sstart, '#');
+ if (end)
+ *end-- = '\0';
+ else
+ end = pos + os_strlen(pos) - 1;
+
+ /* Remove trailing white space. */
+ while (end > pos &&
+ (*end == '\n' || *end == ' ' || *end == '\t' ||
+ *end == '\r'))
+ *end-- = '\0';
+
+ if (*pos == '\0')
+ continue;
+
+ if (_pos)
+ *_pos = pos;
+ return pos;
+ }
+
+ if (_pos)
+ *_pos = NULL;
+ return NULL;
+}
diff --git a/src/utils/config.h b/src/utils/config.h
new file mode 100644
index 0000000..074a88a
--- /dev/null
+++ b/src/utils/config.h
@@ -0,0 +1,29 @@
+/*
+ * Configuration parsing
+ * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef UTILS_CONFIG_H
+#define UTILS_CONFIG_H
+
+/**
+ * wpa_config_get_line - Read the next configuration file line
+ * @s: Buffer for the line
+ * @size: The buffer length
+ * @stream: File stream to read from
+ * @line: Pointer to a variable storing the file line number
+ * @_pos: Buffer for the pointer to the beginning of data on the text line or
+ * %NULL if not needed (returned value used instead)
+ * Returns: Pointer to the beginning of data on the text line or %NULL if no
+ * more text lines are available.
+ *
+ * This function reads the next non-empty line from the configuration file and
+ * removes comments. The returned string is guaranteed to be null-terminated.
+ */
+char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
+ char **_pos);
+
+#endif /* UTILS_CONFIG_H */
diff --git a/src/utils/ext_password.c b/src/utils/ext_password.c
index 5615bd7..cbf92de 100644
--- a/src/utils/ext_password.c
+++ b/src/utils/ext_password.c
@@ -20,6 +20,9 @@ static const struct ext_password_backend *backends[] = {
#ifdef CONFIG_EXT_PASSWORD_TEST
&ext_password_test,
#endif /* CONFIG_EXT_PASSWORD_TEST */
+#ifdef CONFIG_EXT_PASSWORD_FILE
+ &ext_password_file,
+#endif /* CONFIG_EXT_PASSWORD_FILE */
NULL
};
diff --git a/src/utils/ext_password_file.c b/src/utils/ext_password_file.c
new file mode 100644
index 0000000..4bb0095
--- /dev/null
+++ b/src/utils/ext_password_file.c
@@ -0,0 +1,136 @@
+/*
+ * External backend for file-backed passwords
+ * Copyright (c) 2021, Patrick Steinhardt <ps@pks.im>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "utils/config.h"
+#include "ext_password_i.h"
+
+
+/**
+ * Data structure for the file-backed password backend.
+ */
+struct ext_password_file_data {
+ char *path; /* path of the password file */
+};
+
+
+/**
+ * ext_password_file_init - Initialize file-backed password backend
+ * @params: Parameters passed by the user.
+ * Returns: Pointer to the initialized backend.
+ *
+ * This function initializes a new file-backed password backend. The user is
+ * expected to initialize this backend with the parameters being the path of
+ * the file that contains the passwords.
+ */
+static void * ext_password_file_init(const char *params)
+{
+ struct ext_password_file_data *data;
+
+ if (!params) {
+ wpa_printf(MSG_ERROR, "EXT PW FILE: no path given");
+ return NULL;
+ }
+
+ data = os_zalloc(sizeof(*data));
+ if (!data)
+ return NULL;
+
+ data->path = os_strdup(params);
+ if (!data->path) {
+ os_free(data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+/**
+ * ext_password_file_deinit - Deinitialize file-backed password backend
+ * @ctx: The file-backed password backend
+ *
+ * This function frees all data associated with the file-backed password
+ * backend.
+ */
+static void ext_password_file_deinit(void *ctx)
+{
+ struct ext_password_file_data *data = ctx;
+
+ str_clear_free(data->path);
+ os_free(data);
+}
+
+/**
+ * ext_password_file_get - Retrieve password from the file-backed password backend
+ * @ctx: The file-backed password backend
+ * @name: Name of the password to retrieve
+ * Returns: Buffer containing the password if one was found or %NULL.
+ *
+ * This function tries to find a password identified by name in the password
+ * file. The password is expected to be stored in `NAME=PASSWORD` format.
+ * Comments and empty lines in the file are ignored. Invalid lines will cause
+ * an error message, but will not cause the function to fail.
+ */
+static struct wpabuf * ext_password_file_get(void *ctx, const char *name)
+{
+ struct ext_password_file_data *data = ctx;
+ struct wpabuf *password = NULL;
+ char buf[512], *pos;
+ int line = 0;
+ FILE *f;
+
+ f = fopen(data->path, "r");
+ if (!f) {
+ wpa_printf(MSG_ERROR,
+ "EXT PW FILE: could not open file '%s': %s",
+ data->path, strerror(errno));
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EXT PW FILE: get(%s)", name);
+
+ while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
+ char *sep = os_strchr(pos, '=');
+
+ if (!sep) {
+ wpa_printf(MSG_ERROR, "Invalid password line %d.",
+ line);
+ continue;
+ }
+
+ if (!sep[1]) {
+ wpa_printf(MSG_ERROR, "No password for line %d.", line);
+ continue;
+
+ }
+
+ if (os_strncmp(name, pos, sep - pos) != 0)
+ continue;
+
+ password = wpabuf_alloc_copy(sep + 1, os_strlen(sep + 1));
+ goto done;
+ }
+
+ wpa_printf(MSG_ERROR, "Password for '%s' was not found.", name);
+
+done:
+ forced_memzero(buf, sizeof(buf));
+ fclose(f);
+ return password;
+}
+
+
+const struct ext_password_backend ext_password_file = {
+ .name = "file",
+ .init = ext_password_file_init,
+ .deinit = ext_password_file_deinit,
+ .get = ext_password_file_get,
+};
diff --git a/src/utils/ext_password_i.h b/src/utils/ext_password_i.h
index 948eaf5..872ccd1 100644
--- a/src/utils/ext_password_i.h
+++ b/src/utils/ext_password_i.h
@@ -26,4 +26,8 @@ struct wpabuf * ext_password_alloc(size_t len);
extern const struct ext_password_backend ext_password_test;
#endif /* CONFIG_EXT_PASSWORD_TEST */
+#ifdef CONFIG_EXT_PASSWORD_FILE
+extern const struct ext_password_backend ext_password_file;
+#endif /* CONFIG_EXT_PASSWORD_FILE */
+
#endif /* EXT_PASSWORD_I_H */
diff --git a/src/utils/list.h b/src/utils/list.h
index 5298c26..aa62c08 100644
--- a/src/utils/list.h
+++ b/src/utils/list.h
@@ -76,8 +76,8 @@ static inline unsigned int dl_list_len(const struct dl_list *list)
dl_list_entry((list)->prev, type, member))
#define dl_list_for_each(item, list, type, member) \
- for (item = dl_list_first((list), type, member); \
- item && item != dl_list_entry((list), type, member); \
+ for (item = dl_list_entry((list)->next, type, member); \
+ &item->member != (list); \
item = dl_list_entry(item->member.next, type, member))
#define dl_list_for_each_safe(item, n, list, type, member) \
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 6f0c177..1de3720 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -39,7 +39,7 @@ static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
struct os_alloc_trace {
unsigned int magic;
- struct dl_list list;
+ struct dl_list list __attribute__((aligned(16)));
size_t len;
WPA_TRACE_INFO
} __attribute__((aligned(16)));
diff --git a/src/utils/platform.h b/src/utils/platform.h
index 813987e..b2ad856 100644
--- a/src/utils/platform.h
+++ b/src/utils/platform.h
@@ -1,21 +1,18 @@
+/*
+ * Platform definitions for Radiotap parser
+ * Copyright (c) 2021, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
#ifndef PLATFORM_H
#define PLATFORM_H
#include "includes.h"
#include "common.h"
-#define le16_to_cpu le_to_host16
-#define le32_to_cpu le_to_host32
-
-#define get_unaligned(p) \
-({ \
- struct packed_dummy_struct { \
- typeof(*(p)) __val; \
- } __attribute__((packed)) *__ptr = (void *) (p); \
- \
- __ptr->__val; \
-})
-#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((le16 *)(p)))
-#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((le32 *)(p)))
+#define get_unaligned_le16(p) WPA_GET_LE16((void *) (p))
+#define get_unaligned_le32(p) WPA_GET_LE32((void *) (p))
#endif /* PLATFORM_H */
diff --git a/src/utils/radiotap.c b/src/utils/radiotap.c
index 71996eb..6dfe298 100644
--- a/src/utils/radiotap.c
+++ b/src/utils/radiotap.c
@@ -8,10 +8,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See COPYING for more details.
+ * Alternatively, this software may be distributed under the terms of ISC
+ * license, see COPYING for more details.
*/
#include "platform.h"
#include "radiotap_iter.h"
@@ -39,6 +37,8 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = {
[IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
[IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
[IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
+ [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
+ [IEEE80211_RADIOTAP_TIMESTAMP] = { .align = 8, .size = 12, },
/*
* add more here as they are defined in radiotap.h
*/
@@ -111,7 +111,7 @@ int ieee80211_radiotap_iterator_init(
iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
iterator->_next_ns_data = NULL;
iterator->_reset_on_ext = 0;
- iterator->_next_bitmap = &radiotap_header->it_present;
+ iterator->_next_bitmap = (le32 *) (((u8 *) radiotap_header) + offsetof(struct ieee80211_radiotap_header, it_present));
iterator->_next_bitmap++;
iterator->_vns = vns;
iterator->current_namespace = &radiotap_ns;
@@ -222,7 +222,7 @@ static int find_override(struct ieee80211_radiotap_iterator *iterator,
* present fields. @this_arg can be changed by the caller (eg,
* incremented to move inside a compound argument like
* IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
- * little-endian format whatever the endianess of your CPU.
+ * little-endian format whatever the endianness of your CPU.
*
* Alignment Gotcha:
* You must take care when dereferencing iterator.this_arg
diff --git a/src/utils/radiotap.h b/src/utils/radiotap.h
index 460af23..488d5a3 100644
--- a/src/utils/radiotap.h
+++ b/src/utils/radiotap.h
@@ -1,190 +1,51 @@
-/*-
- * Copyright (c) 2003, 2004 David Young. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of David Young may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
- * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- * OF SUCH DAMAGE.
- */
-
/*
- * Modifications to fit into the linux IEEE 802.11 stack,
- * Mike Kershaw (dragorn@kismetwireless.net)
+ * Copyright (c) 2017 Intel Deutschland GmbH
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#ifndef __RADIOTAP_H
+#define __RADIOTAP_H
-#ifndef IEEE80211RADIOTAP_H
-#define IEEE80211RADIOTAP_H
-
-#include <stdint.h>
-
-/* Base version of the radiotap packet header data */
-#define PKTHDR_RADIOTAP_VERSION 0
-
-/* A generic radio capture format is desirable. There is one for
- * Linux, but it is neither rigidly defined (there were not even
- * units given for some fields) nor easily extensible.
- *
- * I suggest the following extensible radio capture format. It is
- * based on a bitmap indicating which fields are present.
- *
- * I am trying to describe precisely what the application programmer
- * should expect in the following, and for that reason I tell the
- * units and origin of each measurement (where it applies), or else I
- * use sufficiently weaselly language ("is a monotonically nondecreasing
- * function of...") that I cannot set false expectations for lawyerly
- * readers.
- */
-
-/* The radio capture header precedes the 802.11 header.
- * All data in the header is little endian on all platforms.
+/**
+ * struct ieee82011_radiotap_header - base radiotap header
*/
struct ieee80211_radiotap_header {
- uint8_t it_version; /* Version 0. Only increases
- * for drastic changes,
- * introduction of compatible
- * new fields does not count.
- */
+ /**
+ * @it_version: radiotap version, always 0
+ */
+ uint8_t it_version;
+
+ /**
+ * @it_pad: padding (or alignment)
+ */
uint8_t it_pad;
- le16 it_len; /* length of the whole
- * header in bytes, including
- * it_version, it_pad,
- * it_len, and data fields.
- */
- le32 it_present; /* A bitmap telling which
- * fields are present. Set bit 31
- * (0x80000000) to extend the
- * bitmap by another 32 bits.
- * Additional extensions are made
- * by setting bit 31.
- */
-};
-/* Name Data type Units
- * ---- --------- -----
- *
- * IEEE80211_RADIOTAP_TSFT __le64 microseconds
- *
- * Value in microseconds of the MAC's 64-bit 802.11 Time
- * Synchronization Function timer when the first bit of the
- * MPDU arrived at the MAC. For received frames, only.
- *
- * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
- *
- * Tx/Rx frequency in MHz, followed by flags (see below).
- *
- * IEEE80211_RADIOTAP_FHSS uint16_t see below
- *
- * For frequency-hopping radios, the hop set (first byte)
- * and pattern (second byte).
- *
- * IEEE80211_RADIOTAP_RATE u8 500kb/s
- *
- * Tx/Rx data rate
- *
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
- * one milliwatt (dBm)
- *
- * RF signal power at the antenna, decibel difference from
- * one milliwatt.
- *
- * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
- * one milliwatt (dBm)
- *
- * RF noise power at the antenna, decibel difference from one
- * milliwatt.
- *
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
- *
- * RF signal power at the antenna, decibel difference from an
- * arbitrary, fixed reference.
- *
- * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
- *
- * RF noise power at the antenna, decibel difference from an
- * arbitrary, fixed reference point.
- *
- * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
- *
- * Quality of Barker code lock. Unitless. Monotonically
- * nondecreasing with "better" lock strength. Called "Signal
- * Quality" in datasheets. (Is there a standard way to measure
- * this?)
- *
- * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
- *
- * Transmit power expressed as unitless distance from max
- * power set at factory calibration. 0 is max power.
- * Monotonically nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
- *
- * Transmit power expressed as decibel distance from max power
- * set at factory calibration. 0 is max power. Monotonically
- * nondecreasing with lower power levels.
- *
- * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
- * one milliwatt (dBm)
- *
- * Transmit power expressed as dBm (decibels from a 1 milliwatt
- * reference). This is the absolute power level measured at
- * the antenna port.
- *
- * IEEE80211_RADIOTAP_FLAGS u8 bitmap
- *
- * Properties of transmitted and received frames. See flags
- * defined below.
- *
- * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
- *
- * Unitless indication of the Rx/Tx antenna for this packet.
- * The first antenna is antenna 0.
- *
- * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
- *
- * Properties of received frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
- *
- * Properties of transmitted frames. See flags defined below.
- *
- * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
- *
- * Number of rts retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
- *
- * Number of unicast retries a transmitted frame used.
- *
- * IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless
- *
- * Contains a bitmap of known fields/flags, the flags, and
- * the MCS index.
- *
- * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitlesss
- *
- * Contains the AMPDU information for the subframe.
- */
-enum ieee80211_radiotap_type {
+ /**
+ * @it_len: overall radiotap header length
+ */
+ le16 it_len;
+
+ /**
+ * @it_present: (first) present word
+ */
+ le32 it_present;
+} STRUCT_PACKED;
+
+/* version is always 0 */
+#define PKTHDR_RADIOTAP_VERSION 0
+
+/* see the radiotap website for the descriptions */
+enum ieee80211_radiotap_presence {
IEEE80211_RADIOTAP_TSFT = 0,
IEEE80211_RADIOTAP_FLAGS = 1,
IEEE80211_RADIOTAP_RATE = 2,
@@ -203,9 +64,11 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TX_FLAGS = 15,
IEEE80211_RADIOTAP_RTS_RETRIES = 16,
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
-
+ /* 18 is XChannel, but it's not defined yet */
IEEE80211_RADIOTAP_MCS = 19,
IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
+ IEEE80211_RADIOTAP_VHT = 21,
+ IEEE80211_RADIOTAP_TIMESTAMP = 22,
/* valid in every it_present bitmap, even vendor namespaces */
IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
@@ -213,79 +76,125 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_EXT = 31
};
-/* Channel flags. */
-#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
-#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
-#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
-#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
-#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
-#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
-#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
-#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
+/* for IEEE80211_RADIOTAP_FLAGS */
+enum ieee80211_radiotap_flags {
+ IEEE80211_RADIOTAP_F_CFP = 0x01,
+ IEEE80211_RADIOTAP_F_SHORTPRE = 0x02,
+ IEEE80211_RADIOTAP_F_WEP = 0x04,
+ IEEE80211_RADIOTAP_F_FRAG = 0x08,
+ IEEE80211_RADIOTAP_F_FCS = 0x10,
+ IEEE80211_RADIOTAP_F_DATAPAD = 0x20,
+ IEEE80211_RADIOTAP_F_BADFCS = 0x40,
+};
+
+/* for IEEE80211_RADIOTAP_CHANNEL */
+enum ieee80211_radiotap_channel_flags {
+ IEEE80211_CHAN_CCK = 0x0020,
+ IEEE80211_CHAN_OFDM = 0x0040,
+ IEEE80211_CHAN_2GHZ = 0x0080,
+ IEEE80211_CHAN_5GHZ = 0x0100,
+ IEEE80211_CHAN_DYN = 0x0400,
+ IEEE80211_CHAN_HALF = 0x4000,
+ IEEE80211_CHAN_QUARTER = 0x8000,
+};
+
+/* for IEEE80211_RADIOTAP_RX_FLAGS */
+enum ieee80211_radiotap_rx_flags {
+ IEEE80211_RADIOTAP_F_RX_BADPLCP = 0x0002,
+};
+
+/* for IEEE80211_RADIOTAP_TX_FLAGS */
+enum ieee80211_radiotap_tx_flags {
+ IEEE80211_RADIOTAP_F_TX_FAIL = 0x0001,
+ IEEE80211_RADIOTAP_F_TX_CTS = 0x0002,
+ IEEE80211_RADIOTAP_F_TX_RTS = 0x0004,
+ IEEE80211_RADIOTAP_F_TX_NOACK = 0x0008,
+};
+
+/* for IEEE80211_RADIOTAP_MCS "have" flags */
+enum ieee80211_radiotap_mcs_have {
+ IEEE80211_RADIOTAP_MCS_HAVE_BW = 0x01,
+ IEEE80211_RADIOTAP_MCS_HAVE_MCS = 0x02,
+ IEEE80211_RADIOTAP_MCS_HAVE_GI = 0x04,
+ IEEE80211_RADIOTAP_MCS_HAVE_FMT = 0x08,
+ IEEE80211_RADIOTAP_MCS_HAVE_FEC = 0x10,
+ IEEE80211_RADIOTAP_MCS_HAVE_STBC = 0x20,
+};
-/* For IEEE80211_RADIOTAP_FLAGS */
-#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
- * during CFP
- */
-#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
- * with short
- * preamble
- */
-#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
- * with WEP encryption
- */
-#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
- * with fragmentation
- */
-#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
-#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
- * 802.11 header and payload
- * (to 32-bit boundary)
- */
-#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* frame failed FCS check */
+enum ieee80211_radiotap_mcs_flags {
+ IEEE80211_RADIOTAP_MCS_BW_MASK = 0x03,
+ IEEE80211_RADIOTAP_MCS_BW_20 = 0,
+ IEEE80211_RADIOTAP_MCS_BW_40 = 1,
+ IEEE80211_RADIOTAP_MCS_BW_20L = 2,
+ IEEE80211_RADIOTAP_MCS_BW_20U = 3,
+
+ IEEE80211_RADIOTAP_MCS_SGI = 0x04,
+ IEEE80211_RADIOTAP_MCS_FMT_GF = 0x08,
+ IEEE80211_RADIOTAP_MCS_FEC_LDPC = 0x10,
+ IEEE80211_RADIOTAP_MCS_STBC_MASK = 0x60,
+ IEEE80211_RADIOTAP_MCS_STBC_1 = 1,
+ IEEE80211_RADIOTAP_MCS_STBC_2 = 2,
+ IEEE80211_RADIOTAP_MCS_STBC_3 = 3,
+ IEEE80211_RADIOTAP_MCS_STBC_SHIFT = 5,
+};
-/* For IEEE80211_RADIOTAP_RX_FLAGS */
-#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* bad PLCP */
+/* for IEEE80211_RADIOTAP_AMPDU_STATUS */
+enum ieee80211_radiotap_ampdu_flags {
+ IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN = 0x0001,
+ IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN = 0x0002,
+ IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN = 0x0004,
+ IEEE80211_RADIOTAP_AMPDU_IS_LAST = 0x0008,
+ IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR = 0x0010,
+ IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN = 0x0020,
+};
-/* For IEEE80211_RADIOTAP_TX_FLAGS */
-#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
- * retries */
-#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
-#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
-#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ACK */
+/* for IEEE80211_RADIOTAP_VHT */
+enum ieee80211_radiotap_vht_known {
+ IEEE80211_RADIOTAP_VHT_KNOWN_STBC = 0x0001,
+ IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA = 0x0002,
+ IEEE80211_RADIOTAP_VHT_KNOWN_GI = 0x0004,
+ IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS = 0x0008,
+ IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM = 0x0010,
+ IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED = 0x0020,
+ IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH = 0x0040,
+ IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID = 0x0080,
+ IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID = 0x0100,
+};
-/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
-#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001
-#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002
-#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004
-#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010
-#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020
+enum ieee80211_radiotap_vht_flags {
+ IEEE80211_RADIOTAP_VHT_FLAG_STBC = 0x01,
+ IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA = 0x02,
+ IEEE80211_RADIOTAP_VHT_FLAG_SGI = 0x04,
+ IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9 = 0x08,
+ IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM = 0x10,
+ IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED = 0x20,
+};
-/* For IEEE80211_RADIOTAP_MCS */
-#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01
-#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02
-#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04
-#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08
-#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10
-#define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20
-#define IEEE80211_RADIOTAP_MCS_HAVE_NESS 0x40
-#define IEEE80211_RADIOTAP_MCS_NESS_BIT1 0x80
+enum ieee80211_radiotap_vht_coding {
+ IEEE80211_RADIOTAP_CODING_LDPC_USER0 = 0x01,
+ IEEE80211_RADIOTAP_CODING_LDPC_USER1 = 0x02,
+ IEEE80211_RADIOTAP_CODING_LDPC_USER2 = 0x04,
+ IEEE80211_RADIOTAP_CODING_LDPC_USER3 = 0x08,
+};
+/* for IEEE80211_RADIOTAP_TIMESTAMP */
+enum ieee80211_radiotap_timestamp_unit_spos {
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK = 0x000F,
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS = 0x0000,
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US = 0x0001,
+ IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS = 0x0003,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK = 0x00F0,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU = 0x0000,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ = 0x0010,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU = 0x0020,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU = 0x0030,
+ IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN = 0x00F0,
+};
-#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03
-#define IEEE80211_RADIOTAP_MCS_BW_20 0
-#define IEEE80211_RADIOTAP_MCS_BW_40 1
-#define IEEE80211_RADIOTAP_MCS_BW_20L 2
-#define IEEE80211_RADIOTAP_MCS_BW_20U 3
-#define IEEE80211_RADIOTAP_MCS_SGI 0x04
-#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08
-#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10
-#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60
-#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5
-#define IEEE80211_RADIOTAP_MCS_STBC_1 1
-#define IEEE80211_RADIOTAP_MCS_STBC_2 2
-#define IEEE80211_RADIOTAP_MCS_STBC_3 3
-#define IEEE80211_RADIOTAP_MCS_NESS_BIT0 0x80
+enum ieee80211_radiotap_timestamp_flags {
+ IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT = 0x00,
+ IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT = 0x01,
+ IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY = 0x02,
+};
-#endif /* IEEE80211_RADIOTAP_H */
+#endif /* __RADIOTAP_H */
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 93888b0..6a12255 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -873,6 +873,11 @@ int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
const u8 *oob_dev_pw,
size_t oob_dev_pw_len);
void wps_registrar_flush(struct wps_registrar *reg);
+int wps_registrar_update_multi_ap(struct wps_registrar *reg,
+ const u8 *multi_ap_backhaul_ssid,
+ size_t multi_ap_backhaul_ssid_len,
+ const u8 *multi_ap_backhaul_network_key,
+ size_t multi_ap_backhaul_network_key_len);
int wps_build_credential_wrap(struct wpabuf *msg,
const struct wps_credential *cred);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 9e1ee36..0db9367 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -3669,6 +3669,35 @@ int wps_registrar_config_ap(struct wps_registrar *reg,
}
+int wps_registrar_update_multi_ap(struct wps_registrar *reg,
+ const u8 *multi_ap_backhaul_ssid,
+ size_t multi_ap_backhaul_ssid_len,
+ const u8 *multi_ap_backhaul_network_key,
+ size_t multi_ap_backhaul_network_key_len)
+{
+ if (multi_ap_backhaul_ssid) {
+ os_memcpy(reg->multi_ap_backhaul_ssid,
+ multi_ap_backhaul_ssid, multi_ap_backhaul_ssid_len);
+ reg->multi_ap_backhaul_ssid_len = multi_ap_backhaul_ssid_len;
+ }
+
+ os_free(reg->multi_ap_backhaul_network_key);
+ reg->multi_ap_backhaul_network_key = NULL;
+ reg->multi_ap_backhaul_network_key_len = 0;
+ if (multi_ap_backhaul_network_key) {
+ reg->multi_ap_backhaul_network_key =
+ os_memdup(multi_ap_backhaul_network_key,
+ multi_ap_backhaul_network_key_len);
+ if (!reg->multi_ap_backhaul_network_key)
+ return -1;
+ reg->multi_ap_backhaul_network_key_len =
+ multi_ap_backhaul_network_key_len;
+ }
+
+ return 0;
+}
+
+
#ifdef CONFIG_WPS_NFC
int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
diff --git a/tests/fuzzing/p2p/p2p.c b/tests/fuzzing/p2p/p2p.c
index 8ffcbbd..fc83c35 100644
--- a/tests/fuzzing/p2p/p2p.c
+++ b/tests/fuzzing/p2p/p2p.c
@@ -115,7 +115,7 @@ static void test_send(void *eloop_data, void *user_ctx)
os_memset(&rx_time, 0, sizeof(rx_time));
p2p_scan_res_handler(ctx->p2p, (u8 *) "\x02\x00\x00\x00\x01\x00", 2412,
&rx_time, 0, ctx->data, ctx->data_len);
- p2p_scan_res_handled(ctx->p2p);
+ p2p_scan_res_handled(ctx->p2p, 0);
p2p_probe_req_rx(ctx->p2p, (u8 *) "\x02\x00\x00\x00\x01\x00",
(u8 *) "\x02\x00\x00\x00\x00\x00",
diff --git a/tests/fuzzing/wnm/Makefile b/tests/fuzzing/wnm/Makefile
index 73eab53..60d27b3 100644
--- a/tests/fuzzing/wnm/Makefile
+++ b/tests/fuzzing/wnm/Makefile
@@ -20,7 +20,7 @@ LIBS += $(SRC)/utils/libutils.a
ELIBS += $(SRC)/crypto/libcrypto.a
ELIBS += $(SRC)/tls/libtls.a
-OBJS += $(WPAS_SRC)/blacklist.o
+OBJS += $(WPAS_SRC)/bssid_ignore.o
OBJS += $(WPAS_SRC)/bss.o
OBJS += $(WPAS_SRC)/config.o
OBJS += $(WPAS_SRC)/config_file.o
diff --git a/tests/fuzzing/wnm/wnm.c b/tests/fuzzing/wnm/wnm.c
index 9c0d541..7afc648 100644
--- a/tests/fuzzing/wnm/wnm.c
+++ b/tests/fuzzing/wnm/wnm.c
@@ -16,7 +16,7 @@
#include "wpa_supplicant_i.h"
#include "bss.h"
#include "wnm_sta.h"
-#include "config.h"
+#include "../../../wpa_supplicant/config.h"
#include "../fuzzer-common.h"
diff --git a/tests/hwsim/build.sh b/tests/hwsim/build.sh
index 2a3dd70..cb47001 100755
--- a/tests/hwsim/build.sh
+++ b/tests/hwsim/build.sh
@@ -26,13 +26,18 @@ while [ "$1" != "" ]; do
esac
done
+JOBS=`nproc`
+if [ -z "$ABC" ]; then
+ JOBS=8
+fi
+
echo "Building TNC testing tools"
cd tnc
-make QUIET=1 -j8
+make QUIET=1 -j$JOBS
echo "Building wlantest"
cd ../../../wlantest
-make QUIET=1 -j8 > /dev/null
+make QUIET=1 -j$JOBS > /dev/null
echo "Building hs20-osu-client"
cd ../hs20/client/
@@ -54,7 +59,7 @@ if [ $use_lcov -eq 1 ]; then
fi
fi
-make QUIET=1 -j8 hostapd hostapd_cli hlr_auc_gw
+make QUIET=1 -j$JOBS hostapd hostapd_cli hlr_auc_gw
echo "Building wpa_supplicant"
cd ../wpa_supplicant
@@ -75,4 +80,4 @@ fi
if [ -z $FIPSLD_CC ]; then
export FIPSLD_CC=gcc
fi
-make QUIET=1 -j8
+make QUIET=1 -j$JOBS
diff --git a/tests/hwsim/example-hostapd.config b/tests/hwsim/example-hostapd.config
index 972d35c..8b466e8 100644
--- a/tests/hwsim/example-hostapd.config
+++ b/tests/hwsim/example-hostapd.config
@@ -112,3 +112,4 @@ CONFIG_OWE=y
CONFIG_DPP=y
CONFIG_DPP2=y
CONFIG_WEP=y
+CONFIG_PASN=y
diff --git a/tests/hwsim/example-wpa_supplicant.config b/tests/hwsim/example-wpa_supplicant.config
index 9e3cc67..a579289 100644
--- a/tests/hwsim/example-wpa_supplicant.config
+++ b/tests/hwsim/example-wpa_supplicant.config
@@ -112,6 +112,7 @@ CONFIG_AUTOSCAN_EXPONENTIAL=y
CONFIG_AUTOSCAN_PERIODIC=y
CONFIG_EXT_PASSWORD_TEST=y
+CONFIG_EXT_PASSWORD_FILE=y
CONFIG_EAP_UNAUTH_TLS=y
@@ -155,3 +156,4 @@ CONFIG_OWE=y
CONFIG_DPP=y
CONFIG_DPP2=y
CONFIG_WEP=y
+CONFIG_PASN=y
diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py
index 5717575..de9263b 100644
--- a/tests/hwsim/hostapd.py
+++ b/tests/hwsim/hostapd.py
@@ -535,6 +535,23 @@ class Hostapd:
def send_file(self, src, dst):
self.host.send_file(src, dst)
+ def get_ptksa(self, bssid, cipher):
+ res = self.request("PTKSA_CACHE_LIST")
+ lines = res.splitlines()
+ for l in lines:
+ if bssid not in l or cipher not in l:
+ continue
+ vals = dict()
+ [index, addr, cipher, expiration, tk, kdk] = l.split(' ', 5)
+ vals['index'] = index
+ vals['addr'] = addr
+ vals['cipher'] = cipher
+ vals['expiration'] = expiration
+ vals['tk'] = tk
+ vals['kdk'] = kdk
+ return vals
+ return None
+
def add_ap(apdev, params, wait_enabled=True, no_enable=False, timeout=30,
global_ctrl_override=None, driver=False):
if isinstance(apdev, dict):
diff --git a/tests/hwsim/remotehost.py b/tests/hwsim/remotehost.py
index dec1ad5..0799b95 100644
--- a/tests/hwsim/remotehost.py
+++ b/tests/hwsim/remotehost.py
@@ -9,6 +9,8 @@ import subprocess
import threading
import tempfile
import os
+import traceback
+import select
logger = logging.getLogger()
@@ -99,7 +101,7 @@ class Host():
return status, buf.decode()
# async execute
- def execute_run(self, command, res, use_reaper=True):
+ def thread_run(self, command, res, use_reaper=True):
if use_reaper:
filename = gen_reaper_file("reaper")
self.send_file(filename, filename)
@@ -113,51 +115,132 @@ class Host():
cmd = _command
else:
cmd = ["ssh", self.user + "@" + self.host, ' '.join(_command)]
- _cmd = self.name + " execute_run: " + ' '.join(cmd)
+ _cmd = self.name + " thread_run: " + ' '.join(cmd)
logger.debug(_cmd)
t = threading.Thread(target=execute_thread, name=filename, args=(cmd, res))
t.start()
return t
- def execute_stop(self, t):
+ def thread_stop(self, t):
if t.name.find("reaper") == -1:
raise Exception("use_reaper required")
pid_file = t.name + ".pid"
- if t.isAlive():
+ if t.is_alive():
cmd = ["kill `cat " + pid_file + "`"]
self.execute(cmd)
# try again
- self.wait_execute_complete(t, 5)
- if t.isAlive():
+ self.thread_wait(t, 5)
+ if t.is_alive():
cmd = ["kill `cat " + pid_file + "`"]
self.execute(cmd)
# try with -9
- self.wait_execute_complete(t, 5)
- if t.isAlive():
+ self.thread_wait(t, 5)
+ if t.is_alive():
cmd = ["kill -9 `cat " + pid_file + "`"]
self.execute(cmd)
- self.wait_execute_complete(t, 5)
- if t.isAlive():
+ self.thread_wait(t, 5)
+ if t.is_alive():
raise Exception("thread still alive")
self.execute(["rm", pid_file])
self.execute(["rm", t.name])
+ self.local_execute(["rm", t.name])
- def wait_execute_complete(self, t, wait=None):
+ def thread_wait(self, t, wait=None):
if wait == None:
wait_str = "infinite"
else:
wait_str = str(wait) + "s"
- logger.debug(self.name + " wait_execute_complete(" + wait_str + "): ")
- if t.isAlive():
+ logger.debug(self.name + " thread_wait(" + wait_str + "): ")
+ if t.is_alive():
t.join(wait)
+ def pending(self, s, timeout=0):
+ [r, w, e] = select.select([s], [], [], timeout)
+ if r:
+ return True
+ return False
+
+ def proc_run(self, command):
+ filename = gen_reaper_file("reaper")
+ self.send_file(filename, filename)
+ self.execute(["chmod", "755", filename])
+ _command = [filename] + command
+
+ if self.host:
+ cmd = ["ssh", self.user + "@" + self.host, ' '.join(_command)]
+ else:
+ cmd = _command
+
+ _cmd = self.name + " proc_run: " + ' '.join(cmd)
+ logger.debug(_cmd)
+ err = tempfile.TemporaryFile()
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=err)
+ proc.reaper_file = filename
+ return proc
+
+ def proc_wait_event(self, proc, events, timeout=10):
+ if not isinstance(events, list):
+ raise Exception("proc_wait_event() events not a list")
+
+ logger.debug(self.name + " proc_wait_event: " + ' '.join(events) + " timeout: " + str(timeout))
+ start = os.times()[4]
+ try:
+ while True:
+ while self.pending(proc.stdout):
+ line = proc.stdout.readline()
+ if not line:
+ return None
+ line = line.decode()
+ logger.debug(line.strip('\n'))
+ for event in events:
+ if event in line:
+ return line
+ now = os.times()[4]
+ remaining = start + timeout - now
+ if remaining <= 0:
+ break
+ if not self.pending(proc.stdout, timeout=remaining):
+ break
+ except:
+ logger.debug(traceback.format_exc())
+ pass
+ return None
+
+ def proc_stop(self, proc):
+ if not proc:
+ return
+
+ self.execute(["kill `cat " + proc.reaper_file + ".pid`"])
+ self.execute(["rm", proc.reaper_file + ".pid"])
+ self.execute(["rm", proc.reaper_file])
+ self.local_execute(["rm", proc.reaper_file])
+ proc.kill()
+
+ def proc_dump(self, proc):
+ if not proc:
+ return ""
+ return proc.stdout.read()
+
+ def execute_and_wait_event(self, command, events, timeout=10):
+ proc = None
+ ev = None
+
+ try:
+ proc = self.proc_run(command)
+ ev = self.proc_wait_event(proc, events, timeout)
+ except:
+ pass
+
+ self.proc_stop(proc)
+ return ev
+
def add_log(self, log_file):
self.logs.append(log_file)
diff --git a/tests/hwsim/rfkill.py b/tests/hwsim/rfkill.py
index f08cf50..72b2527 100755
--- a/tests/hwsim/rfkill.py
+++ b/tests/hwsim/rfkill.py
@@ -126,7 +126,7 @@ class RFKill(object):
@classmethod
def list(cls):
res = []
- rfk = open('/dev/rfkill', 'rb')
+ rfk = open('/dev/rfkill', 'rb', buffering=0)
fd = rfk.fileno()
flgs = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, flgs | os.O_NONBLOCK)
diff --git a/tests/hwsim/test_ap_acs.py b/tests/hwsim/test_ap_acs.py
index eb245e7..08eaee5 100644
--- a/tests/hwsim/test_ap_acs.py
+++ b/tests/hwsim/test_ap_acs.py
@@ -622,3 +622,43 @@ def test_ap_acs_rx_during(dev, apdev):
finally:
for i in range(3):
dev[i].request("SCAN_INTERVAL 5")
+
+def test_ap_acs_he_24g(dev, apdev):
+ """Automatic channel selection on 2.4 GHz with HE"""
+ clear_scan_cache(apdev[0])
+ force_prev_ap_on_24g(apdev[0])
+
+ params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
+ params['channel'] = '0'
+ params['ieee80211ax'] = '1'
+ params['ht_capab'] = '[HT40+]'
+ hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+ wait_acs(hapd)
+
+ freq = hapd.get_status_field("freq")
+ if int(freq) < 2400:
+ raise Exception("Unexpected frequency")
+
+ dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
+
+def test_ap_acs_he_24g_overlap(dev, apdev):
+ """Automatic channel selection on 2.4 GHz with HE (overlap)"""
+ clear_scan_cache(apdev[0])
+ force_prev_ap_on_24g(apdev[0])
+
+ params = {"ssid": "overlapping",
+ "channel": "6", "ieee80211n": "1"}
+ hostapd.add_ap(apdev[1], params)
+
+ params = hostapd.wpa2_params(ssid="test-acs", passphrase="12345678")
+ params['channel'] = '0'
+ params['ieee80211ax'] = '1'
+ params['ht_capab'] = '[HT40+]'
+ hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+ wait_acs(hapd)
+
+ freq = hapd.get_status_field("freq")
+ if int(freq) < 2400:
+ raise Exception("Unexpected frequency")
+
+ dev[0].connect("test-acs", psk="12345678", scan_freq=freq)
diff --git a/tests/hwsim/test_ap_ciphers.py b/tests/hwsim/test_ap_ciphers.py
index d9f827a..eea17c1 100644
--- a/tests/hwsim/test_ap_ciphers.py
+++ b/tests/hwsim/test_ap_ciphers.py
@@ -415,6 +415,35 @@ def test_ap_cipher_mixed_wpa_wpa2(dev, apdev):
hwsim_utils.test_connectivity(dev[0], dev[1])
@remote_compatible
+def test_ap_cipher_wpa_sae(dev, apdev):
+ """WPA-PSK/TKIP and SAE mixed AP - WPA IE and RSNXE coexistence"""
+ skip_with_fips(dev[0])
+ skip_without_tkip(dev[0])
+ ssid = "test-wpa-sae"
+ passphrase = "12345678"
+ params = {"ssid": ssid,
+ "wpa_passphrase": passphrase,
+ "wpa": "3",
+ "wpa_key_mgmt": "WPA-PSK SAE",
+ "rsn_pairwise": "CCMP",
+ "wpa_pairwise": "TKIP",
+ "sae_pwe": "1"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ dev[0].flush_scan_cache()
+
+ dev[0].connect(ssid, psk=passphrase, proto="WPA",
+ pairwise="TKIP", group="TKIP", scan_freq="2412")
+ status = dev[0].get_status()
+ if status['key_mgmt'] != 'WPA-PSK':
+ raise Exception("Incorrect key_mgmt reported")
+ if status['pairwise_cipher'] != 'TKIP':
+ raise Exception("Incorrect pairwise_cipher reported")
+ if status['group_cipher'] != 'TKIP':
+ raise Exception("Incorrect group_cipher reported")
+ hapd.wait_sta()
+ hwsim_utils.test_connectivity(dev[0], hapd)
+
+@remote_compatible
def test_ap_cipher_bip(dev, apdev):
"""WPA2-PSK with BIP"""
check_group_mgmt_cipher(dev[0], apdev[0], "AES-128-CMAC")
diff --git a/tests/hwsim/test_ap_dynamic.py b/tests/hwsim/test_ap_dynamic.py
index 96d35b9..d23cf0c 100644
--- a/tests/hwsim/test_ap_dynamic.py
+++ b/tests/hwsim/test_ap_dynamic.py
@@ -37,6 +37,44 @@ def test_ap_change_ssid(dev, apdev):
dev[0].set_network_quoted(id, "ssid", "test-wpa2-psk-new")
dev[0].connect_network(id)
+def test_ap_change_ssid_wps(dev, apdev):
+ """Dynamic SSID change with hostapd and WPA2-PSK using WPS"""
+ params = hostapd.wpa2_params(ssid="test-wpa2-psk-start",
+ passphrase="12345678")
+ # Use a PSK and not the passphrase, because the PSK will have to be computed
+ # again if we use a passphrase.
+ del params["wpa_passphrase"]
+ params["wpa_psk"] = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
+
+ params.update({"wps_state": "2", "eap_server": "1"})
+ bssid = apdev[0]['bssid']
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ new_ssid = "test-wpa2-psk-new"
+ logger.info("Change SSID dynamically (WPS)")
+ res = hapd.request("SET ssid " + new_ssid)
+ if "OK" not in res:
+ raise Exception("SET command failed")
+ res = hapd.request("RELOAD")
+ if "OK" not in res:
+ raise Exception("RELOAD command failed")
+
+ # Connect to the new ssid using wps:
+ hapd.request("WPS_PBC")
+ if "PBC Status: Active" not in hapd.request("WPS_GET_STATUS"):
+ raise Exception("PBC status not shown correctly")
+
+ dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412", force_scan=True)
+ dev[0].request("WPS_PBC")
+ dev[0].wait_connected(timeout=20)
+ status = dev[0].get_status()
+ if status['wpa_state'] != 'COMPLETED' or status['bssid'] != bssid:
+ raise Exception("Not fully connected")
+ if status['ssid'] != new_ssid:
+ raise Exception("Unexpected SSID %s != %s" % (status['ssid'], new_ssid))
+ dev[0].request("DISCONNECT")
+ dev[0].wait_disconnected()
+
def multi_check(apdev, dev, check, scan_opt=True):
id = []
num_bss = len(check)
diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py
index 7395c79..88e03df 100644
--- a/tests/hwsim/test_ap_eap.py
+++ b/tests/hwsim/test_ap_eap.py
@@ -5922,6 +5922,55 @@ def test_ap_wpa2_eap_tls_13(dev, apdev):
dev[0].request("RECONNECT")
dev[0].wait_connected()
+def test_ap_wpa2_eap_ttls_13(dev, apdev):
+ """EAP-TTLS and TLS 1.3"""
+ params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ tls = dev[0].request("GET tls_library")
+ if "run=OpenSSL 1.1.1" not in tls:
+ raise HwsimSkip("TLS v1.3 not supported")
+ id = eap_connect(dev[0], hapd, "TTLS", "pap user",
+ anonymous_identity="ttls", password="password",
+ ca_cert="auth_serv/ca.pem",
+ phase1="tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1 tls_disable_tlsv1_3=0",
+ phase2="auth=PAP")
+ ver = dev[0].get_status_field("eap_tls_version")
+ if ver != "TLSv1.3":
+ raise Exception("Unexpected TLS version")
+
+ eap_reauth(dev[0], "TTLS")
+ dev[0].request("DISCONNECT")
+ dev[0].wait_disconnected()
+ dev[0].request("PMKSA_FLUSH")
+ dev[0].request("RECONNECT")
+ dev[0].wait_connected()
+
+def test_ap_wpa2_eap_peap_13(dev, apdev):
+ """PEAP and TLS 1.3"""
+ check_eap_capa(dev[0], "MSCHAPV2")
+ params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ tls = dev[0].request("GET tls_library")
+ if "run=OpenSSL 1.1.1" not in tls:
+ raise HwsimSkip("TLS v1.3 not supported")
+ id = eap_connect(dev[0], hapd, "PEAP", "user",
+ anonymous_identity="peap", password="password",
+ ca_cert="auth_serv/ca.pem",
+ phase1="tls_disable_tlsv1_0=1 tls_disable_tlsv1_1=1 tls_disable_tlsv1_2=1 tls_disable_tlsv1_3=0",
+ phase2="auth=MSCHAPV2")
+ ver = dev[0].get_status_field("eap_tls_version")
+ if ver != "TLSv1.3":
+ raise Exception("Unexpected TLS version")
+
+ eap_reauth(dev[0], "PEAP")
+ dev[0].request("DISCONNECT")
+ dev[0].wait_disconnected()
+ dev[0].request("PMKSA_FLUSH")
+ dev[0].request("RECONNECT")
+ dev[0].wait_connected()
+
def test_ap_wpa2_eap_tls_13_ec(dev, apdev):
"""EAP-TLS and TLS 1.3 (EC certificates)"""
params = {"ssid": "test-wpa2-eap",
diff --git a/tests/hwsim/test_ap_ft.py b/tests/hwsim/test_ap_ft.py
index f2ca6f1..1598c89 100644
--- a/tests/hwsim/test_ap_ft.py
+++ b/tests/hwsim/test_ap_ft.py
@@ -136,7 +136,8 @@ def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False,
group_mgmt=None, ocv=None, sae_password=None,
sae_password_id=None, sae_and_psk=False, pmksa_caching=False,
roam_with_reassoc=False, also_non_ft=False, only_one_way=False,
- wait_before_roam=0, return_after_initial=False, ieee80211w="1"):
+ wait_before_roam=0, return_after_initial=False, ieee80211w="1",
+ sae_transition=False):
logger.info("Connect to first AP")
copts = {}
@@ -161,7 +162,9 @@ def run_roams(dev, apdev, hapd0, hapd1, ssid, passphrase, over_ds=False,
copts["identity"] = eap_identity
copts["password"] = "abcdefghijklmnop0123456789abcdef"
else:
- if sae:
+ if sae_transition:
+ copts["key_mgmt"] = "FT-SAE FT-PSK"
+ elif sae:
copts["key_mgmt"] = "SAE FT-SAE" if sae_and_psk else "FT-SAE"
else:
copts["key_mgmt"] = "FT-PSK"
@@ -998,7 +1001,8 @@ def test_ap_ft_over_ds_pull_vlan(dev, apdev):
def start_ft_sae(dev, apdev, wpa_ptk_rekey=None, sae_pwe=None,
rsne_override=None, rsnxe_override=None,
no_beacon_rsnxe2=False, ext_key_id=False,
- skip_prune_assoc=False, ft_rsnxe_used=False):
+ skip_prune_assoc=False, ft_rsnxe_used=False,
+ sae_transition=False):
if "SAE" not in dev.get_capability("auth_alg"):
raise HwsimSkip("SAE not supported")
ssid = "test-ft"
@@ -1022,7 +1026,8 @@ def start_ft_sae(dev, apdev, wpa_ptk_rekey=None, sae_pwe=None,
params['ft_rsnxe_used'] = '1'
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
- params['wpa_key_mgmt'] = "FT-SAE"
+ if not sae_transition:
+ params['wpa_key_mgmt'] = "FT-SAE"
if wpa_ptk_rekey:
params['wpa_ptk_rekey'] = str(wpa_ptk_rekey)
if sae_pwe is not None:
@@ -1041,7 +1046,7 @@ def start_ft_sae(dev, apdev, wpa_ptk_rekey=None, sae_pwe=None,
params['ft_rsnxe_used'] = '1'
hapd1 = hostapd.add_ap(apdev[1], params)
key_mgmt = hapd1.get_config()['key_mgmt']
- if key_mgmt.split(' ')[0] != "FT-SAE":
+ if key_mgmt.split(' ')[0] != "FT-SAE" and not sae_transition:
raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
dev.request("SET sae_groups ")
@@ -1052,6 +1057,12 @@ def test_ap_ft_sae(dev, apdev):
hapd0, hapd1 = start_ft_sae(dev[0], apdev)
run_roams(dev[0], apdev, hapd0, hapd1, "test-ft", "12345678", sae=True)
+def test_ap_ft_sae_transition(dev, apdev):
+ """WPA2-PSK-FT-SAE/PSK AP"""
+ hapd0, hapd1 = start_ft_sae(dev[0], apdev, sae_transition=True)
+ run_roams(dev[0], apdev, hapd0, hapd1, "test-ft", "12345678",
+ sae_transition=True)
+
def test_ap_ft_sae_h2e(dev, apdev):
"""WPA2-PSK-FT-SAE AP (H2E)"""
try:
@@ -1595,7 +1606,14 @@ def test_ap_ft_eap_pull_wildcard_multi_bss(dev, apdev, params):
f.write("interface=%s\n" % ifname2)
f.write("bssid=%s\n" % bssid2)
f.write("ctrl_interface=/var/run/hostapd\n")
+
+ fields = ["ssid", "wpa_passphrase", "nas_identifier", "wpa_key_mgmt",
+ "wpa", "rsn_pairwise", "auth_server_addr"]
+ for name in fields:
+ f.write("%s=%s\n" % (name, params[name]))
for name, val in params.items():
+ if name in fields:
+ continue
f.write("%s=%s\n" % (name, val))
hapd2 = hostapd.add_bss(apdev[0], ifname2, bssconf)
@@ -3334,9 +3352,11 @@ def test_ap_ft_r0_key_expiration(dev, apdev):
passphrase = "12345678"
params = ft_params1(ssid=ssid, passphrase=passphrase)
+ params.pop('r0_key_lifetime', None)
params['ft_r0_key_lifetime'] = "2"
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
+ params.pop('r0_key_lifetime', None)
params['ft_r0_key_lifetime'] = "2"
hapd1 = hostapd.add_ap(apdev[1], params)
diff --git a/tests/hwsim/test_ap_open.py b/tests/hwsim/test_ap_open.py
index 62b4446..a3bea76 100644
--- a/tests/hwsim/test_ap_open.py
+++ b/tests/hwsim/test_ap_open.py
@@ -198,19 +198,15 @@ def test_ap_open_unexpected_assoc_event(dev, apdev):
dev[0].request("DISCONNECT")
dev[0].wait_disconnected(timeout=15)
dev[0].dump_monitor()
- # This will be accepted due to matching network
+ # This association will be ignored by wpa_supplicant since the current
+ # state is not to try to connect after that DISCONNECT command.
dev[0].cmd_execute(['iw', 'dev', dev[0].ifname, 'connect', 'open', "2412",
apdev[0]['bssid']])
- dev[0].wait_connected(timeout=15)
- dev[0].dump_monitor()
-
- dev[0].request("REMOVE_NETWORK all")
- dev[0].wait_disconnected(timeout=5)
+ ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=0.3)
+ dev[0].cmd_execute(['iw', 'dev', dev[0].ifname, 'disconnect'])
dev[0].dump_monitor()
- # This will result in disconnection due to no matching network
- dev[0].cmd_execute(['iw', 'dev', dev[0].ifname, 'connect', 'open', "2412",
- apdev[0]['bssid']])
- dev[0].wait_disconnected(timeout=15)
+ if ev is not None:
+ raise Exception("Unexpected connection")
def test_ap_open_external_assoc(dev, apdev):
"""AP with open mode and external association"""
@@ -301,18 +297,18 @@ def test_ap_open_out_of_memory(dev, apdev):
# not fail
hostapd.add_ap(apdev[1], {"ssid": "open"})
-def test_bssid_black_white_list(dev, apdev):
- """BSSID black/white list"""
+def test_bssid_ignore_accept(dev, apdev):
+ """BSSID ignore/accept list"""
hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
hapd2 = hostapd.add_ap(apdev[1], {"ssid": "open"})
dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
- bssid_whitelist=apdev[1]['bssid'])
+ bssid_accept=apdev[1]['bssid'])
dev[1].connect("open", key_mgmt="NONE", scan_freq="2412",
- bssid_blacklist=apdev[1]['bssid'])
+ bssid_ignore=apdev[1]['bssid'])
dev[2].connect("open", key_mgmt="NONE", scan_freq="2412",
- bssid_whitelist="00:00:00:00:00:00/00:00:00:00:00:00",
- bssid_blacklist=apdev[1]['bssid'])
+ bssid_accept="00:00:00:00:00:00/00:00:00:00:00:00",
+ bssid_ignore=apdev[1]['bssid'])
if dev[0].get_status_field('bssid') != apdev[1]['bssid']:
raise Exception("dev[0] connected to unexpected AP")
if dev[1].get_status_field('bssid') != apdev[0]['bssid']:
@@ -324,11 +320,11 @@ def test_bssid_black_white_list(dev, apdev):
dev[2].request("REMOVE_NETWORK all")
dev[2].connect("open", key_mgmt="NONE", scan_freq="2412",
- bssid_whitelist="00:00:00:00:00:00", wait_connect=False)
+ bssid_accept="00:00:00:00:00:00", wait_connect=False)
dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
- bssid_whitelist="11:22:33:44:55:66/ff:00:00:00:00:00 " + apdev[1]['bssid'] + " aa:bb:cc:dd:ee:ff")
+ bssid_accept="11:22:33:44:55:66/ff:00:00:00:00:00 " + apdev[1]['bssid'] + " aa:bb:cc:dd:ee:ff")
dev[1].connect("open", key_mgmt="NONE", scan_freq="2412",
- bssid_blacklist="11:22:33:44:55:66/ff:00:00:00:00:00 " + apdev[1]['bssid'] + " aa:bb:cc:dd:ee:ff")
+ bssid_ignore="11:22:33:44:55:66/ff:00:00:00:00:00 " + apdev[1]['bssid'] + " aa:bb:cc:dd:ee:ff")
if dev[0].get_status_field('bssid') != apdev[1]['bssid']:
raise Exception("dev[0] connected to unexpected AP")
if dev[1].get_status_field('bssid') != apdev[0]['bssid']:
@@ -586,17 +582,17 @@ def test_ap_open_select_network(dev, apdev):
dev[0].select_network(id1)
dev[0].wait_connected()
- res = dev[0].request("BLACKLIST")
+ res = dev[0].request("BSSID_IGNORE")
if bssid1 in res or bssid2 in res:
- raise Exception("Unexpected blacklist entry")
+ raise Exception("Unexpected BSSID ignore list entry")
hwsim_utils.test_connectivity(dev[0], hapd1)
dev[0].select_network(id2)
dev[0].wait_connected()
hwsim_utils.test_connectivity(dev[0], hapd2)
- res = dev[0].request("BLACKLIST")
+ res = dev[0].request("BSSID_IGNORE")
if bssid1 in res or bssid2 in res:
- raise Exception("Unexpected blacklist entry(2)")
+ raise Exception("Unexpected BSSID ignore list entry(2)")
@remote_compatible
def test_ap_open_disable_enable(dev, apdev):
@@ -917,9 +913,9 @@ def test_ap_open_disable_select(dev, apdev):
dev[0].request("DISABLE_NETWORK %d" % id)
dev[0].wait_disconnected()
- res = dev[0].request("BLACKLIST")
+ res = dev[0].request("BSSID_IGNORE")
if hapd1.own_addr() in res or hapd2.own_addr() in res:
- raise Exception("Unexpected blacklist entry added")
+ raise Exception("Unexpected BSSID ignore list entry added")
dev[0].request("SELECT_NETWORK %d" % id)
dev[0].wait_connected()
diff --git a/tests/hwsim/test_ap_params.py b/tests/hwsim/test_ap_params.py
index 7918057..0735127 100644
--- a/tests/hwsim/test_ap_params.py
+++ b/tests/hwsim/test_ap_params.py
@@ -254,6 +254,29 @@ def test_ap_acl_mgmt(dev, apdev):
if filename.startswith('/tmp/'):
os.unlink(filename)
+def test_ap_acl_accept_changes(dev, apdev):
+ """MAC ACL accept list changes"""
+ ssid = "acl"
+ params = {}
+ params['ssid'] = ssid
+ params['macaddr_acl'] = "1"
+ hapd = hostapd.add_ap(apdev[0], params)
+ hapd.request("ACCEPT_ACL ADD_MAC " + dev[0].own_addr())
+ hapd.request("ACCEPT_ACL ADD_MAC " + dev[1].own_addr())
+ dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+ dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+ dev[1].scan_for_bss(apdev[0]['bssid'], freq="2412")
+ dev[1].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+ hapd.request("ACCEPT_ACL DEL_MAC " + dev[0].own_addr())
+ dev[0].wait_disconnected()
+ dev[0].request("DISCONNECT")
+ ev = dev[1].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=0.1)
+ if ev is not None:
+ raise Exception("Unexpected disconnection")
+ hapd.request("ACCEPT_ACL CLEAR")
+ dev[1].wait_disconnected()
+ dev[1].request("DISCONNECT")
+
@remote_compatible
def test_ap_wds_sta(dev, apdev):
"""WPA2-PSK AP with STA using 4addr mode"""
@@ -843,3 +866,29 @@ def test_ap_wowlan_triggers(dev, apdev):
dev[0].scan_for_bss(bssid, freq="2412")
dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
hwsim_utils.test_connectivity(dev[0], hapd)
+
+def test_ap_notify_mgmt_frames(dev, apdev):
+ """hostapd notify_mgmt_frames configuration enabled"""
+ ssid = "mgmt_frames"
+ params = {'ssid': ssid, 'notify_mgmt_frames': "1"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = hapd.own_addr()
+ dev[0].scan_for_bss(bssid, freq="2412")
+ dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+ ev = hapd.wait_event(["AP-MGMT-FRAME-RECEIVED"], timeout=5)
+ if ev is None:
+ raise Exception("AP-MGMT-FRAME-RECEIVED wait timed out")
+ if "buf=b0" not in ev:
+ raise Exception("Expected auth request in AP-MGMT-FRAME-RECEIVED")
+
+def test_ap_notify_mgmt_frames_disabled(dev, apdev):
+ """hostapd notify_mgmt_frames configuration disabled"""
+ ssid = "mgmt_frames"
+ params = {'ssid': ssid, 'notify_mgmt_frames': "0"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = hapd.own_addr()
+ dev[0].scan_for_bss(bssid, freq="2412")
+ dev[0].connect(ssid, key_mgmt="NONE", scan_freq="2412")
+ ev = hapd.wait_event(["AP-MGMT-FRAME-RECEIVED"], timeout=0.1)
+ if ev is not None:
+ raise Exception("Unexpected AP-MGMT-FRAME-RECEIVED")
diff --git a/tests/hwsim/test_ap_psk.py b/tests/hwsim/test_ap_psk.py
index 9bc1414..db10377 100644
--- a/tests/hwsim/test_ap_psk.py
+++ b/tests/hwsim/test_ap_psk.py
@@ -685,6 +685,8 @@ def setup_psk_ext(dev, apdev, wpa_ptk_rekey=None):
def ext_4way_hs(hapd, dev):
bssid = hapd.own_addr()
addr = dev.own_addr()
+ first = None
+ last = None
while True:
ev = hapd.wait_event(["EAPOL-TX", "AP-STA-CONNECTED"], timeout=15)
if ev is None:
@@ -692,6 +694,9 @@ def ext_4way_hs(hapd, dev):
if "AP-STA-CONNECTED" in ev:
dev.wait_connected(timeout=15)
break
+ if not first:
+ first = ev.split(' ')[2]
+ last = ev.split(' ')[2]
res = dev.request("EAPOL_RX " + bssid + " " + ev.split(' ')[2])
if "OK" not in res:
raise Exception("EAPOL_RX to wpa_supplicant failed")
@@ -703,12 +708,41 @@ def ext_4way_hs(hapd, dev):
res = hapd.request("EAPOL_RX " + addr + " " + ev.split(' ')[2])
if "OK" not in res:
raise Exception("EAPOL_RX to hostapd failed")
+ return first, last
def test_ap_wpa2_psk_ext(dev, apdev):
"""WPA2-PSK AP using external EAPOL I/O"""
hapd = setup_psk_ext(dev[0], apdev[0])
ext_4way_hs(hapd, dev[0])
+def test_ap_wpa2_psk_unexpected(dev, apdev):
+ """WPA2-PSK and supplicant receiving unexpected EAPOL-Key frames"""
+ hapd = setup_psk_ext(dev[0], apdev[0])
+ first, last = ext_4way_hs(hapd, dev[0])
+
+ # Not associated - Delay processing of received EAPOL frame (state=COMPLETED
+ # bssid=02:00:00:00:03:00)
+ other = "02:11:22:33:44:55"
+ res = dev[0].request("EAPOL_RX " + other + " " + first)
+ if "OK" not in res:
+ raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+ # WPA: EAPOL-Key Replay Counter did not increase - dropping packet
+ bssid = hapd.own_addr()
+ res = dev[0].request("EAPOL_RX " + bssid + " " + last)
+ if "OK" not in res:
+ raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+ # WPA: Invalid EAPOL-Key MIC - dropping packet
+ msg = last[0:18] + '01' + last[20:]
+ res = dev[0].request("EAPOL_RX " + bssid + " " + msg)
+ if "OK" not in res:
+ raise Exception("EAPOL_RX to wpa_supplicant failed")
+
+ ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=12)
+ if ev is not None:
+ raise Exception("Unexpected disconnection")
+
def test_ap_wpa2_psk_ext_retry_msg_3(dev, apdev):
"""WPA2-PSK AP using external EAPOL I/O and retry for EAPOL-Key msg 3/4"""
hapd = setup_psk_ext(dev[0], apdev[0])
diff --git a/tests/hwsim/test_ap_roam.py b/tests/hwsim/test_ap_roam.py
index fca3b57..8488889 100644
--- a/tests/hwsim/test_ap_roam.py
+++ b/tests/hwsim/test_ap_roam.py
@@ -26,8 +26,8 @@ def test_ap_roam_open(dev, apdev):
dev[0].roam(apdev[0]['bssid'])
hwsim_utils.test_connectivity(dev[0], hapd0)
-def test_ap_blacklist_all(dev, apdev, params):
- """Ensure we clear the blacklist if all visible APs reject"""
+def test_ap_ignore_bssid_all(dev, apdev, params):
+ """Ensure we clear the ignore BSSID list if all visible APs reject"""
hapd0 = hostapd.add_ap(apdev[0], {"ssid": "test-open", "max_num_sta": "0"})
hapd1 = hostapd.add_ap(apdev[1], {"ssid": "test-open", "max_num_sta": "0"})
bss0 = hapd0.own_addr()
@@ -43,13 +43,13 @@ def test_ap_blacklist_all(dev, apdev, params):
wait_connect=False, bssid=bss1)
if not dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10):
raise Exception("AP 1 didn't reject us")
- blacklist = get_blacklist(dev[0])
- logger.info("blacklist: " + str(blacklist))
+ ignore_list = get_bssid_ignore_list(dev[0])
+ logger.info("ignore list: " + str(ignore_list))
dev[0].request("REMOVE_NETWORK all")
dev[0].dump_monitor()
hapd0.set("max_num_sta", "1")
- # All visible APs were blacklisted; we should clear the blacklist and find
+ # All visible APs were ignored; we should clear the ignore list and find
# the AP that now accepts us.
dev[0].scan_for_bss(bss0, freq=2412)
dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412", bssid=bss0)
@@ -141,8 +141,8 @@ def test_ap_roam_wpa2_psk_pmf_mismatch(dev, apdev):
raise Exception("Unexpected BSSID reported after failed roam attempt: " + bssid)
hwsim_utils.test_connectivity(dev[0], hapd0)
-def get_blacklist(dev):
- return dev.request("BLACKLIST").splitlines()
+def get_bssid_ignore_list(dev):
+ return dev.request("BSSID_IGNORE").splitlines()
def test_ap_reconnect_auth_timeout(dev, apdev, params):
"""Reconnect to 2nd AP and authentication times out"""
@@ -162,7 +162,7 @@ def test_ap_reconnect_auth_timeout(dev, apdev, params):
hapd1 = hostapd.add_ap(apdev[1], params)
bssid1 = hapd1.own_addr()
- wpas.request("BLACKLIST " + bssid0)
+ wpas.request("BSSID_IGNORE " + bssid0)
wpas.scan_for_bss(bssid1, freq=2412)
wpas.request("DISCONNECT")
@@ -179,11 +179,11 @@ def test_ap_reconnect_auth_timeout(dev, apdev, params):
if not ev:
raise Exception("CTRL-EVENT-SCAN-STARTED not seen")
- b = get_blacklist(wpas)
+ b = get_bssid_ignore_list(wpas)
if '00:00:00:00:00:00' in b:
- raise Exception("Unexpected blacklist contents: " + str(b))
+ raise Exception("Unexpected ignore list contents: " + str(b))
if bssid1 not in b:
- raise Exception("Unexpected blacklist contents: " + str(b))
+ raise Exception("Unexpected ignore list contents: " + str(b))
def test_ap_roam_with_reassoc_auth_timeout(dev, apdev, params):
"""Roam using reassoc between two APs and authentication times out"""
@@ -216,9 +216,9 @@ def test_ap_roam_with_reassoc_auth_timeout(dev, apdev, params):
if not ev:
raise Exception("CTRL-EVENT-SCAN-STARTED not seen")
- b = get_blacklist(wpas)
+ b = get_bssid_ignore_list(wpas)
if bssid0 in b:
- raise Exception("Unexpected blacklist contents: " + str(b))
+ raise Exception("Unexpected ignore list contents: " + str(b))
def test_ap_roam_wpa2_psk_failed(dev, apdev, params):
"""Roam failure with WPA2-PSK AP due to wrong passphrase"""
diff --git a/tests/hwsim/test_ap_tdls.py b/tests/hwsim/test_ap_tdls.py
index a2bf6d4..8cdd002 100644
--- a/tests/hwsim/test_ap_tdls.py
+++ b/tests/hwsim/test_ap_tdls.py
@@ -639,6 +639,8 @@ def test_ap_sae_tdls(dev, apdev):
"""SAE AP and two stations using TDLS"""
check_sae_capab(dev[0])
check_sae_capab(dev[1])
+ dev[0].request("SET sae_groups ")
+ dev[1].request("SET sae_groups ")
params = hostapd.wpa2_params(ssid="test-wpa2-psk", passphrase="12345678")
params['wpa_key_mgmt'] = 'SAE'
params["ieee80211w"] = "2"
diff --git a/tests/hwsim/test_dfs.py b/tests/hwsim/test_dfs.py
index 3efe6bb..c587653 100644
--- a/tests/hwsim/test_dfs.py
+++ b/tests/hwsim/test_dfs.py
@@ -652,3 +652,116 @@ def test_dfs_chan_switch(dev, apdev):
hwsim_utils.test_connectivity(dev[0], hapd)
finally:
clear_regdom(hapd, dev)
+
+@long_duration_test
+def test_dfs_no_available_channel(dev, apdev):
+ """DFS and no available channel after radar detection"""
+ try:
+ hapd = None
+ hapd = start_dfs_ap(apdev[0], chanlist="56")
+
+ ev = hapd.wait_event(["AP-ENABLED"], timeout=70)
+ if not ev:
+ raise Exception("AP2 setup timed out")
+
+ dfs_simulate_radar(hapd)
+ ev = wait_dfs_event(hapd, "DFS-RADAR-DETECTED", 5)
+ if "freq=5260 ht_enabled=1 chan_offset=0 chan_width=1" not in ev:
+ raise Exception("Unexpected DFS radar detection freq from AP")
+
+ ev = wait_dfs_event(hapd, "DFS-NEW-CHANNEL", 5)
+ if "freq=5280 chan=56" not in ev:
+ raise Exception("Unexpected DFS new freq: " + ev)
+ ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
+ if "freq=5280" not in ev:
+ raise Exception("Unexpected channel: " + ev)
+ ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
+ if "success=1" not in ev:
+ raise Exception("CAC failed")
+ if "freq=5280" not in ev:
+ raise Exception("Unexpected DFS freq result")
+ ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
+ if not ev:
+ raise Exception("AP setup timed out")
+
+ dfs_simulate_radar(hapd)
+ ev = wait_dfs_event(hapd, "DFS-RADAR-DETECTED", 5)
+ if "freq=5280 ht_enabled=1 chan_offset=0 chan_width=1" not in ev:
+ raise Exception("Unexpected DFS radar detection freq from AP [2]")
+
+ ev = hapd.wait_event(["AP-DISABLED"], timeout=10)
+ if ev is None:
+ raise Exception("AP was not disabled")
+ finally:
+ clear_regdom(hapd, dev)
+
+def dfs_chan_switch_precac(dev, apdev, country):
+ """DFS channel switch pre CAC"""
+ try:
+ hapd = None
+
+ # Toggle regulatory - clean all preCAC
+ hostapd.cmd_execute(apdev[0], ['iw', 'reg', 'set', 'US'])
+
+ hapd = start_dfs_ap(apdev[0], country=country)
+
+ ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
+ if "success=1" not in ev:
+ raise Exception("CAC failed")
+ if "freq=5260" not in ev:
+ raise Exception("Unexpected DFS freq result")
+ ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
+ if not ev:
+ raise Exception("AP setup timed out")
+ freq = hapd.get_status_field("freq")
+ if freq != "5260":
+ raise Exception("Unexpected frequency")
+
+ # TODO add/connect station here
+ # Today skip this step while dev[0].connect()
+ # for some reason toggle regulatory to US
+ # and clean preCAC
+
+ # Back to non DFS channel
+ if "OK" not in hapd.request("CHAN_SWITCH 5 5180 ht"):
+ raise Exception("CHAN_SWITCH 5180 failed")
+
+ ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=5)
+ if not ev:
+ raise Exception("No CSA finished event - 5180")
+ freq = hapd.get_status_field("freq")
+ if freq != "5180":
+ raise Exception("Unexpected frequency")
+
+ # Today cfg80211 first send AP-CSA-FINISHED and next
+ # DFS-PRE-CAC-EXPIRED
+ ev = hapd.wait_event(["DFS-PRE-CAC-EXPIRED"], timeout=3)
+ if not ev and country == 'US':
+ raise Exception("US - no CAC-EXPIRED event")
+
+ # Back again to DFS channel (CAC passed)
+ if "OK" not in hapd.request("CHAN_SWITCH 5 5260 ht"):
+ raise Exception("CHAN_SWITCH 5260 failed")
+
+ if country == 'US':
+ # For non EU we should start CAC again
+ ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
+ if not ev:
+ raise Exception("No DFS CAC start event")
+ else:
+ # For EU preCAC should be used
+ ev = wait_dfs_event(hapd, "AP-CSA-FINISHED", 5)
+ if not ev:
+ raise Exception("No CSA finished event - 5260")
+ finally:
+ clear_regdom(hapd, dev)
+
+@long_duration_test
+def test_dfs_eu_chan_switch_precac(dev, apdev):
+ """DFS channel switch pre CAC - ETSI domain"""
+ dfs_chan_switch_precac(dev, apdev, 'PL')
+
+@long_duration_test
+def test_dfs_us_chan_switch_precac(dev, apdev):
+ """DFS channel switch pre CAC - FCC domain"""
+ dfs_chan_switch_precac(dev, apdev, 'US')
diff --git a/tests/hwsim/test_dpp.py b/tests/hwsim/test_dpp.py
index ff03814..233c6a5 100644
--- a/tests/hwsim/test_dpp.py
+++ b/tests/hwsim/test_dpp.py
@@ -2821,6 +2821,7 @@ def run_dpp_proto_init(dev, test_dev, test, mutual=False, unicast=True,
own = id1b
dev[1].dpp_auth_init(uri=uri0, role=role, configurator=configurator,
conf=conf, own=own)
+ return uri0, role, configurator, conf, own
def test_dpp_proto_after_wrapped_data_auth_req(dev, apdev):
"""DPP protocol testing - attribute after Wrapped Data in Auth Req"""
@@ -3249,7 +3250,7 @@ def test_dpp_proto_stop_at_auth_req(dev, apdev):
def test_dpp_proto_stop_at_auth_resp(dev, apdev):
"""DPP protocol testing - stop when receiving Auth Resp"""
- run_dpp_proto_init(dev, 1, 88)
+ uri0, role, configurator, conf, own = run_dpp_proto_init(dev, 1, 88)
ev = dev[1].wait_event(["DPP-TX "], timeout=5)
if ev is None:
@@ -3263,6 +3264,18 @@ def test_dpp_proto_stop_at_auth_resp(dev, apdev):
if ev is not None:
raise Exception("Unexpected Auth Conf TX")
+ ev = dev[0].wait_event(["DPP-FAIL"], timeout=2)
+ if ev is None or "No Auth Confirm received" not in ev:
+ raise Exception("DPP-FAIL for missing Auth Confirm not reported")
+ time.sleep(0.1)
+
+ # Try again without special testing behavior to confirm Responder is able
+ # to accept a new provisioning attempt.
+ dev[1].set("dpp_test", "0")
+ dev[1].dpp_auth_init(uri=uri0, role=role, configurator=configurator,
+ conf=conf, own=own)
+ wait_auth_success(dev[0], dev[1])
+
def test_dpp_proto_stop_at_auth_conf(dev, apdev):
"""DPP protocol testing - stop when receiving Auth Conf"""
run_dpp_proto_init(dev, 0, 89, init_enrollee=True)
@@ -5378,6 +5391,14 @@ def test_dpp_chirp_configurator(dev, apdev):
if "type=13" not in ev:
raise Exception("Unexpected DPP frame received: " + ev)
+ ev = dev[1].wait_event(["DPP-TX"], timeout=10)
+ if ev is None:
+ raise Exception("Authentication Request TX not seen")
+ if "type=0" not in ev:
+ raise Exception("Unexpected DPP frame TX: " + ev)
+ if "dst=" + dev[0].own_addr() not in ev:
+ raise Exception("Unexpected Authentication Request destination: " + ev)
+
wait_auth_success(dev[0], dev[1], dev[1], dev[0])
def test_dpp_chirp_configurator_inits(dev, apdev):
@@ -5967,6 +5988,9 @@ def test_dpp_enterprise_reject(dev, apdev, params):
def test_dpp_enterprise_tcp(dev, apdev, params):
"""DPP over TCP for enterprise provisioning"""
+ if not openssl_imported:
+ raise HwsimSkip("OpenSSL python method not available")
+
try:
run_dpp_enterprise_tcp(dev, apdev, params)
finally:
@@ -6054,6 +6078,9 @@ def run_dpp_enterprise_tcp_end(params, dev, wt):
def test_dpp_enterprise_tcp2(dev, apdev, params):
"""DPP over TCP for enterprise provisioning (Controller initiating)"""
+ if not openssl_imported:
+ raise HwsimSkip("OpenSSL python method not available")
+
try:
run_dpp_enterprise_tcp2(dev, apdev, params)
finally:
diff --git a/tests/hwsim/test_eap_proto.py b/tests/hwsim/test_eap_proto.py
index 7494b42..3401749 100644
--- a/tests/hwsim/test_eap_proto.py
+++ b/tests/hwsim/test_eap_proto.py
@@ -5629,8 +5629,7 @@ def test_eap_proto_aka_errors(dev, apdev):
tests = [(1, "=eap_aka_learn_ids"),
(2, "=eap_aka_learn_ids"),
(1, "eap_sim_parse_encr;eap_aka_process_challenge"),
- (1, "wpabuf_dup;eap_aka_add_id_msg"),
- (1, "wpabuf_resize;eap_aka_add_id_msg"),
+ (1, "wpabuf_alloc;eap_aka_add_id_msg"),
(1, "eap_aka_getKey"),
(1, "eap_aka_get_emsk"),
(1, "eap_aka_get_session_id")]
diff --git a/tests/hwsim/test_ext_password.py b/tests/hwsim/test_ext_password.py
index dfaf3ea..789b673 100644
--- a/tests/hwsim/test_ext_password.py
+++ b/tests/hwsim/test_ext_password.py
@@ -7,6 +7,8 @@
from remotehost import remote_compatible
import logging
logger = logging.getLogger()
+import os
+import tempfile
import hostapd
from utils import skip_with_fips
@@ -79,3 +81,32 @@ def test_ext_password_interworking(dev, apdev):
dev[0].set_cred(id, "password", "ext:pw1")
interworking_select(dev[0], bssid, freq="2412")
interworking_connect(dev[0], bssid, "TTLS")
+
+def test_ext_password_file_psk(dev, apdev):
+ """External password (file) storage for PSK"""
+ params = hostapd.wpa2_params(ssid="ext-pw-psk", passphrase="12345678")
+ hostapd.add_ap(apdev[0], params)
+ fd, fn = tempfile.mkstemp()
+ with open(fn, "w") as f:
+ f.write("psk1=12345678\n")
+ os.close(fd)
+ dev[0].request("SET ext_password_backend file:%s" % fn)
+ dev[0].connect("ext-pw-psk", raw_psk="ext:psk1", scan_freq="2412")
+ for i in range(2):
+ dev[0].request("REMOVE_NETWORK all")
+ if i == 0:
+ dev[0].wait_disconnected()
+ dev[0].connect("ext-pw-psk", raw_psk="ext:psk2", scan_freq="2412",
+ wait_connect=False)
+ else:
+ dev[0].connect("ext-pw-psk", raw_psk="ext:psk1", scan_freq="2412",
+ wait_connect=False)
+ ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
+ "EXT PW: No PSK found from external storage"],
+ timeout=10)
+ if i == 0:
+ os.unlink(fn)
+ if ev is None:
+ raise Exception("No connection result reported")
+ if "CTRL-EVENT-CONNECTED" in ev:
+ raise Exception("Unexpected connection")
diff --git a/tests/hwsim/test_fils.py b/tests/hwsim/test_fils.py
index 8e4df65..4616ca3 100644
--- a/tests/hwsim/test_fils.py
+++ b/tests/hwsim/test_fils.py
@@ -2330,3 +2330,37 @@ def test_fils_auth_ptk_rekey_ap_ext_key_id(dev, apdev, params):
hwsim_utils.test_connectivity(dev[0], hapd)
finally:
dev[0].set("extended_key_id", "0")
+
+def test_fils_discovery_frame(dev, apdev, params):
+ """FILS Discovery frame generation"""
+ check_fils_capa(dev[0])
+ check_erp_capa(dev[0])
+
+ start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
+
+ bssid = apdev[0]['bssid']
+ params = hostapd.wpa2_eap_params(ssid="fils")
+ params['wpa_key_mgmt'] = "FILS-SHA256"
+ params['auth_server_port'] = "18128"
+ params['erp_send_reauth_start'] = '1'
+ params['erp_domain'] = 'example.com'
+ params['fils_realm'] = 'example.com'
+ params['wpa_group_rekey'] = '1'
+ params['fils_discovery_min_interval'] = '20'
+ params['fils_discovery_max_interval'] = '20'
+ hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
+
+ if "OK" not in hapd.request("ENABLE"):
+ raise HwsimSkip("FILS Discovery frame transmission not supported")
+
+ ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=5)
+ if ev is None:
+ raise Exception("AP startup timed out")
+ if "AP-ENABLED" not in ev:
+ raise Exception("AP startup failed")
+
+ dev[0].request("ERP_FLUSH")
+ dev[0].connect("fils", key_mgmt="FILS-SHA256",
+ eap="PSK", identity="psk.user@example.com",
+ password_hex="0123456789abcdef0123456789abcdef",
+ erp="1", scan_freq="2412")
diff --git a/tests/hwsim/test_he.py b/tests/hwsim/test_he.py
index 28123e8..21c1b55 100644
--- a/tests/hwsim/test_he.py
+++ b/tests/hwsim/test_he.py
@@ -67,6 +67,12 @@ def test_he_params(dev, apdev):
"he_spr_non_srg_obss_pd_max_offset": "0",
"he_spr_srg_obss_pd_min_offset": "0",
"he_spr_srg_obss_pd_max_offset": "0",
+ "he_spr_srg_bss_colors": "1 2 10 63",
+ "he_spr_srg_partial_bssid": "0 1 3 63",
+ "he_6ghz_max_ampdu_len_exp": "7",
+ "he_6ghz_rx_ant_pat": "1",
+ "he_6ghz_tx_ant_pat": "1",
+ "he_6ghz_max_mpdu": "2",
"he_oper_chwidth": "0",
"he_oper_centr_freq_seg0_idx": "1",
"he_oper_centr_freq_seg1_idx": "0"}
@@ -154,27 +160,19 @@ def test_he80(dev, apdev):
dev[0].request("DISCONNECT")
clear_regdom(hapd, dev)
-def test_he_wifi_generation(dev, apdev):
+def _test_he_wifi_generation(dev, apdev, conf, scan_freq):
"""HE and wifi_generation"""
try:
hapd = None
params = {"ssid": "he",
"country_code": "FI",
- "hw_mode": "a",
- "channel": "36",
- "ht_capab": "[HT40+]",
"ieee80211n": "1",
- "ieee80211ac": "1",
- "ieee80211ax": "1",
- "vht_oper_chwidth": "1",
- "vht_capab": "[MAX-MPDU-11454]",
- "vht_oper_centr_freq_seg0_idx": "42",
- "he_oper_chwidth": "1",
- "he_oper_centr_freq_seg0_idx": "42"}
+ "ieee80211ax": "1"}
+ params.update(conf)
hapd = hostapd.add_ap(apdev[0], params)
bssid = apdev[0]['bssid']
- dev[0].connect("he", key_mgmt="NONE", scan_freq="5180")
+ dev[0].connect("he", key_mgmt="NONE", scan_freq=scan_freq)
status = dev[0].get_status()
if 'wifi_generation' not in status:
# For now, assume this is because of missing kernel support
@@ -185,7 +183,7 @@ def test_he_wifi_generation(dev, apdev):
wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
- wpas.connect("he", key_mgmt="NONE", scan_freq="5180")
+ wpas.connect("he", key_mgmt="NONE", scan_freq=scan_freq)
status = wpas.get_status()
if 'wifi_generation' not in status:
# For now, assume this is because of missing kernel support
@@ -202,6 +200,27 @@ def test_he_wifi_generation(dev, apdev):
dev[0].request("DISCONNECT")
clear_regdom(hapd, dev)
+def test_he_wifi_generation(dev, apdev):
+ conf = {
+ "vht_oper_chwidth": "1",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42",
+ "vht_capab": "[MAX-MPDU-11454]",
+ "ieee80211ac": "1",
+ }
+ _test_he_wifi_generation(dev, apdev, conf, "5180")
+
+def test_he_wifi_generation_24(dev, apdev):
+ conf = {
+ "hw_mode": "g",
+ "channel": "1",
+ }
+ _test_he_wifi_generation(dev, apdev, conf, "2412")
+
def he80_test(apdev, dev, channel, ht_capab):
clear_scan_cache(apdev)
try:
@@ -992,7 +1011,7 @@ def test_he_tkip(dev, apdev):
raise Exception("Unexpected STATUS ieee80211n value")
if status["ieee80211ac"] != "0":
raise Exception("Unexpected STATUS ieee80211ac value")
- if status["ieee80211ax"] != "1":
+ if status["ieee80211ax"] != "0":
raise Exception("Unexpected STATUS ieee80211ax value")
if status["secondary_channel"] != "0":
raise Exception("Unexpected STATUS secondary_channel value")
diff --git a/tests/hwsim/test_multi_ap.py b/tests/hwsim/test_multi_ap.py
index 4070d3e..ff761f3 100644
--- a/tests/hwsim/test_multi_ap.py
+++ b/tests/hwsim/test_multi_ap.py
@@ -5,6 +5,7 @@
# See README for more details.
import hostapd
+from wpasupplicant import WpaSupplicant
from utils import *
def test_multi_ap_association(dev, apdev):
@@ -38,6 +39,42 @@ def run_multi_ap_association(dev, apdev, multi_ap, wait_connect=True):
dev[0].connect("multi-ap", psk="12345678", scan_freq="2412",
multi_ap_backhaul_sta="1", wait_connect=wait_connect)
+def test_multi_ap_backhaul_roam_with_bridge(dev, apdev):
+ """Multi-AP backhaul BSS reassociation to another BSS with bridge"""
+ br_ifname = 'sta-br0'
+ ifname = 'wlan5'
+ try:
+ run_multi_ap_backhaul_roam_with_bridge(dev, apdev)
+ finally:
+ subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'down'])
+ subprocess.call(['brctl', 'delif', br_ifname, ifname])
+ subprocess.call(['brctl', 'delbr', br_ifname])
+ subprocess.call(['iw', ifname, 'set', '4addr', 'off'])
+
+def run_multi_ap_backhaul_roam_with_bridge(dev, apdev):
+ br_ifname = 'sta-br0'
+ ifname = 'wlan5'
+ wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+ subprocess.call(['brctl', 'addbr', br_ifname])
+ subprocess.call(['brctl', 'setfd', br_ifname, '0'])
+ subprocess.call(['ip', 'link', 'set', 'dev', br_ifname, 'up'])
+ subprocess.call(['iw', ifname, 'set', '4addr', 'on'])
+ subprocess.check_call(['brctl', 'addif', br_ifname, ifname])
+ wpas.interface_add(ifname, br_ifname=br_ifname)
+ wpas.flush_scan_cache()
+
+ params = hostapd.wpa2_params(ssid="multi-ap", passphrase="12345678")
+ params["multi_ap"] = "1"
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ wpas.connect("multi-ap", psk="12345678", scan_freq="2412",
+ multi_ap_backhaul_sta="1")
+
+ hapd2 = hostapd.add_ap(apdev[1], params)
+ bssid2 = hapd2.own_addr()
+ wpas.scan_for_bss(bssid2, freq="2412", force_scan=True)
+ wpas.roam(bssid2)
+
def test_multi_ap_disabled_on_ap(dev, apdev):
"""Multi-AP association attempt when disabled on AP"""
run_multi_ap_association(dev, apdev, 0, wait_connect=False)
@@ -63,7 +100,8 @@ def test_multi_ap_fronthaul_on_ap(dev, apdev):
if "CTRL-EVENT-DISCONNECTED" not in ev:
raise Exception("Unexpected connection result")
-def run_multi_ap_wps(dev, apdev, params, multi_ap_bssid=None):
+def run_multi_ap_wps(dev, apdev, params, params_backhaul=None, add_apdev=False,
+ run_csa=False, allow_csa_fail=False):
"""Helper for running Multi-AP WPS tests
dev[0] does multi_ap WPS, dev[1] does normal WPS. apdev[0] is the fronthaul
@@ -72,8 +110,14 @@ def run_multi_ap_wps(dev, apdev, params, multi_ap_bssid=None):
the WPS parameters. multi_ap_bssid must be given if it is not equal to the
fronthaul BSSID."""
- if multi_ap_bssid is None:
+ wpas_apdev = None
+
+ if params_backhaul:
+ hapd_backhaul = hostapd.add_ap(apdev[1], params_backhaul)
+ multi_ap_bssid = hapd_backhaul.own_addr()
+ else:
multi_ap_bssid = apdev[0]['bssid']
+
params.update({"wps_state": "2", "eap_server": "1"})
# WPS with multi-ap station dev[0]
@@ -130,6 +174,42 @@ def run_multi_ap_wps(dev, apdev, params, multi_ap_bssid=None):
if len(dev[1].list_networks()) != 1:
raise Exception("Unexpected number of network blocks")
+ try:
+ # Add apdev to the same phy that dev[0]
+ if add_apdev:
+ wpas_apdev = {}
+ wpas_apdev['ifname'] = dev[0].ifname + "_ap"
+ status, buf = dev[0].cmd_execute(['iw', dev[0].ifname,
+ 'interface', 'add',
+ wpas_apdev['ifname'],
+ 'type', 'managed'])
+ if status != 0:
+ raise Exception("iw interface add failed")
+ wpas_hapd = hostapd.add_ap(wpas_apdev, params)
+
+ if run_csa:
+ if 'OK' not in hapd.request("CHAN_SWITCH 5 2462 ht"):
+ raise Exception("chan switch request failed")
+
+ ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=5)
+ if not ev:
+ raise Exception("chan switch failed")
+
+ # now check station
+ ev = dev[0].wait_event(["CTRL-EVENT-CHANNEL-SWITCH",
+ "CTRL-EVENT-DISCONNECTED"], timeout=5)
+ if not ev:
+ raise Exception("sta - no chanswitch event")
+ if "CTRL-EVENT-CHANNEL-SWITCH" not in ev and not allow_csa_fail:
+ raise Exception("Received disconnection event instead of channel switch event")
+
+ if add_apdev:
+ dev[0].cmd_execute(['iw', wpas_apdev['ifname'], 'del'])
+ except:
+ if wpas_apdev:
+ dev[0].cmd_execute(['iw', wpas_apdev['ifname'], 'del'])
+ raise
+
def test_multi_ap_wps_shared(dev, apdev):
"""WPS on shared fronthaul/backhaul AP"""
ssid = "multi-ap-wps"
@@ -140,6 +220,30 @@ def test_multi_ap_wps_shared(dev, apdev):
"multi_ap_backhaul_wpa_passphrase": passphrase})
run_multi_ap_wps(dev, apdev, params)
+def test_multi_ap_wps_shared_csa(dev, apdev):
+ """WPS on shared fronthaul/backhaul AP, run CSA"""
+ ssid = "multi-ap-wps-csa"
+ passphrase = "12345678"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+ params.update({"multi_ap": "3",
+ "multi_ap_backhaul_ssid": '"%s"' % ssid,
+ "multi_ap_backhaul_wpa_passphrase": passphrase})
+ run_multi_ap_wps(dev, apdev, params, run_csa=True)
+
+def test_multi_ap_wps_shared_apdev_csa(dev, apdev):
+ """WPS on shared fronthaul/backhaul AP add apdev on same phy and run CSA"""
+ ssid = "multi-ap-wps-apdev-csa"
+ passphrase = "12345678"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
+ params.update({"multi_ap": "3",
+ "multi_ap_backhaul_ssid": '"%s"' % ssid,
+ "multi_ap_backhaul_wpa_passphrase": passphrase})
+ # This case is currently failing toc omplete CSA on the station interface.
+ # For the time being, ignore that to avoid always failing tests. Full
+ # validation can be enabled once the issue behind this is fixed.
+ run_multi_ap_wps(dev, apdev, params, add_apdev=True, run_csa=True,
+ allow_csa_fail=True)
+
def test_multi_ap_wps_shared_psk(dev, apdev):
"""WPS on shared fronthaul/backhaul AP using PSK"""
ssid = "multi-ap-wps"
@@ -163,9 +267,8 @@ def test_multi_ap_wps_split(dev, apdev):
params_backhaul = hostapd.wpa2_params(ssid=backhaul_ssid,
passphrase=backhaul_passphrase)
params_backhaul.update({"multi_ap": "1"})
- hapd_backhaul = hostapd.add_ap(apdev[1], params_backhaul)
- run_multi_ap_wps(dev, apdev, params, hapd_backhaul.own_addr())
+ run_multi_ap_wps(dev, apdev, params, params_backhaul)
def test_multi_ap_wps_split_psk(dev, apdev):
"""WPS on split fronthaul and backhaul AP"""
@@ -178,9 +281,8 @@ def test_multi_ap_wps_split_psk(dev, apdev):
"multi_ap_backhaul_wpa_psk": backhaul_psk})
params_backhaul = hostapd.wpa2_params(ssid=backhaul_ssid)
params_backhaul.update({"multi_ap": "1", "wpa_psk": backhaul_psk})
- hapd_backhaul = hostapd.add_ap(apdev[1], params_backhaul)
- run_multi_ap_wps(dev, apdev, params, hapd_backhaul.own_addr())
+ run_multi_ap_wps(dev, apdev, params, params_backhaul)
def test_multi_ap_wps_split_mixed(dev, apdev):
"""WPS on split fronthaul and backhaul AP with mixed-mode fronthaul"""
@@ -195,9 +297,8 @@ def test_multi_ap_wps_split_mixed(dev, apdev):
params_backhaul = hostapd.wpa2_params(ssid=backhaul_ssid,
passphrase=backhaul_passphrase)
params_backhaul.update({"multi_ap": "1"})
- hapd_backhaul = hostapd.add_ap(apdev[1], params_backhaul)
- run_multi_ap_wps(dev, apdev, params, hapd_backhaul.own_addr())
+ run_multi_ap_wps(dev, apdev, params, params_backhaul)
def test_multi_ap_wps_split_open(dev, apdev):
"""WPS on split fronthaul and backhaul AP with open fronthaul"""
@@ -209,9 +310,8 @@ def test_multi_ap_wps_split_open(dev, apdev):
params_backhaul = hostapd.wpa2_params(ssid=backhaul_ssid,
passphrase=backhaul_passphrase)
params_backhaul.update({"multi_ap": "1"})
- hapd_backhaul = hostapd.add_ap(apdev[1], params_backhaul)
- run_multi_ap_wps(dev, apdev, params, hapd_backhaul.own_addr())
+ run_multi_ap_wps(dev, apdev, params, params_backhaul)
def test_multi_ap_wps_fail_non_multi_ap(dev, apdev):
"""Multi-AP WPS on non-WPS AP fails"""
diff --git a/tests/hwsim/test_p2p_channel.py b/tests/hwsim/test_p2p_channel.py
index 87a1a24..d57234d 100644
--- a/tests/hwsim/test_p2p_channel.py
+++ b/tests/hwsim/test_p2p_channel.py
@@ -17,7 +17,7 @@ from tshark import run_tshark
from wpasupplicant import WpaSupplicant
from hwsim import HWSimRadio
from p2p_utils import *
-from utils import clear_regdom_dev
+from utils import *
def set_country(country, dev=None):
subprocess.call(['iw', 'reg', 'set', country])
@@ -226,6 +226,7 @@ def test_p2p_channel_avoid2(dev):
def test_p2p_channel_avoid3(dev):
"""P2P and avoid frequencies driver event on 5 GHz"""
try:
+ dev[0].global_request("SET p2p_pref_chan 128:44")
set_country("CN", dev[0])
form(dev[0], dev[1])
set_country("CN", dev[0])
@@ -251,6 +252,7 @@ def test_p2p_channel_avoid3(dev):
finally:
set_country("00")
dev[0].request("DRIVER_EVENT AVOID_FREQUENCIES")
+ dev[0].global_request("SET p2p_pref_chan ")
dev[1].flush_scan_cache()
@remote_compatible
@@ -603,7 +605,7 @@ def test_p2p_autogo_pref_chan_not_in_regulatory(dev, apdev):
raise Exception("Unexpected number of network blocks: " + str(netw))
id = netw[0]['id']
- set_country("SE", dev[0])
+ set_country("JP", dev[0])
res = autogo(dev[0], persistent=id)
if res['freq'] == "5745":
raise Exception("Unexpected channel selected(2): " + res['freq'])
@@ -950,7 +952,8 @@ def _test_p2p_go_move_scm_peer_supports(dev, apdev):
dev[0].remove_group()
finally:
dev[0].global_request("SET p2p_go_freq_change_policy 2")
- set_country("00")
+ disable_hapd(hapd)
+ clear_regdom_dev(dev, 1)
def test_p2p_go_move_scm_peer_does_not_support(dev, apdev):
"""No P2P GO move due to SCM operation (peer does not supports)"""
@@ -996,6 +999,7 @@ def _test_p2p_go_move_scm_peer_does_not_support(dev, apdev):
finally:
dev[0].global_request("SET p2p_go_freq_change_policy 2")
dev[1].request("DRIVER_EVENT AVOID_FREQUENCIES")
+ disable_hapd(hapd)
clear_regdom_dev(dev, 2)
def test_p2p_go_move_scm_multi(dev, apdev):
diff --git a/tests/hwsim/test_p2p_discovery.py b/tests/hwsim/test_p2p_discovery.py
index f4353e8..4bce4ec 100644
--- a/tests/hwsim/test_p2p_discovery.py
+++ b/tests/hwsim/test_p2p_discovery.py
@@ -7,9 +7,12 @@
from remotehost import remote_compatible
import logging
logger = logging.getLogger()
+import binascii
import os
+import struct
import time
+import hostapd
import hwsim_utils
from wpasupplicant import WpaSupplicant
from p2p_utils import *
@@ -776,3 +779,42 @@ def test_discovery_device_name_change(dev):
raise Exception("Unexpected device name(2): " + ev)
wpas.p2p_stop_find()
dev[0].p2p_stop_find()
+
+def test_p2p_group_cli_invalid(dev, apdev):
+ """P2P device discovery with invalid group client info"""
+ attr = struct.pack('<BHBB', 2, 2, 0x25, 0x09)
+
+ attr += struct.pack('<BH', 3, 6) + "\x02\x02\x02\x02\x02\x00".encode()
+
+ cli = bytes()
+ cli += "\x02\x02\x02\x02\x02\x03".encode()
+ cli += "\x02\x02\x02\x02\x02\x04".encode()
+ cli += struct.pack('>BH', 0, 0x3148)
+ dev_type = "\x00\x00\x00\x00\x00\x00\x00\x01".encode()
+ cli += dev_type
+ num_sec = 25
+ cli += struct.pack('B', num_sec)
+ cli += num_sec * dev_type
+ name = "TEST".encode()
+ cli += struct.pack('>HH', 0x1011, len(name)) + name
+ desc = struct.pack('B', len(cli)) + cli
+ attr += struct.pack('<BH', 14, len(desc)) + desc
+
+ p2p_ie = struct.pack('>BBL', 0xdd, 4 + len(attr), 0x506f9a09) + attr
+ ie = binascii.hexlify(p2p_ie).decode()
+
+ params = {"ssid": "DIRECT-test",
+ "eap_server": "1",
+ "wps_state": "2",
+ "wpa_passphrase": "12345678",
+ "wpa": "2",
+ "wpa_key_mgmt": "WPA-PSK",
+ "rsn_pairwise": "CCMP",
+ "vendor_elements": ie}
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ for i in range(2):
+ dev[i].p2p_find(social=True)
+ ev = dev[i].wait_global_event(["P2P-DEVICE-FOUND"], timeout=5)
+ if not ev:
+ raise Exception("P2P device not found")
diff --git a/tests/hwsim/test_pasn.py b/tests/hwsim/test_pasn.py
new file mode 100644
index 0000000..3ee8cf5
--- /dev/null
+++ b/tests/hwsim/test_pasn.py
@@ -0,0 +1,638 @@
+# Test cases for PASN
+# Copyright (C) 2019 Intel Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+from remotehost import remote_compatible
+import binascii
+import os
+import time
+import logging
+logger = logging.getLogger()
+import socket
+import struct
+import subprocess
+
+import hwsim_utils
+import hostapd
+from wpasupplicant import WpaSupplicant
+from utils import *
+from hwsim import HWSimRadio
+from test_erp import check_erp_capa, start_erp_as
+from test_fils import check_fils_capa
+from test_ap_ft import run_roams, ft_params1, ft_params2
+
+def check_pasn_capab(dev):
+ if "PASN" not in dev.get_capability("auth_alg"):
+ raise HwsimSkip("PASN not supported")
+
+def pasn_ap_params(akmp="PASN", cipher="CCMP", group="19"):
+ params = {"ssid": "test-wpa2-pasn",
+ "wpa_passphrase": "12345678",
+ "wpa": "2",
+ "ieee80211w": "2",
+ "wpa_key_mgmt": "WPA-PSK " + akmp,
+ "rsn_pairwise": cipher,
+ "pasn_groups" : group}
+
+ return params
+
+def start_pasn_ap(apdev, params):
+ try:
+ return hostapd.add_ap(apdev, params)
+ except Exception as e:
+ if "Failed to set hostapd parameter wpa_key_mgmt" in str(e) or \
+ "Failed to set hostapd parameter force_kdk_derivation" in str(e):
+ raise HwsimSkip("PASN not supported")
+ raise
+
+def check_pasn_ptk(dev, hapd, cipher):
+ sta_ptksa = dev.get_ptksa(hapd.own_addr(), cipher)
+ ap_ptksa = hapd.get_ptksa(dev.own_addr(), cipher)
+ if not (sta_ptksa and ap_ptksa):
+ raise Exception("Could not get PTKSA entry")
+
+ logger.info("sta: TK: %s KDK: %s" % (sta_ptksa['tk'], sta_ptksa['kdk']))
+ logger.info("ap : TK: %s KDK: %s" % (ap_ptksa['tk'], ap_ptksa['kdk']))
+
+ if sta_ptksa['tk'] != ap_ptksa['tk'] or sta_ptksa['kdk'] != ap_ptksa['kdk']:
+ raise Exception("TK/KDK mismatch")
+
+def check_pasn_akmp_cipher(dev, hapd, akmp="PASN", cipher="CCMP",
+ group="19", status=0, fail=0, nid=""):
+ dev.flush_scan_cache()
+ dev.scan(type="ONLY", freq=2412)
+
+ cmd = "PASN_START bssid=%s akmp=%s cipher=%s group=%s" % (hapd.own_addr(), akmp, cipher, group)
+
+ resp = dev.request(cmd)
+ if nid != "":
+ cmd += " nid=%s" % nid
+
+ if fail:
+ if "OK" in resp:
+ raise Exception("Unexpected success to start PASN authentication")
+ return
+
+ if "OK" not in resp:
+ raise Exception("Failed to start PASN authentication")
+
+ ev = dev.wait_event(["PASN-AUTH-STATUS"], 3)
+ if not ev:
+ raise Exception("PASN: PASN-AUTH-STATUS not seen")
+
+ if hapd.own_addr() + " akmp=" + akmp + ", status=" + str(status) not in ev:
+ raise Exception("PASN: unexpected status")
+
+ if status:
+ return
+
+ check_pasn_ptk(dev, hapd, cipher)
+
+@remote_compatible
+def test_pasn_ccmp(dev, apdev):
+ """PASN authentication with WPA2/CCMP AP"""
+ check_pasn_capab(dev[0])
+
+ params = pasn_ap_params("PASN", "CCMP", "19")
+ hapd = start_pasn_ap(apdev[0], params)
+
+ check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
+
+@remote_compatible
+def test_pasn_gcmp(dev, apdev):
+ """PASN authentication with WPA2/GCMP AP"""
+ check_pasn_capab(dev[0])
+
+ params = pasn_ap_params("PASN", "GCMP", "19")
+ hapd = start_pasn_ap(apdev[0], params)
+
+ check_pasn_akmp_cipher(dev[0], hapd, "PASN", "GCMP")
+
+@remote_compatible
+def test_pasn_ccmp_256(dev, apdev):
+ """PASN authentication with WPA2/CCMP256 AP"""
+ check_pasn_capab(dev[0])
+
+ params = pasn_ap_params("PASN", "CCMP-256", "19")
+ hapd = start_pasn_ap(apdev[0], params)
+
+ check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP-256")
+
+@remote_compatible
+def test_pasn_gcmp_256(dev, apdev):
+ """PASN authentication with WPA2/GCMP-256 AP"""
+ check_pasn_capab(dev[0])
+
+ params = pasn_ap_params("PASN", "GCMP-256", "19")
+ hapd = start_pasn_ap(apdev[0], params)
+
+ check_pasn_akmp_cipher(dev[0], hapd, "PASN", "GCMP-256")
+
+@remote_compatible
+def test_pasn_group_mismatch(dev, apdev):
+ """PASN authentication with WPA2/CCMP AP with group mismatch"""
+ check_pasn_capab(dev[0])
+
+ params = pasn_ap_params("PASN", "CCMP", "20")
+ hapd = start_pasn_ap(apdev[0], params)
+
+ check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", status=77)
+
+@remote_compatible
+def test_pasn_channel_mismatch(dev, apdev):
+ """PASN authentication with WPA2/CCMP AP with channel mismatch"""
+ check_pasn_capab(dev[0])
+
+ params = pasn_ap_params("PASN", "CCMP")
+ params['channel'] = "6"
+ hapd = start_pasn_ap(apdev[0], params)
+
+ check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", fail=1)
+
+@remote_compatible
+def test_pasn_while_connected_same_channel(dev, apdev):
+ """PASN authentication with WPA2/CCMP AP while connected same channel"""
+ check_pasn_capab(dev[0])
+
+ ssid = "test-wpa2-psk"
+ psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
+ params = hostapd.wpa2_params(ssid=ssid)
+ params['wpa_psk'] = psk
+ hapd = start_pasn_ap(apdev[0], params)
+
+ dev[0].connect(ssid, raw_psk=psk, scan_freq="2412")
+
+ params = pasn_ap_params("PASN", "CCMP")
+ hapd = start_pasn_ap(apdev[1], params)
+
+ check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP")
+
+@remote_compatible
+def test_pasn_while_connected_same_ap(dev, apdev):
+ """PASN authentication with WPA2/CCMP AP while connected to it"""
+ check_pasn_capab(dev[0])
+
+ params = hostapd.wpa2_params(ssid="test-wpa2-psk",
+ passphrase="12345678")
+ hapd = start_pasn_ap(apdev[0], params)
+
+ dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412")
+
+ check_pasn_akmp_cipher(dev[0], hapd, "PASN", "CCMP", fail=1)
+
+@remote_compatible
+def test_pasn_while_connected_diff_channel(dev, apdev):
+ """PASN authentication with WPA2/CCMP AP while connected diff channel"""
+ check_pasn_capab(dev[0])
+
+ with HWSimRadio(n_channels=2) as (radio, iface):
+ wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+ wpas.interface_add(iface)
+
+ if wpas.get_mcc() < 2:
+ raise HwsimSkip("PASN: New radio does not support MCC")
+
+ params = hostapd.wpa2_params(ssid="test-wpa2-psk",
+ passphrase="12345678")
+ params['channel'] = "6"
+ hapd = start_pasn_ap(apdev[0], params)
+ wpas.connect("test-wpa2-psk", psk="12345678", scan_freq="2437")
+
+ params = pasn_ap_params("PASN", "CCMP")
+ hapd2 = start_pasn_ap(apdev[1], params)
+
+ check_pasn_akmp_cipher(wpas, hapd2, "PASN", "CCMP")
+
+@remote_compatible
+def test_pasn_sae_pmksa_cache(dev, apdev):
+ """PASN authentication with SAE AP with PMKSA caching"""
+ check_pasn_capab(dev[0])
+ check_sae_capab(dev[0])
+
+ params = hostapd.wpa2_params(ssid="test-sae",
+ passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE PASN'
+ hapd = start_pasn_ap(apdev[0], params)
+
+ dev[0].set("sae_groups", "19")
+ dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412")
+
+ hapd.wait_sta()
+ hwsim_utils.test_connectivity(dev[0], hapd)
+
+ dev[0].request("DISCONNECT")
+ dev[0].wait_disconnected()
+
+ check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
+
+def check_pasn_fils_pmksa_cache(dev, apdev, params, key_mgmt):
+ check_fils_capa(dev[0])
+ check_erp_capa(dev[0])
+ check_pasn_capab(dev[0])
+
+ start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
+
+ bssid = apdev[0]['bssid']
+ params = hostapd.wpa2_eap_params(ssid="fils")
+ params['wpa_key_mgmt'] = key_mgmt + " PASN"
+ params['auth_server_port'] = "18128"
+ params['erp_domain'] = 'example.com'
+ params['fils_realm'] = 'example.com'
+ hapd = start_pasn_ap(apdev[0], params)
+
+ dev[0].scan_for_bss(bssid, freq=2412)
+ dev[0].request("ERP_FLUSH")
+
+ id = dev[0].connect("fils", key_mgmt=key_mgmt,
+ eap="PSK", identity="psk.user@example.com",
+ password_hex="0123456789abcdef0123456789abcdef",
+ erp="1", scan_freq="2412")
+ pmksa = dev[0].get_pmksa(bssid)
+ if pmksa is None:
+ raise Exception("No PMKSA cache entry created")
+
+ hapd.wait_sta()
+ hwsim_utils.test_connectivity(dev[0], hapd)
+
+ dev[0].request("DISCONNECT")
+ dev[0].wait_disconnected()
+
+ check_pasn_akmp_cipher(dev[0], hapd, key_mgmt, "CCMP")
+
+@remote_compatible
+def test_pasn_fils_sha256_pmksa_cache(dev, apdev, params):
+ """PASN authentication with FILS-SHA256 with PMKSA caching"""
+ check_pasn_fils_pmksa_cache(dev, apdev, params, "FILS-SHA256")
+
+@remote_compatible
+def test_pasn_fils_sha384_pmksa_cache(dev, apdev, params):
+ """PASN authentication with FILS-SHA384 with PMKSA caching"""
+ check_pasn_fils_pmksa_cache(dev, apdev, params, "FILS-SHA384")
+
+@remote_compatible
+def test_pasn_sae_kdk(dev, apdev):
+ """Station authentication with SAE AP with KDK derivation during connection"""
+ check_pasn_capab(dev[0])
+ check_sae_capab(dev[0])
+
+ try:
+ params = hostapd.wpa2_params(ssid="test-sae",
+ passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE PASN'
+ params['force_kdk_derivation'] = "1"
+ hapd = start_pasn_ap(apdev[0], params)
+
+ dev[0].set("force_kdk_derivation", "1")
+ dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+ scan_freq="2412")
+
+ check_pasn_ptk(dev[0], hapd, "CCMP")
+ finally:
+ dev[0].set("force_kdk_derivation", "0")
+
+
+def check_pasn_fils_kdk(dev, apdev, params, key_mgmt):
+ check_fils_capa(dev[0])
+ check_erp_capa(dev[0])
+ check_pasn_capab(dev[0])
+
+ start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
+
+ try:
+ bssid = apdev[0]['bssid']
+ params = hostapd.wpa2_eap_params(ssid="fils")
+ params['wpa_key_mgmt'] = key_mgmt
+ params['auth_server_port'] = "18128"
+ params['erp_domain'] = 'example.com'
+ params['fils_realm'] = 'example.com'
+ params['disable_pmksa_caching'] = '1'
+ params['force_kdk_derivation'] = "1"
+ hapd = start_pasn_ap(apdev[0], params)
+
+ dev[0].scan_for_bss(bssid, freq=2412)
+ dev[0].request("ERP_FLUSH")
+ dev[0].set("force_kdk_derivation", "1")
+
+ id = dev[0].connect("fils", key_mgmt=key_mgmt,
+ eap="PSK", identity="psk.user@example.com",
+ password_hex="0123456789abcdef0123456789abcdef",
+ erp="1", scan_freq="2412")
+
+ hapd.wait_sta()
+ hwsim_utils.test_connectivity(dev[0], hapd)
+
+ check_pasn_ptk(dev[0], hapd, "CCMP")
+
+ dev[0].request("DISCONNECT")
+ dev[0].wait_disconnected()
+
+ dev[0].dump_monitor()
+ dev[0].select_network(id, freq=2412)
+ ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED",
+ "EVENT-ASSOC-REJECT",
+ "CTRL-EVENT-CONNECTED"], timeout=10)
+ if ev is None:
+ raise Exception("Connection using FILS/ERP timed out")
+ if "CTRL-EVENT-EAP-STARTED" in ev:
+ raise Exception("Unexpected EAP exchange")
+ if "EVENT-ASSOC-REJECT" in ev:
+ raise Exception("Association failed")
+
+ hapd.wait_sta()
+ hwsim_utils.test_connectivity(dev[0], hapd)
+
+ check_pasn_ptk(dev[0], hapd, "CCMP")
+ finally:
+ dev[0].set("force_kdk_derivation", "0")
+
+@remote_compatible
+def test_pasn_fils_sha256_kdk(dev, apdev, params):
+ """Station authentication with FILS-SHA256 with KDK derivation during connection"""
+ check_pasn_fils_kdk(dev, apdev, params, "FILS-SHA256")
+
+@remote_compatible
+def test_pasn_fils_sha384_kdk(dev, apdev, params):
+ """Station authentication with FILS-SHA384 with KDK derivation during connection"""
+ check_pasn_fils_kdk(dev, apdev, params, "FILS-SHA384")
+
+@remote_compatible
+def test_pasn_sae(dev, apdev):
+ """PASN authentication with SAE AP with PMK derivation + PMKSA caching"""
+ check_pasn_capab(dev[0])
+ check_sae_capab(dev[0])
+
+ params = hostapd.wpa2_params(ssid="test-pasn-sae",
+ passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE PASN'
+ hapd = start_pasn_ap(apdev[0], params)
+
+ dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412",
+ only_add_network=True)
+
+ # first test with a valid PSK
+ check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="0")
+
+ # And now with PMKSA caching
+ check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP")
+
+ # And now with a wrong passphrase
+ if "FAIL" in dev[0].request("PMKSA_FLUSH"):
+ raise Exception("PMKSA_FLUSH failed")
+
+ dev[0].set_network_quoted(0, "psk", "12345678787")
+ check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", status=1, nid="0")
+
+@remote_compatible
+def test_pasn_sae_while_connected_same_channel(dev, apdev):
+ """PASN SAE authentication while connected same channel"""
+ check_pasn_capab(dev[0])
+ check_sae_capab(dev[0])
+
+ params = hostapd.wpa2_params(ssid="test-pasn-wpa2-psk",
+ passphrase="12345678")
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[0].connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2412")
+
+ params = hostapd.wpa2_params(ssid="test-pasn-sae",
+ passphrase="12345678")
+
+ params['wpa_key_mgmt'] = 'SAE PASN'
+ hapd = start_pasn_ap(apdev[1], params)
+
+ dev[0].connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
+ scan_freq="2412", only_add_network=True)
+
+ check_pasn_akmp_cipher(dev[0], hapd, "SAE", "CCMP", nid="1")
+
+@remote_compatible
+def test_pasn_sae_while_connected_diff_channel(dev, apdev):
+ """PASN SAE authentication while connected diff channel"""
+ check_pasn_capab(dev[0])
+ check_sae_capab(dev[0])
+
+ with HWSimRadio(n_channels=2) as (radio, iface):
+ wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+ wpas.interface_add(iface)
+
+ if wpas.get_mcc() < 2:
+ raise HwsimSkip("PASN: New radio does not support MCC")
+
+ params = hostapd.wpa2_params(ssid="test-pasn-wpa2-psk",
+ passphrase="12345678")
+ params['channel'] = "6"
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ wpas.connect("test-pasn-wpa2-psk", psk="12345678", scan_freq="2437")
+
+ params = hostapd.wpa2_params(ssid="test-pasn-sae",
+ passphrase="12345678")
+
+ params['wpa_key_mgmt'] = 'SAE PASN'
+ hapd = start_pasn_ap(apdev[1], params)
+
+ wpas.connect("test-pasn-sae", psk="12345678", key_mgmt="SAE",
+ scan_freq="2412", only_add_network=True)
+
+ check_pasn_akmp_cipher(wpas, hapd, "SAE", "CCMP", nid="1")
+
+def pasn_fils_setup(wpas, apdev, params, key_mgmt):
+ check_fils_capa(wpas)
+ check_erp_capa(wpas)
+
+ wpas.flush_scan_cache()
+
+ start_erp_as(msk_dump=os.path.join(params['logdir'], "msk.lst"))
+
+ bssid = apdev[0]['bssid']
+ params = hostapd.wpa2_eap_params(ssid="fils")
+ params['wpa_key_mgmt'] = key_mgmt + " PASN"
+ params['auth_server_port'] = "18128"
+ params['erp_domain'] = 'example.com'
+ params['fils_realm'] = 'example.com'
+ params['disable_pmksa_caching'] = '1'
+ hapd = hostapd.add_ap(apdev[0]['ifname'], params)
+
+ id = wpas.connect("fils", key_mgmt=key_mgmt,
+ eap="PSK", identity="psk.user@example.com",
+ password_hex="0123456789abcdef0123456789abcdef",
+ erp="1", scan_freq="2412")
+
+ wpas.request("DISCONNECT")
+ wpas.wait_disconnected()
+ wpas.dump_monitor()
+
+ if "FAIL" in wpas.request("PMKSA_FLUSH"):
+ raise Exception("PMKSA_FLUSH failed")
+
+ return hapd
+
+def check_pasn_fils(dev, apdev, params, key_mgmt):
+ check_pasn_capab(dev[0])
+
+ hapd = pasn_fils_setup(dev[0], apdev, params, key_mgmt);
+ check_pasn_akmp_cipher(dev[0], hapd, key_mgmt, "CCMP", nid="0")
+
+@remote_compatible
+def test_pasn_fils_sha256(dev, apdev, params):
+ """PASN FILS authentication using SHA-256"""
+ check_pasn_fils(dev, apdev, params, "FILS-SHA256")
+
+@remote_compatible
+def test_pasn_fils_sha384(dev, apdev, params):
+ """PASN FILS authentication using SHA-384"""
+ check_pasn_fils(dev, apdev, params, "FILS-SHA384")
+
+def check_pasn_fils_connected_same_channel(dev, apdev, params, key_mgmt):
+ check_pasn_capab(dev[0])
+
+ hapd = pasn_fils_setup(dev[0], apdev, params, key_mgmt);
+
+ # Connect to another AP on the same channel
+ hapd1 = hostapd.add_ap(apdev[1], {"ssid": "open"})
+ dev[0].connect("open", key_mgmt="NONE", scan_freq="2412",
+ bg_scan_period="0")
+
+ hwsim_utils.test_connectivity(dev[0], hapd1)
+
+ # And perform the PASN authentication with FILS
+ check_pasn_akmp_cipher(dev[0], hapd, key_mgmt, "CCMP", nid="0")
+
+@remote_compatible
+def test_pasn_fils_sha256_connected_same_channel(dev, apdev, params):
+ """PASN FILS authentication using SHA-256 while connected same channel"""
+ check_pasn_fils_connected_same_channel(dev, apdev, params, "FILS-SHA256")
+
+@remote_compatible
+def test_pasn_fils_sha384_connected_same_channel(dev, apdev, params):
+ """PASN FILS authentication using SHA-384 while connected same channel"""
+ check_pasn_fils_connected_same_channel(dev, apdev, params, "FILS-SHA384")
+
+def check_pasn_fils_connected_diff_channel(dev, apdev, params, key_mgmt):
+ check_pasn_capab(dev[0])
+
+ with HWSimRadio(n_channels=2) as (radio, iface):
+ wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+ wpas.interface_add(iface)
+ if wpas.get_mcc() < 2:
+ raise Exception("New radio does not support MCC")
+
+ hapd = pasn_fils_setup(wpas, apdev, params, key_mgmt);
+
+ # Connect to another AP on a different channel
+ hapd1 = hostapd.add_ap(apdev[1], {"ssid": "open", "channel" : "6"})
+ wpas.connect("open", key_mgmt="NONE", scan_freq="2437",
+ bg_scan_period="0")
+
+ hwsim_utils.test_connectivity(wpas, hapd1)
+
+ # And perform the PASN authentication with FILS
+ check_pasn_akmp_cipher(wpas, hapd, key_mgmt, "CCMP", nid="0")
+
+@remote_compatible
+def test_pasn_fils_sha256_connected_diff_channel(dev, apdev, params):
+ """PASN FILS authentication using SHA-256 while connected diff channel"""
+ check_pasn_fils_connected_diff_channel(dev, apdev, params, "FILS-SHA256")
+
+@remote_compatible
+def test_pasn_fils_sha384_connected_diff_channel(dev, apdev, params):
+ """PASN FILS authentication using SHA-384 while connected diff channel"""
+ check_pasn_fils_connected_diff_channel(dev, apdev, params, "FILS-SHA384")
+
+def test_pasn_ft_psk(dev, apdev):
+ """PASN authentication with FT-PSK"""
+ check_pasn_capab(dev[0])
+
+ ssid = "test-pasn-ft-psk"
+ passphrase = "12345678"
+
+ params = ft_params1(ssid=ssid, passphrase=passphrase)
+ params['wpa_key_mgmt'] += " PASN"
+ hapd0 = hostapd.add_ap(apdev[0], params)
+ params = ft_params2(ssid=ssid, passphrase=passphrase)
+ params['wpa_key_mgmt'] += " PASN"
+ hapd1 = hostapd.add_ap(apdev[1], params)
+
+ run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase)
+
+ if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
+ pasn_hapd = hapd1
+ else:
+ pasn_hapd = hapd0
+
+ check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-PSK", "CCMP")
+
+ run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, only_one_way=1)
+
+ if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
+ pasn_hapd = hapd1
+ else:
+ pasn_hapd = hapd0
+
+ check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-PSK", "CCMP")
+
+def test_pasn_ft_eap(dev, apdev):
+ """PASN authentication with FT-EAP"""
+ check_pasn_capab(dev[0])
+
+ ssid = "test-pasn-ft-psk"
+ passphrase = "12345678"
+ identity = "gpsk user"
+
+ radius = hostapd.radius_params()
+ params = ft_params1(ssid=ssid, passphrase=passphrase)
+ params['wpa_key_mgmt'] = "FT-EAP PASN"
+ params["ieee8021x"] = "1"
+ params = dict(list(radius.items()) + list(params.items()))
+ hapd0 = hostapd.add_ap(apdev[0], params)
+
+ params = ft_params2(ssid=ssid, passphrase=passphrase)
+ params['wpa_key_mgmt'] = "FT-EAP PASN"
+ params["ieee8021x"] = "1"
+ params = dict(list(radius.items()) + list(params.items()))
+ hapd1 = hostapd.add_ap(apdev[1], params)
+
+ run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, eap=True,
+ eap_identity=identity)
+
+ if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
+ pasn_hapd = hapd1
+ else:
+ pasn_hapd = hapd0
+
+ check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-EAP", "CCMP")
+
+def test_pasn_ft_eap_sha384(dev, apdev):
+ """PASN authentication with FT-EAP-SHA-384"""
+ check_pasn_capab(dev[0])
+
+ ssid = "test-pasn-ft-psk"
+ passphrase = "12345678"
+ identity = "gpsk user"
+
+ radius = hostapd.radius_params()
+ params = ft_params1(ssid=ssid, passphrase=passphrase)
+ params["ieee80211w"] = "2"
+ params['wpa_key_mgmt'] = "FT-EAP-SHA384 PASN"
+ params["ieee8021x"] = "1"
+ params = dict(list(radius.items()) + list(params.items()))
+ hapd0 = hostapd.add_ap(apdev[0], params)
+
+ params = ft_params2(ssid=ssid, passphrase=passphrase)
+ params["ieee80211w"] = "2"
+ params['wpa_key_mgmt'] = "FT-EAP-SHA384 PASN"
+ params["ieee8021x"] = "1"
+ params = dict(list(radius.items()) + list(params.items()))
+ hapd1 = hostapd.add_ap(apdev[1], params)
+
+ run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, eap=True,
+ sha384=True)
+
+ if dev[0].get_status_field('bssid') == apdev[0]['bssid']:
+ pasn_hapd = hapd1
+ else:
+ pasn_hapd = hapd0
+
+ check_pasn_akmp_cipher(dev[0], pasn_hapd, "FT-EAP-SHA384", "CCMP")
diff --git a/tests/hwsim/test_scan.py b/tests/hwsim/test_scan.py
index 2e64cee..24a7903 100644
--- a/tests/hwsim/test_scan.py
+++ b/tests/hwsim/test_scan.py
@@ -654,6 +654,10 @@ def test_scan_reqs_with_non_scan_radio_work(dev, apdev):
def test_scan_setband(dev, apdev):
"""Band selection for scan operations"""
+ wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+ wpas.interface_add("wlan5")
+ devs = [ dev[0], dev[1], dev[2], wpas ]
+
try:
hapd = None
hapd2 = None
@@ -678,21 +682,26 @@ def test_scan_setband(dev, apdev):
raise Exception("Failed to set setband")
if "OK" not in dev[2].request("SET setband 2G"):
raise Exception("Failed to set setband")
+ if "OK" not in wpas.request("SET setband 2G,5G"):
+ raise Exception("Failed to set setband")
# Allow a retry to avoid reporting errors during heavy load
for j in range(5):
- for i in range(3):
- dev[i].request("SCAN only_new=1")
+ for d in devs:
+ d.request("SCAN only_new=1")
- for i in range(3):
- ev = dev[i].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
+ for d in devs:
+ ev = d.wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
if ev is None:
raise Exception("Scan timed out")
res0 = dev[0].request("SCAN_RESULTS")
res1 = dev[1].request("SCAN_RESULTS")
res2 = dev[2].request("SCAN_RESULTS")
- if bssid in res0 and bssid2 in res0 and bssid in res1 and bssid2 in res2:
+ res3 = wpas.request("SCAN_RESULTS")
+ if bssid in res0 and bssid2 in res0 and \
+ bssid in res1 and bssid2 in res2 and \
+ bssid in res3 and bssid2 in res3:
break
res = dev[0].request("SCAN_RESULTS")
@@ -710,15 +719,19 @@ def test_scan_setband(dev, apdev):
raise Exception("Missing scan result(2)")
if bssid in res:
raise Exception("Unexpected scan result(2)")
+
+ res = wpas.request("SCAN_RESULTS")
+ if bssid not in res or bssid2 not in res:
+ raise Exception("Missing scan result(3)")
finally:
if hapd:
hapd.request("DISABLE")
if hapd2:
hapd2.request("DISABLE")
subprocess.call(['iw', 'reg', 'set', '00'])
- for i in range(3):
- dev[i].request("SET setband AUTO")
- dev[i].flush_scan_cache()
+ for d in devs:
+ d.request("SET setband AUTO")
+ d.flush_scan_cache()
@remote_compatible
def test_scan_hidden_many(dev, apdev):
@@ -1137,7 +1150,7 @@ def test_scan_fail(dev, apdev):
try:
if "OK" not in dev[0].request("SET setband 2G"):
raise Exception("SET setband failed")
- with alloc_fail(dev[0], 1, "=wpa_setband_scan_freqs_list"):
+ with alloc_fail(dev[0], 1, "=wpa_add_scan_freqs_list"):
# While the frequency list cannot be created due to memory
# allocation failure, this scan is expected to be completed without
# frequency filtering.
@@ -1976,6 +1989,9 @@ def test_scan_ssid_list(dev, apdev):
break
finally:
dev[0].request("VENDOR_ELEM_REMOVE 14 *")
+ hapd.disable()
+ dev[0].flush_scan_cache(freq=2432)
+ dev[0].flush_scan_cache()
if not found:
raise Exception("AP not found in scan results")
@@ -2001,6 +2017,9 @@ def test_scan_short_ssid_list(dev, apdev):
break
finally:
dev[0].request("VENDOR_ELEM_REMOVE 14 *")
+ hapd.disable()
+ dev[0].flush_scan_cache(freq=2432)
+ dev[0].flush_scan_cache()
if not found:
raise Exception("AP not found in scan results")
diff --git a/tests/hwsim/test_sigma_dut.py b/tests/hwsim/test_sigma_dut.py
index e2151cf..8bf06e0 100644
--- a/tests/hwsim/test_sigma_dut.py
+++ b/tests/hwsim/test_sigma_dut.py
@@ -2240,7 +2240,7 @@ def test_sigma_dut_ap_dpp_qr_enrollee_chirp(dev, apdev, params):
dev[1].dpp_listen(2437)
dev[0].dpp_auth_init(uri=uri, conf="sta-dpp", ssid="DPPNET01",
configurator=conf_id)
- dev[1].wait_connected()
+ dev[1].wait_connected(timeout=20)
sigma_dut_cmd_check("ap_reset_default,program,DPP")
finally:
@@ -2334,7 +2334,7 @@ def run_sigma_dut_ap_dpp_qr(dev, apdev, params, ap_conf, sta_conf, extra=""):
cmd = "DPP_AUTH_INIT peer=%d conf=%s %s configurator=%d" % (id0b, sta_conf, extra, conf_id)
if "OK" not in dev[0].request(cmd):
raise Exception("Failed to initiate DPP Authentication")
- dev[1].wait_connected()
+ dev[1].wait_connected(timeout=20)
sigma_dut_cmd_check("ap_reset_default")
finally:
@@ -2389,7 +2389,7 @@ def test_sigma_dut_ap_dpp_offchannel(dev, apdev, params):
cmd = "DPP_AUTH_INIT peer=%d conf=sta-dpp ssid=%s configurator=%d" % (id0b, to_hex("DPPNET01"), conf_id)
if "OK" not in dev[0].request(cmd):
raise Exception("Failed to initiate DPP Authentication")
- dev[1].wait_connected()
+ dev[1].wait_connected(timeout=20)
sigma_dut_cmd_check("ap_reset_default")
finally:
@@ -2914,7 +2914,7 @@ def run_sigma_dut_ap_dpp_self_config(dev, apdev):
res = sigma_dut_cmd(cmd)
if "BootstrapResult,OK,AuthResult,OK,ConfResult,OK" not in res:
raise Exception("Unexpected result: " + res)
- dev[0].wait_connected()
+ dev[0].wait_connected(timeout=20)
dev[0].request("DISCONNECT")
dev[0].wait_disconnected()
sigma_dut_cmd_check("ap_reset_default")
@@ -3391,7 +3391,7 @@ def test_sigma_dut_dpp_reconfig_enrollee(dev, apdev):
if ev is None:
raise Exception("DPP Config Response (reconfig) not transmitted")
- dev[0].wait_connected()
+ dev[0].wait_connected(timeout=20)
ev = dev[1].wait_event(["DPP-CONN-STATUS-RESULT"], timeout=20)
if ev is None:
raise Exception("No connection status reported")
@@ -3413,7 +3413,7 @@ def test_sigma_dut_dpp_reconfig_enrollee(dev, apdev):
if ev is None:
raise Exception("DPP Config Response (reconfig) not transmitted [2]")
- dev[0].wait_connected()
+ dev[0].wait_connected(timeout=20)
finally:
dev[0].set("dpp_config_processing", "0")
stop_sigma_dut(sigma)
@@ -5214,11 +5214,12 @@ def test_sigma_dut_client_privacy(dev, apdev, params):
sigma_dut_cmd_check("sta_reset_default,interface," + ifname)
finally:
stop_sigma_dut(sigma)
- dev[1].set("mac_addr", "0", allow_fail=True)
- dev[1].set("rand_addr_lifetime", "60", allow_fail=True)
- dev[1].set("preassoc_mac_addr", "0", allow_fail=True)
- dev[1].set("gas_rand_mac_addr", "0", allow_fail=True)
- dev[1].set("gas_rand_addr_lifetime", "60", allow_fail=True)
+ dev[0].set("mac_addr", "0", allow_fail=True)
+ dev[0].set("rand_addr_lifetime", "60", allow_fail=True)
+ dev[0].request("MAC_RAND_SCAN enable=0 all")
+ dev[0].set("preassoc_mac_addr", "0", allow_fail=True)
+ dev[0].set("gas_rand_mac_addr", "0", allow_fail=True)
+ dev[0].set("gas_rand_addr_lifetime", "60", allow_fail=True)
out = run_tshark(os.path.join(logdir, "hwsim0.pcapng"),
"wlan.addr == " + addr,
diff --git a/tests/hwsim/test_wpas_ctrl.py b/tests/hwsim/test_wpas_ctrl.py
index 04418f0..bb8ca1a 100644
--- a/tests/hwsim/test_wpas_ctrl.py
+++ b/tests/hwsim/test_wpas_ctrl.py
@@ -266,14 +266,14 @@ def test_wpas_ctrl_network(dev):
"f2:99:88:77:66:55 02:11:22:33:44:55/ff:00:ff:00:ff:00 12:34:56:78:90:ab",
"02:11:22:33:44:55/ff:ff:ff:00:00:00 02:ae:be:ce:53:77/00:00:00:00:00:ff"]
for val in tests:
- dev[0].set_network(id, "bssid_blacklist", val)
- res = dev[0].get_network(id, "bssid_blacklist")
+ dev[0].set_network(id, "bssid_ignore", val)
+ res = dev[0].get_network(id, "bssid_ignore")
if res != val:
- raise Exception("Unexpected bssid_blacklist value: %s != %s" % (res, val))
- dev[0].set_network(id, "bssid_whitelist", val)
- res = dev[0].get_network(id, "bssid_whitelist")
+ raise Exception("Unexpected bssid_ignore value: %s != %s" % (res, val))
+ dev[0].set_network(id, "bssid_accept", val)
+ res = dev[0].get_network(id, "bssid_accept")
if res != val:
- raise Exception("Unexpected bssid_whitelist value: %s != %s" % (res, val))
+ raise Exception("Unexpected bssid_accept value: %s != %s" % (res, val))
tests = ["foo",
"00:11:22:33:44:5",
@@ -281,8 +281,8 @@ def test_wpas_ctrl_network(dev):
"00:11:22:33:44:55/",
"00:11:22:33:44:55/66:77:88:99:aa:b"]
for val in tests:
- if "FAIL" not in dev[0].request("SET_NETWORK %d bssid_blacklist %s" % (id, val)):
- raise Exception("Invalid bssid_blacklist value accepted")
+ if "FAIL" not in dev[0].request("SET_NETWORK %d bssid_ignore %s" % (id, val)):
+ raise Exception("Invalid bssid_ignore value accepted")
@remote_compatible
def test_wpas_ctrl_network_oom(dev):
@@ -687,8 +687,8 @@ def test_wpas_ctrl_addr(dev):
raise Exception("Unexpected success on invalid WPS_REG")
if "FAIL" not in dev[0].request("IBSS_RSN 00:11:22:33:44"):
raise Exception("Unexpected success on invalid IBSS_RSN")
- if "FAIL" not in dev[0].request("BLACKLIST 00:11:22:33:44"):
- raise Exception("Unexpected success on invalid BLACKLIST")
+ if "FAIL" not in dev[0].request("BSSID_IGNORE 00:11:22:33:44"):
+ raise Exception("Unexpected success on invalid BSSID_IGNORE")
@remote_compatible
def test_wpas_ctrl_wps_errors(dev):
@@ -1078,43 +1078,43 @@ def test_wpas_ctrl_nfc_get_handover(dev):
if "FAIL" in dev[0].request("NFC_GET_HANDOVER_SEL " + v):
raise Exception("Unexpected NFC_GET_HANDOVER_SEL failure for " + v)
-def get_blacklist(dev):
- return dev.request("BLACKLIST").splitlines()
+def get_bssid_ignore_list(dev):
+ return dev.request("BSSID_IGNORE").splitlines()
@remote_compatible
-def test_wpas_ctrl_blacklist(dev):
- """wpa_supplicant ctrl_iface BLACKLIST"""
- if "OK" not in dev[0].request("BLACKLIST clear"):
- raise Exception("BLACKLIST clear failed")
- b = get_blacklist(dev[0])
+def test_wpas_ctrl_bssid_ignore(dev):
+ """wpa_supplicant ctrl_iface BSSID_IGNORE"""
+ if "OK" not in dev[0].request("BSSID_IGNORE clear"):
+ raise Exception("BSSID_IGNORE clear failed")
+ b = get_bssid_ignore_list(dev[0])
if len(b) != 0:
- raise Exception("Unexpected blacklist contents: " + str(b))
- if "OK" not in dev[0].request("BLACKLIST 00:11:22:33:44:55"):
- raise Exception("BLACKLIST add failed")
- b = get_blacklist(dev[0])
+ raise Exception("Unexpected BSSID ignore list contents: " + str(b))
+ if "OK" not in dev[0].request("BSSID_IGNORE 00:11:22:33:44:55"):
+ raise Exception("BSSID_IGNORE add failed")
+ b = get_bssid_ignore_list(dev[0])
if "00:11:22:33:44:55" not in b:
- raise Exception("Unexpected blacklist contents: " + str(b))
- if "OK" not in dev[0].request("BLACKLIST 00:11:22:33:44:56"):
- raise Exception("BLACKLIST add failed")
- b = get_blacklist(dev[0])
+ raise Exception("Unexpected BSSID ignore list contents: " + str(b))
+ if "OK" not in dev[0].request("BSSID_IGNORE 00:11:22:33:44:56"):
+ raise Exception("BSSID_IGNORE add failed")
+ b = get_bssid_ignore_list(dev[0])
if "00:11:22:33:44:55" not in b or "00:11:22:33:44:56" not in b:
- raise Exception("Unexpected blacklist contents: " + str(b))
- if "OK" not in dev[0].request("BLACKLIST 00:11:22:33:44:56"):
- raise Exception("BLACKLIST add failed")
- b = get_blacklist(dev[0])
+ raise Exception("Unexpected BSSID ignore list contents: " + str(b))
+ if "OK" not in dev[0].request("BSSID_IGNORE 00:11:22:33:44:56"):
+ raise Exception("BSSID_IGNORE add failed")
+ b = get_bssid_ignore_list(dev[0])
if "00:11:22:33:44:55" not in b or "00:11:22:33:44:56" not in b or len(b) != 2:
- raise Exception("Unexpected blacklist contents: " + str(b))
+ raise Exception("Unexpected BSSID ignore list contents: " + str(b))
- if "OK" not in dev[0].request("BLACKLIST clear"):
- raise Exception("BLACKLIST clear failed")
- if dev[0].request("BLACKLIST") != "":
- raise Exception("Unexpected blacklist contents")
+ if "OK" not in dev[0].request("BSSID_IGNORE clear"):
+ raise Exception("BSSID_IGNORE clear failed")
+ if dev[0].request("BSSID_IGNORE") != "":
+ raise Exception("Unexpected BSSID ignore list contents")
@remote_compatible
-def test_wpas_ctrl_blacklist_oom(dev):
- """wpa_supplicant ctrl_iface BLACKLIST and out-of-memory"""
- with alloc_fail(dev[0], 1, "wpa_blacklist_add"):
- if "FAIL" not in dev[0].request("BLACKLIST aa:bb:cc:dd:ee:ff"):
+def test_wpas_ctrl_bssid_ignore_oom(dev):
+ """wpa_supplicant ctrl_iface BSSID_IGNORE and out-of-memory"""
+ with alloc_fail(dev[0], 1, "wpa_bssid_ignore_add"):
+ if "FAIL" not in dev[0].request("BSSID_IGNORE aa:bb:cc:dd:ee:ff"):
raise Exception("Unexpected success with allocation failure")
def test_wpas_ctrl_log_level(dev):
diff --git a/tests/hwsim/test_wpas_mesh.py b/tests/hwsim/test_wpas_mesh.py
index b7f9846..75bc021 100644
--- a/tests/hwsim/test_wpas_mesh.py
+++ b/tests/hwsim/test_wpas_mesh.py
@@ -80,8 +80,24 @@ def check_mesh_scan(dev, params, other_started=False, beacon_int=0):
if '[MESH]' not in bss['flags']:
raise Exception("BSS output did not include MESH flag")
-def check_mesh_group_added(dev):
- ev = dev.wait_event(["MESH-GROUP-STARTED"])
+def check_dfs_started(dev, timeout=10):
+ ev = dev.wait_event(["DFS-CAC-START"], timeout=timeout)
+ if ev is None:
+ raise Exception("Test exception: CAC did not start")
+
+def check_dfs_finished(dev, timeout=70):
+ ev = dev.wait_event(["DFS-CAC-COMPLETED"], timeout=timeout)
+ if ev is None:
+ raise Exception("Test exception: CAC did not finish")
+
+def check_mesh_radar_handling_finished(dev, timeout=75):
+ ev = dev.wait_event(["CTRL-EVENT-CHANNEL-SWITCH", "MESH-GROUP-STARTED"],
+ timeout=timeout)
+ if ev is None:
+ raise Exception("Test exception: Couldn't join mesh")
+
+def check_mesh_group_added(dev, timeout=10):
+ ev = dev.wait_event(["MESH-GROUP-STARTED"], timeout=timeout)
if ev is None:
raise Exception("Test exception: Couldn't join mesh")
@@ -91,6 +107,10 @@ def check_mesh_group_removed(dev):
if ev is None:
raise Exception("Test exception: Couldn't leave mesh")
+def check_regdom_change(dev, timeout=10):
+ ev = dev.wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=timeout)
+ if ev is None:
+ raise Exception("Test exception: No regdom change happened.")
def check_mesh_peer_connected(dev, timeout=10):
ev = dev.wait_event(["MESH-PEER-CONNECTED"], timeout=timeout)
@@ -167,6 +187,39 @@ def test_wpas_mesh_group_remove(dev):
check_mesh_group_removed(dev[0])
dev[0].mesh_group_remove()
+def dfs_simulate_radar(dev):
+ logger.info("Trigger a simulated radar event")
+ phyname = dev.get_driver_status_field("phyname")
+ radar_file = '/sys/kernel/debug/ieee80211/' + phyname + '/hwsim/dfs_simulate_radar'
+ with open(radar_file, 'w') as f:
+ f.write('1')
+
+@long_duration_test
+def test_mesh_peer_connected_dfs(dev):
+ """Mesh peer connected (DFS)"""
+ dev[0].set("country", "DE")
+ dev[1].set("country", "DE")
+
+ check_regdom_change(dev[0])
+ check_regdom_change(dev[1])
+
+ check_mesh_support(dev[0])
+ add_open_mesh_network(dev[0], freq="5500", beacon_int=160)
+ add_open_mesh_network(dev[1], freq="5500", beacon_int=160)
+ check_dfs_started(dev[0])
+ check_dfs_finished(dev[0])
+ check_mesh_joined_connected(dev, timeout0=10)
+
+ dfs_simulate_radar(dev[0])
+
+ check_mesh_radar_handling_finished(dev[0], timeout=75)
+
+ dev[0].set("country", "00")
+ dev[1].set("country", "00")
+
+ check_regdom_change(dev[0])
+ check_regdom_change(dev[1])
+
def test_wpas_mesh_peer_connected(dev):
"""wpa_supplicant MESH peer connected"""
check_mesh_support(dev[0])
diff --git a/tests/hwsim/tshark.py b/tests/hwsim/tshark.py
index d6a57f0..32cdf47 100644
--- a/tests/hwsim/tshark.py
+++ b/tests/hwsim/tshark.py
@@ -12,6 +12,8 @@ import subprocess
import logging
logger = logging.getLogger()
+from utils import *
+
class UnknownFieldsException(Exception):
def __init__(self, fields):
Exception.__init__(self, "unknown tshark fields %s" % ','.join(fields))
@@ -41,6 +43,8 @@ def _run_tshark(filename, filter, display=None, wait=True):
stderr=subprocess.PIPE)
except Exception as e:
logger.info("Could run run tshark check: " + str(e))
+ if "No such file or directory: 'tshark'" in str(e):
+ raise HwsimSkip("No tshark available")
cmd = None
return None
@@ -111,6 +115,8 @@ def run_tshark_json(filename, filter):
stderr=subprocess.PIPE)
except Exception as e:
logger.info("Could run run tshark: " + str(e))
+ if "No such file or directory: 'tshark'" in str(e):
+ raise HwsimSkip("No tshark available")
return None
output = cmd.communicate()
out = output[0].decode()
diff --git a/tests/hwsim/wlantest.py b/tests/hwsim/wlantest.py
index 6d4343b..16765d2 100644
--- a/tests/hwsim/wlantest.py
+++ b/tests/hwsim/wlantest.py
@@ -29,7 +29,7 @@ class Wlantest:
return
cls.remote_host.execute(["killall", "-9", "wlantest"])
- cls.remote_host.wait_execute_complete(cls.exe_thread, 5)
+ cls.remote_host.thread_wait(cls.exe_thread, 5)
cls.exe_thread = None
cls.exe_res = []
@@ -64,7 +64,7 @@ class Wlantest:
pcap_file, log_file)
cls.remote_host.add_log(log_file)
cls.remote_host.add_log(pcap_file)
- cls.exe_thread = cls.remote_host.execute_run(cmd.split(), cls.exe_res)
+ cls.exe_thread = cls.remote_host.thread_run(cmd.split(), cls.exe_res)
# Give wlantest a chance to start working
time.sleep(1)
diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py
index 92c8552..fed1d10 100644
--- a/tests/hwsim/wpasupplicant.py
+++ b/tests/hwsim/wpasupplicant.py
@@ -1095,8 +1095,8 @@ class WpaSupplicant:
"disable_max_amsdu", "ampdu_factor", "ampdu_density",
"disable_ht40", "disable_sgi", "disable_ldpc",
"ht40_intolerant", "update_identifier", "mac_addr",
- "erp", "bg_scan_period", "bssid_blacklist",
- "bssid_whitelist", "mem_only_psk", "eap_workaround",
+ "erp", "bg_scan_period", "bssid_ignore",
+ "bssid_accept", "mem_only_psk", "eap_workaround",
"engine", "fils_dh_group", "bssid_hint",
"dpp_csign", "dpp_csign_expiry",
"dpp_netaccesskey", "dpp_netaccesskey_expiry", "dpp_pfs",
@@ -1628,3 +1628,21 @@ class WpaSupplicant:
res = self.request("DPP_CONFIGURATOR_REMOVE %d" % conf_id)
if "OK" not in res:
raise Exception("DPP_CONFIGURATOR_REMOVE failed")
+
+ def get_ptksa(self, bssid, cipher):
+ res = self.request("PTKSA_CACHE_LIST")
+ lines = res.splitlines()
+ for l in lines:
+ if bssid not in l or cipher not in l:
+ continue
+
+ vals = dict()
+ [index, addr, cipher, expiration, tk, kdk] = l.split(' ', 5)
+ vals['index'] = index
+ vals['addr'] = addr
+ vals['cipher'] = cipher
+ vals['expiration'] = expiration
+ vals['tk'] = tk
+ vals['kdk'] = kdk
+ return vals
+ return None
diff --git a/tests/remote/monitor.py b/tests/remote/monitor.py
index 5bd801c..0f77d50 100644
--- a/tests/remote/monitor.py
+++ b/tests/remote/monitor.py
@@ -110,7 +110,7 @@ def run(host, setup_params):
log = log_dir + tc_name + "_" + host.name + log_monitor + ".pcap"
host.add_log(log)
- thread = host.execute_run([tshark, "-w", log], monitor_res)
+ thread = host.thread_run([tshark, "-w", log], monitor_res)
host.thread = thread
@@ -122,7 +122,7 @@ def stop(host):
if host.thread is None:
return
- host.execute_stop(host.thread)
+ host.thread_stop(host.thread)
host.thread = None
# Add monitor to existing interface
diff --git a/tests/remote/run-tests.py b/tests/remote/run-tests.py
index e26e348..67993a3 100755
--- a/tests/remote/run-tests.py
+++ b/tests/remote/run-tests.py
@@ -13,6 +13,7 @@ import time
import traceback
import getopt
from datetime import datetime
+from random import shuffle
import logging
logger = logging.getLogger()
@@ -32,7 +33,7 @@ from hwsim_wrapper import run_hwsim_test
def usage():
print("USAGE: " + sys.argv[0] + " -t devices")
print("USAGE: " + sys.argv[0] + " -t check_devices")
- print("USAGE: " + sys.argv[0] + " -d <dut_name> -t <all|sanity|tests_to_run> [-r <ref_name>] [-c <cfg_file.py>] [-m <all|monitor_name>] [-h hwsim_tests] [-f hwsim_modules][-R][-T][-P][-v]")
+ print("USAGE: " + sys.argv[0] + " -d <dut_name> -t <all|sanity|tests_to_run> [-r <ref_name>] [-c <cfg_file.py>] [-m <all|monitor_name>] [-h hwsim_tests] [-f hwsim_modules][-R][-T][-P][-S][-v]")
print("USAGE: " + sys.argv[0])
def get_devices(devices, duts, refs, monitors):
@@ -79,10 +80,11 @@ def main():
trace = False
restart = False
perf = False
+ shuffle_tests = False
# parse input parameters
try:
- opts, args = getopt.getopt(sys.argv[1:], "d:f:r:t:l:k:c:m:h:vRPT",
+ opts, args = getopt.getopt(sys.argv[1:], "d:f:r:t:l:k:c:m:h:vRPTS",
["dut=", "modules=", "ref=", "tests=",
"log-dir=",
"cfg=", "key=", "monitor=", "hwsim="])
@@ -100,6 +102,8 @@ def main():
trace = True
elif option == "-P":
perf = True
+ elif option == "-S":
+ shuffle_tests = True
elif option in ("-d", "--dut"):
duts.append(argument)
elif option in ("-r", "--ref"):
@@ -283,6 +287,10 @@ def main():
continue
tests_to_run.append(t)
+ if shuffle_tests:
+ shuffle(tests_to_run)
+ shuffle(hwsim_tests_to_run)
+
# lock devices
try:
get_devices(devices, duts, refs, monitors)
diff --git a/tests/remote/rutils.py b/tests/remote/rutils.py
index e80901b..6902991 100644
--- a/tests/remote/rutils.py
+++ b/tests/remote/rutils.py
@@ -342,12 +342,12 @@ def ping_run(host, ip, result, ifname=None, addr_type="ipv4", deadline="5", qos=
flush_arp_cache(host)
- thread = host.execute_run(ping, result)
+ thread = host.thread_run(ping, result)
return thread
def ping_wait(host, thread, timeout=None):
- host.wait_execute_complete(thread, timeout)
- if thread.isAlive():
+ host.thread_wait(thread, timeout)
+ if thread.is_alive():
raise Exception("ping thread still alive")
def flush_arp_cache(host):
@@ -496,24 +496,24 @@ def iperf_run(server, client, server_ip, client_res, server_res,
flush_arp_cache(server)
flush_arp_cache(client)
- server_thread = server.execute_run(iperf_server, server_res)
+ server_thread = server.thread_run(iperf_server, server_res)
time.sleep(1)
- client_thread = client.execute_run(iperf_client, client_res)
+ client_thread = client.thread_run(iperf_client, client_res)
return server_thread, client_thread
def iperf_wait(server, client, server_thread, client_thread, timeout=None, iperf="iperf"):
- client.wait_execute_complete(client_thread, timeout)
- if client_thread.isAlive():
+ client.thread_wait(client_thread, timeout)
+ if client_thread.is_alive():
raise Exception("iperf client thread still alive")
- server.wait_execute_complete(server_thread, 5)
- if server_thread.isAlive():
+ server.thread_wait(server_thread, 5)
+ if server_thread.is_alive():
server.execute(["killall", "-s", "INT", iperf])
time.sleep(1)
- server.wait_execute_complete(server_thread, 5)
- if server_thread.isAlive():
+ server.thread_wait(server_thread, 5)
+ if server_thread.is_alive():
raise Exception("iperf server thread still alive")
return
diff --git a/wlantest/Makefile b/wlantest/Makefile
index 6023751..0045020 100644
--- a/wlantest/Makefile
+++ b/wlantest/Makefile
@@ -25,6 +25,7 @@ CFLAGS += -DCONFIG_SAE
CFLAGS += -DCONFIG_OWE
CFLAGS += -DCONFIG_DPP
CFLAGS += -DCONFIG_SHA384
+CFLAGS += -DCONFIG_PASN
OBJS += ../src/common/ieee802_11_common.o
OBJS += ../src/common/wpa_common.o
diff --git a/wlantest/bss.c b/wlantest/bss.c
index 3208e65..0e5b603 100644
--- a/wlantest/bss.c
+++ b/wlantest/bss.c
@@ -178,14 +178,18 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
elems->osen_len + 2);
}
- if (elems->rsn_ie == NULL) {
+ /* S1G does not include RSNE in beacon, so only clear it from
+ * Probe Response frames. Note this assumes short beacons were dropped
+ * due to missing SSID above.
+ */
+ if (!elems->rsn_ie && (!elems->s1g_capab || beacon != 1)) {
if (bss->rsnie[0]) {
add_note(wt, MSG_INFO, "BSS " MACSTR
" - RSN IE removed", MAC2STR(bss->bssid));
bss->rsnie[0] = 0;
update = 1;
}
- } else {
+ } else if (elems->rsn_ie) {
if (bss->rsnie[0] == 0 ||
os_memcmp(bss->rsnie, elems->rsn_ie - 2,
elems->rsn_ie_len + 2) != 0) {
@@ -289,8 +293,8 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
"pairwise=%s%s%s%s%s%s%s"
"group=%s%s%s%s%s%s%s%s%s"
"mgmt_group_cipher=%s%s%s%s%s"
- "key_mgmt=%s%s%s%s%s%s%s%s%s"
- "rsn_capab=%s%s%s%s%s%s%s",
+ "key_mgmt=%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+ "rsn_capab=%s%s%s%s%s%s%s%s%s%s",
MAC2STR(bss->bssid),
bss->proto == 0 ? "OPEN " : "",
bss->proto & WPA_PROTO_WPA ? "WPA " : "",
@@ -333,7 +337,14 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
"EAP-SHA256 " : "",
bss->key_mgmt & WPA_KEY_MGMT_PSK_SHA256 ?
"PSK-SHA256 " : "",
+ bss->key_mgmt & WPA_KEY_MGMT_OWE ? "OWE " : "",
+ bss->key_mgmt & WPA_KEY_MGMT_PASN ? "PASN " : "",
bss->key_mgmt & WPA_KEY_MGMT_OSEN ? "OSEN " : "",
+ bss->key_mgmt & WPA_KEY_MGMT_DPP ? "DPP " : "",
+ bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B ?
+ "EAP-SUITE-B " : "",
+ bss->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ?
+ "EAP-SUITE-B-192 " : "",
bss->rsn_capab & WPA_CAPABILITY_PREAUTH ? "PREAUTH " : "",
bss->rsn_capab & WPA_CAPABILITY_NO_PAIRWISE ?
"NO_PAIRWISE " : "",
@@ -341,6 +352,11 @@ void bss_update(struct wlantest *wt, struct wlantest_bss *bss,
bss->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "",
bss->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ?
"PEERKEY " : "",
+ bss->rsn_capab & WPA_CAPABILITY_SPP_A_MSDU_CAPABLE ?
+ "SPP-A-MSDU-CAPAB " : "",
+ bss->rsn_capab & WPA_CAPABILITY_SPP_A_MSDU_REQUIRED ?
+ "SPP-A-MSDU-REQUIRED " : "",
+ bss->rsn_capab & WPA_CAPABILITY_PBAC ? "PBAC " : "",
bss->rsn_capab & WPA_CAPABILITY_OCVC ? "OCVC " : "",
bss->rsn_capab & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST ?
"ExtKeyID " : "");
diff --git a/wlantest/inject.c b/wlantest/inject.c
index 54a0554..399f1a3 100644
--- a/wlantest/inject.c
+++ b/wlantest/inject.c
@@ -68,7 +68,8 @@ static int is_robust_mgmt(u8 *frame, size_t len)
stype = WLAN_FC_GET_STYPE(fc);
if (stype == WLAN_FC_STYPE_DEAUTH || stype == WLAN_FC_STYPE_DISASSOC)
return 1;
- if (stype == WLAN_FC_STYPE_ACTION) {
+ if (stype == WLAN_FC_STYPE_ACTION ||
+ stype == WLAN_FC_STYPE_ACTION_NO_ACK) {
if (len < 25)
return 0;
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c
index b632013..aedf9e8 100644
--- a/wlantest/rx_data.c
+++ b/wlantest/rx_data.c
@@ -119,19 +119,6 @@ static void rx_data_process(struct wlantest *wt, const u8 *bssid,
}
-static void write_decrypted_note(struct wlantest *wt, const u8 *decrypted,
- const u8 *tk, size_t tk_len, int keyid)
-{
- char tk_hex[65];
-
- if (!decrypted)
- return;
-
- wpa_snprintf_hex(tk_hex, sizeof(tk_hex), tk, tk_len);
- add_note(wt, MSG_EXCESSIVE, "TK[%d] %s", keyid, tk_hex);
-}
-
-
static u8 * try_ptk(int pairwise_cipher, struct wpa_ptk *ptk,
const struct ieee80211_hdr *hdr,
const u8 *data, size_t data_len, size_t *decrypted_len)
diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c
index 1e5d667..eaf97c3 100644
--- a/wlantest/rx_eapol.c
+++ b/wlantest/rx_eapol.c
@@ -120,7 +120,7 @@ static int try_pmk(struct wlantest *wt, struct wlantest_bss *bss,
sta->snonce, sta->anonce, sta->addr,
bss->bssid, sta->pmk_r1_name,
&ptk, ptk_name, sta->key_mgmt,
- sta->pairwise_cipher) < 0 ||
+ sta->pairwise_cipher, 0) < 0 ||
check_mic(ptk.kck, ptk.kck_len, sta->key_mgmt, ver, data,
len) < 0)
return -1;
@@ -128,7 +128,7 @@ static int try_pmk(struct wlantest *wt, struct wlantest_bss *bss,
"Pairwise key expansion",
bss->bssid, sta->addr, sta->anonce,
sta->snonce, &ptk, sta->key_mgmt,
- sta->pairwise_cipher, NULL, 0) < 0 ||
+ sta->pairwise_cipher, NULL, 0, 0) < 0 ||
check_mic(ptk.kck, ptk.kck_len, sta->key_mgmt, ver, data,
len) < 0) {
return -1;
diff --git a/wlantest/rx_ip.c b/wlantest/rx_ip.c
index fdf80b7..b0fdd20 100644
--- a/wlantest/rx_ip.c
+++ b/wlantest/rx_ip.c
@@ -120,63 +120,64 @@ void rx_data_ip(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr,
const u8 *dst, const u8 *src, const u8 *data, size_t len,
const u8 *peer_addr)
{
- const struct ip *ip;
+ struct ip ip;
const u8 *payload;
size_t plen;
uint16_t frag_off, ip_len;
- ip = (const struct ip *) data;
- if (len < sizeof(*ip))
+ if (len < sizeof(ip))
return;
- if (ip->ip_v != 4) {
+ os_memcpy(&ip, data, sizeof(ip));
+
+ if (ip.ip_v != 4) {
if (hwsim_test_packet(data, len)) {
add_note(wt, MSG_INFO, "hwsim_test package");
return;
}
add_note(wt, MSG_DEBUG, "Unexpected IP protocol version %u in "
"IPv4 packet (bssid=" MACSTR " str=" MACSTR
- " dst=" MACSTR ")", ip->ip_v, MAC2STR(bssid),
+ " dst=" MACSTR ")", ip.ip_v, MAC2STR(bssid),
MAC2STR(src), MAC2STR(dst));
return;
}
- if (ip->ip_hl * 4 < sizeof(*ip)) {
+ if (ip.ip_hl * 4 < sizeof(ip)) {
add_note(wt, MSG_DEBUG, "Unexpected IP header length %u in "
"IPv4 packet (bssid=" MACSTR " str=" MACSTR
- " dst=" MACSTR ")", ip->ip_hl, MAC2STR(bssid),
+ " dst=" MACSTR ")", ip.ip_hl, MAC2STR(bssid),
MAC2STR(src), MAC2STR(dst));
return;
}
- if (ip->ip_hl * 4 > len) {
+ if (ip.ip_hl * 4 > len) {
add_note(wt, MSG_DEBUG, "Truncated IP header (ihl=%u len=%u) "
"in IPv4 packet (bssid=" MACSTR " str=" MACSTR
- " dst=" MACSTR ")", ip->ip_hl, (unsigned) len,
+ " dst=" MACSTR ")", ip.ip_hl, (unsigned) len,
MAC2STR(bssid), MAC2STR(src), MAC2STR(dst));
return;
}
- /* TODO: check header checksum in ip->ip_sum */
+ /* TODO: check header checksum in ip.ip_sum */
- frag_off = be_to_host16(ip->ip_off);
+ frag_off = be_to_host16(ip.ip_off);
if (frag_off & 0x1fff) {
wpa_printf(MSG_EXCESSIVE, "IP fragment reassembly not yet "
"supported");
return;
}
- ip_len = be_to_host16(ip->ip_len);
+ ip_len = be_to_host16(ip.ip_len);
if (ip_len > len)
return;
if (ip_len < len)
len = ip_len;
- payload = data + 4 * ip->ip_hl;
- plen = len - 4 * ip->ip_hl;
+ payload = data + 4 * ip.ip_hl;
+ plen = len - 4 * ip.ip_hl;
- switch (ip->ip_p) {
+ switch (ip.ip_p) {
#ifndef __APPLE__
case IPPROTO_ICMP:
- rx_data_icmp(wt, bssid, sta_addr, ip->ip_dst.s_addr,
- ip->ip_src.s_addr, payload, plen, peer_addr);
+ rx_data_icmp(wt, bssid, sta_addr, ip.ip_dst.s_addr,
+ ip.ip_src.s_addr, payload, plen, peer_addr);
break;
#endif /* __APPLE__ */
}
diff --git a/wlantest/rx_mgmt.c b/wlantest/rx_mgmt.c
index 0bc7eb2..f7690e0 100644
--- a/wlantest/rx_mgmt.c
+++ b/wlantest/rx_mgmt.c
@@ -51,6 +51,8 @@ static const char * mgmt_stype(u16 stype)
return "DEAUTH";
case WLAN_FC_STYPE_ACTION:
return "ACTION";
+ case WLAN_FC_STYPE_ACTION_NO_ACK:
+ return "ACTION-NO-ACK";
}
return "??";
}
@@ -290,7 +292,7 @@ static void process_ft_auth(struct wlantest *wt, struct wlantest_bss *bss,
wpa_pmk_r1_to_ptk(sta->pmk_r1, sta->pmk_r1_len, parse.fte_snonce,
parse.fte_anonce, sta->addr, bss->bssid,
sta->pmk_r1_name, &ptk, ptk_name, sta->key_mgmt,
- sta->pairwise_cipher) < 0)
+ sta->pairwise_cipher, 0) < 0)
return;
add_note(wt, MSG_DEBUG, "Derived new PTK");
@@ -494,7 +496,7 @@ static int try_rmsk(struct wlantest *wt, struct wlantest_bss *bss,
sta->snonce, sta->anonce, NULL, 0,
&ptk, ick, &ick_len,
sta->key_mgmt, sta->pairwise_cipher,
- NULL, NULL) < 0)
+ NULL, NULL, 0) < 0)
return -1;
/* Check AES-SIV decryption with the derived key */
@@ -1779,7 +1781,8 @@ static void rx_mgmt_action_ft_response(struct wlantest *wt,
wpa_pmk_r1_to_ptk(sta->pmk_r1, sta->pmk_r1_len, parse.fte_snonce,
parse.fte_anonce, new_sta->addr, bss->bssid,
sta->pmk_r1_name, &ptk, ptk_name,
- new_sta->key_mgmt, new_sta->pairwise_cipher) < 0)
+ new_sta->key_mgmt, new_sta->pairwise_cipher,
+ 0) < 0)
return;
add_note(wt, MSG_DEBUG, "Derived new PTK");
@@ -1913,8 +1916,126 @@ static void rx_mgmt_action_sa_query(struct wlantest *wt,
}
+static void
+rx_mgmt_location_measurement_report(struct wlantest *wt,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, bool no_ack)
+{
+ const u8 *pos = mgmt->u.action.u.public_action.variable;
+ const u8 *end = ((const u8 *) mgmt) + len;
+
+ if (end - pos < 1) {
+ add_note(wt, MSG_INFO,
+ "Too short Location Measurement Report frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "Location Measurement Report " MACSTR " --> "
+ MACSTR " (dialog token %u)",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), *pos);
+ pos++;
+
+ if (!no_ack)
+ add_note(wt, MSG_INFO,
+ "Protected Fine Timing Measurement Report incorrectly as an Action frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+
+ wpa_hexdump(MSG_MSGDUMP, "Location Measurement Report contents",
+ pos, end - pos);
+}
+
+
+static void rx_mgmt_action_no_bss_public(struct wlantest *wt,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, bool no_ack)
+{
+ switch (mgmt->u.action.u.public_action.action) {
+ case WLAN_PA_LOCATION_MEASUREMENT_REPORT:
+ rx_mgmt_location_measurement_report(wt, mgmt, len, no_ack);
+ break;
+ }
+}
+
+
+static void rx_mgmt_prot_ftm_request(struct wlantest *wt,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, bool no_ack)
+{
+ wpa_printf(MSG_DEBUG, "Protected Fine Timing Measurement Request "
+ MACSTR " --> " MACSTR,
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
+ if (no_ack)
+ add_note(wt, MSG_INFO,
+ "Protected Fine Timing Measurement Request incorrectly as an Action No Ack frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+}
+
+
+static void rx_mgmt_prot_ftm(struct wlantest *wt,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, bool no_ack)
+{
+ wpa_printf(MSG_DEBUG, "Protected Fine Timing Measurement "
+ MACSTR " --> " MACSTR,
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
+ if (no_ack)
+ add_note(wt, MSG_INFO,
+ "Protected Fine Timing Measurement incorrectly as an Action No Ack frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+}
+
+
+static void rx_mgmt_prot_ftm_report(struct wlantest *wt,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, bool no_ack)
+{
+ wpa_printf(MSG_DEBUG, "Protected Fine Timing Measurement Report "
+ MACSTR " --> " MACSTR,
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
+ if (!no_ack)
+ add_note(wt, MSG_INFO,
+ "Protected Fine Timing Measurement Report incorrectly as an Action frame from "
+ MACSTR, MAC2STR(mgmt->sa));
+}
+
+
+static void
+rx_mgmt_action_no_bss_protected_ftm(struct wlantest *wt,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, bool no_ack)
+{
+ switch (mgmt->u.action.u.public_action.action) {
+ case WLAN_PROT_FTM_REQUEST:
+ rx_mgmt_prot_ftm_request(wt, mgmt, len, no_ack);
+ break;
+ case WLAN_PROT_FTM:
+ rx_mgmt_prot_ftm(wt, mgmt, len, no_ack);
+ break;
+ case WLAN_PROT_FTM_REPORT:
+ rx_mgmt_prot_ftm_report(wt, mgmt, len, no_ack);
+ break;
+ }
+}
+
+
+static void rx_mgmt_action_no_bss(struct wlantest *wt,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ bool no_ack)
+{
+ switch (mgmt->u.action.category) {
+ case WLAN_ACTION_PUBLIC:
+ rx_mgmt_action_no_bss_public(wt, mgmt, len, no_ack);
+ break;
+ case WLAN_ACTION_PROTECTED_FTM:
+ rx_mgmt_action_no_bss_protected_ftm(wt, mgmt, len, no_ack);
+ break;
+ }
+}
+
+
static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
- int valid)
+ int valid, bool no_ack)
{
const struct ieee80211_mgmt *mgmt;
struct wlantest_bss *bss;
@@ -1929,6 +2050,24 @@ static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
MAC2STR(mgmt->bssid), mgmt->u.action.category);
return; /* Ignore group addressed Action frames for now */
}
+
+ if (len < 24 + 2) {
+ add_note(wt, MSG_INFO, "Too short Action frame from " MACSTR,
+ MAC2STR(mgmt->sa));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "ACTION%s " MACSTR " -> " MACSTR
+ " BSSID=" MACSTR " (category=%u) (valid=%d)",
+ no_ack ? "-NO-ACK" : "",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da), MAC2STR(mgmt->bssid),
+ mgmt->u.action.category, valid);
+ wpa_hexdump(MSG_MSGDUMP, "ACTION payload", data + 24, len - 24);
+
+ if (is_broadcast_ether_addr(mgmt->bssid)) {
+ rx_mgmt_action_no_bss(wt, mgmt, len, no_ack);
+ return;
+ }
bss = bss_get(wt, mgmt->bssid);
if (bss == NULL)
return;
@@ -1939,18 +2078,6 @@ static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
if (sta == NULL)
return;
- if (len < 24 + 1) {
- add_note(wt, MSG_INFO, "Too short Action frame from " MACSTR,
- MAC2STR(mgmt->sa));
- return;
- }
-
- wpa_printf(MSG_DEBUG, "ACTION " MACSTR " -> " MACSTR
- " (category=%u) (valid=%d)",
- MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
- mgmt->u.action.category, valid);
- wpa_hexdump(MSG_MSGDUMP, "ACTION payload", data + 24, len - 24);
-
if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
sta->state < STATE3) {
add_note(wt, MSG_INFO, "Action frame sent when STA is not in "
@@ -2061,7 +2188,8 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
fc = le_to_host16(mgmt->frame_control);
stype = WLAN_FC_GET_STYPE(fc);
- if (stype == WLAN_FC_STYPE_ACTION) {
+ if (stype == WLAN_FC_STYPE_ACTION ||
+ stype == WLAN_FC_STYPE_ACTION_NO_ACK) {
if (len < 24 + 1)
return 0;
if (mgmt->u.action.category == WLAN_ACTION_PUBLIC)
@@ -2138,6 +2266,56 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
}
+static u8 * try_tk(struct wpa_ptk *ptk, const u8 *data, size_t len,
+ size_t *dlen)
+{
+ const struct ieee80211_hdr *hdr;
+ u8 *decrypted, *frame;
+
+ hdr = (const struct ieee80211_hdr *) data;
+ decrypted = ccmp_decrypt(ptk->tk, hdr, data + 24, len - 24, dlen);
+ if (!decrypted)
+ return NULL;
+
+ frame = os_malloc(24 + *dlen);
+ if (frame) {
+ os_memcpy(frame, data, 24);
+ os_memcpy(frame + 24, decrypted, *dlen);
+ *dlen += 24;
+ }
+ os_free(decrypted);
+ return frame;
+}
+
+
+static u8 * mgmt_ccmp_decrypt_tk(struct wlantest *wt, const u8 *data,
+ size_t len, size_t *dlen)
+{
+ struct wlantest_ptk *ptk;
+ u8 *decrypted;
+ int prev_level = wpa_debug_level;
+ int keyid;
+
+ keyid = data[24 + 3] >> 6;
+
+ wpa_debug_level = MSG_WARNING;
+ dl_list_for_each(ptk, &wt->ptk, struct wlantest_ptk, list) {
+ decrypted = try_tk(&ptk->ptk, data, len, dlen);
+ if (decrypted) {
+ wpa_debug_level = prev_level;
+ add_note(wt, MSG_DEBUG,
+ "Found TK match from the list of all known TKs");
+ write_decrypted_note(wt, decrypted, ptk->ptk.tk,
+ ptk->ptk.tk_len, keyid);
+ return decrypted;
+ }
+ }
+ wpa_debug_level = prev_level;
+
+ return NULL;
+}
+
+
static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
size_t *dlen)
{
@@ -2147,19 +2325,11 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
int keyid;
u8 *decrypted, *frame = NULL;
u8 pn[6], *rsc;
+ u16 fc;
+ u8 mask;
hdr = (const struct ieee80211_hdr *) data;
- bss = bss_get(wt, hdr->addr3);
- if (bss == NULL)
- return NULL;
- if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
- sta = sta_get(bss, hdr->addr2);
- else
- sta = sta_get(bss, hdr->addr1);
- if (sta == NULL || !sta->ptk_set) {
- add_note(wt, MSG_MSGDUMP, "No PTK known to decrypt the frame");
- return NULL;
- }
+ fc = le_to_host16(hdr->frame_control);
if (len < 24 + 4)
return NULL;
@@ -2171,7 +2341,11 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
return NULL;
}
- if (data[24 + 2] != 0 || (data[24 + 3] & 0x1f) != 0) {
+ mask = 0x1f;
+ if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION ||
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION_NO_ACK)
+ mask &= ~0x10; /* FTM */
+ if (data[24 + 2] != 0 || (data[24 + 3] & mask) != 0) {
add_note(wt, MSG_INFO, "CCMP mgmt frame from " MACSTR " used "
"non-zero reserved bit", MAC2STR(hdr->addr2));
}
@@ -2183,6 +2357,21 @@ static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
MACSTR, keyid, MAC2STR(hdr->addr2));
}
+ bss = bss_get(wt, hdr->addr3);
+ if (bss == NULL)
+ return mgmt_ccmp_decrypt_tk(wt, data, len, dlen);
+ if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
+ sta = sta_get(bss, hdr->addr2);
+ else
+ sta = sta_get(bss, hdr->addr1);
+ if (sta == NULL || !sta->ptk_set) {
+ decrypted = mgmt_ccmp_decrypt_tk(wt, data, len, dlen);
+ if (!decrypted)
+ add_note(wt, MSG_MSGDUMP,
+ "No PTK known to decrypt the frame");
+ return decrypted;
+ }
+
if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
rsc = sta->rsc_tods[16];
else
@@ -2236,7 +2425,8 @@ static int check_mgmt_ccmp(struct wlantest *wt, const u8 *data, size_t len)
mgmt = (const struct ieee80211_mgmt *) data;
fc = le_to_host16(mgmt->frame_control);
- if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
+ if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION ||
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION_NO_ACK) {
if (len > 24 &&
mgmt->u.action.category == WLAN_ACTION_PUBLIC)
return 0; /* Not a robust management frame */
@@ -2255,7 +2445,8 @@ static int check_mgmt_ccmp(struct wlantest *wt, const u8 *data, size_t len)
if ((bss->rsn_capab & WPA_CAPABILITY_MFPC) &&
(sta->rsn_capab & WPA_CAPABILITY_MFPC) &&
(sta->state == STATE3 ||
- WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION)) {
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION ||
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION_NO_ACK)) {
add_note(wt, MSG_INFO, "Robust individually-addressed "
"management frame sent without CCMP by "
MACSTR, MAC2STR(mgmt->sa));
@@ -2285,7 +2476,8 @@ void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
if ((hdr->addr1[0] & 0x01) &&
(stype == WLAN_FC_STYPE_DEAUTH ||
stype == WLAN_FC_STYPE_DISASSOC ||
- stype == WLAN_FC_STYPE_ACTION)) {
+ stype == WLAN_FC_STYPE_ACTION ||
+ stype == WLAN_FC_STYPE_ACTION_NO_ACK)) {
if (check_bip(wt, data, len) < 0)
valid = 0;
}
@@ -2305,7 +2497,8 @@ void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
!(hdr->addr1[0] & 0x01) &&
(stype == WLAN_FC_STYPE_DEAUTH ||
stype == WLAN_FC_STYPE_DISASSOC ||
- stype == WLAN_FC_STYPE_ACTION)) {
+ stype == WLAN_FC_STYPE_ACTION ||
+ stype == WLAN_FC_STYPE_ACTION_NO_ACK)) {
decrypted = mgmt_ccmp_decrypt(wt, data, len, &dlen);
if (decrypted) {
write_pcap_decrypted(wt, decrypted, dlen, NULL, 0);
@@ -2319,7 +2512,8 @@ void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
!(hdr->addr1[0] & 0x01) &&
(stype == WLAN_FC_STYPE_DEAUTH ||
stype == WLAN_FC_STYPE_DISASSOC ||
- stype == WLAN_FC_STYPE_ACTION)) {
+ stype == WLAN_FC_STYPE_ACTION ||
+ stype == WLAN_FC_STYPE_ACTION_NO_ACK)) {
if (check_mgmt_ccmp(wt, data, len) < 0)
valid = 0;
}
@@ -2353,7 +2547,10 @@ void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
rx_mgmt_disassoc(wt, data, len, valid);
break;
case WLAN_FC_STYPE_ACTION:
- rx_mgmt_action(wt, data, len, valid);
+ rx_mgmt_action(wt, data, len, valid, false);
+ break;
+ case WLAN_FC_STYPE_ACTION_NO_ACK:
+ rx_mgmt_action(wt, data, len, valid, true);
break;
}
diff --git a/wlantest/sta.c b/wlantest/sta.c
index 62dae07..02ecb78 100644
--- a/wlantest/sta.c
+++ b/wlantest/sta.c
@@ -180,8 +180,8 @@ skip_rsn_wpa:
wpa_printf(MSG_INFO, "STA " MACSTR
" proto=%s%s%s%s"
"pairwise=%s%s%s%s%s%s%s"
- "key_mgmt=%s%s%s%s%s%s%s%s%s%s%s"
- "rsn_capab=%s%s%s%s%s%s",
+ "key_mgmt=%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+ "rsn_capab=%s%s%s%s%s%s%s%s%s%s",
MAC2STR(sta->addr),
sta->proto == 0 ? "OPEN " : "",
sta->proto & WPA_PROTO_WPA ? "WPA " : "",
@@ -206,7 +206,10 @@ skip_rsn_wpa:
"EAP-SHA256 " : "",
sta->key_mgmt & WPA_KEY_MGMT_PSK_SHA256 ?
"PSK-SHA256 " : "",
+ sta->key_mgmt & WPA_KEY_MGMT_OWE ? "OWE " : "",
+ sta->key_mgmt & WPA_KEY_MGMT_PASN ? "PASN " : "",
sta->key_mgmt & WPA_KEY_MGMT_OSEN ? "OSEN " : "",
+ sta->key_mgmt & WPA_KEY_MGMT_DPP ? "DPP " : "",
sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B ?
"EAP-SUITE-B " : "",
sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ?
@@ -218,5 +221,12 @@ skip_rsn_wpa:
sta->rsn_capab & WPA_CAPABILITY_MFPC ? "MFPC " : "",
sta->rsn_capab & WPA_CAPABILITY_PEERKEY_ENABLED ?
"PEERKEY " : "",
- sta->rsn_capab & WPA_CAPABILITY_OCVC ? "OCVC " : "");
+ sta->rsn_capab & WPA_CAPABILITY_SPP_A_MSDU_CAPABLE ?
+ "SPP-A-MSDU-CAPAB " : "",
+ sta->rsn_capab & WPA_CAPABILITY_SPP_A_MSDU_REQUIRED ?
+ "SPP-A-MSDU-REQUIRED " : "",
+ sta->rsn_capab & WPA_CAPABILITY_PBAC ? "PBAC " : "",
+ sta->rsn_capab & WPA_CAPABILITY_OCVC ? "OCVC " : "",
+ sta->rsn_capab & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST ?
+ "ExtKeyID " : "");
}
diff --git a/wlantest/wlantest.c b/wlantest/wlantest.c
index 1b8d714..62c89e2 100644
--- a/wlantest/wlantest.c
+++ b/wlantest/wlantest.c
@@ -323,6 +323,19 @@ size_t notes_len(struct wlantest *wt, size_t hdrlen)
}
+void write_decrypted_note(struct wlantest *wt, const u8 *decrypted,
+ const u8 *tk, size_t tk_len, int keyid)
+{
+ char tk_hex[65];
+
+ if (!decrypted)
+ return;
+
+ wpa_snprintf_hex(tk_hex, sizeof(tk_hex), tk, tk_len);
+ add_note(wt, MSG_EXCESSIVE, "TK[%d] %s", keyid, tk_hex);
+}
+
+
int wlantest_relog(struct wlantest *wt)
{
int ret = 0;
diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h
index 0c266f4..658a3a0 100644
--- a/wlantest/wlantest.h
+++ b/wlantest/wlantest.h
@@ -232,6 +232,8 @@ void add_note(struct wlantest *wt, int level, const char *fmt, ...)
PRINTF_FORMAT(3, 4);
void clear_notes(struct wlantest *wt);
size_t notes_len(struct wlantest *wt, size_t hdrlen);
+void write_decrypted_note(struct wlantest *wt, const u8 *decrypted,
+ const u8 *tk, size_t tk_len, int keyid);
int add_wep(struct wlantest *wt, const char *key);
int read_cap_file(struct wlantest *wt, const char *fname);
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index ed7e358..fd74c16 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -32,6 +32,10 @@ ifeq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
L_CFLAGS += -DANDROID_LIB_STUB
endif
+ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB_EVENT),)
+L_CFLAGS += -DANDROID_LIB_EVENT
+endif
+
# Disable roaming in wpa_supplicant
ifdef CONFIG_NO_ROAMING
L_CFLAGS += -DCONFIG_NO_ROAMING
@@ -90,6 +94,7 @@ OBJS += notify.c
OBJS += bss.c
OBJS += eap_register.c
OBJS += src/utils/common.c
+OBJS += src/utils/config.c
OBJS += src/utils/wpa_debug.c
OBJS += src/utils/wpabuf.c
OBJS += src/utils/bitfield.c
@@ -367,6 +372,17 @@ L_CFLAGS += -DCONFIG_WIFI_DISPLAY
OBJS += wifi_display.c
endif
+ifdef CONFIG_PASN
+L_CFLAGS += -DCONFIG_PASN
+L_CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += src/common/ptksa_cache.c
+OBJS += pasn_supplicant.c
+endif
+
ifdef CONFIG_HS20
OBJS += hs20_supplicant.c
L_CFLAGS += -DCONFIG_HS20
@@ -1601,6 +1617,12 @@ L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
NEED_EXT_PASSWORD=y
endif
+ifdef CONFIG_EXT_PASSWORD_FILE
+OBJS += src/utils/ext_password_file.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD_FILE
+NEED_EXT_PASSWORD=y
+endif
+
ifdef NEED_EXT_PASSWORD
OBJS += src/utils/ext_password.c
L_CFLAGS += -DCONFIG_EXT_PASSWORD
@@ -1631,7 +1653,7 @@ endif
OBJS += src/drivers/driver_common.c
-OBJS += wpa_supplicant.c events.c blacklist.c wpas_glue.c scan.c
+OBJS += wpa_supplicant.c events.c bssid_ignore.c wpas_glue.c scan.c
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.c
OBJS_t += src/radius/radius_client.c
OBJS_t += src/radius/radius.c
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 9adadf1..bc3aa1d 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -83,6 +83,7 @@ OBJS += notify.o
OBJS += bss.o
OBJS += eap_register.o
OBJS += ../src/utils/common.o
+OBJS += ../src/utils/config.o
OBJS += ../src/utils/wpa_debug.o
OBJS += ../src/utils/wpabuf.o
OBJS += ../src/utils/bitfield.o
@@ -390,6 +391,17 @@ CFLAGS += -DCONFIG_WIFI_DISPLAY
OBJS += wifi_display.o
endif
+ifdef CONFIG_PASN
+CFLAGS += -DCONFIG_PASN
+CFLAGS += -DCONFIG_PTKSA_CACHE
+NEED_HMAC_SHA256_KDF=y
+NEED_HMAC_SHA384_KDF=y
+NEED_SHA256=y
+NEED_SHA384=y
+OBJS += ../src/common/ptksa_cache.o
+OBJS += pasn_supplicant.o
+endif
+
ifdef CONFIG_HS20
OBJS += hs20_supplicant.o
CFLAGS += -DCONFIG_HS20
@@ -1739,6 +1751,12 @@ CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
NEED_EXT_PASSWORD=y
endif
+ifdef CONFIG_EXT_PASSWORD_FILE
+OBJS += ../src/utils/ext_password_file.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_FILE
+NEED_EXT_PASSWORD=y
+endif
+
ifdef NEED_EXT_PASSWORD
OBJS += ../src/utils/ext_password.o
CFLAGS += -DCONFIG_EXT_PASSWORD
@@ -1781,7 +1799,7 @@ endif
OBJS += ../src/drivers/driver_common.o
OBJS_priv += ../src/drivers/driver_common.o
-OBJS += wpa_supplicant.o events.o blacklist.o wpas_glue.o scan.o
+OBJS += wpa_supplicant.o events.o bssid_ignore.o wpas_glue.o scan.o
OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o
OBJS_t += ../src/radius/radius_client.o
OBJS_t += ../src/radius/radius.o
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index ac88a7d..cfefa48 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -44,6 +44,7 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
static bool is_chanwidth160_supported(struct hostapd_hw_modes *mode,
struct hostapd_config *conf)
{
@@ -63,6 +64,7 @@ static bool is_chanwidth160_supported(struct hostapd_hw_modes *mode,
return true;
return false;
}
+#endif /* CONFIG_P2P */
static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
@@ -264,6 +266,16 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG,
"HT secondary channel offset %d for P2P group",
conf->secondary_channel);
+ } else if (ssid->p2p_group && conf->secondary_channel &&
+ conf->hw_mode != HOSTAPD_MODE_IEEE80211A) {
+ /* This ended up trying to configure invalid
+ * 2.4 GHz channels (e.g., HT40+ on channel 11)
+ * in some cases, so clear the secondary channel
+ * configuration now to avoid such cases that
+ * would lead to group formation failures. */
+ wpa_printf(MSG_DEBUG,
+ "Disable HT secondary channel for P2P group on 2.4 GHz");
+ conf->secondary_channel = 0;
}
#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/blacklist.h b/wpa_supplicant/blacklist.h
deleted file mode 100644
index a1c60d5..0000000
--- a/wpa_supplicant/blacklist.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * wpa_supplicant - Temporary BSSID blacklist
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef BLACKLIST_H
-#define BLACKLIST_H
-
-struct wpa_blacklist {
- struct wpa_blacklist *next;
- u8 bssid[ETH_ALEN];
- int count;
- /* Time of most recent blacklist event. */
- struct os_reltime blacklist_start;
- /*
- * Number of seconds after blacklist_start that the entry will be
- * considered blacklisted.
- */
- int timeout_secs;
-};
-
-struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
- const u8 *bssid);
-int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
-int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
-int wpa_blacklist_is_blacklisted(struct wpa_supplicant *wpa_s, const u8 *bssid);
-void wpa_blacklist_clear(struct wpa_supplicant *wpa_s);
-void wpa_blacklist_update(struct wpa_supplicant *wpa_s);
-
-#endif /* BLACKLIST_H */
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index e9c2f82..e13783c 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -19,18 +19,6 @@
#include "scan.h"
#include "bss.h"
-
-#define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
-#define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
-#define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
-#define WPA_BSS_MODE_CHANGED_FLAG BIT(3)
-#define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4)
-#define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5)
-#define WPA_BSS_WPS_CHANGED_FLAG BIT(6)
-#define WPA_BSS_RATES_CHANGED_FLAG BIT(7)
-#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
-
-
static void wpa_bss_set_hessid(struct wpa_bss *bss)
{
#ifdef CONFIG_INTERWORKING
@@ -588,8 +576,8 @@ static u32 wpa_bss_compare_res(const struct wpa_bss *old,
}
-static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
- const struct wpa_bss *bss)
+void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
+ const struct wpa_bss *bss)
{
if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
wpas_notify_bss_freq_changed(wpa_s, bss->id);
@@ -1390,6 +1378,8 @@ const u8 * wpa_bss_get_fils_cache_id(const struct wpa_bss *bss)
int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
{
+ if (!bss)
+ return 0;
return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
capab);
}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 7cb1745..4078b9b 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -20,10 +20,20 @@ struct wpa_scan_res;
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
#define WPA_BSS_OWE_TRANSITION BIT(7)
+#define WPA_BSS_FREQ_CHANGED_FLAG BIT(0)
+#define WPA_BSS_SIGNAL_CHANGED_FLAG BIT(1)
+#define WPA_BSS_PRIVACY_CHANGED_FLAG BIT(2)
+#define WPA_BSS_MODE_CHANGED_FLAG BIT(3)
+#define WPA_BSS_WPAIE_CHANGED_FLAG BIT(4)
+#define WPA_BSS_RSNIE_CHANGED_FLAG BIT(5)
+#define WPA_BSS_WPS_CHANGED_FLAG BIT(6)
+#define WPA_BSS_RATES_CHANGED_FLAG BIT(7)
+#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
+
struct wpa_bss_anqp_elem {
struct dl_list list;
u16 infoid;
- bool protected; /* received in a protected GAS response */
+ bool protected_response; /* received in a protected GAS response */
struct wpabuf *payload;
};
@@ -120,6 +130,8 @@ static inline const u8 * wpa_bss_ie_ptr(const struct wpa_bss *bss)
return bss->ies;
}
+void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
+ const struct wpa_bss *bss);
void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_res *res,
@@ -177,7 +189,7 @@ static inline int bss_is_pbss(struct wpa_bss *bss)
static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level)
{
- if (bss != NULL && new_level < 0)
+ if (bss != NULL && new_level > -WPA_INVALID_NOISE && new_level < 0)
bss->level = new_level;
}
diff --git a/wpa_supplicant/blacklist.c b/wpa_supplicant/bssid_ignore.c
index 2f32644..e378577 100644
--- a/wpa_supplicant/blacklist.c
+++ b/wpa_supplicant/bssid_ignore.c
@@ -1,6 +1,6 @@
/*
- * wpa_supplicant - Temporary BSSID blacklist
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * wpa_supplicant - List of temporarily ignored BSSIDs
+ * Copyright (c) 2003-2021, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,32 +10,32 @@
#include "common.h"
#include "wpa_supplicant_i.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
/**
- * wpa_blacklist_get - Get the blacklist entry for a BSSID
+ * wpa_bssid_ignore_get - Get the ignore list entry for a BSSID
* @wpa_s: Pointer to wpa_supplicant data
* @bssid: BSSID
- * Returns: Matching blacklist entry for the BSSID or %NULL if not found
+ * Returns: Matching entry for the BSSID or %NULL if not found
*/
-struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
- const u8 *bssid)
+struct wpa_bssid_ignore * wpa_bssid_ignore_get(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
{
- struct wpa_blacklist *e;
+ struct wpa_bssid_ignore *e;
if (wpa_s == NULL || bssid == NULL)
return NULL;
if (wpa_s->current_ssid &&
wpa_s->current_ssid->was_recently_reconfigured) {
- wpa_blacklist_clear(wpa_s);
+ wpa_bssid_ignore_clear(wpa_s);
wpa_s->current_ssid->was_recently_reconfigured = false;
return NULL;
}
- wpa_blacklist_update(wpa_s);
+ wpa_bssid_ignore_update(wpa_s);
- e = wpa_s->blacklist;
+ e = wpa_s->bssid_ignore;
while (e) {
if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
return e;
@@ -47,33 +47,33 @@ struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
/**
- * wpa_blacklist_add - Add an BSSID to the blacklist
+ * wpa_bssid_ignore_add - Add an BSSID to the ignore list
* @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID to be added to the blacklist
- * Returns: Current blacklist count on success, -1 on failure
+ * @bssid: BSSID to be added to the ignore list
+ * Returns: Current ignore list count on success, -1 on failure
*
- * This function adds the specified BSSID to the blacklist or increases the
- * blacklist count if the BSSID was already listed. It should be called when
+ * This function adds the specified BSSID to the ignore list or increases the
+ * ignore count if the BSSID was already listed. It should be called when
* an association attempt fails either due to the selected BSS rejecting
* association or due to timeout.
*
- * This blacklist is used to force %wpa_supplicant to go through all available
+ * This ignore list is used to force %wpa_supplicant to go through all available
* BSSes before retrying to associate with an BSS that rejected or timed out
* association. It does not prevent the listed BSS from being used; it only
* changes the order in which they are tried.
*/
-int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
- struct wpa_blacklist *e;
+ struct wpa_bssid_ignore *e;
struct os_reltime now;
if (wpa_s == NULL || bssid == NULL)
return -1;
- e = wpa_blacklist_get(wpa_s, bssid);
+ e = wpa_bssid_ignore_get(wpa_s, bssid);
os_get_reltime(&now);
if (e) {
- e->blacklist_start = now;
+ e->start = now;
e->count++;
if (e->count > 5)
e->timeout_secs = 1800;
@@ -86,7 +86,7 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
else
e->timeout_secs = 10;
wpa_printf(MSG_INFO, "BSSID " MACSTR
- " blacklist count incremented to %d, blacklisting for %d seconds",
+ " ignore list count incremented to %d, ignoring for %d seconds",
MAC2STR(bssid), e->count, e->timeout_secs);
return e->count;
}
@@ -97,11 +97,11 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
os_memcpy(e->bssid, bssid, ETH_ALEN);
e->count = 1;
e->timeout_secs = 10;
- e->blacklist_start = now;
- e->next = wpa_s->blacklist;
- wpa_s->blacklist = e;
+ e->start = now;
+ e->next = wpa_s->bssid_ignore;
+ wpa_s->bssid_ignore = e;
wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR
- " into blacklist, blacklisting for %d seconds",
+ " into ignore list, ignoring for %d seconds",
MAC2STR(bssid), e->timeout_secs);
return e->count;
@@ -109,28 +109,28 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
/**
- * wpa_blacklist_del - Remove an BSSID from the blacklist
+ * wpa_bssid_ignore_del - Remove an BSSID from the ignore list
* @wpa_s: Pointer to wpa_supplicant data
- * @bssid: BSSID to be removed from the blacklist
+ * @bssid: BSSID to be removed from the ignore list
* Returns: 0 on success, -1 on failure
*/
-int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_bssid_ignore_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
- struct wpa_blacklist *e, *prev = NULL;
+ struct wpa_bssid_ignore *e, *prev = NULL;
if (wpa_s == NULL || bssid == NULL)
return -1;
- e = wpa_s->blacklist;
+ e = wpa_s->bssid_ignore;
while (e) {
if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
if (prev == NULL) {
- wpa_s->blacklist = e->next;
+ wpa_s->bssid_ignore = e->next;
} else {
prev->next = e->next;
}
- wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
- "blacklist", MAC2STR(bssid));
+ wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR
+ " from ignore list", MAC2STR(bssid));
os_free(e);
return 0;
}
@@ -142,75 +142,75 @@ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
/**
- * wpa_blacklist_is_blacklisted - Check the blacklist status of a BSS
+ * wpa_bssid_ignore_is_listed - Check whether a BSSID is ignored temporarily
* @wpa_s: Pointer to wpa_supplicant data
* @bssid: BSSID to be checked
- * Returns: count if BSS is currently considered to be blacklisted, 0 otherwise
+ * Returns: count if BSS is currently considered to be ignored, 0 otherwise
*/
-int wpa_blacklist_is_blacklisted(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_bssid_ignore_is_listed(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
- struct wpa_blacklist *e;
+ struct wpa_bssid_ignore *e;
struct os_reltime now;
- e = wpa_blacklist_get(wpa_s, bssid);
+ e = wpa_bssid_ignore_get(wpa_s, bssid);
if (!e)
return 0;
os_get_reltime(&now);
- if (os_reltime_expired(&now, &e->blacklist_start, e->timeout_secs))
+ if (os_reltime_expired(&now, &e->start, e->timeout_secs))
return 0;
return e->count;
}
/**
- * wpa_blacklist_clear - Clear the blacklist of all entries
+ * wpa_bssid_ignore_clear - Clear the ignore list of all entries
* @wpa_s: Pointer to wpa_supplicant data
*/
-void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
+void wpa_bssid_ignore_clear(struct wpa_supplicant *wpa_s)
{
- struct wpa_blacklist *e, *prev;
+ struct wpa_bssid_ignore *e, *prev;
- e = wpa_s->blacklist;
- wpa_s->blacklist = NULL;
+ e = wpa_s->bssid_ignore;
+ wpa_s->bssid_ignore = NULL;
while (e) {
prev = e;
e = e->next;
- wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
- "blacklist (clear)", MAC2STR(prev->bssid));
+ wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR
+ " from ignore list (clear)", MAC2STR(prev->bssid));
os_free(prev);
}
}
/**
- * wpa_blacklist_update - Update the entries in the blacklist,
+ * wpa_bssid_ignore_update - Update the entries in the ignore list,
* deleting entries that have been expired for over an hour.
* @wpa_s: Pointer to wpa_supplicant data
*/
-void wpa_blacklist_update(struct wpa_supplicant *wpa_s)
+void wpa_bssid_ignore_update(struct wpa_supplicant *wpa_s)
{
- struct wpa_blacklist *e, *prev = NULL;
+ struct wpa_bssid_ignore *e, *prev = NULL;
struct os_reltime now;
if (!wpa_s)
return;
- e = wpa_s->blacklist;
+ e = wpa_s->bssid_ignore;
os_get_reltime(&now);
while (e) {
- if (os_reltime_expired(&now, &e->blacklist_start,
+ if (os_reltime_expired(&now, &e->start,
e->timeout_secs + 3600)) {
- struct wpa_blacklist *to_delete = e;
+ struct wpa_bssid_ignore *to_delete = e;
if (prev) {
prev->next = e->next;
e = prev->next;
} else {
- wpa_s->blacklist = e->next;
- e = wpa_s->blacklist;
+ wpa_s->bssid_ignore = e->next;
+ e = wpa_s->bssid_ignore;
}
wpa_printf(MSG_INFO, "Removed BSSID " MACSTR
- " from blacklist (expired)",
+ " from ignore list (expired)",
MAC2STR(to_delete->bssid));
os_free(to_delete);
} else {
diff --git a/wpa_supplicant/bssid_ignore.h b/wpa_supplicant/bssid_ignore.h
new file mode 100644
index 0000000..721b0e1
--- /dev/null
+++ b/wpa_supplicant/bssid_ignore.h
@@ -0,0 +1,33 @@
+/*
+ * wpa_supplicant - List of temporarily ignored BSSIDs
+ * Copyright (c) 2003-2021, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BSSID_IGNORE_H
+#define BSSID_IGNORE_H
+
+struct wpa_bssid_ignore {
+ struct wpa_bssid_ignore *next;
+ u8 bssid[ETH_ALEN];
+ int count;
+ /* Time of the most recent trigger to ignore this BSSID. */
+ struct os_reltime start;
+ /*
+ * Number of seconds after start that the entey will be considered
+ * valid.
+ */
+ int timeout_secs;
+};
+
+struct wpa_bssid_ignore * wpa_bssid_ignore_get(struct wpa_supplicant *wpa_s,
+ const u8 *bssid);
+int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_bssid_ignore_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_bssid_ignore_is_listed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+void wpa_bssid_ignore_clear(struct wpa_supplicant *wpa_s);
+void wpa_bssid_ignore_update(struct wpa_supplicant *wpa_s);
+
+#endif /* BSSID_IGNORE_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index c516154..ce5c80d 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -442,47 +442,99 @@ static char * wpa_config_write_bssid_hint(const struct parse_data *data,
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_bssid_ignore(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_ignore,
+ &ssid->num_bssid_ignore,
+ "bssid_ignore", 1, 1);
+}
+
+
+/* deprecated alias for bssid_ignore for backwards compatibility */
static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
return wpa_config_parse_addr_list(data, line, value,
- &ssid->bssid_blacklist,
- &ssid->num_bssid_blacklist,
- "bssid_blacklist", 1, 1);
+ &ssid->bssid_ignore,
+ &ssid->num_bssid_ignore,
+ "bssid_ignore", 1, 1);
}
#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_bssid_ignore(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_ignore,
+ ssid->num_bssid_ignore,
+ "bssid_ignore");
+}
+
+
+/* deprecated alias for bssid_ignore for backwards compatibility */
static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- return wpa_config_write_addr_list(data, ssid->bssid_blacklist,
- ssid->num_bssid_blacklist,
- "bssid_blacklist");
+ return wpa_config_write_addr_list(data, ssid->bssid_ignore,
+ ssid->num_bssid_ignore,
+ "bssid_ignore");
}
+
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_bssid_accept(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ return wpa_config_parse_addr_list(data, line, value,
+ &ssid->bssid_accept,
+ &ssid->num_bssid_accept,
+ "bssid_accept", 1, 1);
+}
+
+
+/* deprecated alias for bssid_accept for backwards compatibility */
static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
return wpa_config_parse_addr_list(data, line, value,
- &ssid->bssid_whitelist,
- &ssid->num_bssid_whitelist,
- "bssid_whitelist", 1, 1);
+ &ssid->bssid_accept,
+ &ssid->num_bssid_accept,
+ "bssid_accept", 1, 1);
}
#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_bssid_accept(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_addr_list(data, ssid->bssid_accept,
+ ssid->num_bssid_accept,
+ "bssid_accept");
+}
+
+
+/* deprecated alias for bssid_accept for backwards compatibility */
static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- return wpa_config_write_addr_list(data, ssid->bssid_whitelist,
- ssid->num_bssid_whitelist,
- "bssid_whitelist");
+ return wpa_config_write_addr_list(data, ssid->bssid_accept,
+ ssid->num_bssid_accept,
+ "bssid_accept");
}
+
+#endif /* NO_CONFIG_WRITE */
+
+
+#ifndef NO_CONFIG_WRITE
#endif /* NO_CONFIG_WRITE */
@@ -2362,8 +2414,10 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
{ FUNC(bssid_hint) },
- { FUNC(bssid_blacklist) },
- { FUNC(bssid_whitelist) },
+ { FUNC(bssid_ignore) },
+ { FUNC(bssid_accept) },
+ { FUNC(bssid_blacklist) }, /* deprecated alias for bssid_ignore */
+ { FUNC(bssid_whitelist) }, /* deprecated alias for bssid_accept */
{ FUNC_KEY(psk) },
{ INT(mem_only_psk) },
{ STR_KEY(sae_password) },
@@ -2763,8 +2817,8 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
os_free(ssid->freq_list);
os_free(ssid->bgscan);
os_free(ssid->p2p_client_list);
- os_free(ssid->bssid_blacklist);
- os_free(ssid->bssid_whitelist);
+ os_free(ssid->bssid_ignore);
+ os_free(ssid->bssid_accept);
#ifdef CONFIG_HT_OVERRIDES
os_free(ssid->ht_mcs);
#endif /* CONFIG_HT_OVERRIDES */
@@ -2890,6 +2944,7 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->p2p_no_go_freq.range);
os_free(config->autoscan);
os_free(config->freq_list);
+ os_free(config->initial_freq_list);
wpabuf_free(config->wps_nfc_dh_pubkey);
wpabuf_free(config->wps_nfc_dh_privkey);
wpabuf_free(config->wps_nfc_dev_pw);
@@ -4308,6 +4363,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
config->ap_isolate = DEFAULT_AP_ISOLATE;
config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
config->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
+ config->scan_res_valid_for_connect = DEFAULT_SCAN_RES_VALID_FOR_CONNECT;
config->wmm_ac_params[0] = ac_be;
config->wmm_ac_params[1] = ac_bk;
config->wmm_ac_params[2] = ac_vi;
@@ -4547,6 +4603,26 @@ static int wpa_config_process_freq_list(const struct global_parse_data *data,
}
+static int
+wpa_config_process_initial_freq_list(const struct global_parse_data *data,
+ struct wpa_config *config, int line,
+ const char *value)
+{
+ int *freqs;
+
+ freqs = wpa_config_parse_int_array(value);
+ if (!freqs)
+ return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
+ os_free(config->initial_freq_list);
+ config->initial_freq_list = freqs;
+ return 0;
+}
+
+
#ifdef CONFIG_P2P
static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
struct wpa_config *config, int line,
@@ -5082,7 +5158,9 @@ static const struct global_parse_data global_fields[] = {
{ FUNC(ap_vendor_elements), 0 },
{ INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
{ FUNC(freq_list), 0 },
+ { FUNC(initial_freq_list), 0},
{ INT(scan_cur_freq), 0 },
+ { INT(scan_res_valid_for_connect), 0},
{ INT(sched_scan_interval), 0 },
{ INT(sched_scan_start_delay), 0 },
{ INT(tdls_external_control), 0},
@@ -5126,6 +5204,12 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM },
{ INT_RANGE(extended_key_id, 0, 1), 0 },
#endif /* CONFIG_WNM */
+ { INT_RANGE(wowlan_disconnect_on_deinit, 0, 1), 0},
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ { INT_RANGE(force_kdk_derivation, 0, 1), 0 },
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
};
#undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 648573d..aac4a9d 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -45,6 +45,7 @@
#define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75
#define DEFAULT_OCE_SUPPORT OCE_STA
#define DEFAULT_EXTENDED_KEY_ID 0
+#define DEFAULT_SCAN_RES_VALID_FOR_CONNECT 5
#include "config_ssid.h"
#include "wps/wps.h"
@@ -917,6 +918,19 @@ struct wpa_config {
int *freq_list;
/**
+ * initial_freq_list - like freq_list but for initial scan
+ *
+ * This is an optional zero-terminated array of frequencies in
+ * megahertz (MHz) to allow for narrowing scanning range when
+ * the application is started.
+ *
+ * This can be used to speed up initial connection time if the
+ * channel is known ahead of time, without limiting the scanned
+ * frequencies during normal use.
+ */
+ int *initial_freq_list;
+
+ /**
* scan_cur_freq - Whether to scan only the current channel
*
* If true, attempt to scan only the current channel if any other
@@ -925,6 +939,15 @@ struct wpa_config {
int scan_cur_freq;
/**
+ * scan_res_valid_for_connect - Seconds scans are valid for association
+ *
+ * This configures the number of seconds old scan results are considered
+ * valid for association. When scan results are older than this value
+ * a new scan is triggered prior to the association.
+ */
+ int scan_res_valid_for_connect;
+
+ /**
* changed_parameters - Bitmap of changed parameters since last update
*/
unsigned int changed_parameters;
@@ -1541,9 +1564,31 @@ struct wpa_config {
/**
* p2p_device_random_mac_addr - P2P Device MAC address policy default
*
- * 0 = use permanent MAC address
+ * 0 = use permanent MAC address (the one set by default by the device
+ * driver). Notice that, if the device driver is configured to
+ * always use random MAC addresses, this flag breaks reinvoking a
+ * persistent group, so flags 1 or 2 should be used instead with
+ * such drivers if persistent groups are used.
* 1 = use random MAC address on creating the interface if there is no
- * persistent groups.
+ * persistent group. Besides, if a persistent group is created,
+ * p2p_device_persistent_mac_addr is set to the MAC address of the
+ * P2P Device interface, so that this address will be subsequently
+ * used to change the MAC address of the P2P Device interface. With
+ * no persistent group, the random MAC address is created by
+ * wpa_supplicant, changing the one set by the device driver.
+ * The device driver shall support SIOCGIFFLAGS/SIOCSIFFLAGS ioctl
+ * interface control operations.
+ * 2 = this flag should be used when the device driver uses random MAC
+ * addresses by default when a P2P Device interface is created.
+ * If p2p_device_persistent_mac_addr is set, use this MAC address
+ * on creating the P2P Device interface. If not set, use the
+ * default method adopted by the device driver (e.g., random MAC
+ * address). Besides, if a persistent group is created,
+ * p2p_device_persistent_mac_addr is set to the MAC address of the
+ * P2P Device interface, so that this address will be subsequently
+ * used in place of the default address set by the device driver.
+ * (This option does not need support of SIOCGIFFLAGS/SIOCSIFFLAGS
+ * ioctl interface control operations and uses NL80211_ATTR_MAC).
*
* By default, permanent MAC address is used.
*/
@@ -1586,6 +1631,25 @@ struct wpa_config {
* 1 = use Extended Key ID when possible
*/
int extended_key_id;
+
+ /**
+ * wowlan_disconnect_on_deinit - Trigger disconnect on wpa_supplicant
+ * interface deinit even if the driver has enabled WoWLAN.
+ *
+ * 0 = Do not disconnect
+ * 1 = Trigger disconnection
+ */
+ int wowlan_disconnect_on_deinit;
+
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ /*
+ * Normally, KDK should be derived if and only if both sides support
+ * secure LTF. Allow forcing KDK derivation for testing purposes.
+ */
+ int force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN*/
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 246644a..a535e3f 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -23,105 +23,7 @@
#include "p2p/p2p.h"
#include "eap_peer/eap_methods.h"
#include "eap_peer/eap.h"
-
-
-static int newline_terminated(const char *buf, size_t buflen)
-{
- size_t len = os_strlen(buf);
- if (len == 0)
- return 0;
- if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
- buf[len - 1] != '\n')
- return 0;
- return 1;
-}
-
-
-static void skip_line_end(FILE *stream)
-{
- char buf[100];
- while (fgets(buf, sizeof(buf), stream)) {
- buf[sizeof(buf) - 1] = '\0';
- if (newline_terminated(buf, sizeof(buf)))
- return;
- }
-}
-
-
-/**
- * wpa_config_get_line - Read the next configuration file line
- * @s: Buffer for the line
- * @size: The buffer length
- * @stream: File stream to read from
- * @line: Pointer to a variable storing the file line number
- * @_pos: Buffer for the pointer to the beginning of data on the text line or
- * %NULL if not needed (returned value used instead)
- * Returns: Pointer to the beginning of data on the text line or %NULL if no
- * more text lines are available.
- *
- * This function reads the next non-empty line from the configuration file and
- * removes comments. The returned string is guaranteed to be null-terminated.
- */
-static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
- char **_pos)
-{
- char *pos, *end, *sstart;
-
- while (fgets(s, size, stream)) {
- (*line)++;
- s[size - 1] = '\0';
- if (!newline_terminated(s, size)) {
- /*
- * The line was truncated - skip rest of it to avoid
- * confusing error messages.
- */
- wpa_printf(MSG_INFO, "Long line in configuration file "
- "truncated");
- skip_line_end(stream);
- }
- pos = s;
-
- /* Skip white space from the beginning of line. */
- while (*pos == ' ' || *pos == '\t' || *pos == '\r')
- pos++;
-
- /* Skip comment lines and empty lines */
- if (*pos == '#' || *pos == '\n' || *pos == '\0')
- continue;
-
- /*
- * Remove # comments unless they are within a double quoted
- * string.
- */
- sstart = os_strchr(pos, '"');
- if (sstart)
- sstart = os_strrchr(sstart + 1, '"');
- if (!sstart)
- sstart = pos;
- end = os_strchr(sstart, '#');
- if (end)
- *end-- = '\0';
- else
- end = pos + os_strlen(pos) - 1;
-
- /* Remove trailing white space. */
- while (end > pos &&
- (*end == '\n' || *end == ' ' || *end == '\t' ||
- *end == '\r'))
- *end-- = '\0';
-
- if (*pos == '\0')
- continue;
-
- if (_pos)
- *_pos = pos;
- return pos;
- }
-
- if (_pos)
- *_pos = NULL;
- return NULL;
-}
+#include "utils/config.h"
static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
@@ -767,8 +669,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(scan_ssid);
write_bssid(f, ssid);
write_bssid_hint(f, ssid);
- write_str(f, "bssid_blacklist", ssid);
- write_str(f, "bssid_whitelist", ssid);
+ write_str(f, "bssid_ignore", ssid);
+ write_str(f, "bssid_accept", ssid);
write_psk(f, ssid);
INT(mem_only_psk);
STR(sae_password);
@@ -1475,9 +1377,23 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
}
fprintf(f, "\n");
}
+ if (config->initial_freq_list && config->initial_freq_list[0]) {
+ int i;
+ fprintf(f, "initial_freq_list=");
+ for (i = 0; config->initial_freq_list[i]; i++) {
+ fprintf(f, "%s%d", i > 0 ? " " : "",
+ config->initial_freq_list[i]);
+ }
+ fprintf(f, "\n");
+ }
if (config->scan_cur_freq != DEFAULT_SCAN_CUR_FREQ)
fprintf(f, "scan_cur_freq=%d\n", config->scan_cur_freq);
+ if (config->scan_res_valid_for_connect !=
+ DEFAULT_SCAN_RES_VALID_FOR_CONNECT)
+ fprintf(f, "scan_res_valid_for_connect=%d\n",
+ config->scan_res_valid_for_connect);
+
if (config->sched_scan_interval)
fprintf(f, "sched_scan_interval=%u\n",
config->sched_scan_interval);
@@ -1611,6 +1527,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
if (config->extended_key_id != DEFAULT_EXTENDED_KEY_ID)
fprintf(f, "extended_key_id=%d\n",
config->extended_key_id);
+ if (config->wowlan_disconnect_on_deinit)
+ fprintf(f, "wowlan_disconnect_on_deinit=%d\n",
+ config->wowlan_disconnect_on_deinit);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index b4fdc8a..3f7b314 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -153,16 +153,16 @@ struct wpa_ssid {
u8 bssid[ETH_ALEN];
/**
- * bssid_blacklist - List of inacceptable BSSIDs
+ * bssid_ignore - List of inacceptable BSSIDs
*/
- u8 *bssid_blacklist;
- size_t num_bssid_blacklist;
+ u8 *bssid_ignore;
+ size_t num_bssid_ignore;
/**
- * bssid_blacklist - List of acceptable BSSIDs
+ * bssid_accept - List of acceptable BSSIDs
*/
- u8 *bssid_whitelist;
- size_t num_bssid_whitelist;
+ u8 *bssid_accept;
+ size_t num_bssid_accept;
/**
* bssid_set - Whether BSSID is configured for this network
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 8306950..0d4c2bc 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -22,6 +22,7 @@
#ifdef CONFIG_DPP
#include "common/dpp.h"
#endif /* CONFIG_DPP */
+#include "common/ptksa_cache.h"
#include "crypto/tls.h"
#include "ap/hostapd.h"
#include "eap_peer/eap.h"
@@ -48,7 +49,7 @@
#include "scan.h"
#include "ctrl_iface.h"
#include "interworking.h"
-#include "blacklist.h"
+#include "bssid_ignore.h"
#include "autoscan.h"
#include "wnm_sta.h"
#include "offchannel.h"
@@ -299,20 +300,30 @@ static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd)
}
-static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *band)
+static int wpas_ctrl_set_band(struct wpa_supplicant *wpa_s, char *bands)
{
union wpa_event_data event;
+ u32 setband_mask = WPA_SETBAND_AUTO;
- if (os_strcmp(band, "AUTO") == 0)
- wpa_s->setband = WPA_SETBAND_AUTO;
- else if (os_strcmp(band, "5G") == 0)
- wpa_s->setband = WPA_SETBAND_5G;
- else if (os_strcmp(band, "2G") == 0)
- wpa_s->setband = WPA_SETBAND_2G;
- else
- return -1;
+ /*
+ * For example:
+ * SET setband 2G,6G
+ * SET setband 5G
+ * SET setband AUTO
+ */
+ if (!os_strstr(bands, "AUTO")) {
+ if (os_strstr(bands, "5G"))
+ setband_mask |= WPA_SETBAND_5G;
+ if (os_strstr(bands, "6G"))
+ setband_mask |= WPA_SETBAND_6G;
+ if (os_strstr(bands, "2G"))
+ setband_mask |= WPA_SETBAND_2G;
+ if (setband_mask == WPA_SETBAND_AUTO)
+ return -1;
+ }
- if (wpa_drv_setband(wpa_s, wpa_s->setband) == 0) {
+ wpa_s->setband_mask = setband_mask;
+ if (wpa_drv_setband(wpa_s, wpa_s->setband_mask) == 0) {
os_memset(&event, 0, sizeof(event));
event.channel_list_changed.initiator = REGDOM_SET_BY_USER;
event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN;
@@ -2543,20 +2554,20 @@ static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
- char *cmd, char *buf,
- size_t buflen)
+static int wpa_supplicant_ctrl_iface_bssid_ignore(struct wpa_supplicant *wpa_s,
+ char *cmd, char *buf,
+ size_t buflen)
{
u8 bssid[ETH_ALEN];
- struct wpa_blacklist *e;
+ struct wpa_bssid_ignore *e;
char *pos, *end;
int ret;
- /* cmd: "BLACKLIST [<BSSID>]" */
+ /* cmd: "BSSID_IGNORE [<BSSID>]" */
if (*cmd == '\0') {
pos = buf;
end = buf + buflen;
- e = wpa_s->blacklist;
+ e = wpa_s->bssid_ignore;
while (e) {
ret = os_snprintf(pos, end - pos, MACSTR "\n",
MAC2STR(e->bssid));
@@ -2570,12 +2581,12 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
cmd++;
if (os_strncmp(cmd, "clear", 5) == 0) {
- wpa_blacklist_clear(wpa_s);
+ wpa_bssid_ignore_clear(wpa_s);
os_memcpy(buf, "OK\n", 3);
return 3;
}
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: BSSID_IGNORE bssid='%s'", cmd);
if (hwaddr_aton(cmd, bssid)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
return -1;
@@ -2585,10 +2596,10 @@ static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
* Add the BSSID twice, so its count will be 2, causing it to be
* skipped when processing scan results.
*/
- ret = wpa_blacklist_add(wpa_s, bssid);
+ ret = wpa_bssid_ignore_add(wpa_s, bssid);
if (ret < 0)
return -1;
- ret = wpa_blacklist_add(wpa_s, bssid);
+ ret = wpa_bssid_ignore_add(wpa_s, bssid);
if (ret < 0)
return -1;
os_memcpy(buf, "OK\n", 3);
@@ -4488,6 +4499,15 @@ static int ctrl_iface_get_capability_auth_alg(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_FILS_SK_PFS */
#endif /* CONFIG_FILS */
+#ifdef CONFIG_PASN
+ ret = os_snprintf(pos, end - pos, "%sPASN",
+ pos == buf ? "" : " ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+#endif /* CONFIG_PASN */
+
return pos - buf;
}
@@ -4813,6 +4833,31 @@ static int wpa_supplicant_ctrl_iface_get_capability(
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_OCV
+ if (os_strcmp(field, "ocv") == 0) {
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV))
+ res = os_snprintf(buf, buflen, "supported");
+ else
+ res = os_snprintf(buf, buflen, "not supported");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_OCV */
+
+ if (os_strcmp(field, "beacon_prot") == 0) {
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION) ||
+ (wpa_s->drv_flags2 &
+ WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT))
+ res = os_snprintf(buf, buflen, "supported");
+ else
+ res = os_snprintf(buf, buflen, "not supported");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
@@ -5285,7 +5330,7 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
os_snprintf(title, sizeof(title), "anqp[%u]",
elem->infoid);
pos = anqp_add_hex(pos, end, title, elem->payload);
- if (elem->protected) {
+ if (elem->protected_response) {
ret = os_snprintf(pos, end - pos,
"protected-anqp-info[%u]=1\n",
elem->infoid);
@@ -8414,13 +8459,14 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->consecutive_conn_failures = 0;
wpa_drv_radio_disable(wpa_s, 0);
- wpa_blacklist_clear(wpa_s);
+ wpa_bssid_ignore_clear(wpa_s);
wpa_supplicant_ctrl_iface_remove_network(wpa_s, "all");
wpa_supplicant_ctrl_iface_remove_cred(wpa_s, "all");
wpa_config_flush_blobs(wpa_s->conf);
wpa_s->conf->auto_interworking = 0;
wpa_s->conf->okc = 0;
+ ptksa_cache_flush(wpa_s->ptksa, NULL, WPA_CIPHER_NONE);
wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
rsn_preauth_deinit(wpa_s->wpa);
@@ -8521,6 +8567,13 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
free_bss_tmp_disallowed(wpa_s);
os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data));
+
+#ifdef CONFIG_PASN
+ wpas_pasn_auth_stop(wpa_s);
+#endif /* CONFIG_PASN */
+
+ if (wpa_s->mac_addr_changed && wpa_s->conf->mac_addr == 0)
+ wpas_restore_permanent_mac_addr(wpa_s);
}
@@ -9774,8 +9827,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
if (wpa_s->vendor_elem[frame] == NULL) {
wpa_s->vendor_elem[frame] = buf;
- wpas_vendor_elem_update(wpa_s);
- return 0;
+ goto update_ies;
}
if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) {
@@ -9785,8 +9837,14 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
wpabuf_free(buf);
+
+update_ies:
wpas_vendor_elem_update(wpa_s);
+ if (frame == VENDOR_ELEM_PROBE_REQ ||
+ frame == VENDOR_ELEM_PROBE_REQ_P2P)
+ wpa_supplicant_set_default_scan_ies(wpa_s);
+
return 0;
}
@@ -10093,6 +10151,7 @@ static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
{
+ ptksa_cache_flush(wpa_s->ptksa, NULL, WPA_CIPHER_NONE);
wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
#ifdef CONFIG_AP
wpas_ap_pmksa_cache_flush(wpa_s);
@@ -10425,6 +10484,73 @@ static int wpas_ctrl_iface_configure_mscs(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_PASN
+static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *token, *context = NULL;
+ u8 bssid[ETH_ALEN];
+ int akmp = -1, cipher = -1, got_bssid = 0;
+ u16 group = 0xFFFF;
+ int id = 0;
+
+ /*
+ * Entry format: bssid=<BSSID> akmp=<AKMP> cipher=<CIPHER> group=<group>
+ */
+ while ((token = str_token(cmd, " ", &context))) {
+ if (os_strncmp(token, "bssid=", 6) == 0) {
+ if (hwaddr_aton(token + 6, bssid))
+ return -1;
+ got_bssid = 1;
+ } else if (os_strcmp(token, "akmp=PASN") == 0) {
+ akmp = WPA_KEY_MGMT_PASN;
+#ifdef CONFIG_IEEE80211R
+ } else if (os_strcmp(token, "akmp=FT-PSK") == 0) {
+ akmp = WPA_KEY_MGMT_FT_PSK;
+ } else if (os_strcmp(token, "akmp=FT-EAP-SHA384") == 0) {
+ akmp = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
+ } else if (os_strcmp(token, "akmp=FT-EAP") == 0) {
+ akmp = WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+ } else if (os_strcmp(token, "akmp=SAE") == 0) {
+ akmp = WPA_KEY_MGMT_SAE;
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_FILS
+ } else if (os_strcmp(token, "akmp=FILS-SHA256") == 0) {
+ akmp = WPA_KEY_MGMT_FILS_SHA256;
+ } else if (os_strcmp(token, "akmp=FILS-SHA384") == 0) {
+ akmp = WPA_KEY_MGMT_FILS_SHA384;
+#endif /* CONFIG_FILS */
+ } else if (os_strcmp(token, "cipher=CCMP-256") == 0) {
+ cipher = WPA_CIPHER_CCMP_256;
+ } else if (os_strcmp(token, "cipher=GCMP-256") == 0) {
+ cipher = WPA_CIPHER_GCMP_256;