aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/code_structure.doxygen4
-rw-r--r--doc/p2p.doxygen4
-rw-r--r--hostapd/config_file.c25
-rw-r--r--hostapd/ctrl_iface.c43
-rw-r--r--hostapd/hlr_auc_gw.milenage_db2
-rw-r--r--hostapd/hostapd.conf10
-rw-r--r--hostapd/hostapd_cli.c2
-rw-r--r--src/ap/acs.c4
-rw-r--r--src/ap/ap_config.c11
-rw-r--r--src/ap/ap_config.h3
-rw-r--r--src/ap/beacon.c79
-rw-r--r--src/ap/ctrl_iface_ap.c56
-rw-r--r--src/ap/dhcp_snoop.c2
-rw-r--r--src/ap/dpp_hostapd.c19
-rw-r--r--src/ap/hostapd.h2
-rw-r--r--src/ap/hw_features.c2
-rw-r--r--src/ap/ieee802_11.c388
-rw-r--r--src/ap/ieee802_11.h2
-rw-r--r--src/ap/ieee802_11_he.c3
-rw-r--r--src/ap/ndisc_snoop.c2
-rw-r--r--src/ap/neighbor_db.c8
-rw-r--r--src/ap/neighbor_db.h3
-rw-r--r--src/ap/wnm_ap.c12
-rw-r--r--src/ap/wnm_ap.h4
-rw-r--r--src/ap/wpa_auth.c18
-rw-r--r--src/ap/wpa_auth_ft.c16
-rw-r--r--src/ap/wps_hostapd.c5
-rw-r--r--src/common/dpp.c175
-rw-r--r--src/common/dpp.h30
-rw-r--r--src/common/dpp_auth.c18
-rw-r--r--src/common/dpp_backup.c75
-rw-r--r--src/common/dpp_crypto.c1885
-rw-r--r--src/common/dpp_i.h70
-rw-r--r--src/common/dpp_pkex.c280
-rw-r--r--src/common/dpp_reconfig.c34
-rw-r--r--src/common/dpp_tcp.c13
-rw-r--r--src/common/hw_features_common.c25
-rw-r--r--src/common/ieee802_11_common.c44
-rw-r--r--src/common/ieee802_11_common.h2
-rw-r--r--src/common/ieee802_11_defs.h56
-rw-r--r--src/common/ptksa_cache.c18
-rw-r--r--src/common/qca-vendor.h665
-rw-r--r--src/common/sae.c12
-rw-r--r--src/common/wpa_common.c5
-rw-r--r--src/common/wpa_common.h1
-rw-r--r--src/common/wpa_ctrl.h8
-rw-r--r--src/crypto/crypto.h371
-rw-r--r--src/crypto/crypto_internal-rsa.c2
-rw-r--r--src/crypto/crypto_openssl.c1009
-rw-r--r--src/crypto/crypto_wolfssl.c8
-rw-r--r--src/crypto/random.c42
-rw-r--r--src/crypto/tls_openssl.c23
-rw-r--r--src/drivers/driver.h6
-rw-r--r--src/drivers/driver_common.c2
-rw-r--r--src/drivers/driver_hostap.h2
-rw-r--r--src/drivers/driver_macsec_qca.c58
-rw-r--r--src/drivers/driver_ndis.c16
-rw-r--r--src/drivers/driver_nl80211.c29
-rw-r--r--src/drivers/driver_nl80211.h1
-rw-r--r--src/drivers/driver_nl80211_capa.c2
-rw-r--r--src/eap_peer/eap_proxy_dummy.c2
-rw-r--r--src/eap_peer/eap_teap.c10
-rw-r--r--src/eap_peer/eap_tls_common.h2
-rw-r--r--src/eap_server/eap_tls_common.h2
-rw-r--r--src/l2_packet/l2_packet_none.c2
-rw-r--r--src/p2p/p2p.c4
-rw-r--r--src/p2p/p2p_build.c2
-rw-r--r--src/p2p/p2p_go_neg.c4
-rw-r--r--src/p2p/p2p_i.h3
-rw-r--r--src/p2p/p2p_pd.c2
-rw-r--r--src/pae/ieee802_1x_kay.c10
-rw-r--r--src/radius/radius_client.c2
-rw-r--r--src/rsn_supp/pmksa_cache.c92
-rw-r--r--src/rsn_supp/pmksa_cache.h9
-rw-r--r--src/rsn_supp/tdls.c43
-rw-r--r--src/rsn_supp/wpa.c27
-rw-r--r--src/rsn_supp/wpa.h6
-rw-r--r--src/rsn_supp/wpa_i.h3
-rw-r--r--src/utils/config.c18
-rw-r--r--src/utils/eloop.c25
-rw-r--r--src/utils/os_unix.c4
-rw-r--r--src/wps/wps.c2
-rw-r--r--src/wps/wps_defs.h2
-rw-r--r--src/wps/wps_registrar.c26
-rw-r--r--src/wps/wps_upnp.c2
-rw-r--r--tests/hwsim/auth_serv/hlr_auc_gw.milenage_db2
-rw-r--r--tests/hwsim/auth_serv/rsa3072-server.pem74
-rw-r--r--tests/hwsim/auth_serv/rsa3072-user-rsa2048.pem74
-rw-r--r--tests/hwsim/auth_serv/rsa3072-user.pem74
-rw-r--r--tests/hwsim/fst_test_common.py5
-rw-r--r--tests/hwsim/multi-bss-iface-per_sta_vif.conf4
-rw-r--r--tests/hwsim/multi-bss-iface.conf4
-rw-r--r--tests/hwsim/test_ap_eap.py28
-rw-r--r--tests/hwsim/test_ap_vlan.py54
-rw-r--r--tests/hwsim/test_ap_wps.py56
-rw-r--r--tests/hwsim/test_connect_cmd.py19
-rw-r--r--tests/hwsim/test_dpp.py69
-rw-r--r--tests/hwsim/test_dscp.py407
-rw-r--r--tests/hwsim/test_fst_config.py107
-rw-r--r--tests/hwsim/test_p2p_autogo.py2
-rw-r--r--tests/hwsim/test_rrm.py9
-rw-r--r--tests/hwsim/test_sae.py17
-rw-r--r--tests/hwsim/test_scs.py196
-rw-r--r--tests/hwsim/test_wmediumd.py2
-rw-r--r--tests/hwsim/test_wnm.py2
-rw-r--r--tests/hwsim/test_wpas_ap.py22
-rw-r--r--tests/hwsim/test_wpas_config.py9
-rw-r--r--tests/hwsim/test_wpas_mesh.py12
-rwxr-xr-xtests/hwsim/vm/inside.sh4
-rw-r--r--tests/hwsim/vm/regdb/regulatory.dbbin0 -> 4036 bytes
-rw-r--r--tests/hwsim/vm/regdb/regulatory.db.p7sbin0 -> 1182 bytes
-rw-r--r--wlantest/bss.c1
-rw-r--r--wlantest/inject.c24
-rw-r--r--wlantest/rx_eapol.c6
-rw-r--r--wpa_supplicant/Android.mk3
-rw-r--r--wpa_supplicant/ChangeLog3
-rw-r--r--wpa_supplicant/Makefile12
-rw-r--r--wpa_supplicant/README84
-rw-r--r--wpa_supplicant/ap.c126
-rw-r--r--wpa_supplicant/ap.h1
-rw-r--r--wpa_supplicant/config.c50
-rw-r--r--wpa_supplicant/config.h11
-rw-r--r--wpa_supplicant/config_file.c13
-rw-r--r--wpa_supplicant/config_none.c2
-rw-r--r--wpa_supplicant/config_ssid.h16
-rw-r--r--wpa_supplicant/ctrl_iface.c623
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.sgml2
-rwxr-xr-xwpa_supplicant/eapol_test.py37
-rw-r--r--wpa_supplicant/events.c237
-rw-r--r--wpa_supplicant/gas_query.c10
-rw-r--r--wpa_supplicant/gas_query.h1
-rw-r--r--wpa_supplicant/mesh.c31
-rw-r--r--wpa_supplicant/mesh_mpm.c10
-rw-r--r--wpa_supplicant/notify.c10
-rw-r--r--wpa_supplicant/op_classes.c8
-rw-r--r--wpa_supplicant/p2p_supplicant.c164
-rw-r--r--wpa_supplicant/p2p_supplicant.h5
-rw-r--r--wpa_supplicant/p2p_supplicant_sd.c4
-rw-r--r--wpa_supplicant/preauth_test.c6
-rw-r--r--wpa_supplicant/robust_av.c1332
-rw-r--r--wpa_supplicant/scan.c57
-rw-r--r--wpa_supplicant/systemd/wpa_supplicant.service.in1
-rw-r--r--wpa_supplicant/wpa_cli.c47
-rw-r--r--wpa_supplicant/wpa_supplicant.c284
-rw-r--r--wpa_supplicant/wpa_supplicant.conf2
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h138
-rw-r--r--wpa_supplicant/wpas_glue.c2
147 files changed, 8017 insertions, 2618 deletions
diff --git a/doc/code_structure.doxygen b/doc/code_structure.doxygen
index 454f179753d3..927ea4e85d7a 100644
--- a/doc/code_structure.doxygen
+++ b/doc/code_structure.doxygen
@@ -62,7 +62,7 @@ with with hostapd. The following C files are currently used:
Definitions shared by multiple files
\ref l2_packet.h, \ref l2_packet_linux.c, and \ref l2_packet_pcap.c
- Layer 2 (link) access wrapper (includes native Linux implementation
+ Layer 2 (link) access wrapper (includes Linux packet socket
and wrappers for libdnet/libpcap). A new l2_packet implementation
may need to be added when porting to new operating systems that are
not supported by libdnet/libpcap. Makefile can be used to select which
@@ -130,7 +130,7 @@ with with hostapd. The following C files are currently used:
Definition of TLS library wrapper
\ref tls_none.c
- Dummy implementation of TLS library wrapper for cases where TLS
+ Stub implementation of TLS library wrapper for cases where TLS
functionality is not included.
\ref tls_openssl.c
diff --git a/doc/p2p.doxygen b/doc/p2p.doxygen
index d4d86e3edfa2..6ab6e9e05a10 100644
--- a/doc/p2p.doxygen
+++ b/doc/p2p.doxygen
@@ -274,8 +274,8 @@ for removing the group interface for the failed group.
P2P protocol includes service discovery functionality that can be used
to discover which services are provided by the peers before forming a
group. This leverages the Generic Advertisement Service (GAS) protocol
-from IEEE 802.11u and P2P vendor-specific contents inside the Native
-GAS messages.
+from IEEE 802.11u and P2P vendor-specific contents inside the GAS
+messages.
The P2P module takes care of GAS encapsulation, fragmentation, and
actual transmission and reception of the Action frames needed for
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 9bc1dc7756e9..daf3f37ad99e 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -13,6 +13,7 @@
#include "utils/common.h"
#include "utils/uuid.h"
+#include "utils/crc32.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "crypto/sha256.h"
@@ -2396,16 +2397,19 @@ static int hostapd_config_fill(struct hostapd_config *conf,
wpa_printf(MSG_INFO, "Line %d: DEPRECATED: 'dump_file' configuration variable is not used anymore",
line);
} else if (os_strcmp(buf, "ssid") == 0) {
- bss->ssid.ssid_len = os_strlen(pos);
- if (bss->ssid.ssid_len > SSID_MAX_LEN ||
- bss->ssid.ssid_len < 1) {
+ struct hostapd_ssid *ssid = &bss->ssid;
+
+ ssid->ssid_len = os_strlen(pos);
+ if (ssid->ssid_len > SSID_MAX_LEN || ssid->ssid_len < 1) {
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
line, pos);
return 1;
}
- os_memcpy(bss->ssid.ssid, pos, bss->ssid.ssid_len);
- bss->ssid.ssid_set = 1;
+ os_memcpy(ssid->ssid, pos, ssid->ssid_len);
+ ssid->ssid_set = 1;
+ ssid->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
} else if (os_strcmp(buf, "ssid2") == 0) {
+ struct hostapd_ssid *ssid = &bss->ssid;
size_t slen;
char *str = wpa_config_parse_string(pos, &slen);
if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
@@ -2414,9 +2418,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(str);
return 1;
}
- os_memcpy(bss->ssid.ssid, str, slen);
- bss->ssid.ssid_len = slen;
- bss->ssid.ssid_set = 1;
+ os_memcpy(ssid->ssid, str, slen);
+ ssid->ssid_len = slen;
+ ssid->ssid_set = 1;
+ ssid->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
os_free(str);
} else if (os_strcmp(buf, "utf8_ssid") == 0) {
bss->ssid.utf8_ssid = atoi(pos) > 0;
@@ -3515,6 +3520,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->he_op.he_twt_responder = atoi(pos);
} else if (os_strcmp(buf, "he_rts_threshold") == 0) {
conf->he_op.he_rts_threshold = atoi(pos);
+ } else if (os_strcmp(buf, "he_er_su_disable") == 0) {
+ conf->he_op.he_er_su_disable = atoi(pos);
} else if (os_strcmp(buf, "he_basic_mcs_nss_set") == 0) {
conf->he_op.he_basic_mcs_nss_set = atoi(pos);
} else if (os_strcmp(buf, "he_mu_edca_qos_info_param_count") == 0) {
@@ -4705,6 +4712,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
if (get_hex_config(bss->ext_capa, EXT_CAPA_MAX_LEN,
line, "ext_capa", pos))
return 1;
+ } else if (os_strcmp(buf, "rnr") == 0) {
+ bss->rnr = atoi(pos);
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 4a2d60627070..6c99a3105f49 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -840,7 +840,7 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
const char *pos, *end;
int disassoc_timer = 0;
struct sta_info *sta;
- u8 req_mode = 0, valid_int = 0x01;
+ u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
u8 bss_term_dur[12];
char *url = NULL;
int ret;
@@ -878,6 +878,12 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
valid_int = atoi(pos);
}
+ pos = os_strstr(cmd, " dialog_token=");
+ if (pos) {
+ pos += 14;
+ dialog_token = atoi(pos);
+ }
+
pos = os_strstr(cmd, " bss_term=");
if (pos) {
pos += 10;
@@ -984,7 +990,7 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
#endif /* CONFIG_MBO */
ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
- valid_int, bss_term_dur, url,
+ valid_int, bss_term_dur, dialog_token, url,
nei_len ? nei_rep : NULL, nei_len,
mbo_len ? mbo : NULL, mbo_len);
#ifdef CONFIG_MBO
@@ -1455,10 +1461,10 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
wps_version_number & 0x0f);
hostapd_wps_update_ie(hapd);
}
- } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
- wps_testing_dummy_cred = atoi(value);
- wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
- wps_testing_dummy_cred);
+ } else if (os_strcasecmp(cmd, "wps_testing_stub_cred") == 0) {
+ wps_testing_stub_cred = atoi(value);
+ wpa_printf(MSG_DEBUG, "WPS: Testing - stub_cred=%d",
+ wps_testing_stub_cred);
} else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
wps_corrupt_pkhash = atoi(value);
wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
@@ -3185,8 +3191,9 @@ static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
u8 bssid[ETH_ALEN];
struct wpabuf *nr, *lci = NULL, *civic = NULL;
int stationary = 0;
+ int bss_parameters = 0;
char *tmp;
- int ret;
+ int ret = -1;
if (!(hapd->conf->radio_measurements[0] &
WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
@@ -3240,8 +3247,7 @@ static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
if (!lci) {
wpa_printf(MSG_ERROR,
"CTRL: SET_NEIGHBOR: Bad LCI subelement");
- wpabuf_free(nr);
- return -1;
+ goto fail;
}
}
@@ -3257,9 +3263,7 @@ static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
if (!civic) {
wpa_printf(MSG_ERROR,
"CTRL: SET_NEIGHBOR: Bad civic subelement");
- wpabuf_free(nr);
- wpabuf_free(lci);
- return -1;
+ goto fail;
}
}
@@ -3269,10 +3273,21 @@ static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf)
if (os_strstr(buf, "stat"))
stationary = 1;
+ tmp = os_strstr(buf, "bss_parameter=");
+ if (tmp) {
+ bss_parameters = atoi(tmp + 14);
+ if (bss_parameters < 0 || bss_parameters > 0xff) {
+ wpa_printf(MSG_ERROR,
+ "CTRL: SET_NEIGHBOR: Bad bss_parameters subelement");
+ goto fail;
+ }
+ }
+
set:
ret = hostapd_neighbor_set(hapd, bssid, &ssid, nr, lci, civic,
- stationary);
+ stationary, bss_parameters);
+fail:
wpabuf_free(nr);
wpabuf_free(lci);
wpabuf_free(civic);
@@ -4470,7 +4485,7 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
{
#ifdef CONFIG_WPS_TESTING
wps_version_number = 0x20;
- wps_testing_dummy_cred = 0;
+ wps_testing_stub_cred = 0;
wps_corrupt_pkhash = 0;
#endif /* CONFIG_WPS_TESTING */
diff --git a/hostapd/hlr_auc_gw.milenage_db b/hostapd/hlr_auc_gw.milenage_db
index c156a29aeda0..a250653108b3 100644
--- a/hostapd/hlr_auc_gw.milenage_db
+++ b/hostapd/hlr_auc_gw.milenage_db
@@ -3,7 +3,7 @@
# 4.3.20 Test Set 20. SQN is the last used SQN value.
# These values can be used for both UMTS (EAP-AKA) and GSM (EAP-SIM)
# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
-# dummy values will need to be included in this file.
+# stub values will need to be included in this file.
# IMSI Ki OPc AMF SQN [RES_len]
232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index b5d15061f850..67d4cefb920b 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -841,6 +841,11 @@ wmm_ac_vo_acm=0
# unsigned integer = duration in units of 16 us
#he_rts_threshold=0
+#he_er_su_disable: Disable 242-tone HE ER SU PPDU reception by the AP
+# 0 = enable reception (default)
+# 1 = disable reception
+#he_er_su_disable=0
+
# HE operating channel information; see matching vht_* parameters for details.
# he_oper_centr_freq_seg0_idx field is used to indicate center frequency of 80
# and 160 MHz bandwidth operation. In 80+80 MHz operation, it is the center
@@ -1832,7 +1837,7 @@ own_ip_addr=127.0.0.1
#assoc_sa_query_retry_timeout=201
# ocv: Operating Channel Validation
-# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# This is a countermeasure against multi-channel on-path 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.
@@ -2916,6 +2921,9 @@ own_ip_addr=127.0.0.1
# that allows sending of such data. Default: 0.
#stationary_ap=0
+# Enable reduced neighbor reporting (RNR)
+#rnr=0
+
##### Airtime policy configuration ###########################################
# Set the airtime policy operating mode:
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index eaa628ad0676..0e7fdd6bccfb 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1048,7 +1048,7 @@ static char ** hostapd_complete_set(const char *str, int pos)
int arg = get_cmd_arg_num(str, pos);
const char *fields[] = {
#ifdef CONFIG_WPS_TESTING
- "wps_version_number", "wps_testing_dummy_cred",
+ "wps_version_number", "wps_testing_stub_cred",
"wps_corrupt_pkhash",
#endif /* CONFIG_WPS_TESTING */
#ifdef CONFIG_INTERWORKING
diff --git a/src/ap/acs.c b/src/ap/acs.c
index a112045364e3..46429f265433 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -309,8 +309,6 @@ acs_survey_interference_factor(struct freq_survey *survey, s8 min_nf)
else if (survey->filled & SURVEY_HAS_CHAN_TIME_RX)
busy = survey->channel_time_rx;
else {
- /* This shouldn't really happen as survey data is checked in
- * acs_sanity_check() */
wpa_printf(MSG_ERROR, "ACS: Survey data missing");
return 0;
}
@@ -392,7 +390,7 @@ static int acs_usable_bw40_chan(const struct hostapd_channel_data *chan)
static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan)
{
- const int allowed[] = { 5180, 5260, 5550, 5580, 5660, 5745, 5955, 6035,
+ const int allowed[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955, 6035,
6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675,
6755, 6835, 6915, 6995 };
unsigned int i;
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 7b6d54c35fc2..86b6e097cf89 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -273,7 +273,7 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->he_op.he_basic_mcs_nss_set = 0xfffc;
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_op.he_bss_color = os_random() % 63 + 1;
conf->he_op.he_twt_responder = 1;
conf->he_6ghz_max_mpdu = 2;
conf->he_6ghz_max_ampdu_len_exp = 7;
@@ -1423,6 +1423,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
#endif /* CONFIG_SAE_PK */
+#ifdef CONFIG_FILS
+ if (full_config && bss->fils_discovery_min_int &&
+ bss->unsol_bcast_probe_resp_interval) {
+ wpa_printf(MSG_ERROR,
+ "Cannot enable both FILS discovery and unsolicited broadcast Probe Response at the same time");
+ return -1;
+ }
+#endif /* CONFIG_FILS */
+
return 0;
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index ced36f9cc828..b8f791e56307 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -894,6 +894,8 @@ struct hostapd_bss_config {
u8 ext_capa_mask[EXT_CAPA_MAX_LEN];
u8 ext_capa[EXT_CAPA_MAX_LEN];
+
+ u8 rnr;
};
/**
@@ -916,6 +918,7 @@ struct he_operation {
u8 he_twt_required;
u8 he_twt_responder;
u16 he_rts_threshold;
+ u8 he_er_su_disable;
u16 he_basic_mcs_nss_set;
};
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 15fc2b3db064..22782f54e480 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -469,6 +469,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AX */
+ buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP);
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
buflen += hostapd_eid_dpp_cc_len(hapd);
@@ -573,6 +574,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
(hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
+ pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP);
pos = hostapd_eid_fils_indic(hapd, pos, 0);
pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
@@ -642,7 +644,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
enum ssid_match_result {
NO_SSID_MATCH,
EXACT_SSID_MATCH,
- WILDCARD_SSID_MATCH
+ WILDCARD_SSID_MATCH,
+ CO_LOCATED_SSID_MATCH,
};
static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
@@ -653,7 +656,9 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
size_t short_ssid_list_len)
{
const u8 *pos, *end;
+ struct hostapd_iface *iface = hapd->iface;
int wildcard = 0;
+ size_t i, j;
if (ssid_len == 0)
wildcard = 1;
@@ -687,7 +692,33 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
}
}
- return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+ if (wildcard)
+ return WILDCARD_SSID_MATCH;
+
+ if (!iface->interfaces || iface->interfaces->count <= 1 ||
+ is_6ghz_op_class(hapd->iconf->op_class))
+ return NO_SSID_MATCH;
+
+ for (i = 0; i < iface->interfaces->count; i++) {
+ struct hostapd_iface *colocated;
+
+ colocated = iface->interfaces->iface[i];
+
+ if (colocated == iface ||
+ !is_6ghz_op_class(colocated->conf->op_class))
+ continue;
+
+ for (j = 0; j < colocated->num_bss; j++) {
+ struct hostapd_bss_config *conf;
+
+ conf = colocated->bss[j]->conf;
+ if (ssid_len == conf->ssid.ssid_len &&
+ os_memcmp(ssid, conf->ssid.ssid, ssid_len) == 0)
+ return CO_LOCATED_SSID_MATCH;
+ }
+ }
+
+ return NO_SSID_MATCH;
}
@@ -1284,6 +1315,8 @@ static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
total_len += 3;
}
+ total_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_ACTION);
+
pos = hostapd_eid_fils_indic(hapd, buf, 0);
buf_len = pos - buf;
total_len += buf_len;
@@ -1352,6 +1385,8 @@ static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len)
/* Fill in the Length field value */
*length_pos = pos - (length_pos + 1);
+ pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_ACTION);
+
/* FILS Indication element */
if (buf_len) {
os_memcpy(pos, buf, buf_len);
@@ -1438,6 +1473,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211AX */
+ tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON);
tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
tail_len += hostapd_eid_dpp_cc_len(hapd);
@@ -1562,6 +1598,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
(hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax))
tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
+ tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON);
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
@@ -1743,7 +1780,7 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
}
-int ieee802_11_set_beacon(struct hostapd_data *hapd)
+static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct wpa_driver_ap_params params;
struct hostapd_freq_params freq;
@@ -1832,6 +1869,42 @@ fail:
}
+int ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ int ret;
+ size_t i, j;
+ bool is_6g;
+
+ ret = __ieee802_11_set_beacon(hapd);
+ if (ret != 0)
+ return ret;
+
+ if (!iface->interfaces || iface->interfaces->count <= 1)
+ return 0;
+
+ /* Update Beacon frames in case of 6 GHz colocation */
+ is_6g = is_6ghz_op_class(iface->conf->op_class);
+ for (j = 0; j < iface->interfaces->count; j++) {
+ struct hostapd_iface *colocated;
+
+ colocated = iface->interfaces->iface[j];
+ if (colocated == iface || !colocated || !colocated->conf)
+ continue;
+
+ if (is_6g == is_6ghz_op_class(colocated->conf->op_class))
+ continue;
+
+ for (i = 0; i < colocated->num_bss; i++) {
+ if (colocated->bss[i] && colocated->bss[i]->started)
+ __ieee802_11_set_beacon(colocated->bss[i]);
+ }
+ }
+
+ return 0;
+}
+
+
int ieee802_11_set_beacons(struct hostapd_iface *iface)
{
size_t i;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 28e40ba9cede..1d8fb8246581 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -50,9 +50,35 @@ static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
}
-static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
- struct sta_info *sta,
- char *buf, size_t buflen)
+static int hostapd_get_sta_conn_time(struct sta_info *sta,
+ struct hostap_sta_driver_data *data,
+ char *buf, size_t buflen)
+{
+ struct os_reltime age;
+ unsigned long secs;
+ int ret;
+
+ if (sta->connected_time.sec) {
+ /* Locally maintained time in AP mode */
+ os_reltime_age(&sta->connected_time, &age);
+ secs = (unsigned long) age.sec;
+ } else if (data->flags & STA_DRV_DATA_CONN_TIME) {
+ /* Time from the driver in mesh mode */
+ secs = data->connected_sec;
+ } else {
+ return 0;
+ }
+
+ ret = os_snprintf(buf, buflen, "connected_time=%lu\n", secs);
+ if (os_snprintf_error(buflen, ret))
+ return 0;
+ return ret;
+}
+
+
+static int hostapd_get_sta_info(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ char *buf, size_t buflen)
{
struct hostap_sta_driver_data data;
int ret;
@@ -160,26 +186,9 @@ static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
len += ret;
}
- return len;
-}
+ len += hostapd_get_sta_conn_time(sta, &data, buf + len, buflen - len);
-
-static int hostapd_get_sta_conn_time(struct sta_info *sta,
- char *buf, size_t buflen)
-{
- struct os_reltime age;
- int ret;
-
- if (!sta->connected_time.sec)
- return 0;
-
- os_reltime_age(&sta->connected_time, &age);
-
- ret = os_snprintf(buf, buflen, "connected_time=%u\n",
- (unsigned int) age.sec);
- if (os_snprintf_error(buflen, ret))
- return 0;
- return ret;
+ return len;
}
@@ -263,8 +272,7 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
if (res >= 0)
len += res;
- len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
- len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
+ len += hostapd_get_sta_info(hapd, sta, buf + len, buflen - len);
#ifdef CONFIG_SAE
if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index edc77da2e797..551936b8e43c 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -88,6 +88,7 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
}
}
+#ifdef CONFIG_HS20
if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (!(sta->flags & WLAN_STA_AUTHORIZED))
@@ -96,6 +97,7 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
(u8 *) buf, len);
}
}
+#endif /* CONFIG_HS20 */
if (msgtype == DHCPACK) {
if (b->your_ip == 0)
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 93ffd8cf7c36..41769f475544 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -2276,6 +2276,8 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd,
NULL);
hostapd_dpp_chirp_stop(hapd);
+ if (hapd->iface->interfaces)
+ dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd);
#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
@@ -2387,6 +2389,7 @@ hostapd_dpp_chirp_scan_res_handler(struct hostapd_iface *iface)
unsigned int i;
struct hostapd_hw_modes *mode;
int c;
+ bool chan6 = hapd->iface->hw_features == NULL;
if (!bi)
return;
@@ -2406,7 +2409,21 @@ hostapd_dpp_chirp_scan_res_handler(struct hostapd_iface *iface)
}
/* Preferred chirping channels */
- int_array_add_unique(&hapd->dpp_chirp_freqs, 2437);
+ mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211G);
+ if (mode) {
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+
+ if (chan->flag & (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR) ||
+ chan->freq != 2437)
+ continue;
+ chan6 = true;
+ break;
+ }
+ }
+ if (chan6)
+ int_array_add_unique(&hapd->dpp_chirp_freqs, 2437);
mode = dpp_get_mode(hapd, HOSTAPD_MODE_IEEE80211A);
if (mode) {
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 07d0aaa92100..f3ca7529ac96 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -138,6 +138,8 @@ struct hostapd_neighbor_entry {
/* LCI update time */
struct os_time lci_date;
int stationary;
+ u32 short_ssid;
+ u8 bss_parameters;
};
struct hostapd_sae_commit_queue {
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index bb5404fa7dd4..4b66b02f4e16 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -838,6 +838,8 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
iface->freq, NULL,
iface->hw_features,
iface->num_hw_features);
+ if (!pri_chan)
+ return 0;
hostapd_encode_edmg_chan(iface->conf->enable_edmg,
iface->conf->edmg_channel,
pri_chan->chan,
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 22cce961063e..db41049287fc 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2398,7 +2398,7 @@ static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd,
buf_len = wpabuf_len(wd);
if (buf_len < 6) {
- wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
buf_len);
return -1;
}
@@ -2474,7 +2474,7 @@ static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd,
buf_len = wpabuf_len(wd);
if (buf_len < 6) {
- wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%lu",
+ wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu",
buf_len);
return -1;
}
@@ -2704,7 +2704,7 @@ static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta,
buf_len = wpabuf_len(wd);
if (buf_len < 6) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%lu",
+ wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu",
buf_len);
return -1;
}
@@ -7071,4 +7071,386 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
return eid;
}
+
+static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
+ size_t *current_len)
+{
+ struct hostapd_neighbor_entry *nr;
+ size_t total_len = 0, len = *current_len;
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ if (!nr->nr || wpabuf_len(nr->nr) < 12)
+ continue;
+
+ if (nr->short_ssid == hapd->conf->ssid.short_ssid)
+ continue;
+
+ /* Start a new element */
+ if (!len ||
+ len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
+ len = RNR_HEADER_LEN;
+ total_len += RNR_HEADER_LEN;
+ }
+
+ len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
+ total_len += RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN;
+ }
+
+ *current_len = len;
+ return total_len;
+}
+
+
+static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd,
+ struct hostapd_data *reporting_hapd,
+ size_t *current_len)
+{
+ size_t total_len = 0, len = *current_len;
+ int tbtt_count = 0;
+ size_t i, start = 0;
+
+ while (start < hapd->iface->num_bss) {
+ if (!len ||
+ len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
+ len = RNR_HEADER_LEN;
+ total_len += RNR_HEADER_LEN;
+ }
+
+ len += RNR_TBTT_HEADER_LEN;
+ total_len += RNR_TBTT_HEADER_LEN;
+
+ for (i = start; i < hapd->iface->num_bss; i++) {
+ struct hostapd_data *bss = hapd->iface->bss[i];
+
+ if (!bss || !bss->conf || !bss->started)
+ continue;
+
+ if (bss == reporting_hapd ||
+ bss->conf->ignore_broadcast_ssid)
+ continue;
+
+ if (len + RNR_TBTT_INFO_LEN > 255 ||
+ tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
+ break;
+
+ len += RNR_TBTT_INFO_LEN;
+ total_len += RNR_TBTT_INFO_LEN;
+ tbtt_count++;
+ }
+ start = i;
+ }
+
+ if (!tbtt_count)
+ total_len = 0;
+ else
+ *current_len = len;
+
+ return total_len;
+}
+
+
+enum colocation_mode {
+ NO_COLOCATED_6GHZ,
+ STANDALONE_6GHZ,
+ COLOCATED_6GHZ,
+ COLOCATED_LOWER_BAND,
+};
+
+static enum colocation_mode get_colocation_mode(struct hostapd_data *hapd)
+{
+ u8 i;
+ bool is_6ghz = is_6ghz_op_class(hapd->iconf->op_class);
+
+ if (!hapd->iface || !hapd->iface->interfaces)
+ return NO_COLOCATED_6GHZ;
+
+ if (is_6ghz && hapd->iface->interfaces->count == 1)
+ return STANDALONE_6GHZ;
+
+ for (i = 0; i < hapd->iface->interfaces->count; i++) {
+ struct hostapd_iface *iface;
+ bool is_colocated_6ghz;
+
+ iface = hapd->iface->interfaces->iface[i];
+ if (iface == hapd->iface || !iface || !iface->conf)
+ continue;
+
+ is_colocated_6ghz = is_6ghz_op_class(iface->conf->op_class);
+ if (!is_6ghz && is_colocated_6ghz)
+ return COLOCATED_LOWER_BAND;
+ if (is_6ghz && !is_colocated_6ghz)
+ return COLOCATED_6GHZ;
+ }
+
+ if (is_6ghz)
+ return STANDALONE_6GHZ;
+
+ return NO_COLOCATED_6GHZ;
+}
+
+
+static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd,
+ size_t *current_len)
+{
+ struct hostapd_iface *iface;
+ size_t len = 0;
+ size_t i;
+
+ if (!hapd->iface || !hapd->iface->interfaces)
+ return 0;
+
+ for (i = 0; i < hapd->iface->interfaces->count; i++) {
+ iface = hapd->iface->interfaces->iface[i];
+
+ if (iface == hapd->iface ||
+ !is_6ghz_op_class(iface->conf->op_class))
+ continue;
+
+ len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd,
+ current_len);
+ }
+
+ return len;
+}
+
+
+size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type)
+{
+ size_t total_len = 0, current_len = 0;
+ enum colocation_mode mode = get_colocation_mode(hapd);
+
+ switch (type) {
+ case WLAN_FC_STYPE_BEACON:
+ if (hapd->conf->rnr)
+ total_len += hostapd_eid_nr_db_len(hapd, &current_len);
+ /* fallthrough */
+
+ case WLAN_FC_STYPE_PROBE_RESP:
+ if (mode == COLOCATED_LOWER_BAND)
+ total_len += hostapd_eid_rnr_colocation_len(
+ hapd, &current_len);
+
+ if (hapd->conf->rnr && hapd->iface->num_bss > 1)
+ total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
+ &current_len);
+ break;
+
+ case WLAN_FC_STYPE_ACTION:
+ if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
+ total_len += hostapd_eid_rnr_iface_len(hapd, hapd,
+ &current_len);
+ break;
+
+ default:
+ break;
+ }
+
+ return total_len;
+}
+
+
+static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid,
+ size_t *current_len)
+{
+ struct hostapd_neighbor_entry *nr;
+ size_t len = *current_len;
+ u8 *size_offset = (eid - len) + 1;
+
+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+ list) {
+ if (!nr->nr || wpabuf_len(nr->nr) < 12)
+ continue;
+
+ if (nr->short_ssid == hapd->conf->ssid.short_ssid)
+ continue;
+
+ /* Start a new element */
+ if (!len ||
+ len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
+ *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
+ size_offset = eid++;
+ len = RNR_HEADER_LEN;
+ }
+
+ /* TBTT Information Header subfield (2 octets) */
+ *eid++ = 0;
+ /* TBTT Information Length */
+ *eid++ = RNR_TBTT_INFO_LEN;
+ /* Operating Class */
+ *eid++ = wpabuf_head_u8(nr->nr)[10];
+ /* Channel Number */
+ *eid++ = wpabuf_head_u8(nr->nr)[11];
+ len += RNR_TBTT_HEADER_LEN;
+ /* TBTT Information Set */
+ /* TBTT Information field */
+ /* Neighbor AP TBTT Offset */
+ *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
+ /* BSSID */
+ os_memcpy(eid, nr->bssid, ETH_ALEN);
+ eid += ETH_ALEN;
+ /* Short SSID */
+ os_memcpy(eid, &nr->short_ssid, 4);
+ eid += 4;
+ /* BSS parameters */
+ *eid++ = nr->bss_parameters;
+ /* 20 MHz PSD */
+ *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
+ len += RNR_TBTT_INFO_LEN;
+ *size_offset = (eid - size_offset) - 1;
+ }
+
+ *current_len = len;
+ return eid;
+}
+
+
+static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd,
+ struct hostapd_data *reporting_hapd,
+ u8 *eid, size_t *current_len)
+{
+ struct hostapd_data *bss;
+ struct hostapd_iface *iface = hapd->iface;
+ size_t i, start = 0;
+ size_t len = *current_len;
+ u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1;
+ u8 tbtt_count = 0, op_class, channel, bss_param;
+
+ if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq)
+ return eid;
+
+ if (ieee80211_freq_to_channel_ext(iface->freq,
+ hapd->iconf->secondary_channel,
+ hostapd_get_oper_chwidth(hapd->iconf),
+ &op_class, &channel) ==
+ NUM_HOSTAPD_MODES)
+ return eid;
+
+ while (start < iface->num_bss) {
+ if (!len ||
+ len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) {
+ eid_start = eid;
+ *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
+ size_offset = eid++;
+ len = RNR_HEADER_LEN;
+ tbtt_count = 0;
+ }
+
+ tbtt_count_pos = eid++;
+ *eid++ = RNR_TBTT_INFO_LEN;
+ *eid++ = op_class;
+ *eid++ = hapd->iconf->channel;
+ len += RNR_TBTT_HEADER_LEN;
+
+ for (i = start; i < iface->num_bss; i++) {
+ bss_param = 0;
+ bss = iface->bss[i];
+ if (!bss || !bss->conf || !bss->started)
+ continue;
+
+ if (bss == reporting_hapd ||
+ bss->conf->ignore_broadcast_ssid)
+ continue;
+
+ if (len + RNR_TBTT_INFO_LEN > 255 ||
+ tbtt_count >= RNR_TBTT_INFO_COUNT_MAX)
+ break;
+
+ *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN;
+ os_memcpy(eid, bss->conf->bssid, ETH_ALEN);
+ eid += ETH_ALEN;
+ os_memcpy(eid, &bss->conf->ssid.short_ssid, 4);
+ eid += 4;
+ if (bss->conf->ssid.short_ssid ==
+ reporting_hapd->conf->ssid.short_ssid)
+ bss_param |= RNR_BSS_PARAM_SAME_SSID;
+
+ if (is_6ghz_op_class(hapd->iconf->op_class) &&
+ bss->conf->unsol_bcast_probe_resp_interval)
+ bss_param |=
+ RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE;
+
+ bss_param |= RNR_BSS_PARAM_CO_LOCATED;
+
+ *eid++ = bss_param;
+ *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1;
+ len += RNR_TBTT_INFO_LEN;
+ tbtt_count += 1;
+ }
+
+ start = i;
+ *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1);
+ *size_offset = (eid - size_offset) - 1;
+ }
+
+ if (tbtt_count == 0)
+ return eid_start;
+
+ *current_len = len;
+ return eid;
+}
+
+
+static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
+ size_t *current_len)
+{
+ struct hostapd_iface *iface;
+ size_t i;
+
+ if (!hapd->iface || !hapd->iface->interfaces)
+ return eid;
+
+ for (i = 0; i < hapd->iface->interfaces->count; i++) {
+ iface = hapd->iface->interfaces->iface[i];
+
+ if (iface == hapd->iface ||
+ !is_6ghz_op_class(iface->conf->op_class))
+ continue;
+
+ eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid,
+ current_len);
+ }
+
+ return eid;
+}
+
+
+u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type)
+{
+ u8 *eid_start = eid;
+ size_t current_len = 0;
+ enum colocation_mode mode = get_colocation_mode(hapd);
+
+ switch (type) {
+ case WLAN_FC_STYPE_BEACON:
+ if (hapd->conf->rnr)
+ eid = hostapd_eid_nr_db(hapd, eid, &current_len);
+ /* fallthrough */
+
+ case WLAN_FC_STYPE_PROBE_RESP:
+ if (mode == COLOCATED_LOWER_BAND)
+ eid = hostapd_eid_rnr_colocation(hapd, eid,
+ &current_len);
+
+ if (hapd->conf->rnr && hapd->iface->num_bss > 1)
+ eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
+ &current_len);
+ break;
+
+ case WLAN_FC_STYPE_ACTION:
+ if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ)
+ eid = hostapd_eid_rnr_iface(hapd, hapd, eid,
+ &current_len);
+ break;
+
+ default:
+ return eid_start;
+ }
+
+ if (eid == eid_start + 2)
+ return eid_start;
+
+ return eid;
+}
+
#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index ea8c60846936..c59ad5e38e92 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -194,5 +194,7 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
+size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type);
+u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index cbe5e639588f..6cd6c90dcf02 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -192,6 +192,9 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
params |= (hapd->iface->conf->he_op.he_rts_threshold <<
HE_OPERATION_RTS_THRESHOLD_OFFSET);
+ if (hapd->iface->conf->he_op.he_er_su_disable)
+ params |= HE_OPERATION_ER_SU_DISABLE;
+
if (hapd->iface->conf->he_op.he_bss_color_disabled)
params |= HE_OPERATION_BSS_COLOR_DISABLED;
if (hapd->iface->conf->he_op.he_bss_color_partial)
diff --git a/src/ap/ndisc_snoop.c b/src/ap/ndisc_snoop.c
index 4d6a92e086bd..788c12fdc1cf 100644
--- a/src/ap/ndisc_snoop.c
+++ b/src/ap/ndisc_snoop.c
@@ -150,10 +150,12 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
return;
}
break;
+#ifdef CONFIG_HS20
case ROUTER_ADVERTISEMENT:
if (hapd->conf->disable_dgaf)
ucast_to_stas(hapd, buf, len);
break;
+#endif /* CONFIG_HS20 */
case NEIGHBOR_ADVERTISEMENT:
if (hapd->conf->na_mcast_to_ucast)
ucast_to_stas(hapd, buf, len);
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 2bbe31859214..229edd2a94c4 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -10,6 +10,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/crc32.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "neighbor_db.h"
@@ -120,7 +121,8 @@ hostapd_neighbor_add(struct hostapd_data *hapd)
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid,
const struct wpabuf *nr, const struct wpabuf *lci,
- const struct wpabuf *civic, int stationary)
+ const struct wpabuf *civic, int stationary,
+ u8 bss_parameters)
{
struct hostapd_neighbor_entry *entry;
@@ -134,6 +136,7 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
os_memcpy(entry->bssid, bssid, ETH_ALEN);
os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid));
+ entry->short_ssid = crc32(ssid->ssid, ssid->ssid_len);
entry->nr = wpabuf_dup(nr);
if (!entry->nr)
@@ -152,6 +155,7 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
}
entry->stationary = stationary;
+ entry->bss_parameters = bss_parameters;
return 0;
@@ -311,7 +315,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
wpabuf_put_u8(nr, center_freq2_idx);
hostapd_neighbor_set(hapd, hapd->own_addr, &ssid, nr, hapd->iconf->lci,
- hapd->iconf->civic, hapd->iconf->stationary_ap);
+ hapd->iconf->civic, hapd->iconf->stationary_ap, 0);
wpabuf_free(nr);
#endif /* NEED_AP_MLME */
diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
index bed0a2f5fb7f..992671b62608 100644
--- a/src/ap/neighbor_db.h
+++ b/src/ap/neighbor_db.h
@@ -17,7 +17,8 @@ int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen);
int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid,
const struct wpabuf *nr, const struct wpabuf *lci,
- const struct wpabuf *civic, int stationary);
+ const struct wpabuf *civic, int stationary,
+ u8 bss_parameters);
void hostapd_neighbor_set_own_report(struct hostapd_data *hapd);
int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
const struct wpa_ssid_value *ssid);
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index d32967e6cef6..0042ed6a115a 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -788,8 +788,8 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
u8 req_mode, int disassoc_timer, u8 valid_int,
- const u8 *bss_term_dur, const char *url,
- const u8 *nei_rep, size_t nei_rep_len,
+ const u8 *bss_term_dur, u8 dialog_token,
+ const char *url, const u8 *nei_rep, size_t nei_rep_len,
const u8 *mbo_attrs, size_t mbo_len)
{
u8 *buf, *pos;
@@ -797,8 +797,10 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
size_t url_len;
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
- MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x",
- MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int);
+ MACSTR
+ " req_mode=0x%x disassoc_timer=%d valid_int=0x%x dialog_token=%u",
+ MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int,
+ dialog_token);
buf = os_zalloc(1000 + nei_rep_len + mbo_len);
if (buf == NULL)
return -1;
@@ -810,7 +812,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
mgmt->u.action.category = WLAN_ACTION_WNM;
mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
- mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+ mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
mgmt->u.action.u.bss_tm_req.req_mode = req_mode;
mgmt->u.action.u.bss_tm_req.disassoc_timer =
host_to_le16(disassoc_timer);
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
index 1806ba0e0525..f86c6b2afabf 100644
--- a/src/ap/wnm_ap.h
+++ b/src/ap/wnm_ap.h
@@ -20,8 +20,8 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
int disassoc_timer);
int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
u8 req_mode, int disassoc_timer, u8 valid_int,
- const u8 *bss_term_dur, const char *url,
- const u8 *nei_rep, size_t nei_rep_len,
+ const u8 *bss_term_dur, u8 dialog_token,
+ const char *url, const u8 *nei_rep, size_t nei_rep_len,
const u8 *mbo_attrs, size_t mbo_len);
void ap_sta_reset_steer_flag_timer(void *eloop_ctx, void *timeout_ctx);
int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta,
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 83805681ed97..6d60f262991b 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -2742,7 +2742,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
struct wpabuf *plain;
u8 *len, *tmp, *tmp2;
u8 hdr[2];
- u8 *gtk, dummy_gtk[32];
+ u8 *gtk, stub_gtk[32];
size_t gtk_len;
struct wpa_group *gsm;
size_t plain_len;
@@ -2785,11 +2785,11 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
*/
- if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
+ if (random_get_bytes(stub_gtk, gtk_len) < 0) {
wpabuf_clear_free(plain);
return NULL;
}
- gtk = dummy_gtk;
+ gtk = stub_gtk;
}
hdr[0] = gsm->GN & 0x03;
hdr[1] = 0;
@@ -3372,7 +3372,7 @@ static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
- u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32];
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, stub_gtk[32];
size_t gtk_len, kde_len, wpa_ie_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
@@ -3458,9 +3458,9 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
*/
- if (random_get_bytes(dummy_gtk, gtk_len) < 0)
+ if (random_get_bytes(stub_gtk, gtk_len) < 0)
goto done;
- gtk = dummy_gtk;
+ gtk = stub_gtk;
}
gtkidx = gsm->GN;
_rsc = rsc;
@@ -3853,7 +3853,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
size_t kde_len;
- u8 *gtk, dummy_gtk[32];
+ u8 *gtk, stub_gtk[32];
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
@@ -3885,9 +3885,9 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
*/
- if (random_get_bytes(dummy_gtk, gsm->GTK_len) < 0)
+ if (random_get_bytes(stub_gtk, gsm->GTK_len) < 0)
return;
- gtk = dummy_gtk;
+ gtk = stub_gtk;
}
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index e80086b93d8d..fef1104d2aa0 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -455,7 +455,7 @@ static int wpa_ft_rrb_lin(const struct tlv_list *tlvs1,
pos += wpa_ft_tlv_lin(tlvs2, pos, endpos);
pos += wpa_ft_vlan_lin(vlan, pos, endpos);
- /* sanity check */
+ /* validity check */
if (pos != endpos) {
wpa_printf(MSG_ERROR, "FT: Length error building RRB");
goto err;
@@ -2259,7 +2259,7 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
const u8 *kek, *igtk;
size_t kek_len;
size_t igtk_len;
- u8 dummy_igtk[WPA_IGTK_MAX_LEN];
+ u8 stub_igtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2;
@@ -2292,11 +2292,11 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
* Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS.
*/
- if (random_get_bytes(dummy_igtk, igtk_len / 8) < 0) {
+ if (random_get_bytes(stub_igtk, igtk_len / 8) < 0) {
os_free(subelem);
return NULL;
}
- igtk = dummy_igtk;
+ igtk = stub_igtk;
}
if (aes_wrap(kek, kek_len, igtk_len / 8, igtk, pos)) {
wpa_printf(MSG_DEBUG,
@@ -2319,7 +2319,7 @@ static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
const u8 *kek, *bigtk;
size_t kek_len;
size_t bigtk_len;
- u8 dummy_bigtk[WPA_IGTK_MAX_LEN];
+ u8 stub_bigtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2;
@@ -2352,11 +2352,11 @@ static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
* Provide unique random BIGTK to each OSEN STA to prevent use
* of BIGTK in the BSS.
*/
- if (random_get_bytes(dummy_bigtk, bigtk_len / 8) < 0) {
+ if (random_get_bytes(stub_bigtk, bigtk_len / 8) < 0) {
os_free(subelem);
return NULL;
}
- bigtk = dummy_bigtk;
+ bigtk = stub_bigtk;
}
if (aes_wrap(kek, kek_len, bigtk_len / 8, bigtk, pos)) {
wpa_printf(MSG_DEBUG,
@@ -3590,7 +3590,7 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
}
/*
- * Do some sanity checking on the target AP address (not own and not
+ * Do some validity checking on the target AP address (not own and not
* broadcast. This could be extended to filter based on a list of known
* APs in the MD (if such a list were configured).
*/
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 9f22e39a2e6a..4f1c76b7b65c 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1964,6 +1964,11 @@ int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
cred.key_len = len / 2;
}
+ if (!hapd->wps) {
+ wpa_printf(MSG_ERROR, "WPS: WPS config does not exist");
+ return -1;
+ }
+
return wps_registrar_config_ap(hapd->wps->registrar, &cred);
}
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 3c8c7682d514..1fd074f05627 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -8,8 +8,6 @@
*/
#include "utils/includes.h"
-#include <openssl/opensslv.h>
-#include <openssl/err.h>
#include "utils/common.h"
#include "utils/base64.h"
@@ -38,22 +36,6 @@ int dpp_version_override = 1;
enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED;
#endif /* CONFIG_TESTING_OPTIONS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-/* Compatibility wrappers for older versions. */
-
-#ifdef CONFIG_DPP2
-static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
-{
- if (pkey->type != EVP_PKEY_EC)
- return NULL;
- return pkey->pkey.ec;
-}
-#endif /* CONFIG_DPP2 */
-
-#endif
-
void dpp_auth_fail(struct dpp_authentication *auth, const char *txt)
{
@@ -180,7 +162,7 @@ void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info)
os_free(info->info);
os_free(info->chan);
os_free(info->pk);
- EVP_PKEY_free(info->pubkey);
+ crypto_ec_key_deinit(info->pubkey);
str_clear_free(info->configurator_params);
os_free(info);
}
@@ -1268,9 +1250,9 @@ void dpp_auth_deinit(struct dpp_authentication *auth)
dpp_configuration_free(auth->conf2_ap);
dpp_configuration_free(auth->conf_sta);
dpp_configuration_free(auth->conf2_sta);
- EVP_PKEY_free(auth->own_protocol_key);
- EVP_PKEY_free(auth->peer_protocol_key);
- EVP_PKEY_free(auth->reconfig_old_protocol_key);
+ crypto_ec_key_deinit(auth->own_protocol_key);
+ crypto_ec_key_deinit(auth->peer_protocol_key);
+ crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
wpabuf_free(auth->req_msg);
wpabuf_free(auth->resp_msg);
wpabuf_free(auth->conf_req);
@@ -1360,14 +1342,15 @@ dpp_build_conf_start(struct dpp_authentication *auth,
}
-int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
- const char *kid, const struct dpp_curve_params *curve)
+int dpp_build_jwk(struct wpabuf *buf, const char *name,
+ struct crypto_ec_key *key, const char *kid,
+ const struct dpp_curve_params *curve)
{
struct wpabuf *pub;
const u8 *pos;
int ret = -1;
- pub = dpp_get_pubkey_point(key, 0);
+ pub = crypto_ec_key_get_pubkey_point(key, 0);
if (!pub)
goto fail;
@@ -2160,14 +2143,13 @@ static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
}
-EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
- const struct dpp_curve_params **key_curve)
+struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
+ const struct dpp_curve_params **key_curve)
{
struct json_token *token;
const struct dpp_curve_params *curve;
struct wpabuf *x = NULL, *y = NULL;
- EC_GROUP *group;
- EVP_PKEY *pkey = NULL;
+ struct crypto_ec_key *key = NULL;
token = json_get_member(jwk, "kty");
if (!token || token->type != JSON_STRING) {
@@ -2220,22 +2202,18 @@ EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
goto fail;
}
- group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
- if (!group) {
- wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK");
+ key = crypto_ec_key_set_pub(curve->ike_group, wpabuf_head(x),
+ wpabuf_head(y), wpabuf_len(x));
+ if (!key)
goto fail;
- }
- pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y),
- wpabuf_len(x));
- EC_GROUP_free(group);
*key_curve = curve;
fail:
wpabuf_free(x);
wpabuf_free(y);
- return pkey;
+ return key;
}
@@ -2325,7 +2303,7 @@ static int dpp_parse_connector(struct dpp_authentication *auth,
{
struct json_token *root, *groups, *netkey, *token;
int ret = -1;
- EVP_PKEY *key = NULL;
+ struct crypto_ec_key *key = NULL;
const struct dpp_curve_params *curve;
unsigned int rules = 0;
@@ -2392,7 +2370,7 @@ skip_groups:
goto fail;
dpp_debug_print_key("DPP: Received netAccessKey", key);
- if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) {
+ if (crypto_ec_key_cmp(key, auth->own_protocol_key)) {
wpa_printf(MSG_DEBUG,
"DPP: netAccessKey in connector does not match own protocol key");
#ifdef CONFIG_TESTING_OPTIONS
@@ -2409,47 +2387,45 @@ skip_groups:
ret = 0;
fail:
- EVP_PKEY_free(key);
+ crypto_ec_key_deinit(key);
json_free(root);
return ret;
}
-static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
+static void dpp_copy_csign(struct dpp_config_obj *conf,
+ struct crypto_ec_key *csign)
{
- unsigned char *der = NULL;
- int der_len;
+ struct wpabuf *c_sign_key;
- der_len = i2d_PUBKEY(csign, &der);
- if (der_len <= 0)
+ c_sign_key = crypto_ec_key_get_subject_public_key(csign);
+ if (!c_sign_key)
return;
+
wpabuf_free(conf->c_sign_key);
- conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
- OPENSSL_free(der);
+ conf->c_sign_key = c_sign_key;
}
-static void dpp_copy_ppkey(struct dpp_config_obj *conf, EVP_PKEY *ppkey)
+static void dpp_copy_ppkey(struct dpp_config_obj *conf,
+ struct crypto_ec_key *ppkey)
{
- unsigned char *der = NULL;
- int der_len;
+ struct wpabuf *pp_key;
- der_len = i2d_PUBKEY(ppkey, &der);
- if (der_len <= 0)
+ pp_key = crypto_ec_key_get_subject_public_key(ppkey);
+ if (!pp_key)
return;
+
wpabuf_free(conf->pp_key);
- conf->pp_key = wpabuf_alloc_copy(der, der_len);
- OPENSSL_free(der);
+ conf->pp_key = pp_key;
}
static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
struct dpp_config_obj *conf)
{
- unsigned char *der = NULL;
- int der_len;
- EC_KEY *eckey;
- EVP_PKEY *own_key;
+ struct wpabuf *net_access_key;
+ struct crypto_ec_key *own_key;
own_key = auth->own_protocol_key;
#ifdef CONFIG_DPP2
@@ -2457,19 +2433,13 @@ static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
auth->reconfig_old_protocol_key)
own_key = auth->reconfig_old_protocol_key;
#endif /* CONFIG_DPP2 */
- eckey = EVP_PKEY_get1_EC_KEY(own_key);
- if (!eckey)
- return;
- der_len = i2d_ECPrivateKey(eckey, &der);
- if (der_len <= 0) {
- EC_KEY_free(eckey);
+ net_access_key = crypto_ec_key_get_ecprivate_key(own_key, true);
+ if (!net_access_key)
return;
- }
+
wpabuf_free(auth->net_access_key);
- auth->net_access_key = wpabuf_alloc_copy(der, der_len);
- OPENSSL_free(der);
- EC_KEY_free(eckey);
+ auth->net_access_key = net_access_key;
}
@@ -2480,7 +2450,7 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
struct dpp_signed_connector_info info;
struct json_token *token, *csign, *ppkey;
int ret = -1;
- EVP_PKEY *csign_pub = NULL, *pp_pub = NULL;
+ struct crypto_ec_key *csign_pub = NULL, *pp_pub = NULL;
const struct dpp_curve_params *key_curve = NULL, *pp_curve = NULL;
const char *signed_connector;
@@ -2560,8 +2530,8 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
ret = 0;
fail:
- EVP_PKEY_free(csign_pub);
- EVP_PKEY_free(pp_pub);
+ crypto_ec_key_deinit(csign_pub);
+ crypto_ec_key_deinit(pp_pub);
os_free(info.payload);
return ret;
}
@@ -2586,7 +2556,7 @@ static int dpp_parse_cred_dot1x(struct dpp_authentication *auth,
return -1;
}
wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Received certBag", conf->certbag);
- conf->certs = dpp_pkcs7_certs(conf->certbag);
+ conf->certs = crypto_pkcs7_get_certificates(conf->certbag);
if (!conf->certs) {
dpp_auth_fail(auth, "No certificates in certBag");
return -1;
@@ -3394,11 +3364,11 @@ void dpp_configurator_free(struct dpp_configurator *conf)
{
if (!conf)
return;
- EVP_PKEY_free(conf->csign);
+ crypto_ec_key_deinit(conf->csign);
os_free(conf->kid);
os_free(conf->connector);
- EVP_PKEY_free(conf->connector_key);
- EVP_PKEY_free(conf->pp_key);
+ crypto_ec_key_deinit(conf->connector_key);
+ crypto_ec_key_deinit(conf->pp_key);
os_free(conf);
}
@@ -3406,23 +3376,19 @@ void dpp_configurator_free(struct dpp_configurator *conf)
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
size_t buflen)
{
- EC_KEY *eckey;
- int key_len, ret = -1;
- unsigned char *key = NULL;
+ struct wpabuf *key;
+ int ret = -1;
if (!conf->csign)
return -1;
- eckey = EVP_PKEY_get1_EC_KEY(conf->csign);
- if (!eckey)
+ key = crypto_ec_key_get_ecprivate_key(conf->csign, true);
+ if (!key)
return -1;
- key_len = i2d_ECPrivateKey(eckey, &key);
- if (key_len > 0)
- ret = wpa_snprintf_hex(buf, buflen, key, key_len);
+ ret = wpa_snprintf_hex(buf, buflen, wpabuf_head(key), wpabuf_len(key));
- EC_KEY_free(eckey);
- OPENSSL_free(key);
+ wpabuf_clear_free(key);
return ret;
}
@@ -3434,7 +3400,7 @@ static int dpp_configurator_gen_kid(struct dpp_configurator *conf)
size_t len[1];
int res;
- csign_pub = dpp_get_pubkey_point(conf->csign, 1);
+ csign_pub = crypto_ec_key_get_pubkey_point(conf->csign, 1);
if (!csign_pub) {
wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key");
return -1;
@@ -3670,7 +3636,7 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
struct json_token *root = NULL, *netkey, *token;
struct json_token *own_root = NULL;
enum dpp_status_error ret = 255, res;
- EVP_PKEY *own_key = NULL, *peer_key = NULL;
+ struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
struct wpabuf *own_key_pub = NULL;
const struct dpp_curve_params *curve, *own_curve;
struct dpp_signed_connector_info info;
@@ -3776,9 +3742,9 @@ fail:
os_memset(intro, 0, sizeof(*intro));
os_memset(Nx, 0, sizeof(Nx));
os_free(info.payload);
- EVP_PKEY_free(own_key);
+ crypto_ec_key_deinit(own_key);
wpabuf_free(own_key_pub);
- EVP_PKEY_free(peer_key);
+ crypto_ec_key_deinit(peer_key);
json_free(root);
json_free(own_root);
return ret;
@@ -4129,7 +4095,7 @@ static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi,
wpa_printf(MSG_DEBUG,
"DPP: Update own bootstrapping key to match peer curve from NFC handover");
- EVP_PKEY_free(own_bi->pubkey);
+ crypto_ec_key_deinit(own_bi->pubkey);
own_bi->pubkey = NULL;
if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 ||
@@ -4275,33 +4241,24 @@ int dpp_configurator_from_backup(struct dpp_global *dpp,
struct dpp_asymmetric_key *key)
{
struct dpp_configurator *conf;
- const EC_KEY *eckey, *eckey_pp;
- const EC_GROUP *group, *group_pp;
- int nid;
- const struct dpp_curve_params *curve;
+ const struct dpp_curve_params *curve, *curve_pp;
if (!key->csign || !key->pp_key)
return -1;
- eckey = EVP_PKEY_get0_EC_KEY(key->csign);
- if (!eckey)
- return -1;
- group = EC_KEY_get0_group(eckey);
- if (!group)
- return -1;
- nid = EC_GROUP_get_curve_name(group);
- curve = dpp_get_curve_nid(nid);
+
+ curve = dpp_get_curve_ike_group(crypto_ec_key_group(key->csign));
if (!curve) {
wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key");
return -1;
}
- eckey_pp = EVP_PKEY_get0_EC_KEY(key->pp_key);
- if (!eckey_pp)
- return -1;
- group_pp = EC_KEY_get0_group(eckey_pp);
- if (!group_pp)
+
+ curve_pp = dpp_get_curve_ike_group(crypto_ec_key_group(key->pp_key));
+ if (!curve_pp) {
+ wpa_printf(MSG_INFO, "DPP: Unsupported group in ppKey");
return -1;
- if (EC_GROUP_get_curve_name(group) !=
- EC_GROUP_get_curve_name(group_pp)) {
+ }
+
+ if (curve != curve_pp) {
wpa_printf(MSG_INFO,
"DPP: Mismatch in c-sign-key and ppKey groups");
return -1;
diff --git a/src/common/dpp.h b/src/common/dpp.h
index 75de3cae93e9..a47c685f64b9 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -11,13 +11,11 @@
#define DPP_H
#ifdef CONFIG_DPP
-#include <openssl/x509.h>
-
#include "utils/list.h"
#include "common/wpa_common.h"
#include "crypto/sha256.h"
+#include "crypto/crypto.h"
-struct crypto_ecdh;
struct hostapd_ip_addr;
struct dpp_global;
struct json_token;
@@ -157,7 +155,7 @@ struct dpp_bootstrap_info {
bool channels_listed;
u8 version;
int own;
- EVP_PKEY *pubkey;
+ struct crypto_ec_key *pubkey;
u8 pubkey_hash[SHA256_MAC_LEN];
u8 pubkey_hash_chirp[SHA256_MAC_LEN];
const struct dpp_curve_params *curve;
@@ -180,12 +178,12 @@ struct dpp_pkex {
u8 peer_mac[ETH_ALEN];
char *identifier;
char *code;
- EVP_PKEY *x;
- EVP_PKEY *y;
+ struct crypto_ec_key *x;
+ struct crypto_ec_key *y;
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
u8 z[DPP_MAX_HASH_LEN];
- EVP_PKEY *peer_bootstrap_key;
+ struct crypto_ec_key *peer_bootstrap_key;
struct wpabuf *exchange_req;
struct wpabuf *exchange_resp;
unsigned int t; /* number of failures on code use */
@@ -234,8 +232,8 @@ struct dpp_configuration {
struct dpp_asymmetric_key {
struct dpp_asymmetric_key *next;
- EVP_PKEY *csign;
- EVP_PKEY *pp_key;
+ struct crypto_ec_key *csign;
+ struct crypto_ec_key *pp_key;
char *config_template;
char *connector_template;
};
@@ -266,9 +264,9 @@ struct dpp_authentication {
u8 i_capab;
u8 r_capab;
enum dpp_netrole e_netrole;
- EVP_PKEY *own_protocol_key;
- EVP_PKEY *peer_protocol_key;
- EVP_PKEY *reconfig_old_protocol_key;
+ struct crypto_ec_key *own_protocol_key;
+ struct crypto_ec_key *peer_protocol_key;
+ struct crypto_ec_key *reconfig_old_protocol_key;
struct wpabuf *req_msg;
struct wpabuf *resp_msg;
struct wpabuf *reconfig_req_msg;
@@ -361,13 +359,13 @@ struct dpp_configurator {
struct dl_list list;
unsigned int id;
int own;
- EVP_PKEY *csign;
+ struct crypto_ec_key *csign;
u8 kid_hash[SHA256_MAC_LEN];
char *kid;
const struct dpp_curve_params *curve;
char *connector; /* own Connector for reconfiguration */
- EVP_PKEY *connector_key;
- EVP_PKEY *pp_key;
+ struct crypto_ec_key *connector_key;
+ struct crypto_ec_key *pp_key;
};
struct dpp_introduction {
@@ -633,7 +631,6 @@ void dpp_pfs_free(struct dpp_pfs *pfs);
struct wpabuf * dpp_build_csr(struct dpp_authentication *auth,
const char *name);
-struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7);
int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr);
struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
@@ -676,6 +673,7 @@ int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data,
int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config);
void dpp_controller_stop(struct dpp_global *dpp);
+void dpp_controller_stop_for_ctx(struct dpp_global *dpp, void *cb_ctx);
struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
unsigned int id);
void dpp_controller_new_qr_code(struct dpp_global *dpp,
diff --git a/src/common/dpp_auth.c b/src/common/dpp_auth.c
index 0cabd647fb81..f81f1eecbc7e 100644
--- a/src/common/dpp_auth.c
+++ b/src/common/dpp_auth.c
@@ -456,7 +456,7 @@ static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
#endif /* CONFIG_TESTING_OPTIONS */
wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len);
- EVP_PKEY_free(auth->own_protocol_key);
+ crypto_ec_key_deinit(auth->own_protocol_key);
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_protocol_key_override_len) {
const struct dpp_curve_params *tmp_curve;
@@ -475,7 +475,7 @@ static int dpp_auth_build_resp_ok(struct dpp_authentication *auth)
if (!auth->own_protocol_key)
goto fail;
- pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ pr = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
if (!pr)
goto fail;
@@ -671,8 +671,7 @@ dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles,
unsigned int freq, const u8 *hdr, const u8 *attr_start,
size_t attr_len)
{
- EVP_PKEY *pi = NULL;
- EVP_PKEY_CTX *ctx = NULL;
+ struct crypto_ec_key *pi = NULL;
size_t secret_len;
const u8 *addr[2];
size_t len[2];
@@ -928,8 +927,7 @@ not_compatible:
return auth;
fail:
bin_clear_free(unwrapped, unwrapped_len);
- EVP_PKEY_free(pi);
- EVP_PKEY_CTX_free(ctx);
+ crypto_ec_key_deinit(pi);
dpp_auth_deinit(auth);
return NULL;
}
@@ -1235,7 +1233,7 @@ struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx,
if (!auth->own_protocol_key)
goto fail;
- pi = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ pi = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
if (!pi)
goto fail;
@@ -1405,7 +1403,7 @@ struct wpabuf *
dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
const u8 *attr_start, size_t attr_len)
{
- EVP_PKEY *pr;
+ struct crypto_ec_key *pr;
size_t secret_len;
const u8 *addr[2];
size_t len[2];
@@ -1567,7 +1565,7 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
dpp_auth_fail(auth, "Failed to derive ECDH shared secret");
goto fail;
}
- EVP_PKEY_free(auth->peer_protocol_key);
+ crypto_ec_key_deinit(auth->peer_protocol_key);
auth->peer_protocol_key = pr;
pr = NULL;
@@ -1737,7 +1735,7 @@ dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
fail:
bin_clear_free(unwrapped, unwrapped_len);
bin_clear_free(unwrapped2, unwrapped2_len);
- EVP_PKEY_free(pr);
+ crypto_ec_key_deinit(pr);
return NULL;
}
diff --git a/src/common/dpp_backup.c b/src/common/dpp_backup.c
index 947a5e9ea33e..fb3f776d2ea2 100644
--- a/src/common/dpp_backup.c
+++ b/src/common/dpp_backup.c
@@ -7,8 +7,6 @@
*/
#include "utils/includes.h"
-#include <openssl/opensslv.h>
-#include <openssl/err.h>
#include "utils/common.h"
#include "crypto/aes.h"
@@ -19,28 +17,13 @@
#ifdef CONFIG_DPP2
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-/* Compatibility wrappers for older versions. */
-
-static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
-{
- if (pkey->type != EVP_PKEY_EC)
- return NULL;
- return pkey->pkey.ec;
-}
-
-#endif
-
-
void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
{
while (key) {
struct dpp_asymmetric_key *next = key->next;
- EVP_PKEY_free(key->csign);
- EVP_PKEY_free(key->pp_key);
+ crypto_ec_key_deinit(key->csign);
+ crypto_ec_key_deinit(key->pp_key);
str_clear_free(key->config_template);
str_clear_free(key->connector_template);
os_free(key);
@@ -56,23 +39,13 @@ static struct wpabuf * dpp_build_conf_params(struct dpp_configurator *conf)
/* TODO: proper template values */
const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
const char *connector_template = NULL;
- EC_KEY *eckey;
- unsigned char *der = NULL;
- int der_len;
if (!conf->pp_key)
return NULL;
- eckey = EVP_PKEY_get0_EC_KEY(conf->pp_key);
- if (!eckey)
- return NULL;
- EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
- der_len = i2d_ECPrivateKey(eckey, &der);
- if (der_len > 0)
- priv_key = wpabuf_alloc_copy(der, der_len);
- OPENSSL_free(der);
+ priv_key = crypto_ec_key_get_ecprivate_key(conf->pp_key, false);
if (!priv_key)
- goto fail;
+ return NULL;
len = 100 + os_strlen(conf_template);
if (connector_template)
@@ -178,20 +151,11 @@ static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
{
struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
- EC_KEY *eckey;
- unsigned char *der = NULL;
- int der_len;
- eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
- if (!eckey)
+ priv_key = crypto_ec_key_get_ecprivate_key(auth->conf->csign, false);
+ if (!priv_key)
return NULL;
- EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
- der_len = i2d_ECPrivateKey(eckey, &der);
- if (der_len > 0)
- priv_key = wpabuf_alloc_copy(der, der_len);
- OPENSSL_free(der);
-
alg = dpp_build_key_alg(auth->conf->curve);
/* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
@@ -900,7 +864,6 @@ dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
struct asn1_oid oid;
char txt[80];
struct dpp_asymmetric_key *key;
- EC_KEY *eckey;
wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
@@ -975,18 +938,9 @@ dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
hdr.payload, hdr.length);
pos = hdr.payload + hdr.length;
- eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
- if (!eckey) {
- wpa_printf(MSG_INFO,
- "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- key->csign = EVP_PKEY_new();
- if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
- EC_KEY_free(eckey);
+ key->csign = crypto_ec_key_parse_priv(hdr.payload, hdr.length);
+ if (!key->csign)
goto fail;
- }
if (wpa_debug_show_keys)
dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
@@ -1096,18 +1050,9 @@ dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
wpa_hexdump_key(MSG_MSGDUMP, "DPP: privacyProtectionKey",
hdr.payload, hdr.length);
pos = hdr.payload + hdr.length;
- eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
- if (!eckey) {
- wpa_printf(MSG_INFO,
- "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- key->pp_key = EVP_PKEY_new();
- if (!key->pp_key || EVP_PKEY_assign_EC_KEY(key->pp_key, eckey) != 1) {
- EC_KEY_free(eckey);
+ key->pp_key = crypto_ec_key_parse_priv(hdr.payload, hdr.length);
+ if (!key->pp_key)
goto fail;
- }
if (wpa_debug_show_keys)
dpp_debug_print_key("DPP: Received privacyProtectionKey",
key->pp_key);
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index c75fc78711a8..da59730eb7b7 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -8,11 +8,6 @@
*/
#include "utils/includes.h"
-#include <openssl/opensslv.h>
-#include <openssl/err.h>
-#include <openssl/asn1.h>
-#include <openssl/asn1t.h>
-#include <openssl/pem.h>
#include "utils/common.h"
#include "utils/base64.h"
@@ -22,42 +17,11 @@
#include "crypto/random.h"
#include "crypto/sha384.h"
#include "crypto/sha512.h"
+#include "tls/asn1.h"
#include "dpp.h"
#include "dpp_i.h"
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-/* Compatibility wrappers for older versions. */
-
-static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
-{
- sig->r = r;
- sig->s = s;
- return 1;
-}
-
-
-static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
- const BIGNUM **ps)
-{
- if (pr)
- *pr = sig->r;
- if (ps)
- *ps = sig->s;
-}
-
-
-static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
-{
- if (pkey->type != EVP_PKEY_EC)
- return NULL;
- return pkey->pkey.ec;
-}
-
-#endif
-
static const struct dpp_curve_params dpp_curves[] = {
/* The mandatory to support and the default NIST P-256 curve needs to
* be the first entry on this list. */
@@ -101,36 +65,6 @@ const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name)
}
-static const struct dpp_curve_params *
-dpp_get_curve_oid(const ASN1_OBJECT *poid)
-{
- ASN1_OBJECT *oid;
- int i;
-
- for (i = 0; dpp_curves[i].name; i++) {
- oid = OBJ_txt2obj(dpp_curves[i].name, 0);
- if (oid && OBJ_cmp(poid, oid) == 0)
- return &dpp_curves[i];
- }
- return NULL;
-}
-
-
-const struct dpp_curve_params * dpp_get_curve_nid(int nid)
-{
- int i, tmp;
-
- if (!nid)
- return NULL;
- for (i = 0; dpp_curves[i].name; i++) {
- tmp = OBJ_txt2nid(dpp_curves[i].name);
- if (tmp == nid)
- return &dpp_curves[i];
- }
- return NULL;
-}
-
-
const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group)
{
int i;
@@ -143,90 +77,22 @@ const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group)
}
-void dpp_debug_print_point(const char *title, const EC_GROUP *group,
- const EC_POINT *point)
-{
- BIGNUM *x, *y;
- BN_CTX *ctx;
- char *x_str = NULL, *y_str = NULL;
-
- if (!wpa_debug_show_keys)
- return;
-
- ctx = BN_CTX_new();
- x = BN_new();
- y = BN_new();
- if (!ctx || !x || !y ||
- EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) != 1)
- goto fail;
-
- x_str = BN_bn2hex(x);
- y_str = BN_bn2hex(y);
- if (!x_str || !y_str)
- goto fail;
-
- wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
-
-fail:
- OPENSSL_free(x_str);
- OPENSSL_free(y_str);
- BN_free(x);
- BN_free(y);
- BN_CTX_free(ctx);
-}
-
-
-void dpp_debug_print_key(const char *title, EVP_PKEY *key)
+void dpp_debug_print_key(const char *title, struct crypto_ec_key *key)
{
- EC_KEY *eckey;
- BIO *out;
- size_t rlen;
- char *txt;
- int res;
- unsigned char *der = NULL;
- int der_len;
- const EC_GROUP *group;
- const EC_POINT *point;
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- return;
-
- EVP_PKEY_print_private(out, key, 0, NULL);
- rlen = BIO_ctrl_pending(out);
- txt = os_malloc(rlen + 1);
- if (txt) {
- res = BIO_read(out, txt, rlen);
- if (res > 0) {
- txt[res] = '\0';
- wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
- }
- os_free(txt);
- }
- BIO_free(out);
-
- eckey = EVP_PKEY_get1_EC_KEY(key);
- if (!eckey)
- return;
+ struct wpabuf *der = NULL;
- group = EC_KEY_get0_group(eckey);
- point = EC_KEY_get0_public_key(eckey);
- if (group && point)
- dpp_debug_print_point(title, group, point);
+ crypto_ec_key_debug_print(key, title);
- der_len = i2d_ECPrivateKey(eckey, &der);
- if (der_len > 0)
- wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len);
- OPENSSL_free(der);
- if (der_len <= 0) {
- der = NULL;
- der_len = i2d_EC_PUBKEY(eckey, &der);
- if (der_len > 0)
- wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len);
- OPENSSL_free(der);
+ der = crypto_ec_key_get_ecprivate_key(key, true);
+ if (der) {
+ wpa_hexdump_buf_key(MSG_DEBUG, "DPP: ECPrivateKey", der);
+ } else {
+ der = crypto_ec_key_get_subject_public_key(key);
+ if (der)
+ wpa_hexdump_buf_key(MSG_DEBUG, "DPP: EC_PUBKEY", der);
}
- EC_KEY_free(eckey);
+ wpabuf_clear_free(der);
}
@@ -363,336 +229,65 @@ int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
#endif /* CONFIG_DPP2 */
-int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len)
-{
- int num_bytes, offset;
-
- num_bytes = BN_num_bytes(bn);
- if ((size_t) num_bytes > len)
- return -1;
- offset = len - num_bytes;
- os_memset(pos, 0, offset);
- BN_bn2bin(bn, pos + offset);
- return 0;
-}
-
-
-struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix)
-{
- int len, res;
- EC_KEY *eckey;
- struct wpabuf *buf;
- unsigned char *pos;
-
- eckey = EVP_PKEY_get1_EC_KEY(pkey);
- if (!eckey)
- return NULL;
- EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
- len = i2o_ECPublicKey(eckey, NULL);
- if (len <= 0) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to determine public key encoding length");
- EC_KEY_free(eckey);
- return NULL;
- }
-
- buf = wpabuf_alloc(len);
- if (!buf) {
- EC_KEY_free(eckey);
- return NULL;
- }
-
- pos = wpabuf_put(buf, len);
- res = i2o_ECPublicKey(eckey, &pos);
- EC_KEY_free(eckey);
- if (res != len) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to encode public key (res=%d/%d)",
- res, len);
- wpabuf_free(buf);
- return NULL;
- }
-
- if (!prefix) {
- /* Remove 0x04 prefix to match DPP definition */
- pos = wpabuf_mhead(buf);
- os_memmove(pos, pos + 1, len - 1);
- buf->used--;
- }
-
- return buf;
-}
-
-
-EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
- const u8 *buf_x, const u8 *buf_y,
- size_t len)
-{
- EC_KEY *eckey = NULL;
- BN_CTX *ctx;
- EC_POINT *point = NULL;
- BIGNUM *x = NULL, *y = NULL;
- EVP_PKEY *pkey = NULL;
-
- ctx = BN_CTX_new();
- if (!ctx) {
- wpa_printf(MSG_ERROR, "DPP: Out of memory");
- return NULL;
- }
-
- point = EC_POINT_new(group);
- x = BN_bin2bn(buf_x, len, NULL);
- y = BN_bin2bn(buf_y, len, NULL);
- if (!point || !x || !y) {
- wpa_printf(MSG_ERROR, "DPP: Out of memory");
- goto fail;
- }
-
- if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
- wpa_printf(MSG_ERROR,
- "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (!EC_POINT_is_on_curve(group, point, ctx) ||
- EC_POINT_is_at_infinity(group, point)) {
- wpa_printf(MSG_ERROR, "DPP: Invalid point");
- goto fail;
- }
- dpp_debug_print_point("DPP: dpp_set_pubkey_point_group", group, point);
-
- eckey = EC_KEY_new();
- if (!eckey ||
- EC_KEY_set_group(eckey, group) != 1 ||
- EC_KEY_set_public_key(eckey, point) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to set EC_KEY: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
-
- pkey = EVP_PKEY_new();
- if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
- wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
- goto fail;
- }
-
-out:
- BN_free(x);
- BN_free(y);
- EC_KEY_free(eckey);
- EC_POINT_free(point);
- BN_CTX_free(ctx);
- return pkey;
-fail:
- EVP_PKEY_free(pkey);
- pkey = NULL;
- goto out;
-}
-
-
-EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len)
+struct crypto_ec_key * dpp_set_pubkey_point(struct crypto_ec_key *group_key,
+ const u8 *buf, size_t len)
{
- const EC_KEY *eckey;
- const EC_GROUP *group;
- EVP_PKEY *pkey = NULL;
+ int ike_group = crypto_ec_key_group(group_key);
if (len & 1)
return NULL;
- eckey = EVP_PKEY_get0_EC_KEY(group_key);
- if (!eckey) {
- wpa_printf(MSG_ERROR,
- "DPP: Could not get EC_KEY from group_key");
+ if (ike_group < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
return NULL;
}
- group = EC_KEY_get0_group(eckey);
- if (group)
- pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2,
- len / 2);
- else
- wpa_printf(MSG_ERROR, "DPP: Could not get EC group");
-
- return pkey;
+ return crypto_ec_key_set_pub(ike_group, buf, buf + len / 2, len / 2);
}
-EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
+struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve)
{
- EVP_PKEY_CTX *kctx = NULL;
- EC_KEY *ec_params = NULL;
- EVP_PKEY *params = NULL, *key = NULL;
- int nid;
+ struct crypto_ec_key *key;
wpa_printf(MSG_DEBUG, "DPP: Generating a keypair");
- nid = OBJ_txt2nid(curve->name);
- if (nid == NID_undef) {
- wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name);
- return NULL;
- }
-
- ec_params = EC_KEY_new_by_curve_name(nid);
- if (!ec_params) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate EC_KEY parameters");
- goto fail;
- }
- EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
- params = EVP_PKEY_new();
- if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to generate EVP_PKEY parameters");
- goto fail;
- }
-
- kctx = EVP_PKEY_CTX_new(params, NULL);
- if (!kctx ||
- EVP_PKEY_keygen_init(kctx) != 1 ||
- EVP_PKEY_keygen(kctx, &key) != 1) {
- wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key");
- key = NULL;
- goto fail;
- }
-
- if (wpa_debug_show_keys)
- dpp_debug_print_key("Own generated key", key);
+ key = crypto_ec_key_gen(curve->ike_group);
+ if (key && wpa_debug_show_keys)
+ dpp_debug_print_key("Own generated key", key);
-fail:
- EC_KEY_free(ec_params);
- EVP_PKEY_free(params);
- EVP_PKEY_CTX_free(kctx);
return key;
}
-EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
- const u8 *privkey, size_t privkey_len)
+struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve,
+ const u8 *privkey, size_t privkey_len)
{
- EVP_PKEY *pkey;
- EC_KEY *eckey;
- const EC_GROUP *group;
- int nid;
+ struct crypto_ec_key *key;
+ int group;
- pkey = EVP_PKEY_new();
- if (!pkey)
- return NULL;
- eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len);
- if (!eckey) {
- wpa_printf(MSG_INFO,
- "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- EVP_PKEY_free(pkey);
+ key = crypto_ec_key_parse_priv(privkey, privkey_len);
+ if (!key) {
+ wpa_printf(MSG_INFO, "DPP: Failed to parse private key");
return NULL;
}
- group = EC_KEY_get0_group(eckey);
- if (!group) {
- EC_KEY_free(eckey);
- EVP_PKEY_free(pkey);
+
+ group = crypto_ec_key_group(key);
+ if (group < 0) {
+ crypto_ec_key_deinit(key);
return NULL;
}
- nid = EC_GROUP_get_curve_name(group);
- *curve = dpp_get_curve_nid(nid);
+
+ *curve = dpp_get_curve_ike_group(group);
if (!*curve) {
wpa_printf(MSG_INFO,
- "DPP: Unsupported curve (nid=%d) in pre-assigned key",
- nid);
- EC_KEY_free(eckey);
- EVP_PKEY_free(pkey);
- return NULL;
- }
-
- if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
- EC_KEY_free(eckey);
- EVP_PKEY_free(pkey);
+ "DPP: Unsupported curve (group=%d) in pre-assigned key",
+ group);
+ crypto_ec_key_deinit(key);
return NULL;
}
- return pkey;
-}
-
-
-typedef struct {
- /* AlgorithmIdentifier ecPublicKey with optional parameters present
- * as an OID identifying the curve */
- X509_ALGOR *alg;
- /* Compressed format public key per ANSI X9.63 */
- ASN1_BIT_STRING *pub_key;
-} DPP_BOOTSTRAPPING_KEY;
-
-ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
- ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
- ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
-} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
-
-IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
-
-
-static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
-{
- unsigned char *der = NULL;
- int der_len;
- const EC_KEY *eckey;
- struct wpabuf *ret = NULL;
- size_t len;
- const EC_GROUP *group;
- const EC_POINT *point;
- BN_CTX *ctx;
- DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
- int nid;
-
- ctx = BN_CTX_new();
- eckey = EVP_PKEY_get0_EC_KEY(key);
- if (!ctx || !eckey)
- goto fail;
-
- group = EC_KEY_get0_group(eckey);
- point = EC_KEY_get0_public_key(eckey);
- if (!group || !point)
- goto fail;
- dpp_debug_print_point("DPP: bootstrap public key", group, point);
- nid = EC_GROUP_get_curve_name(group);
-
- bootstrap = DPP_BOOTSTRAPPING_KEY_new();
- if (!bootstrap ||
- X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
- V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
- goto fail;
-
- len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
- NULL, 0, ctx);
- if (len == 0)
- goto fail;
-
- der = OPENSSL_malloc(len);
- if (!der)
- goto fail;
- len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
- der, len, ctx);
-
- OPENSSL_free(bootstrap->pub_key->data);
- bootstrap->pub_key->data = der;
- der = NULL;
- bootstrap->pub_key->length = len;
- /* No unused bits */
- bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
- bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
-
- der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
- if (der_len <= 0) {
- wpa_printf(MSG_ERROR,
- "DDP: Failed to build DER encoded public key");
- goto fail;
- }
- ret = wpabuf_alloc_copy(der, der_len);
-fail:
- DPP_BOOTSTRAPPING_KEY_free(bootstrap);
- OPENSSL_free(der);
- BN_CTX_free(ctx);
- return ret;
+ return key;
}
@@ -701,7 +296,7 @@ int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi)
struct wpabuf *der;
int res;
- der = dpp_bootstrap_key_der(bi->pubkey);
+ der = crypto_ec_key_get_subject_public_key(bi->pubkey);
if (!der)
return -1;
wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
@@ -736,7 +331,7 @@ int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
goto fail;
bi->own = 1;
- der = dpp_bootstrap_key_der(bi->pubkey);
+ der = crypto_ec_key_get_subject_public_key(bi->pubkey);
if (!der)
goto fail;
wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)",
@@ -883,86 +478,48 @@ int dpp_derive_bk_ke(struct dpp_authentication *auth)
}
-int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer, u8 *secret, size_t *secret_len)
+int dpp_ecdh(struct crypto_ec_key *own, struct crypto_ec_key *peer,
+ u8 *secret, size_t *secret_len)
{
- EVP_PKEY_CTX *ctx;
+ struct crypto_ecdh *ecdh;
+ struct wpabuf *peer_pub, *secret_buf = NULL;
int ret = -1;
- ERR_clear_error();
*secret_len = 0;
- ctx = EVP_PKEY_CTX_new(own, NULL);
- if (!ctx) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ ecdh = crypto_ecdh_init2(crypto_ec_key_group(own), own);
+ if (!ecdh) {
+ wpa_printf(MSG_ERROR, "DPP: crypto_ecdh_init2() failed");
return -1;
}
- if (EVP_PKEY_derive_init(ctx) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive_init failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- if (EVP_PKEY_derive_set_peer(ctx, peer) != 1) {
+ peer_pub = crypto_ec_key_get_pubkey_point(peer, 0);
+ if (!peer_pub) {
wpa_printf(MSG_ERROR,
- "DPP: EVP_PKEY_derive_set_peet failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ "DPP: crypto_ec_key_get_pubkey_point() failed");
goto fail;
}
- if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive(NULL) failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ secret_buf = crypto_ecdh_set_peerkey(ecdh, 1, wpabuf_head(peer_pub),
+ wpabuf_len(peer_pub));
+ if (!secret_buf) {
+ wpa_printf(MSG_ERROR, "DPP: crypto_ecdh_set_peerkey() failed");
goto fail;
}
- if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
- u8 buf[200];
- int level = *secret_len > 200 ? MSG_ERROR : MSG_DEBUG;
-
- /* It looks like OpenSSL can return unexpectedly large buffer
- * need for shared secret from EVP_PKEY_derive(NULL) in some
- * cases. For example, group 19 has shown cases where secret_len
- * is set to 72 even though the actual length ends up being
- * updated to 32 when EVP_PKEY_derive() is called with a buffer
- * for the value. Work around this by trying to fetch the value
- * and continue if it is within supported range even when the
- * initial buffer need is claimed to be larger. */
- wpa_printf(level,
- "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
- (int) *secret_len);
- if (*secret_len > 200)
- goto fail;
- if (EVP_PKEY_derive(ctx, buf, secret_len) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
- wpa_printf(MSG_ERROR,
- "DPP: Unexpected secret_len=%d from EVP_PKEY_derive()",
- (int) *secret_len);
- goto fail;
- }
- wpa_hexdump_key(MSG_DEBUG, "DPP: Unexpected secret_len change",
- buf, *secret_len);
- os_memcpy(secret, buf, *secret_len);
- forced_memzero(buf, sizeof(buf));
- goto done;
- }
-
- if (EVP_PKEY_derive(ctx, secret, secret_len) != 1) {
- wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_derive failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (wpabuf_len(secret_buf) > DPP_MAX_SHARED_SECRET_LEN) {
+ wpa_printf(MSG_ERROR, "DPP: ECDH secret longer than expected");
goto fail;
}
-done:
+ *secret_len = wpabuf_len(secret_buf);
+ os_memcpy(secret, wpabuf_head(secret_buf), wpabuf_len(secret_buf));
ret = 0;
fail:
- EVP_PKEY_CTX_free(ctx);
+ wpabuf_clear_free(secret_buf);
+ wpabuf_free(peer_pub);
+ crypto_ecdh_deinit(ecdh);
return ret;
}
@@ -996,118 +553,32 @@ int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi,
const u8 *data, size_t data_len)
{
- EVP_PKEY *pkey;
- const unsigned char *p;
- int res;
- X509_PUBKEY *pub = NULL;
- ASN1_OBJECT *ppkalg;
- const unsigned char *pk;
- int ppklen;
- X509_ALGOR *pa;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20800000L)
- ASN1_OBJECT *pa_oid;
-#else
- const ASN1_OBJECT *pa_oid;
-#endif
- const void *pval;
- int ptype;
- const ASN1_OBJECT *poid;
- char buf[100];
+ struct crypto_ec_key *key;
if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key");
return -1;
}
- /* DER encoded ASN.1 SubjectPublicKeyInfo
- *
- * SubjectPublicKeyInfo ::= SEQUENCE {
- * algorithm AlgorithmIdentifier,
- * subjectPublicKey BIT STRING }
- *
- * AlgorithmIdentifier ::= SEQUENCE {
- * algorithm OBJECT IDENTIFIER,
- * parameters ANY DEFINED BY algorithm OPTIONAL }
- *
- * subjectPublicKey = compressed format public key per ANSI X9.63
- * algorithm = ecPublicKey (1.2.840.10045.2.1)
- * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g.,
- * prime256v1 (1.2.840.10045.3.1.7)
- */
-
- p = data;
- pkey = d2i_PUBKEY(NULL, &p, data_len);
-
- if (!pkey) {
+ key = crypto_ec_key_parse_pub(data, data_len);
+ if (!key) {
wpa_printf(MSG_DEBUG,
"DPP: Could not parse URI public-key SubjectPublicKeyInfo");
return -1;
}
- if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) {
- wpa_printf(MSG_DEBUG,
- "DPP: SubjectPublicKeyInfo does not describe an EC key");
- EVP_PKEY_free(pkey);
- return -1;
- }
-
- res = X509_PUBKEY_set(&pub, pkey);
- if (res != 1) {
- wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey");
- goto fail;
- }
-
- res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub);
- if (res != 1) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not extract SubjectPublicKeyInfo parameters");
- goto fail;
- }
- res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0);
- if (res < 0 || (size_t) res >= sizeof(buf)) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not extract SubjectPublicKeyInfo algorithm");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf);
- if (os_strcmp(buf, "id-ecPublicKey") != 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Unsupported SubjectPublicKeyInfo algorithm");
- goto fail;
- }
-
- X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa);
- if (ptype != V_ASN1_OBJECT) {
- wpa_printf(MSG_DEBUG,
- "DPP: SubjectPublicKeyInfo parameters did not contain an OID");
- goto fail;
- }
- poid = pval;
- res = OBJ_obj2txt(buf, sizeof(buf), poid, 0);
- if (res < 0 || (size_t) res >= sizeof(buf)) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not extract SubjectPublicKeyInfo parameters OID");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf);
- bi->curve = dpp_get_curve_oid(poid);
+ bi->curve = dpp_get_curve_ike_group(crypto_ec_key_group(key));
if (!bi->curve) {
wpa_printf(MSG_DEBUG,
- "DPP: Unsupported SubjectPublicKeyInfo curve: %s",
- buf);
+ "DPP: Unsupported SubjectPublicKeyInfo curve: group %d",
+ crypto_ec_key_group(key));
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen);
-
- X509_PUBKEY_free(pub);
- bi->pubkey = pkey;
+ bi->pubkey = key;
return 0;
fail:
- X509_PUBKEY_free(pub);
- EVP_PKEY_free(pkey);
+ crypto_ec_key_deinit(key);
return -1;
}
@@ -1115,7 +586,7 @@ fail:
static struct wpabuf *
dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
const u8 *prot_hdr, u16 prot_hdr_len,
- const EVP_MD **ret_md)
+ int *hash_func)
{
struct json_token *root, *token;
struct wpabuf *kid = NULL;
@@ -1161,17 +632,16 @@ dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve,
goto fail;
}
if (os_strcmp(token->string, "ES256") == 0 ||
- os_strcmp(token->string, "BS256") == 0)
- *ret_md = EVP_sha256();
- else if (os_strcmp(token->string, "ES384") == 0 ||
- os_strcmp(token->string, "BS384") == 0)
- *ret_md = EVP_sha384();
- else if (os_strcmp(token->string, "ES512") == 0 ||
- os_strcmp(token->string, "BS512") == 0)
- *ret_md = EVP_sha512();
- else
- *ret_md = NULL;
- if (!*ret_md) {
+ os_strcmp(token->string, "BS256") == 0) {
+ *hash_func = CRYPTO_HASH_ALG_SHA256;
+ } else if (os_strcmp(token->string, "ES384") == 0 ||
+ os_strcmp(token->string, "BS384") == 0) {
+ *hash_func = CRYPTO_HASH_ALG_SHA384;
+ } else if (os_strcmp(token->string, "ES512") == 0 ||
+ os_strcmp(token->string, "BS512") == 0) {
+ *hash_func = CRYPTO_HASH_ALG_SHA512;
+ } else {
+ *hash_func = -1;
wpa_printf(MSG_DEBUG,
"DPP: Unsupported JWS Protected Header alg=%s",
token->string);
@@ -1192,7 +662,8 @@ fail:
}
-static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
+static int dpp_check_pubkey_match(struct crypto_ec_key *pub,
+ struct wpabuf *r_hash)
{
struct wpabuf *uncomp;
int res;
@@ -1202,7 +673,7 @@ static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
if (wpabuf_len(r_hash) != SHA256_MAC_LEN)
return -1;
- uncomp = dpp_get_pubkey_point(pub, 1);
+ uncomp = crypto_ec_key_get_pubkey_point(pub, 1);
if (!uncomp)
return -1;
addr[0] = wpabuf_head(uncomp);
@@ -1226,33 +697,19 @@ static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
enum dpp_status_error
dpp_process_signed_connector(struct dpp_signed_connector_info *info,
- EVP_PKEY *csign_pub, const char *connector)
+ struct crypto_ec_key *csign_pub,
+ const char *connector)
{
enum dpp_status_error ret = 255;
const char *pos, *end, *signed_start, *signed_end;
struct wpabuf *kid = NULL;
unsigned char *prot_hdr = NULL, *signature = NULL;
- size_t prot_hdr_len = 0, signature_len = 0;
- const EVP_MD *sign_md = NULL;
- unsigned char *der = NULL;
- int der_len;
- int res;
- EVP_MD_CTX *md_ctx = NULL;
- ECDSA_SIG *sig = NULL;
- BIGNUM *r = NULL, *s = NULL;
+ size_t prot_hdr_len = 0, signature_len = 0, signed_len;
+ int res, hash_func = -1;
const struct dpp_curve_params *curve;
- const EC_KEY *eckey;
- const EC_GROUP *group;
- int nid;
+ u8 *hash = NULL;
- eckey = EVP_PKEY_get0_EC_KEY(csign_pub);
- if (!eckey)
- goto fail;
- group = EC_KEY_get0_group(eckey);
- if (!group)
- goto fail;
- nid = EC_GROUP_get_curve_name(group);
- curve = dpp_get_curve_nid(nid);
+ curve = dpp_get_curve_ike_group(crypto_ec_key_group(csign_pub));
if (!curve)
goto fail;
wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv);
@@ -1275,7 +732,7 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info,
wpa_hexdump_ascii(MSG_DEBUG,
"DPP: signedConnector - JWS Protected Header",
prot_hdr, prot_hdr_len);
- kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md);
+ kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &hash_func);
if (!kid) {
ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
@@ -1331,57 +788,45 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info,
goto fail;
}
- /* JWS Signature encodes the signature (r,s) as two octet strings. Need
- * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */
- r = BN_bin2bn(signature, signature_len / 2, NULL);
- s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL);
- sig = ECDSA_SIG_new();
- if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1)
+ hash = os_malloc(curve->hash_len);
+ if (!hash)
goto fail;
- r = NULL;
- s = NULL;
- der_len = i2d_ECDSA_SIG(sig, &der);
- if (der_len <= 0) {
- wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature");
- goto fail;
- }
- wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len);
- md_ctx = EVP_MD_CTX_create();
- if (!md_ctx)
+ signed_len = signed_end - signed_start + 1;
+ if (hash_func == CRYPTO_HASH_ALG_SHA256)
+ res = sha256_vector(1, (const u8 **) &signed_start, &signed_len,
+ hash);
+ else if (hash_func == CRYPTO_HASH_ALG_SHA384)
+ res = sha384_vector(1, (const u8 **) &signed_start, &signed_len,
+ hash);
+ else if (hash_func == CRYPTO_HASH_ALG_SHA512)
+ res = sha512_vector(1, (const u8 **) &signed_start, &signed_len,
+ hash);
+ else
goto fail;
- ERR_clear_error();
- if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (EVP_DigestVerifyUpdate(md_ctx, signed_start,
- signed_end - signed_start + 1) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (res)
goto fail;
- }
- res = EVP_DigestVerifyFinal(md_ctx, der, der_len);
+
+ res = crypto_ec_key_verify_signature_r_s(csign_pub,
+ hash, curve->hash_len,
+ signature, signature_len / 2,
+ signature + signature_len / 2,
+ signature_len / 2);
if (res != 1) {
wpa_printf(MSG_DEBUG,
- "DPP: EVP_DigestVerifyFinal failed (res=%d): %s",
- res, ERR_error_string(ERR_get_error(), NULL));
+ "DPP: signedConnector signature check failed (res=%d)",
+ res);
ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
ret = DPP_STATUS_OK;
fail:
- EVP_MD_CTX_destroy(md_ctx);
+ os_free(hash);
os_free(prot_hdr);
wpabuf_free(kid);
os_free(signature);
- ECDSA_SIG_free(sig);
- BN_free(r);
- BN_free(s);
- OPENSSL_free(der);
return ret;
}
@@ -1391,13 +836,11 @@ dpp_check_signed_connector(struct dpp_signed_connector_info *info,
const u8 *csign_key, size_t csign_key_len,
const u8 *peer_connector, size_t peer_connector_len)
{
- const unsigned char *p;
- EVP_PKEY *csign = NULL;
+ struct crypto_ec_key *csign;
char *signed_connector = NULL;
enum dpp_status_error res = DPP_STATUS_INVALID_CONNECTOR;
- p = csign_key;
- csign = d2i_PUBKEY(NULL, &p, csign_key_len);
+ csign = crypto_ec_key_parse_pub(csign_key, csign_key_len);
if (!csign) {
wpa_printf(MSG_ERROR,
"DPP: Failed to parse local C-sign-key information");
@@ -1414,7 +857,7 @@ dpp_check_signed_connector(struct dpp_signed_connector_info *info,
res = dpp_process_signed_connector(info, csign, signed_connector);
fail:
os_free(signed_connector);
- EVP_PKEY_free(csign);
+ crypto_ec_key_deinit(csign);
return res;
}
@@ -1433,21 +876,25 @@ int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth)
nonce_len = auth->curve->nonce_len;
if (auth->initiator) {
- pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
- prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ pix = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
+ prx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
+ 0);
if (auth->own_bi)
- bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ bix = crypto_ec_key_get_pubkey_point(
+ auth->own_bi->pubkey, 0);
else
bix = NULL;
- brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ brx = crypto_ec_key_get_pubkey_point(auth->peer_bi->pubkey, 0);
} else {
- pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
- prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ pix = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
+ 0);
+ prx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
if (auth->peer_bi)
- bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ bix = crypto_ec_key_get_pubkey_point(
+ auth->peer_bi->pubkey, 0);
else
bix = NULL;
- brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ brx = crypto_ec_key_get_pubkey_point(auth->own_bi->pubkey, 0);
}
if (!pix || !prx || !brx)
goto fail;
@@ -1512,25 +959,29 @@ int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth)
nonce_len = auth->curve->nonce_len;
if (auth->initiator) {
- pix = dpp_get_pubkey_point(auth->own_protocol_key, 0);
- prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
+ pix = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
+ prx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
+ 0);
if (auth->own_bi)
- bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ bix = crypto_ec_key_get_pubkey_point(
+ auth->own_bi->pubkey, 0);
else
bix = NULL;
if (!auth->peer_bi)
goto fail;
- brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ brx = crypto_ec_key_get_pubkey_point(auth->peer_bi->pubkey, 0);
} else {
- pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0);
- prx = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ pix = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
+ 0);
+ prx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
if (auth->peer_bi)
- bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0);
+ bix = crypto_ec_key_get_pubkey_point(
+ auth->peer_bi->pubkey, 0);
else
bix = NULL;
if (!auth->own_bi)
goto fail;
- brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0);
+ brx = crypto_ec_key_get_pubkey_point(auth->own_bi->pubkey, 0);
}
if (!pix || !prx || !brx)
goto fail;
@@ -1583,122 +1034,83 @@ fail:
int dpp_auth_derive_l_responder(struct dpp_authentication *auth)
{
- const EC_GROUP *group;
- EC_POINT *l = NULL;
- const EC_KEY *BI, *bR, *pR;
- const EC_POINT *BI_point;
- BN_CTX *bnctx;
- BIGNUM *lx, *sum, *q;
- const BIGNUM *bR_bn, *pR_bn;
+ struct crypto_ec *ec;
+ struct crypto_ec_point *L = NULL;
+ const struct crypto_ec_point *BI;
+ const struct crypto_bignum *bR, *pR, *q;
+ struct crypto_bignum *sum = NULL, *lx = NULL;
int ret = -1;
/* L = ((bR + pR) modulo q) * BI */
- bnctx = BN_CTX_new();
- sum = BN_new();
- q = BN_new();
- lx = BN_new();
- if (!bnctx || !sum || !q || !lx)
- goto fail;
- BI = EVP_PKEY_get0_EC_KEY(auth->peer_bi->pubkey);
- if (!BI)
- goto fail;
- BI_point = EC_KEY_get0_public_key(BI);
- group = EC_KEY_get0_group(BI);
- if (!group)
+ ec = crypto_ec_init(crypto_ec_key_group(auth->peer_bi->pubkey));
+ if (!ec)
goto fail;
- bR = EVP_PKEY_get0_EC_KEY(auth->own_bi->pubkey);
- pR = EVP_PKEY_get0_EC_KEY(auth->own_protocol_key);
- if (!bR || !pR)
+ q = crypto_ec_get_order(ec);
+ BI = crypto_ec_key_get_public_key(auth->peer_bi->pubkey);
+ bR = crypto_ec_key_get_private_key(auth->own_bi->pubkey);
+ pR = crypto_ec_key_get_private_key(auth->own_protocol_key);
+ sum = crypto_bignum_init();
+ L = crypto_ec_point_init(ec);
+ lx = crypto_bignum_init();
+ if (!q || !BI || !bR || !pR || !sum || !L || !lx ||
+ crypto_bignum_addmod(bR, pR, q, sum) ||
+ crypto_ec_point_mul(ec, BI, sum, L) ||
+ crypto_ec_point_x(ec, L, lx) ||
+ crypto_bignum_to_bin(lx, auth->Lx, sizeof(auth->Lx),
+ auth->secret_len) < 0)
goto fail;
- bR_bn = EC_KEY_get0_private_key(bR);
- pR_bn = EC_KEY_get0_private_key(pR);
- if (!bR_bn || !pR_bn)
- goto fail;
- if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
- BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1)
- goto fail;
- l = EC_POINT_new(group);
- if (!l ||
- EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
- bnctx) != 1) {
- wpa_printf(MSG_ERROR,
- "OpenSSL: failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
- goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
auth->Lx_len = auth->secret_len;
ret = 0;
fail:
- EC_POINT_clear_free(l);
- BN_clear_free(lx);
- BN_clear_free(sum);
- BN_free(q);
- BN_CTX_free(bnctx);
+ crypto_bignum_deinit(lx, 1);
+ crypto_bignum_deinit(sum, 1);
+ crypto_ec_point_deinit(L, 1);
+ crypto_ec_deinit(ec);
return ret;
}
int dpp_auth_derive_l_initiator(struct dpp_authentication *auth)
{
- const EC_GROUP *group;
- EC_POINT *l = NULL, *sum = NULL;
- const EC_KEY *bI, *BR, *PR;
- const EC_POINT *BR_point, *PR_point;
- BN_CTX *bnctx;
- BIGNUM *lx;
- const BIGNUM *bI_bn;
+ struct crypto_ec *ec;
+ struct crypto_ec_point *L = NULL, *sum = NULL;
+ const struct crypto_ec_point *BR, *PR;
+ const struct crypto_bignum *bI;
+ struct crypto_bignum *lx = NULL;
int ret = -1;
/* L = bI * (BR + PR) */
- bnctx = BN_CTX_new();
- lx = BN_new();
- if (!bnctx || !lx)
+ ec = crypto_ec_init(crypto_ec_key_group(auth->peer_bi->pubkey));
+ if (!ec)
goto fail;
- BR = EVP_PKEY_get0_EC_KEY(auth->peer_bi->pubkey);
- PR = EVP_PKEY_get0_EC_KEY(auth->peer_protocol_key);
- if (!BR || !PR)
- goto fail;
- BR_point = EC_KEY_get0_public_key(BR);
- PR_point = EC_KEY_get0_public_key(PR);
- bI = EVP_PKEY_get0_EC_KEY(auth->own_bi->pubkey);
- if (!bI)
- goto fail;
- group = EC_KEY_get0_group(bI);
- bI_bn = EC_KEY_get0_private_key(bI);
- if (!group || !bI_bn)
- goto fail;
- sum = EC_POINT_new(group);
- l = EC_POINT_new(group);
- if (!sum || !l ||
- EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 ||
- EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL,
- bnctx) != 1) {
- wpa_printf(MSG_ERROR,
- "OpenSSL: failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ BR = crypto_ec_key_get_public_key(auth->peer_bi->pubkey);
+ PR = crypto_ec_key_get_public_key(auth->peer_protocol_key);
+ bI = crypto_ec_key_get_private_key(auth->own_bi->pubkey);
+ sum = crypto_ec_point_init(ec);
+ L = crypto_ec_point_init(ec);
+ lx = crypto_bignum_init();
+ if (!BR || !PR || !bI || !sum || !L || !lx ||
+ crypto_ec_point_add(ec, BR, PR, sum) ||
+ crypto_ec_point_mul(ec, sum, bI, L) ||
+ crypto_ec_point_x(ec, L, lx) ||
+ crypto_bignum_to_bin(lx, auth->Lx, sizeof(auth->Lx),
+ auth->secret_len) < 0)
goto fail;
- }
- if (dpp_bn2bin_pad(lx, auth->Lx, auth->secret_len) < 0)
- goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len);
auth->Lx_len = auth->secret_len;
ret = 0;
fail:
- EC_POINT_clear_free(l);
- EC_POINT_clear_free(sum);
- BN_clear_free(lx);
- BN_CTX_free(bnctx);
+ crypto_bignum_deinit(lx, 1);
+ crypto_ec_point_deinit(sum, 1);
+ crypto_ec_point_deinit(L, 1);
+ crypto_ec_deinit(ec);
return ret;
}
@@ -1731,7 +1143,8 @@ int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, unsigned int hash_len)
int dpp_derive_pmkid(const struct dpp_curve_params *curve,
- EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid)
+ struct crypto_ec_key *own_key,
+ struct crypto_ec_key *peer_key, u8 *pmkid)
{
struct wpabuf *nkx, *pkx;
int ret = -1, res;
@@ -1740,8 +1153,8 @@ int dpp_derive_pmkid(const struct dpp_curve_params *curve,
u8 hash[SHA256_MAC_LEN];
/* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
- nkx = dpp_get_pubkey_point(own_key, 0);
- pkx = dpp_get_pubkey_point(peer_key, 0);
+ nkx = crypto_ec_key_get_pubkey_point(own_key, 0);
+ pkx = crypto_ec_key_get_pubkey_point(peer_key, 0);
if (!nkx || !pkx)
goto fail;
addr[0] = wpabuf_head(nkx);
@@ -1981,13 +1394,10 @@ static const u8 pkex_resp_y_bp_p512r1[64] = {
};
-static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
- int init)
+static struct crypto_ec_key *
+dpp_pkex_get_role_elem(const struct dpp_curve_params *curve, int init)
{
- EC_GROUP *group;
- size_t len = curve->prime_len;
const u8 *x, *y;
- EVP_PKEY *res;
switch (curve->ike_group) {
case 19:
@@ -2018,31 +1428,24 @@ static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve,
return NULL;
}
- group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
- if (!group)
- return NULL;
- res = dpp_set_pubkey_point_group(group, x, y, len);
- EC_GROUP_free(group);
- return res;
+ return crypto_ec_key_set_pub(curve->ike_group, x, y, curve->prime_len);
}
-EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
- const u8 *mac_init, const char *code,
- const char *identifier, BN_CTX *bnctx,
- EC_GROUP **ret_group)
+struct crypto_ec_point *
+dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
+ const char *code, const char *identifier,
+ struct crypto_ec **ret_ec)
{
u8 hash[DPP_MAX_HASH_LEN];
const u8 *addr[3];
size_t len[3];
unsigned int num_elem = 0;
- EC_POINT *Qi = NULL;
- EVP_PKEY *Pi = NULL;
- const EC_KEY *Pi_ec;
- const EC_POINT *Pi_point;
- BIGNUM *hash_bn = NULL;
- const EC_GROUP *group = NULL;
- EC_GROUP *group2 = NULL;
+ struct crypto_ec_point *Qi = NULL;
+ struct crypto_ec_key *Pi_key = NULL;
+ const struct crypto_ec_point *Pi = NULL;
+ struct crypto_bignum *hash_bn = NULL;
+ struct crypto_ec *ec = NULL;
/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
@@ -2066,66 +1469,55 @@ EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
wpa_hexdump_key(MSG_DEBUG,
"DPP: H(MAC-Initiator | [identifier |] code)",
hash, curve->hash_len);
- Pi = dpp_pkex_get_role_elem(curve, 1);
- if (!Pi)
- goto fail;
- dpp_debug_print_key("DPP: Pi", Pi);
- Pi_ec = EVP_PKEY_get0_EC_KEY(Pi);
- if (!Pi_ec)
+ Pi_key = dpp_pkex_get_role_elem(curve, 1);
+ if (!Pi_key)
goto fail;
- Pi_point = EC_KEY_get0_public_key(Pi_ec);
+ dpp_debug_print_key("DPP: Pi", Pi_key);
- group = EC_KEY_get0_group(Pi_ec);
- if (!group)
+ ec = crypto_ec_init(curve->ike_group);
+ if (!ec)
goto fail;
- group2 = EC_GROUP_dup(group);
- if (!group2)
- goto fail;
- Qi = EC_POINT_new(group2);
- if (!Qi) {
- EC_GROUP_free(group2);
- goto fail;
- }
- hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
- if (!hash_bn ||
- EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1)
+
+ Pi = crypto_ec_key_get_public_key(Pi_key);
+ Qi = crypto_ec_point_init(ec);
+ hash_bn = crypto_bignum_init_set(hash, curve->hash_len);
+ if (!Pi || !Qi || !hash_bn || crypto_ec_point_mul(ec, Pi, hash_bn, Qi))
goto fail;
- if (EC_POINT_is_at_infinity(group, Qi)) {
+
+ if (crypto_ec_point_is_at_infinity(ec, Qi)) {
wpa_printf(MSG_INFO, "DPP: Qi is the point-at-infinity");
goto fail;
}
- dpp_debug_print_point("DPP: Qi", group, Qi);
+ crypto_ec_point_debug_print(ec, Qi, "DPP: Qi");
out:
- EVP_PKEY_free(Pi);
- BN_clear_free(hash_bn);
- if (ret_group && Qi)
- *ret_group = group2;
+ crypto_ec_key_deinit(Pi_key);
+ crypto_bignum_deinit(hash_bn, 1);
+ if (ret_ec && Qi)
+ *ret_ec = ec;
else
- EC_GROUP_free(group2);
+ crypto_ec_deinit(ec);
return Qi;
fail:
- EC_POINT_free(Qi);
+ crypto_ec_point_deinit(Qi, 1);
Qi = NULL;
goto out;
}
-EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
- const u8 *mac_resp, const char *code,
- const char *identifier, BN_CTX *bnctx,
- EC_GROUP **ret_group)
+struct crypto_ec_point *
+dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
+ const char *code, const char *identifier,
+ struct crypto_ec **ret_ec)
{
u8 hash[DPP_MAX_HASH_LEN];
const u8 *addr[3];
size_t len[3];
unsigned int num_elem = 0;
- EC_POINT *Qr = NULL;
- EVP_PKEY *Pr = NULL;
- const EC_KEY *Pr_ec;
- const EC_POINT *Pr_point;
- BIGNUM *hash_bn = NULL;
- const EC_GROUP *group = NULL;
- EC_GROUP *group2 = NULL;
+ struct crypto_ec_point *Qr = NULL;
+ struct crypto_ec_key *Pr_key = NULL;
+ const struct crypto_ec_point *Pr = NULL;
+ struct crypto_bignum *hash_bn = NULL;
+ struct crypto_ec *ec = NULL;
/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
@@ -2149,45 +1541,37 @@ EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
wpa_hexdump_key(MSG_DEBUG,
"DPP: H(MAC-Responder | [identifier |] code)",
hash, curve->hash_len);
- Pr = dpp_pkex_get_role_elem(curve, 0);
- if (!Pr)
- goto fail;
- dpp_debug_print_key("DPP: Pr", Pr);
- Pr_ec = EVP_PKEY_get0_EC_KEY(Pr);
- if (!Pr_ec)
+ Pr_key = dpp_pkex_get_role_elem(curve, 0);
+ if (!Pr_key)
goto fail;
- Pr_point = EC_KEY_get0_public_key(Pr_ec);
+ dpp_debug_print_key("DPP: Pr", Pr_key);
- group = EC_KEY_get0_group(Pr_ec);
- if (!group)
+ ec = crypto_ec_init(curve->ike_group);
+ if (!ec)
goto fail;
- group2 = EC_GROUP_dup(group);
- if (!group2)
- goto fail;
- Qr = EC_POINT_new(group2);
- if (!Qr) {
- EC_GROUP_free(group2);
- goto fail;
- }
- hash_bn = BN_bin2bn(hash, curve->hash_len, NULL);
- if (!hash_bn ||
- EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1)
+
+ Pr = crypto_ec_key_get_public_key(Pr_key);
+ Qr = crypto_ec_point_init(ec);
+ hash_bn = crypto_bignum_init_set(hash, curve->hash_len);
+ if (!Pr || !Qr || !hash_bn || crypto_ec_point_mul(ec, Pr, hash_bn, Qr))
goto fail;
- if (EC_POINT_is_at_infinity(group, Qr)) {
+
+ if (crypto_ec_point_is_at_infinity(ec, Qr)) {
wpa_printf(MSG_INFO, "DPP: Qr is the point-at-infinity");
goto fail;
}
- dpp_debug_print_point("DPP: Qr", group, Qr);
+ crypto_ec_point_debug_print(ec, Qr, "DPP: Qr");
+
out:
- EVP_PKEY_free(Pr);
- BN_clear_free(hash_bn);
- if (ret_group && Qr)
- *ret_group = group2;
+ crypto_ec_key_deinit(Pr_key);
+ crypto_bignum_deinit(hash_bn, 1);
+ if (ret_ec && Qr)
+ *ret_ec = ec;
else
- EC_GROUP_free(group2);
+ crypto_ec_deinit(ec);
return Qr;
fail:
- EC_POINT_free(Qr);
+ crypto_ec_point_deinit(Qr, 1);
Qr = NULL;
goto out;
}
@@ -2257,15 +1641,12 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
size_t net_access_key_len,
struct json_token *peer_net_access_key)
{
- BN_CTX *bnctx = NULL;
- EVP_PKEY *own_key = NULL, *peer_key = NULL;
- BIGNUM *sum = NULL, *q = NULL, *mx = NULL;
- EC_POINT *m = NULL;
- const EC_KEY *cR, *pR;
- const EC_GROUP *group;
- const BIGNUM *cR_bn, *pR_bn;
- const EC_POINT *CI_point;
- const EC_KEY *CI;
+ struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
+ struct crypto_bignum *sum = NULL;
+ const struct crypto_bignum *q, *cR, *pR;
+ struct crypto_ec *ec = NULL;
+ struct crypto_ec_point *M = NULL;
+ const struct crypto_ec_point *CI;
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
u8 prk[DPP_MAX_HASH_LEN];
const struct dpp_curve_params *curve;
@@ -2303,37 +1684,23 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
auth->e_nonce, auth->curve->nonce_len);
/* M = { cR + pR } * CI */
- cR = EVP_PKEY_get0_EC_KEY(own_key);
- pR = EVP_PKEY_get0_EC_KEY(auth->own_protocol_key);
- if (!pR)
- goto fail;
- group = EC_KEY_get0_group(pR);
- bnctx = BN_CTX_new();
- sum = BN_new();
- mx = BN_new();
- q = BN_new();
- m = EC_POINT_new(group);
- if (!cR || !bnctx || !sum || !mx || !q || !m)
- goto fail;
- cR_bn = EC_KEY_get0_private_key(cR);
- pR_bn = EC_KEY_get0_private_key(pR);
- if (!cR_bn || !pR_bn)
- goto fail;
- CI = EVP_PKEY_get0_EC_KEY(peer_key);
- CI_point = EC_KEY_get0_public_key(CI);
- if (EC_GROUP_get_order(group, q, bnctx) != 1 ||
- BN_mod_add(sum, cR_bn, pR_bn, q, bnctx) != 1 ||
- EC_POINT_mul(group, m, NULL, CI_point, sum, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, m, mx, NULL,
- bnctx) != 1) {
- wpa_printf(MSG_ERROR,
- "OpenSSL: failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ ec = crypto_ec_init(curve->ike_group);
+ if (!ec)
goto fail;
- }
- if (dpp_bn2bin_pad(mx, Mx, curve->prime_len) < 0)
+ sum = crypto_bignum_init();
+ q = crypto_ec_get_order(ec);
+ M = crypto_ec_point_init(ec);
+ cR = crypto_ec_key_get_private_key(own_key);
+ pR = crypto_ec_key_get_private_key(auth->own_protocol_key);
+ CI = crypto_ec_key_get_public_key(peer_key);
+ if (!sum || !q || !M || !cR || !pR || !CI ||
+ crypto_bignum_addmod(cR, pR, q, sum) ||
+ crypto_ec_point_mul(ec, CI, sum, M) ||
+ crypto_ec_point_to_bin(ec, M, Mx, NULL)) {
+ wpa_printf(MSG_ERROR, "DPP: Error during M computation");
goto fail;
+ }
wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
/* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
@@ -2355,19 +1722,17 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
auth->ke, curve->hash_len);
res = 0;
- EVP_PKEY_free(auth->reconfig_old_protocol_key);
+ crypto_ec_key_deinit(auth->reconfig_old_protocol_key);
auth->reconfig_old_protocol_key = own_key;
own_key = NULL;
fail:
forced_memzero(prk, sizeof(prk));
forced_memzero(Mx, sizeof(Mx));
- EC_POINT_clear_free(m);
- BN_free(q);
- BN_clear_free(mx);
- BN_clear_free(sum);
- EVP_PKEY_free(own_key);
- EVP_PKEY_free(peer_key);
- BN_CTX_free(bnctx);
+ crypto_ec_point_deinit(M, 1);
+ crypto_bignum_deinit(sum, 1);
+ crypto_ec_key_deinit(own_key);
+ crypto_ec_key_deinit(peer_key);
+ crypto_ec_deinit(ec);
return res;
}
@@ -2376,14 +1741,11 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
const u8 *r_proto, u16 r_proto_len,
struct json_token *net_access_key)
{
- BN_CTX *bnctx = NULL;
- EVP_PKEY *pr = NULL, *peer_key = NULL;
- EC_POINT *sum = NULL, *m = NULL;
- BIGNUM *mx = NULL;
- const EC_KEY *cI, *CR, *PR;
- const EC_GROUP *group;
- const EC_POINT *CR_point, *PR_point;
- const BIGNUM *cI_bn;
+ struct crypto_ec_key *pr = NULL, *peer_key = NULL;
+ const struct crypto_ec_point *CR, *PR;
+ const struct crypto_bignum *cI;
+ struct crypto_ec *ec = NULL;
+ struct crypto_ec_point *sum = NULL, *M = NULL;
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
u8 prk[DPP_MAX_HASH_LEN];
int res = -1;
@@ -2397,7 +1759,7 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
goto fail;
}
dpp_debug_print_key("Peer (Responder) Protocol Key", pr);
- EVP_PKEY_free(auth->peer_protocol_key);
+ crypto_ec_key_deinit(auth->peer_protocol_key);
auth->peer_protocol_key = pr;
pr = NULL;
@@ -2413,25 +1775,23 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
}
/* M = cI * { CR + PR } */
- cI = EVP_PKEY_get0_EC_KEY(auth->conf->connector_key);
- cI_bn = EC_KEY_get0_private_key(cI);
- group = EC_KEY_get0_group(cI);
- bnctx = BN_CTX_new();
- sum = EC_POINT_new(group);
- m = EC_POINT_new(group);
- mx = BN_new();
- CR = EVP_PKEY_get0_EC_KEY(peer_key);
- PR = EVP_PKEY_get0_EC_KEY(auth->peer_protocol_key);
- CR_point = EC_KEY_get0_public_key(CR);
- PR_point = EC_KEY_get0_public_key(PR);
- if (!bnctx || !sum || !m || !mx ||
- EC_POINT_add(group, sum, CR_point, PR_point, bnctx) != 1 ||
- EC_POINT_mul(group, m, NULL, sum, cI_bn, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, m, mx, NULL,
- bnctx) != 1 ||
- dpp_bn2bin_pad(mx, Mx, curve->prime_len) < 0)
+ ec = crypto_ec_init(curve->ike_group);
+ if (!ec)
goto fail;
+ cI = crypto_ec_key_get_private_key(auth->conf->connector_key);
+ sum = crypto_ec_point_init(ec);
+ M = crypto_ec_point_init(ec);
+ CR = crypto_ec_key_get_public_key(peer_key);
+ PR = crypto_ec_key_get_public_key(auth->peer_protocol_key);
+ if (!cI || !sum || !M || !CR || !PR ||
+ crypto_ec_point_add(ec, CR, PR, sum) ||
+ crypto_ec_point_mul(ec, sum, cI, M) ||
+ crypto_ec_point_to_bin(ec, M, Mx, NULL)) {
+ wpa_printf(MSG_ERROR, "DPP: Error during M computation");
+ goto fail;
+ }
+
wpa_hexdump_key(MSG_DEBUG, "DPP: M.x", Mx, curve->prime_len);
/* ke = HKDF(C-nonce | E-nonce, "dpp reconfig key", M.x) */
@@ -2456,12 +1816,11 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
fail:
forced_memzero(prk, sizeof(prk));
forced_memzero(Mx, sizeof(Mx));
- EVP_PKEY_free(pr);
- EVP_PKEY_free(peer_key);
- EC_POINT_clear_free(sum);
- EC_POINT_clear_free(m);
- BN_clear_free(mx);
- BN_CTX_free(bnctx);
+ crypto_ec_key_deinit(pr);
+ crypto_ec_key_deinit(peer_key);
+ crypto_ec_point_deinit(sum, 1);
+ crypto_ec_point_deinit(M, 1);
+ crypto_ec_deinit(ec);
return res;
}
@@ -2497,78 +1856,56 @@ dpp_build_conn_signature(struct dpp_configurator *conf,
size_t *signed3_len)
{
const struct dpp_curve_params *curve;
+ struct wpabuf *sig = NULL;
char *signed3 = NULL;
- unsigned char *signature = NULL;
- const unsigned char *p;
- size_t signature_len;
- EVP_MD_CTX *md_ctx = NULL;
- ECDSA_SIG *sig = NULL;
char *dot = ".";
- const EVP_MD *sign_md;
- const BIGNUM *r, *s;
+ const u8 *vector[3];
+ size_t vector_len[3];
+ u8 *hash;
+ int ret;
+
+ vector[0] = (const u8 *) signed1;
+ vector[1] = (const u8 *) dot;
+ vector[2] = (const u8 *) signed2;
+ vector_len[0] = signed1_len;
+ vector_len[1] = 1;
+ vector_len[2] = signed2_len;
curve = conf->curve;
+ hash = os_malloc(curve->hash_len);
+ if (!hash)
+ goto fail;
if (curve->hash_len == SHA256_MAC_LEN) {
- sign_md = EVP_sha256();
+ ret = sha256_vector(3, vector, vector_len, hash);
} else if (curve->hash_len == SHA384_MAC_LEN) {
- sign_md = EVP_sha384();
+ ret = sha384_vector(3, vector, vector_len, hash);
} else if (curve->hash_len == SHA512_MAC_LEN) {
- sign_md = EVP_sha512();
+ ret = sha512_vector(3, vector, vector_len, hash);
} else {
wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
goto fail;
}
-
- md_ctx = EVP_MD_CTX_create();
- if (!md_ctx)
- goto fail;
-
- ERR_clear_error();
- if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL, conf->csign) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 ||
- EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 ||
- EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "DPP: Hash computation failed");
goto fail;
}
- signature = os_malloc(signature_len);
- if (!signature)
- goto fail;
- if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) {
- wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ wpa_hexdump(MSG_DEBUG, "DPP: Hash value for Connector signature",
+ hash, curve->hash_len);
+
+ sig = crypto_ec_key_sign_r_s(conf->csign, hash, curve->hash_len);
+ if (!sig) {
+ wpa_printf(MSG_ERROR, "DPP: Signature computation failed");
goto fail;
}
- wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)",
- signature, signature_len);
- /* Convert to raw coordinates r,s */
- p = signature;
- sig = d2i_ECDSA_SIG(NULL, &p, signature_len);
- if (!sig)
- goto fail;
- ECDSA_SIG_get0(sig, &r, &s);
- if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 ||
- dpp_bn2bin_pad(s, signature + curve->prime_len,
- curve->prime_len) < 0)
- goto fail;
- signature_len = 2 * curve->prime_len;
+
wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)",
- signature, signature_len);
- signed3 = base64_url_encode(signature, signature_len, signed3_len);
+ wpabuf_head(sig), wpabuf_len(sig));
+ signed3 = base64_url_encode(wpabuf_head(sig), wpabuf_len(sig),
+ signed3_len);
+
fail:
- EVP_MD_CTX_destroy(md_ctx);
- ECDSA_SIG_free(sig);
- os_free(signature);
+ os_free(hash);
+ wpabuf_free(sig);
return signed3;
}
@@ -2618,7 +1955,7 @@ struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
size_t net_access_key_len)
{
struct wpabuf *pub = NULL;
- EVP_PKEY *own_key;
+ struct crypto_ec_key *own_key;
struct dpp_pfs *pfs;
pfs = os_zalloc(sizeof(*pfs));
@@ -2631,7 +1968,7 @@ struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
goto fail;
}
- EVP_PKEY_free(own_key);
+ crypto_ec_key_deinit(own_key);
pfs->ecdh = crypto_ecdh_init(pfs->curve->ike_group);
if (!pfs->ecdh)
@@ -2696,19 +2033,15 @@ void dpp_pfs_free(struct dpp_pfs *pfs)
struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
{
- X509_REQ *req = NULL;
+ struct crypto_csr *csr = NULL;
struct wpabuf *buf = NULL;
- unsigned char *der;
- int der_len;
- EVP_PKEY *key;
- const EVP_MD *sign_md;
+ struct crypto_ec_key *key;
unsigned int hash_len = auth->curve->hash_len;
- EC_KEY *eckey;
- BIO *out = NULL;
+ struct wpabuf *priv_key;
u8 cp[DPP_CP_LEN];
- char *password;
+ char *password = NULL;
size_t password_len;
- int res;
+ int hash_sign_algo;
/* TODO: use auth->csrattrs */
@@ -2716,35 +2049,18 @@ struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
* a specific group to be used */
key = auth->own_protocol_key;
- eckey = EVP_PKEY_get1_EC_KEY(key);
- if (!eckey)
- goto fail;
- der = NULL;
- der_len = i2d_ECPrivateKey(eckey, &der);
- if (der_len <= 0)
+ priv_key = crypto_ec_key_get_ecprivate_key(key, true);
+ if (!priv_key)
goto fail;
wpabuf_free(auth->priv_key);
- auth->priv_key = wpabuf_alloc_copy(der, der_len);
- OPENSSL_free(der);
- if (!auth->priv_key)
- goto fail;
+ auth->priv_key = priv_key;
- req = X509_REQ_new();
- if (!req || !X509_REQ_set_pubkey(req, key))
+ csr = crypto_csr_init();
+ if (!csr || crypto_csr_set_ec_public_key(csr, key))
goto fail;
- if (name) {
- X509_NAME *n;
-
- n = X509_REQ_get_subject_name(req);
- if (!n)
- goto fail;
-
- if (X509_NAME_add_entry_by_txt(
- n, "CN", MBSTRING_UTF8,
- (const unsigned char *) name, -1, -1, 0) != 1)
- goto fail;
- }
+ if (name && crypto_csr_set_name(csr, CSR_NAME_CN, name))
+ goto fail;
/* cp = HKDF-Expand(bk, "CSR challengePassword", 64) */
if (dpp_hkdf_expand(hash_len, auth->bk, hash_len,
@@ -2755,222 +2071,75 @@ struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name)
cp, DPP_CP_LEN);
password = base64_encode_no_lf(cp, DPP_CP_LEN, &password_len);
forced_memzero(cp, DPP_CP_LEN);
- if (!password)
- goto fail;
-
- res = X509_REQ_add1_attr_by_NID(req, NID_pkcs9_challengePassword,
- V_ASN1_UTF8STRING,
- (const unsigned char *) password,
- password_len);
- bin_clear_free(password, password_len);
- if (!res)
+ if (!password ||
+ crypto_csr_set_attribute(csr, CSR_ATTR_CHALLENGE_PASSWORD,
+ ASN1_TAG_UTF8STRING, (const u8 *) password,
+ password_len))
goto fail;
- /* TODO */
-
/* TODO: hash func selection based on csrAttrs */
if (hash_len == SHA256_MAC_LEN) {
- sign_md = EVP_sha256();
+ hash_sign_algo = CRYPTO_HASH_ALG_SHA256;
} else if (hash_len == SHA384_MAC_LEN) {
- sign_md = EVP_sha384();
+ hash_sign_algo = CRYPTO_HASH_ALG_SHA384;
} else if (hash_len == SHA512_MAC_LEN) {
- sign_md = EVP_sha512();
+ hash_sign_algo = CRYPTO_HASH_ALG_SHA512;
} else {
wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm");
goto fail;
}
- if (!X509_REQ_sign(req, key, sign_md))
- goto fail;
-
- der = NULL;
- der_len = i2d_X509_REQ(req, &der);
- if (der_len < 0)
+ buf = crypto_csr_sign(csr, key, hash_sign_algo);
+ if (!buf)
goto fail;
- buf = wpabuf_alloc_copy(der, der_len);
- OPENSSL_free(der);
-
wpa_hexdump_buf(MSG_DEBUG, "DPP: CSR", buf);
fail:
- BIO_free_all(out);
- X509_REQ_free(req);
+ bin_clear_free(password, password_len);
+ crypto_csr_deinit(csr);
return buf;
}
-struct wpabuf * dpp_pkcs7_certs(const struct wpabuf *pkcs7)
-{
-#ifdef OPENSSL_IS_BORINGSSL
- CBS pkcs7_cbs;
-#else /* OPENSSL_IS_BORINGSSL */
- PKCS7 *p7 = NULL;
- const unsigned char *p = wpabuf_head(pkcs7);
-#endif /* OPENSSL_IS_BORINGSSL */
- STACK_OF(X509) *certs;
- int i, num;
- BIO *out = NULL;
- size_t rlen;
- struct wpabuf *pem = NULL;
- int res;
-
-#ifdef OPENSSL_IS_BORINGSSL
- certs = sk_X509_new_null();
- if (!certs)
- goto fail;
- CBS_init(&pkcs7_cbs, wpabuf_head(pkcs7), wpabuf_len(pkcs7));
- if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
- wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-#else /* OPENSSL_IS_BORINGSSL */
- p7 = d2i_PKCS7(NULL, &p, wpabuf_len(pkcs7));
- if (!p7) {
- wpa_printf(MSG_INFO, "DPP: Could not parse PKCS#7 object: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
-
- switch (OBJ_obj2nid(p7->type)) {
- case NID_pkcs7_signed:
- certs = p7->d.sign->cert;
- break;
- case NID_pkcs7_signedAndEnveloped:
- certs = p7->d.signed_and_enveloped->cert;
- break;
- default:
- certs = NULL;
- break;
- }
-#endif /* OPENSSL_IS_BORINGSSL */
-
- if (!certs || ((num = sk_X509_num(certs)) == 0)) {
- wpa_printf(MSG_INFO,
- "DPP: No certificates found in PKCS#7 object");
- goto fail;
- }
-
- out = BIO_new(BIO_s_mem());
- if (!out)
- goto fail;
-
- for (i = 0; i < num; i++) {
- X509 *cert = sk_X509_value(certs, i);
-
- PEM_write_bio_X509(out, cert);
- }
-
- rlen = BIO_ctrl_pending(out);
- pem = wpabuf_alloc(rlen);
- if (!pem)
- goto fail;
- res = BIO_read(out, wpabuf_put(pem, 0), rlen);
- if (res <= 0) {
- wpabuf_free(pem);
- pem = NULL;
- goto fail;
- }
- wpabuf_put(pem, res);
-
-fail:
-#ifdef OPENSSL_IS_BORINGSSL
- if (certs)
- sk_X509_pop_free(certs, X509_free);
-#else /* OPENSSL_IS_BORINGSSL */
- PKCS7_free(p7);
-#endif /* OPENSSL_IS_BORINGSSL */
- if (out)
- BIO_free_all(out);
-
- return pem;
-}
-
-
-int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr)
+int dpp_validate_csr(struct dpp_authentication *auth,
+ const struct wpabuf *csrbuf)
{
- X509_REQ *req;
- const unsigned char *pos;
- EVP_PKEY *pkey;
- int res, loc, ret = -1;
- X509_ATTRIBUTE *attr;
- ASN1_TYPE *type;
- ASN1_STRING *str;
- unsigned char *utf8 = NULL;
+ struct crypto_csr *csr;
+ const u8 *attr;
+ size_t attr_len;
+ int attr_type;
unsigned char *cp = NULL;
size_t cp_len;
u8 exp_cp[DPP_CP_LEN];
unsigned int hash_len = auth->curve->hash_len;
+ int ret = -1;
- pos = wpabuf_head(csr);
- req = d2i_X509_REQ(NULL, &pos, wpabuf_len(csr));
- if (!req) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to parse CSR");
- return -1;
- }
-
- pkey = X509_REQ_get_pubkey(req);
- if (!pkey) {
- wpa_printf(MSG_DEBUG, "DPP: Failed to get public key from CSR");
- goto fail;
- }
-
- res = X509_REQ_verify(req, pkey);
- EVP_PKEY_free(pkey);
- if (res != 1) {
- wpa_printf(MSG_DEBUG,
- "DPP: CSR does not have a valid signature");
- goto fail;
- }
-
- loc = X509_REQ_get_attr_by_NID(req, NID_pkcs9_challengePassword, -1);
- if (loc < 0) {
+ csr = crypto_csr_verify(csrbuf);
+ if (!csr) {
wpa_printf(MSG_DEBUG,
- "DPP: CSR does not include challengePassword");
+ "DPP: CSR invalid or invalid signature");
goto fail;
}
- attr = X509_REQ_get_attr(req, loc);
+ attr = crypto_csr_get_attribute(csr, CSR_ATTR_CHALLENGE_PASSWORD,
+ &attr_len, &attr_type);
if (!attr) {
wpa_printf(MSG_DEBUG,
- "DPP: Could not get challengePassword attribute");
- goto fail;
- }
-
- type = X509_ATTRIBUTE_get0_type(attr, 0);
- if (!type) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not get challengePassword attribute type");
+ "DPP: CSR does not include challengePassword");
goto fail;
}
-
- res = ASN1_TYPE_get(type);
/* This is supposed to be UTF8String, but allow other strings as well
* since challengePassword is using ASCII (base64 encoded). */
- if (res != V_ASN1_UTF8STRING && res != V_ASN1_PRINTABLESTRING &&
- res != V_ASN1_IA5STRING) {
+ if (attr_type != ASN1_TAG_UTF8STRING &&
+ attr_type != ASN1_TAG_PRINTABLESTRING &&
+ attr_type != ASN1_TAG_IA5STRING) {
wpa_printf(MSG_DEBUG,
"DPP: Unexpected challengePassword attribute type %d",
- res);
- goto fail;
- }
-
- str = X509_ATTRIBUTE_get0_data(attr, 0, res, NULL);
- if (!str) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not get ASN.1 string for challengePassword");
+ attr_type);
goto fail;
}
- res = ASN1_STRING_to_UTF8(&utf8, str);
- if (res < 0) {
- wpa_printf(MSG_DEBUG,
- "DPP: Could not get UTF8 version of challengePassword");
- goto fail;
- }
-
- cp = base64_decode((const char *) utf8, res, &cp_len);
- OPENSSL_free(utf8);
+ cp = base64_decode((const char *) attr, attr_len, &cp_len);
if (!cp) {
wpa_printf(MSG_DEBUG,
"DPP: Could not base64 decode challengePassword");
@@ -3001,7 +2170,7 @@ int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr)
ret = 0;
fail:
os_free(cp);
- X509_REQ_free(req);
+ crypto_csr_deinit(csr);
return ret;
}
@@ -3011,50 +2180,46 @@ struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
const u8 *pp_key,
size_t pp_key_len)
{
- const unsigned char *p;
- EVP_PKEY *csign = NULL, *ppkey = NULL;
+ struct crypto_ec_key *csign = NULL, *ppkey = NULL;
struct dpp_reconfig_id *id = NULL;
- BN_CTX *ctx = NULL;
- BIGNUM *bn = NULL, *q = NULL;
- const EC_KEY *eckey;
- const EC_GROUP *group;
- EC_POINT *e_id = NULL;
-
- p = csign_key;
- csign = d2i_PUBKEY(NULL, &p, csign_key_len);
+ struct crypto_ec *ec = NULL;
+ const struct crypto_bignum *q;
+ struct crypto_bignum *bn = NULL;
+ struct crypto_ec_point *e_id = NULL;
+ const struct crypto_ec_point *generator;
+
+ csign = crypto_ec_key_parse_pub(csign_key, csign_key_len);
if (!csign)
goto fail;
if (!pp_key)
goto fail;
- p = pp_key;
- ppkey = d2i_PUBKEY(NULL, &p, pp_key_len);
+ ppkey = crypto_ec_key_parse_pub(pp_key, pp_key_len);
if (!ppkey)
goto fail;
- eckey = EVP_PKEY_get0_EC_KEY(csign);
- if (!eckey)
- goto fail;
- group = EC_KEY_get0_group(eckey);
- if (!group)
+ ec = crypto_ec_init(crypto_ec_key_group(csign));
+ if (!ec)
goto fail;
- e_id = EC_POINT_new(group);
- ctx = BN_CTX_new();
- bn = BN_new();
- q = BN_new();
- if (!e_id || !ctx || !bn || !q ||
- !EC_GROUP_get_order(group, q, ctx) ||
- !BN_rand_range(bn, q) ||
- !EC_POINT_mul(group, e_id, bn, NULL, NULL, ctx))
+ e_id = crypto_ec_point_init(ec);
+ bn = crypto_bignum_init();
+ q = crypto_ec_get_order(ec);
+ generator = crypto_ec_get_generator(ec);
+ if (!e_id || !bn || !q || !generator ||
+ crypto_bignum_rand(bn, q) ||
+ crypto_ec_point_mul(ec, generator, bn, e_id))
goto fail;
- dpp_debug_print_point("DPP: Generated random point E-id", group, e_id);
+ crypto_ec_point_debug_print(ec, e_id,
+ "DPP: Generated random point E-id");
id = os_zalloc(sizeof(*id));
if (!id)
goto fail;
- id->group = group;
+
+ id->ec = ec;
+ ec = NULL;
id->e_id = e_id;
e_id = NULL;
id->csign = csign;
@@ -3062,93 +2227,58 @@ struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
id->pp_key = ppkey;
ppkey = NULL;
fail:
- EC_POINT_free(e_id);
- EVP_PKEY_free(csign);
- EVP_PKEY_free(ppkey);
- BN_clear_free(bn);
- BN_CTX_free(ctx);
+ crypto_ec_point_deinit(e_id, 1);
+ crypto_ec_key_deinit(csign);
+ crypto_ec_key_deinit(ppkey);
+ crypto_bignum_deinit(bn, 1);
+ crypto_ec_deinit(ec);
return id;
}
-static EVP_PKEY * dpp_pkey_from_point(const EC_GROUP *group,
- const EC_POINT *point)
-{
- EC_KEY *eckey;
- EVP_PKEY *pkey = NULL;
-
- eckey = EC_KEY_new();
- if (!eckey ||
- EC_KEY_set_group(eckey, group) != 1 ||
- EC_KEY_set_public_key(eckey, point) != 1) {
- wpa_printf(MSG_ERROR,
- "DPP: Failed to set EC_KEY: %s",
- ERR_error_string(ERR_get_error(), NULL));
- goto fail;
- }
- EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
-
- pkey = EVP_PKEY_new();
- if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) {
- wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY");
- EVP_PKEY_free(pkey);
- pkey = NULL;
- goto fail;
- }
-
-fail:
- EC_KEY_free(eckey);
- return pkey;
-}
-
-
int dpp_update_reconfig_id(struct dpp_reconfig_id *id)
{
- BN_CTX *ctx = NULL;
- BIGNUM *bn = NULL, *q = NULL;
- EC_POINT *e_prime_id = NULL, *a_nonce = NULL;
+ const struct crypto_bignum *q;
+ struct crypto_bignum *bn;
+ const struct crypto_ec_point *pp, *generator;
+ struct crypto_ec_point *e_prime_id, *a_nonce;
int ret = -1;
- const EC_KEY *pp;
- const EC_POINT *pp_point;
-
- pp = EVP_PKEY_get0_EC_KEY(id->pp_key);
- if (!pp)
- goto fail;
- pp_point = EC_KEY_get0_public_key(pp);
- e_prime_id = EC_POINT_new(id->group);
- a_nonce = EC_POINT_new(id->group);
- ctx = BN_CTX_new();
- bn = BN_new();
- q = BN_new();
+
+ pp = crypto_ec_key_get_public_key(id->pp_key);
+ e_prime_id = crypto_ec_point_init(id->ec);
+ a_nonce = crypto_ec_point_init(id->ec);
+ bn = crypto_bignum_init();
+ q = crypto_ec_get_order(id->ec);
+ generator = crypto_ec_get_generator(id->ec);
+
/* Generate random 0 <= a-nonce < q
* A-NONCE = a-nonce * G
* E'-id = E-id + a-nonce * P_pk */
- if (!pp_point || !e_prime_id || !a_nonce || !ctx || !bn || !q ||
- !EC_GROUP_get_order(id->group, q, ctx) ||
- !BN_rand_range(bn, q) || /* bn = a-nonce */
- !EC_POINT_mul(id->group, a_nonce, bn, NULL, NULL, ctx) ||
- !EC_POINT_mul(id->group, e_prime_id, NULL, pp_point, bn, ctx) ||
- !EC_POINT_add(id->group, e_prime_id, id->e_id, e_prime_id, ctx))
- goto fail;
-
- dpp_debug_print_point("DPP: Generated A-NONCE", id->group, a_nonce);
- dpp_debug_print_point("DPP: Encrypted E-id to E'-id",
- id->group, e_prime_id);
-
- EVP_PKEY_free(id->a_nonce);
- EVP_PKEY_free(id->e_prime_id);
- id->a_nonce = dpp_pkey_from_point(id->group, a_nonce);
- id->e_prime_id = dpp_pkey_from_point(id->group, e_prime_id);
+ if (!pp || !e_prime_id || !a_nonce || !bn || !q || !generator ||
+ crypto_bignum_rand(bn, q) || /* bn = a-nonce */
+ crypto_ec_point_mul(id->ec, generator, bn, a_nonce) ||
+ crypto_ec_point_mul(id->ec, pp, bn, e_prime_id) ||
+ crypto_ec_point_add(id->ec, id->e_id, e_prime_id, e_prime_id))
+ goto fail;
+
+ crypto_ec_point_debug_print(id->ec, a_nonce,
+ "DPP: Generated A-NONCE");
+ crypto_ec_point_debug_print(id->ec, e_prime_id,
+ "DPP: Encrypted E-id to E'-id");
+
+ crypto_ec_key_deinit(id->a_nonce);
+ crypto_ec_key_deinit(id->e_prime_id);
+ id->a_nonce = crypto_ec_key_set_pub_point(id->ec, a_nonce);
+ id->e_prime_id = crypto_ec_key_set_pub_point(id->ec, e_prime_id);
if (!id->a_nonce || !id->e_prime_id)
goto fail;
ret = 0;
fail:
- EC_POINT_free(e_prime_id);
- EC_POINT_free(a_nonce);
- BN_clear_free(bn);
- BN_CTX_free(ctx);
+ crypto_ec_point_deinit(e_prime_id, 1);
+ crypto_ec_point_deinit(a_nonce, 1);
+ crypto_bignum_deinit(bn, 1);
return ret;
}
@@ -3156,55 +2286,50 @@ fail:
void dpp_free_reconfig_id(struct dpp_reconfig_id *id)
{
if (id) {
- EC_POINT_clear_free(id->e_id);
- EVP_PKEY_free(id->csign);
- EVP_PKEY_free(id->a_nonce);
- EVP_PKEY_free(id->e_prime_id);
- EVP_PKEY_free(id->pp_key);
+ crypto_ec_point_deinit(id->e_id, 1);
+ crypto_ec_key_deinit(id->csign);
+ crypto_ec_key_deinit(id->a_nonce);
+ crypto_ec_key_deinit(id->e_prime_id);
+ crypto_ec_key_deinit(id->pp_key);
+ crypto_ec_deinit(id->ec);
os_free(id);
}
}
-EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
- EVP_PKEY *e_prime_id)
+struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
+ struct crypto_ec_key *a_nonce,
+ struct crypto_ec_key *e_prime_id)
{
- const EC_KEY *pp_ec, *a_nonce_ec, *e_prime_id_ec;
- const BIGNUM *pp_bn;
- const EC_GROUP *group;
- EC_POINT *e_id = NULL;
- const EC_POINT *a_nonce_point, *e_prime_id_point;
- BN_CTX *ctx = NULL;
+ struct crypto_ec *ec;
+ const struct crypto_bignum *pp;
+ struct crypto_ec_point *e_id = NULL;
+ const struct crypto_ec_point *a_nonce_point, *e_prime_id_point;
if (!ppkey)
return NULL;
/* E-id = E'-id - s_C * A-NONCE */
- pp_ec = EVP_PKEY_get0_EC_KEY(ppkey);
- a_nonce_ec = EVP_PKEY_get0_EC_KEY(a_nonce);
- e_prime_id_ec = EVP_PKEY_get0_EC_KEY(e_prime_id);
- if (!pp_ec || !a_nonce_ec || !e_prime_id_ec)
+ ec = crypto_ec_init(crypto_ec_key_group(ppkey));
+ if (!ec)
return NULL;
- pp_bn = EC_KEY_get0_private_key(pp_ec);
- group = EC_KEY_get0_group(pp_ec);
- a_nonce_point = EC_KEY_get0_public_key(a_nonce_ec);
- e_prime_id_point = EC_KEY_get0_public_key(e_prime_id_ec);
- ctx = BN_CTX_new();
- if (!pp_bn || !group || !a_nonce_point || !e_prime_id_point || !ctx)
- goto fail;
- e_id = EC_POINT_new(group);
- if (!e_id ||
- !EC_POINT_mul(group, e_id, NULL, a_nonce_point, pp_bn, ctx) ||
- !EC_POINT_invert(group, e_id, ctx) ||
- !EC_POINT_add(group, e_id, e_prime_id_point, e_id, ctx)) {
- EC_POINT_clear_free(e_id);
+
+ pp = crypto_ec_key_get_private_key(ppkey);
+ a_nonce_point = crypto_ec_key_get_public_key(a_nonce);
+ e_prime_id_point = crypto_ec_key_get_public_key(e_prime_id);
+ e_id = crypto_ec_point_init(ec);
+ if (!pp || !a_nonce_point || !e_prime_id_point || !e_id ||
+ crypto_ec_point_mul(ec, a_nonce_point, pp, e_id) ||
+ crypto_ec_point_invert(ec, e_id) ||
+ crypto_ec_point_add(ec, e_id, e_prime_id_point, e_id)) {
+ crypto_ec_point_deinit(e_id, 1);
goto fail;
}
- dpp_debug_print_point("DPP: Decrypted E-id", group, e_id);
+ crypto_ec_point_debug_print(ec, e_id, "DPP: Decrypted E-id");
fail:
- BN_CTX_free(ctx);
+ crypto_ec_deinit(ec);
return e_id;
}
@@ -3216,64 +2341,46 @@ fail:
int dpp_test_gen_invalid_key(struct wpabuf *msg,
const struct dpp_curve_params *curve)
{
- BN_CTX *ctx;
- BIGNUM *x, *y;
+ struct crypto_ec *ec;
+ struct crypto_ec_key *key = NULL;
+ const struct crypto_ec_point *pub_key;
+ struct crypto_ec_point *p = NULL;
+ u8 *x, *y;
int ret = -1;
- EC_GROUP *group;
- EC_POINT *point;
- group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name));
- if (!group)
- return -1;
-
- ctx = BN_CTX_new();
- point = EC_POINT_new(group);
- x = BN_new();
- y = BN_new();
- if (!ctx || !point || !x || !y)
+ ec = crypto_ec_init(curve->ike_group);
+ x = wpabuf_put(msg, curve->prime_len);
+ y = wpabuf_put(msg, curve->prime_len);
+ if (!ec)
goto fail;
- if (BN_rand(x, curve->prime_len * 8, 0, 0) != 1)
+retry:
+ /* Generate valid key pair */
+ key = crypto_ec_key_gen(curve->ike_group);
+ if (!key)
goto fail;
- /* Generate a random y coordinate that results in a point that is not
- * on the curve. */
- for (;;) {
- if (BN_rand(y, curve->prime_len * 8, 0, 0) != 1)
- goto fail;
+ /* Retrieve public key coordinates */
+ pub_key = crypto_ec_key_get_public_key(key);
+ if (!pub_key)
+ goto fail;
- if (EC_POINT_set_affine_coordinates_GFp(group, point, x, y,
- ctx) != 1) {
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(OPENSSL_IS_BORINGSSL)
- /* Unlike older OpenSSL versions, OpenSSL 1.1.1 and BoringSSL
- * return an error from EC_POINT_set_affine_coordinates_GFp()
- * when the point is not on the curve. */
- break;
-#else /* >=1.1.0 or OPENSSL_IS_BORINGSSL */
- goto fail;
-#endif /* >= 1.1.0 or OPENSSL_IS_BORINGSSL */
- }
+ crypto_ec_point_to_bin(ec, pub_key, x, y);
- if (!EC_POINT_is_on_curve(group, point, ctx))
- break;
+ /* And corrupt them */
+ y[curve->prime_len - 1] ^= 0x01;
+ p = crypto_ec_point_from_bin(ec, x);
+ if (p && crypto_ec_point_is_on_curve(ec, p)) {
+ crypto_ec_point_deinit(p, 0);
+ p = NULL;
+ goto retry;
}
- if (dpp_bn2bin_pad(x, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0 ||
- dpp_bn2bin_pad(y, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0)
- goto fail;
-
ret = 0;
fail:
- if (ret < 0)
- wpa_printf(MSG_INFO, "DPP: Failed to generate invalid key");
- BN_free(x);
- BN_free(y);
- EC_POINT_free(point);
- BN_CTX_free(ctx);
- EC_GROUP_free(group);
-
+ crypto_ec_point_deinit(p, 0);
+ crypto_ec_key_deinit(key);
+ crypto_ec_deinit(ec);
return ret;
}
diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h
index af12467a5d92..087878a508cb 100644
--- a/src/common/dpp_i.h
+++ b/src/common/dpp_i.h
@@ -37,10 +37,11 @@ struct wpabuf * dpp_build_conn_status(enum dpp_status_error result,
struct json_token * dpp_parse_own_connector(const char *own_connector);
int dpp_connector_match_groups(struct json_token *own_root,
struct json_token *peer_root, bool reconfig);
-int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key,
- const char *kid, const struct dpp_curve_params *curve);
-EVP_PKEY * dpp_parse_jwk(struct json_token *jwk,
- const struct dpp_curve_params **key_curve);
+int dpp_build_jwk(struct wpabuf *buf, const char *name,
+ struct crypto_ec_key *key, const char *kid,
+ const struct dpp_curve_params *curve);
+struct crypto_ec_key * dpp_parse_jwk(struct json_token *jwk,
+ const struct dpp_curve_params **key_curve);
int dpp_prepare_channel_list(struct dpp_authentication *auth,
unsigned int neg_freq,
struct hostapd_hw_modes *own_modes, u16 num_modes);
@@ -65,32 +66,27 @@ struct dpp_signed_connector_info {
enum dpp_status_error
dpp_process_signed_connector(struct dpp_signed_connector_info *info,
- EVP_PKEY *csign_pub, const char *connector);
+ struct crypto_ec_key *csign_pub,
+ const char *connector);
enum dpp_status_error
dpp_check_signed_connector(struct dpp_signed_connector_info *info,
const u8 *csign_key, size_t csign_key_len,
const u8 *peer_connector, size_t peer_connector_len);
const struct dpp_curve_params * dpp_get_curve_name(const char *name);
const struct dpp_curve_params * dpp_get_curve_jwk_crv(const char *name);
-const struct dpp_curve_params * dpp_get_curve_nid(int nid);
const struct dpp_curve_params * dpp_get_curve_ike_group(u16 group);
int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi,
const u8 *data, size_t data_len);
-struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix);
-EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group,
- const u8 *buf_x, const u8 *buf_y,
- size_t len);
-EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len);
-int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len);
+struct crypto_ec_key * dpp_set_pubkey_point(struct crypto_ec_key *group_key,
+ const u8 *buf, size_t len);
int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len,
const char *label, u8 *out, size_t outlen);
int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
-int dpp_ecdh(EVP_PKEY *own, EVP_PKEY *peer, u8 *secret, size_t *secret_len);
-void dpp_debug_print_point(const char *title, const EC_GROUP *group,
- const EC_POINT *point);
-void dpp_debug_print_key(const char *title, EVP_PKEY *key);
+int dpp_ecdh(struct crypto_ec_key *own, struct crypto_ec_key *peer,
+ u8 *secret, size_t *secret_len);
+void dpp_debug_print_key(const char *title, struct crypto_ec_key *key);
int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len,
const u8 *salt, size_t salt_len, unsigned int iterations,
u8 *buf, size_t buflen);
@@ -99,9 +95,9 @@ int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi,
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
const u8 *privkey, size_t privkey_len);
-EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
- const u8 *privkey, size_t privkey_len);
-EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve);
+struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve,
+ const u8 *privkey, size_t privkey_len);
+struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve);
int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len);
int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len);
int dpp_derive_bk_ke(struct dpp_authentication *auth);
@@ -111,15 +107,16 @@ int dpp_auth_derive_l_responder(struct dpp_authentication *auth);
int dpp_auth_derive_l_initiator(struct dpp_authentication *auth);
int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, unsigned int hash_len);
int dpp_derive_pmkid(const struct dpp_curve_params *curve,
- EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid);
-EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve,
- const u8 *mac_init, const char *code,
- const char *identifier, BN_CTX *bnctx,
- EC_GROUP **ret_group);
-EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve,
- const u8 *mac_resp, const char *code,
- const char *identifier, BN_CTX *bnctx,
- EC_GROUP **ret_group);
+ struct crypto_ec_key *own_key,
+ struct crypto_ec_key *peer_key, u8 *pmkid);
+struct crypto_ec_point *
+dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
+ const char *code, const char *identifier,
+ struct crypto_ec **ret_ec);
+struct crypto_ec_point *
+dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
+ const char *code, const char *identifier,
+ struct crypto_ec **ret_ec);
int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
const u8 *Mx, size_t Mx_len,
const u8 *Nx, size_t Nx_len,
@@ -133,20 +130,21 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth,
int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth,
const u8 *r_proto, u16 r_proto_len,
struct json_token *net_access_key);
-EC_POINT * dpp_decrypt_e_id(EVP_PKEY *ppkey, EVP_PKEY *a_nonce,
- EVP_PKEY *e_prime_id);
+struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
+ struct crypto_ec_key *a_nonce,
+ struct crypto_ec_key *e_prime_id);
char * dpp_sign_connector(struct dpp_configurator *conf,
const struct wpabuf *dppcon);
int dpp_test_gen_invalid_key(struct wpabuf *msg,
const struct dpp_curve_params *curve);
struct dpp_reconfig_id {
- const EC_GROUP *group;
- EC_POINT *e_id; /* E-id */
- EVP_PKEY *csign;
- EVP_PKEY *a_nonce; /* A-NONCE */
- EVP_PKEY *e_prime_id; /* E'-id */
- EVP_PKEY *pp_key;
+ struct crypto_ec *ec;
+ struct crypto_ec_point *e_id; /* E-id */
+ struct crypto_ec_key *csign;
+ struct crypto_ec_key *a_nonce; /* A-NONCE */
+ struct crypto_ec_key *e_prime_id; /* E'-id */
+ struct crypto_ec_key *pp_key;
};
/* dpp_tcp.c */
diff --git a/src/common/dpp_pkex.c b/src/common/dpp_pkex.c
index 807ab7d0a1ce..06532b5457bd 100644
--- a/src/common/dpp_pkex.c
+++ b/src/common/dpp_pkex.c
@@ -8,8 +8,6 @@
*/
#include "utils/includes.h"
-#include <openssl/opensslv.h>
-#include <openssl/err.h>
#include "utils/common.h"
#include "common/wpa_ctrl.h"
@@ -27,30 +25,13 @@ u8 dpp_pkex_ephemeral_key_override[600];
size_t dpp_pkex_ephemeral_key_override_len = 0;
#endif /* CONFIG_TESTING_OPTIONS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-/* Compatibility wrappers for older versions. */
-
-static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
-{
- if (pkey->type != EVP_PKEY_EC)
- return NULL;
- return pkey->pkey.ec;
-}
-
-#endif
-
static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
{
- const EC_KEY *X_ec;
- const EC_POINT *X_point;
- BN_CTX *bnctx = NULL;
- EC_GROUP *group = NULL;
- EC_POINT *Qi = NULL, *M = NULL;
- struct wpabuf *M_buf = NULL;
- BIGNUM *Mx = NULL, *My = NULL;
+ struct crypto_ec *ec = NULL;
+ const struct crypto_ec_point *X;
+ struct crypto_ec_point *Qi = NULL, *M = NULL;
+ u8 *Mx, *My;
struct wpabuf *msg = NULL;
size_t attr_len;
const struct dpp_curve_params *curve = pkex->own_bi->curve;
@@ -58,11 +39,8 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
- bnctx = BN_CTX_new();
- if (!bnctx)
- goto fail;
Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
- pkex->identifier, bnctx, &group);
+ pkex->identifier, &ec);
if (!Qi)
goto fail;
@@ -86,21 +64,15 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
goto fail;
/* M = X + Qi */
- X_ec = EVP_PKEY_get0_EC_KEY(pkex->x);
- if (!X_ec)
+ X = crypto_ec_key_get_public_key(pkex->x);
+ M = crypto_ec_point_init(ec);
+ if (!X || !M)
goto fail;
- X_point = EC_KEY_get0_public_key(X_ec);
- if (!X_point)
- goto fail;
- dpp_debug_print_point("DPP: X", group, X_point);
- M = EC_POINT_new(group);
- Mx = BN_new();
- My = BN_new();
- if (!M || !Mx || !My ||
- EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1)
+ crypto_ec_point_debug_print(ec, X, "DPP: X");
+
+ if (crypto_ec_point_add(ec, X, Qi, M))
goto fail;
- dpp_debug_print_point("DPP: M", group, M);
+ crypto_ec_point_debug_print(ec, M, "DPP: M");
/* Initiator -> Responder: group, [identifier,] M */
attr_len = 4 + 2;
@@ -154,21 +126,17 @@ skip_finite_cyclic_group:
}
#endif /* CONFIG_TESTING_OPTIONS */
- if (dpp_bn2bin_pad(Mx, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0 ||
- dpp_bn2bin_pad(Mx, pkex->Mx, curve->prime_len) < 0 ||
- dpp_bn2bin_pad(My, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0)
+ Mx = wpabuf_put(msg, curve->prime_len);
+ My = wpabuf_put(msg, curve->prime_len);
+ if (crypto_ec_point_to_bin(ec, M, Mx, My))
goto fail;
+ os_memcpy(pkex->Mx, Mx, curve->prime_len);
+
out:
- wpabuf_free(M_buf);
- EC_POINT_free(M);
- EC_POINT_free(Qi);
- BN_clear_free(Mx);
- BN_clear_free(My);
- BN_CTX_free(bnctx);
- EC_GROUP_free(group);
+ crypto_ec_point_deinit(M, 1);
+ crypto_ec_point_deinit(Qi, 1);
+ crypto_ec_deinit(ec);
return msg;
fail:
wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request");
@@ -227,7 +195,7 @@ fail:
static struct wpabuf *
dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
enum dpp_status_error status,
- const BIGNUM *Nx, const BIGNUM *Ny)
+ const u8 *Nx, const u8 *Ny)
{
struct wpabuf *msg = NULL;
size_t attr_len;
@@ -291,12 +259,9 @@ skip_status:
}
#endif /* CONFIG_TESTING_OPTIONS */
- if (dpp_bn2bin_pad(Nx, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0 ||
- dpp_bn2bin_pad(Nx, pkex->Nx, curve->prime_len) < 0 ||
- dpp_bn2bin_pad(Ny, wpabuf_put(msg, curve->prime_len),
- curve->prime_len) < 0)
- goto fail;
+ wpabuf_put_data(msg, Nx, curve->prime_len);
+ wpabuf_put_data(msg, Ny, curve->prime_len);
+ os_memcpy(pkex->Nx, Nx, curve->prime_len);
skip_encrypted_key:
if (status == DPP_STATUS_BAD_GROUP) {
@@ -352,14 +317,11 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
const struct dpp_curve_params *curve = bi->curve;
u16 ike_group;
struct dpp_pkex *pkex = NULL;
- EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL;
- BN_CTX *bnctx = NULL;
- EC_GROUP *group = NULL;
- BIGNUM *Mx = NULL, *My = NULL;
- const EC_KEY *Y_ec;
- EC_KEY *X_ec = NULL;
- const EC_POINT *Y_point;
- BIGNUM *Nx = NULL, *Ny = NULL;
+ struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL,
+ *N = NULL;
+ struct crypto_ec *ec = NULL;
+ const struct crypto_ec_point *Y;
+ u8 *x_coord = NULL, *y_coord = NULL;
u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
size_t Kx_len;
int res;
@@ -424,34 +386,27 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
}
/* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
- bnctx = BN_CTX_new();
- if (!bnctx)
- goto fail;
- Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx,
- &group);
+ Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, &ec);
if (!Qi)
goto fail;
/* X' = M - Qi */
- X = EC_POINT_new(group);
- M = EC_POINT_new(group);
- Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
- My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
- if (!X || !M || !Mx || !My ||
- EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, M) ||
- !EC_POINT_is_on_curve(group, M, bnctx) ||
- EC_POINT_invert(group, Qi, bnctx) != 1 ||
- EC_POINT_add(group, X, M, Qi, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, X) ||
- !EC_POINT_is_on_curve(group, X, bnctx)) {
+ X = crypto_ec_point_init(ec);
+ M = crypto_ec_point_from_bin(ec, attr_key);
+ if (!X || !M ||
+ crypto_ec_point_is_at_infinity(ec, M) ||
+ !crypto_ec_point_is_on_curve(ec, M) ||
+ crypto_ec_point_invert(ec, Qi) ||
+ crypto_ec_point_add(ec, M, Qi, X) ||
+ crypto_ec_point_is_at_infinity(ec, X) ||
+ !crypto_ec_point_is_on_curve(ec, X)) {
wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
"Invalid Encrypted Key value");
bi->pkex_t++;
goto fail;
}
- dpp_debug_print_point("DPP: M", group, M);
- dpp_debug_print_point("DPP: X'", group, X);
+ crypto_ec_point_debug_print(ec, M, "DPP: M");
+ crypto_ec_point_debug_print(ec, X, "DPP: X'");
pkex = os_zalloc(sizeof(*pkex));
if (!pkex)
@@ -472,18 +427,19 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
os_memcpy(pkex->Mx, attr_key, attr_key_len / 2);
- X_ec = EC_KEY_new();
- if (!X_ec ||
- EC_KEY_set_group(X_ec, group) != 1 ||
- EC_KEY_set_public_key(X_ec, X) != 1)
+ x_coord = os_malloc(curve->prime_len);
+ y_coord = os_malloc(curve->prime_len);
+ if (!x_coord || !y_coord ||
+ crypto_ec_point_to_bin(ec, X, x_coord, y_coord))
goto fail;
- pkex->x = EVP_PKEY_new();
- if (!pkex->x ||
- EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1)
+
+ pkex->x = crypto_ec_key_set_pub(curve->ike_group, x_coord,
+ y_coord, crypto_ec_prime_len(ec));
+ if (!pkex->x)
goto fail;
/* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
- Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL);
+ Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, NULL);
if (!Qr)
goto fail;
@@ -507,24 +463,20 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
goto fail;
/* N = Y + Qr */
- Y_ec = EVP_PKEY_get0_EC_KEY(pkex->y);
- if (!Y_ec)
+ Y = crypto_ec_key_get_public_key(pkex->y);
+ if (!Y)
goto fail;
- Y_point = EC_KEY_get0_public_key(Y_ec);
- if (!Y_point)
- goto fail;
- dpp_debug_print_point("DPP: Y", group, Y_point);
- N = EC_POINT_new(group);
- Nx = BN_new();
- Ny = BN_new();
- if (!N || !Nx || !Ny ||
- EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 ||
- EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1)
+ crypto_ec_point_debug_print(ec, Y, "DPP: Y");
+
+ N = crypto_ec_point_init(ec);
+ if (!N ||
+ crypto_ec_point_add(ec, Y, Qr, N) ||
+ crypto_ec_point_to_bin(ec, N, x_coord, y_coord))
goto fail;
- dpp_debug_print_point("DPP: N", group, N);
+ crypto_ec_point_debug_print(ec, N, "DPP: N");
pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK,
- Nx, Ny);
+ x_coord, y_coord);
if (!pkex->exchange_resp)
goto fail;
@@ -548,18 +500,14 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
pkex->exchange_done = 1;
out:
- BN_CTX_free(bnctx);
- EC_POINT_free(Qi);
- EC_POINT_free(Qr);
- BN_free(Mx);
- BN_free(My);
- BN_free(Nx);
- BN_free(Ny);
- EC_POINT_free(M);
- EC_POINT_free(N);
- EC_POINT_free(X);
- EC_KEY_free(X_ec);
- EC_GROUP_free(group);
+ os_free(x_coord);
+ os_free(y_coord);
+ crypto_ec_point_deinit(Qi, 1);
+ crypto_ec_point_deinit(Qr, 1);
+ crypto_ec_point_deinit(M, 1);
+ crypto_ec_point_deinit(N, 1);
+ crypto_ec_point_deinit(X, 1);
+ crypto_ec_deinit(ec);
return pkex;
fail:
wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed");
@@ -688,13 +636,11 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
{
const u8 *attr_status, *attr_id, *attr_key, *attr_group;
u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len;
- EC_GROUP *group = NULL;
- BN_CTX *bnctx = NULL;
+ struct crypto_ec *ec = NULL;
struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
const struct dpp_curve_params *curve = pkex->own_bi->curve;
- EC_POINT *Qr = NULL, *Y = NULL, *N = NULL;
- BIGNUM *Nx = NULL, *Ny = NULL;
- EC_KEY *Y_ec = NULL;
+ struct crypto_ec_point *Qr = NULL, *Y = NULL, *N = NULL;
+ u8 *x_coord = NULL, *y_coord = NULL;
size_t Jx_len, Kx_len;
u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
const u8 *addr[4];
@@ -765,45 +711,39 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
}
/* Qr = H(MAC-Responder | [identifier |] code) * Pr */
- bnctx = BN_CTX_new();
- if (!bnctx)
- goto fail;
Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
- pkex->identifier, bnctx, &group);
+ pkex->identifier, &ec);
if (!Qr)
goto fail;
/* Y' = N - Qr */
- Y = EC_POINT_new(group);
- N = EC_POINT_new(group);
- Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL);
- Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL);
- if (!Y || !N || !Nx || !Ny ||
- EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, N) ||
- !EC_POINT_is_on_curve(group, N, bnctx) ||
- EC_POINT_invert(group, Qr, bnctx) != 1 ||
- EC_POINT_add(group, Y, N, Qr, bnctx) != 1 ||
- EC_POINT_is_at_infinity(group, Y) ||
- !EC_POINT_is_on_curve(group, Y, bnctx)) {
+ Y = crypto_ec_point_init(ec);
+ N = crypto_ec_point_from_bin(ec, attr_key);
+ if (!Y || !N ||
+ crypto_ec_point_is_at_infinity(ec, N) ||
+ !crypto_ec_point_is_on_curve(ec, N) ||
+ crypto_ec_point_invert(ec, Qr) ||
+ crypto_ec_point_add(ec, N, Qr, Y) ||
+ crypto_ec_point_is_at_infinity(ec, Y) ||
+ !crypto_ec_point_is_on_curve(ec, Y)) {
dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
pkex->t++;
goto fail;
}
- dpp_debug_print_point("DPP: N", group, N);
- dpp_debug_print_point("DPP: Y'", group, Y);
+ crypto_ec_point_debug_print(ec, N, "DPP: N");
+ crypto_ec_point_debug_print(ec, Y, "DPP: Y'");
pkex->exchange_done = 1;
/* ECDH: J = a * Y' */
- Y_ec = EC_KEY_new();
- if (!Y_ec ||
- EC_KEY_set_group(Y_ec, group) != 1 ||
- EC_KEY_set_public_key(Y_ec, Y) != 1)
+ x_coord = os_malloc(curve->prime_len);
+ y_coord = os_malloc(curve->prime_len);
+ if (!x_coord || !y_coord ||
+ crypto_ec_point_to_bin(ec, Y, x_coord, y_coord))
goto fail;
- pkex->y = EVP_PKEY_new();
- if (!pkex->y ||
- EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1)
+ pkex->y = crypto_ec_key_set_pub(curve->ike_group, x_coord, y_coord,
+ curve->prime_len);
+ if (!pkex->y)
goto fail;
if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0)
goto fail;
@@ -812,9 +752,9 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
Jx, Jx_len);
/* u = HMAC(J.x, MAC-Initiator | A.x | Y'.x | X.x) */
- A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
- Y_pub = dpp_get_pubkey_point(pkex->y, 0);
- X_pub = dpp_get_pubkey_point(pkex->x, 0);
+ A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
+ Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
+ X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
if (!A_pub || !Y_pub || !X_pub)
goto fail;
addr[0] = pkex->own_mac;
@@ -855,14 +795,12 @@ out:
wpabuf_free(A_pub);
wpabuf_free(X_pub);
wpabuf_free(Y_pub);
- EC_POINT_free(Qr);
- EC_POINT_free(Y);
- EC_POINT_free(N);
- BN_free(Nx);
- BN_free(Ny);
- EC_KEY_free(Y_ec);
- BN_CTX_free(bnctx);
- EC_GROUP_free(group);
+ os_free(x_coord);
+ os_free(y_coord);
+ crypto_ec_point_deinit(Qr, 1);
+ crypto_ec_point_deinit(Y, 1);
+ crypto_ec_point_deinit(N, 1);
+ crypto_ec_deinit(ec);
return msg;
fail:
wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed");
@@ -1078,9 +1016,9 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
Jx, Jx_len);
/* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
- A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
- Y_pub = dpp_get_pubkey_point(pkex->y, 0);
- X_pub = dpp_get_pubkey_point(pkex->x, 0);
+ A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
+ Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
+ X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
if (!A_pub || !Y_pub || !X_pub)
goto fail;
addr[0] = pkex->peer_mac;
@@ -1115,7 +1053,7 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
Lx, Lx_len);
/* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
- B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0);
+ B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
if (!B_pub)
goto fail;
addr[0] = pkex->own_mac;
@@ -1240,9 +1178,9 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
Lx, Lx_len);
/* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
- B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0);
- X_pub = dpp_get_pubkey_point(pkex->x, 0);
- Y_pub = dpp_get_pubkey_point(pkex->y, 0);
+ B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
+ X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
+ Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
if (!B_pub || !X_pub || !Y_pub)
goto fail;
addr[0] = pkex->peer_mac;
@@ -1315,9 +1253,9 @@ void dpp_pkex_free(struct dpp_pkex *pkex)
os_free(pkex->identifier);
os_free(pkex->code);
- EVP_PKEY_free(pkex->x);
- EVP_PKEY_free(pkex->y);
- EVP_PKEY_free(pkex->peer_bootstrap_key);
+ crypto_ec_key_deinit(pkex->x);
+ crypto_ec_key_deinit(pkex->y);
+ crypto_ec_key_deinit(pkex->peer_bootstrap_key);
wpabuf_free(pkex->exchange_req);
wpabuf_free(pkex->exchange_resp);
os_free(pkex);
diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c
index c4a027363fce..7137bc5fdd43 100644
--- a/src/common/dpp_reconfig.c
+++ b/src/common/dpp_reconfig.c
@@ -7,8 +7,6 @@
*/
#include "utils/includes.h"
-#include <openssl/opensslv.h>
-#include <openssl/err.h>
#include "utils/common.h"
#include "utils/json.h"
@@ -40,8 +38,7 @@ struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
struct dpp_reconfig_id *id)
{
struct wpabuf *msg = NULL;
- EVP_PKEY *csign = NULL;
- const unsigned char *p;
+ struct crypto_ec_key *csign = NULL;
struct wpabuf *uncomp;
u8 hash[SHA256_MAC_LEN];
const u8 *addr[1];
@@ -49,7 +46,7 @@ struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
int res;
size_t attr_len;
const struct dpp_curve_params *own_curve;
- EVP_PKEY *own_key;
+ struct crypto_ec_key *own_key;
struct wpabuf *a_nonce = NULL, *e_id = NULL;
wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame");
@@ -61,16 +58,15 @@ struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
goto fail;
}
- p = csign_key;
- csign = d2i_PUBKEY(NULL, &p, csign_key_len);
+ csign = crypto_ec_key_parse_pub(csign_key, csign_key_len);
if (!csign) {
wpa_printf(MSG_ERROR,
"DPP: Failed to parse local C-sign-key information");
goto fail;
}
- uncomp = dpp_get_pubkey_point(csign, 1);
- EVP_PKEY_free(csign);
+ uncomp = crypto_ec_key_get_pubkey_point(csign, 1);
+ crypto_ec_key_deinit(csign);
if (!uncomp)
goto fail;
addr[0] = wpabuf_head(uncomp);
@@ -88,8 +84,8 @@ struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
goto fail;
}
- a_nonce = dpp_get_pubkey_point(id->a_nonce, 0);
- e_id = dpp_get_pubkey_point(id->e_prime_id, 0);
+ a_nonce = crypto_ec_key_get_pubkey_point(id->a_nonce, 0);
+ e_id = crypto_ec_key_get_pubkey_point(id->e_prime_id, 0);
if (!a_nonce || !e_id)
goto fail;
@@ -126,7 +122,7 @@ struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key,
fail:
wpabuf_free(a_nonce);
wpabuf_free(e_id);
- EVP_PKEY_free(own_key);
+ crypto_ec_key_deinit(own_key);
return msg;
}
@@ -230,8 +226,8 @@ dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
{
struct dpp_authentication *auth;
const struct dpp_curve_params *curve;
- EVP_PKEY *a_nonce, *e_prime_id;
- EC_POINT *e_id;
+ struct crypto_ec_key *a_nonce, *e_prime_id;
+ struct crypto_ec_point *e_id;
curve = dpp_get_curve_ike_group(group);
if (!curve) {
@@ -260,13 +256,13 @@ dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
e_prime_id = dpp_set_pubkey_point(conf->csign, e_id_attr, e_id_len);
if (!e_prime_id) {
wpa_printf(MSG_INFO, "DPP: Invalid E'-id");
- EVP_PKEY_free(a_nonce);
+ crypto_ec_key_deinit(a_nonce);
return NULL;
}
dpp_debug_print_key("E'-id", e_prime_id);
e_id = dpp_decrypt_e_id(conf->pp_key, a_nonce, e_prime_id);
- EVP_PKEY_free(a_nonce);
- EVP_PKEY_free(e_prime_id);
+ crypto_ec_key_deinit(a_nonce);
+ crypto_ec_key_deinit(e_prime_id);
if (!e_id) {
wpa_printf(MSG_INFO, "DPP: Could not decrypt E'-id");
return NULL;
@@ -275,7 +271,7 @@ dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx,
* Enrollee has already been started and is waiting for updated
* configuration instead of replying again before such configuration
* becomes available */
- EC_POINT_clear_free(e_id);
+ crypto_ec_point_deinit(e_id, 1);
auth = dpp_alloc_auth(dpp, msg_ctx);
if (!auth)
@@ -341,7 +337,7 @@ static int dpp_reconfig_build_resp(struct dpp_authentication *auth,
wpabuf_put_le16(clear, wpabuf_len(conn_status));
wpabuf_put_buf(clear, conn_status);
- pr = dpp_get_pubkey_point(auth->own_protocol_key, 0);
+ pr = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
if (!pr)
goto fail;
diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c
index c373f107791c..fb8ef1c5bfaf 100644
--- a/src/common/dpp_tcp.c
+++ b/src/common/dpp_tcp.c
@@ -671,10 +671,8 @@ static int dpp_controller_rx_auth_req(struct dpp_connection *conn,
}
if (dpp_set_configurator(conn->auth,
- conn->ctrl->configurator_params) < 0) {
- dpp_connection_remove(conn);
+ conn->ctrl->configurator_params) < 0)
return -1;
- }
return dpp_tcp_send_msg(conn, conn->auth->resp_msg);
}
@@ -700,7 +698,6 @@ static int dpp_controller_rx_auth_resp(struct dpp_connection *conn,
return 0;
}
wpa_printf(MSG_DEBUG, "DPP: No confirm generated");
- dpp_connection_remove(conn);
return -1;
}
@@ -862,7 +859,6 @@ static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn,
return -1;
if (dpp_set_configurator(auth, conn->ctrl->configurator_params) < 0) {
dpp_auth_deinit(auth);
- dpp_connection_remove(conn);
return -1;
}
@@ -1723,6 +1719,13 @@ void dpp_controller_stop(struct dpp_global *dpp)
}
+void dpp_controller_stop_for_ctx(struct dpp_global *dpp, void *cb_ctx)
+{
+ if (dpp && dpp->controller && dpp->controller->cb_ctx == cb_ctx)
+ dpp_controller_stop(dpp);
+}
+
+
static bool dpp_tcp_peer_id_match(struct dpp_authentication *auth,
unsigned int id)
{
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index ad2aebfef5b5..e7ac3b2aac6b 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -114,7 +114,7 @@ int allowed_ht40_channel_pair(enum hostapd_hw_mode mode,
{
int ok, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
- 149, 157, 165, 184, 192 };
+ 149, 157, 165, 173, 184, 192 };
size_t k;
int ht40_plus, pri_chan, sec_chan;
@@ -405,7 +405,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
int center_segment1, u32 vht_caps,
struct he_capabilities *he_cap)
{
- if (!he_cap)
+ if (!he_cap || !he_cap->he_supported)
he_enabled = 0;
os_memset(data, 0, sizeof(*data));
data->mode = mode;
@@ -417,7 +417,16 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
data->sec_channel_offset = sec_channel_offset;
data->center_freq1 = freq + sec_channel_offset * 10;
data->center_freq2 = 0;
- data->bandwidth = sec_channel_offset ? 40 : 20;
+ if (oper_chwidth == CHANWIDTH_80MHZ)
+ data->bandwidth = 80;
+ else if (oper_chwidth == CHANWIDTH_160MHZ ||
+ oper_chwidth == CHANWIDTH_80P80MHZ)
+ data->bandwidth = 160;
+ else if (sec_channel_offset)
+ data->bandwidth = 40;
+ else
+ data->bandwidth = 20;
+
hostapd_encode_edmg_chan(enable_edmg, edmg_channel, channel,
&data->edmg);
@@ -441,9 +450,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
"Segment 0 center frequency isn't set");
return -1;
}
-
- data->center_freq1 = data->freq;
- data->bandwidth = 20;
+ if (!sec_channel_offset)
+ data->center_freq1 = data->freq;
} else {
int freq1, freq2 = 0;
int bw = center_idx_to_bw_6ghz(center_segment0);
@@ -491,7 +499,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
if (data->he_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
- if (mode == HOSTAPD_MODE_IEEE80211G && sec_channel_offset) {
+ if (sec_channel_offset == 0)
+ break;
+
+ if (mode == HOSTAPD_MODE_IEEE80211G) {
if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) {
wpa_printf(MSG_ERROR,
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 3e5cfb01d565..5b74ddcdf62b 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1011,8 +1011,8 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211A;
}
- /* 5 GHz, channels 100..140 */
- if (freq >= 5000 && freq <= 5700) {
+ /* 5 GHz, channels 100..144 */
+ if (freq >= 5500 && freq <= 5720) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
@@ -1531,6 +1531,16 @@ int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
}
+/*
+ * 802.11-2020: Table E-4 - Global operating classes
+ * DFS_50_100_Behavior: 118, 119, 120, 121, 122, 123
+ */
+int is_dfs_global_op_class(u8 op_class)
+{
+ return (op_class >= 118) && (op_class <= 123);
+}
+
+
static int is_11b(u8 rate)
{
return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
@@ -1895,9 +1905,9 @@ const struct oper_class_map global_op_class[] = {
{ 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, P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, NO_P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, NO_P2P_SUPP },
- { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, NO_P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 134, 1, 233, 32, BW160, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP },
@@ -2293,6 +2303,30 @@ bool is_6ghz_psc_frequency(int freq)
}
+/**
+ * get_6ghz_sec_channel - Get the relative position of the secondary channel
+ * to the primary channel in 6 GHz
+ * @channel: Primary channel to be checked for (in global op class 131)
+ * Returns: 1 = secondary channel above, -1 = secondary channel below
+ */
+
+int get_6ghz_sec_channel(int channel)
+{
+ /*
+ * In the 6 GHz band, primary channels are numbered as 1, 5, 9, 13.., so
+ * the 40 MHz channels are formed with the channel pairs as (1,5),
+ * (9,13), (17,21)..
+ * The secondary channel for a given primary channel is below the
+ * primary channel for the channels 5, 13, 21.. and it is above the
+ * primary channel for the channels 1, 9, 17..
+ */
+
+ if (((channel - 1) / 4) % 2)
+ return -1;
+ return 1;
+}
+
+
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len)
{
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index fe2b1bca601b..e4e4c613e9c6 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -218,6 +218,7 @@ int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
int sec_channel, u8 *op_class, u8 *channel);
int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
u16 num_modes);
+int is_dfs_global_op_class(u8 op_class);
enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
int supp_rates_11b_only(struct ieee802_11_elems *elems);
@@ -264,6 +265,7 @@ int center_idx_to_bw_6ghz(u8 idx);
bool is_6ghz_freq(int freq);
bool is_6ghz_op_class(u8 op_class);
bool is_6ghz_psc_frequency(int freq);
+int get_6ghz_sec_channel(int channel);
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 519a13b1d064..928b53500c5c 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1337,6 +1337,7 @@ struct ieee80211_ampe_ie {
#define CHANWIDTH_4320MHZ 5
#define CHANWIDTH_6480MHZ 6
#define CHANWIDTH_8640MHZ 7
+#define CHANWIDTH_40MHZ_6GHZ 8
#define HE_NSS_MAX_STREAMS 8
@@ -1360,6 +1361,10 @@ struct ieee80211_ampe_ie {
#define DPP_CC_OUI_TYPE 0x1e
#define SAE_PK_IE_VENDOR_TYPE 0x506f9a1f
#define SAE_PK_OUI_TYPE 0x1f
+#define QM_IE_VENDOR_TYPE 0x506f9a22
+#define QM_IE_OUI_TYPE 0x22
+#define WFA_CAPA_IE_VENDOR_TYPE 0x506f9a23
+#define WFA_CAPA_OUI_TYPE 0x23
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_TEAR_DOWN BIT(4)
@@ -2341,6 +2346,26 @@ struct ieee80211_he_mu_edca_parameter_set {
/* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
#define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
+/*
+ * IEEE Std 802.11-2020 and IEEE Std 802.11ax-2021
+ * 9.4.2.170 Reduced Neighbor Report element
+ */
+#define RNR_HEADER_LEN 2
+#define RNR_TBTT_HEADER_LEN 4
+#define RNR_TBTT_INFO_COUNT(x) (((x) & 0xf) << 4)
+#define RNR_TBTT_INFO_COUNT_MAX 16
+#define RNR_TBTT_INFO_LEN 13
+#define RNR_NEIGHBOR_AP_OFFSET_UNKNOWN 255
+/* Figure 9-632a - BSS Parameters subfield format */
+#define RNR_BSS_PARAM_OCT_RECOMMENDED BIT(0)
+#define RNR_BSS_PARAM_SAME_SSID BIT(1)
+#define RNR_BSS_PARAM_MULTIPLE_BSSID BIT(2)
+#define RNR_BSS_PARAM_TRANSMITTED_BSSID BIT(3)
+#define RNR_BSS_PARAM_MEMBER_CO_LOCATED_ESS BIT(4)
+#define RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE BIT(5)
+#define RNR_BSS_PARAM_CO_LOCATED BIT(6)
+#define RNR_20_MHZ_PSD_MAX_TXPOWER 255 /* dBm */
+
/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
@@ -2445,4 +2470,35 @@ enum mscs_description_subelem {
*/
#define FD_MAX_INTERVAL_6GHZ 20 /* TUs */
+/* Protected Vendor-specific QoS Management Action frame identifiers - WFA */
+#define QM_ACTION_VENDOR_TYPE 0x506f9a1a
+#define QM_ACTION_OUI_TYPE 0x1a
+
+/* QoS Management Action frame OUI subtypes */
+#define QM_DSCP_POLICY_QUERY 0
+#define QM_DSCP_POLICY_REQ 1
+#define QM_DSCP_POLICY_RESP 2
+
+/* QoS Management attributes */
+enum qm_attr_id {
+ QM_ATTR_PORT_RANGE = 1,
+ QM_ATTR_DSCP_POLICY = 2,
+ QM_ATTR_TCLAS = 3,
+ QM_ATTR_DOMAIN_NAME = 4,
+};
+
+/* DSCP Policy attribute - Request Type */
+enum dscp_policy_request_type {
+ DSCP_POLICY_REQ_ADD = 0, /* ADD/UPDATE */
+ DSCP_POLICY_REQ_REMOVE = 1,
+};
+
+/* Request/Response Control field of DSCP Policy Request/Response frame */
+#define DSCP_POLICY_CTRL_MORE BIT(0)
+#define DSCP_POLICY_CTRL_RESET BIT(1)
+
+/* Wi-Fi Alliance Capabilities element - Capabilities field */
+#define WFA_CAPA_QM_DSCP_POLICY BIT(0)
+#define WFA_CAPA_QM_UNSOLIC_DSCP BIT(1)
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/ptksa_cache.c b/src/common/ptksa_cache.c
index 6a053d65019d..8fcb135077f2 100644
--- a/src/common/ptksa_cache.c
+++ b/src/common/ptksa_cache.c
@@ -269,7 +269,7 @@ struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
u32 life_time,
const struct wpa_ptk *ptk)
{
- struct ptksa_cache_entry *entry, *tmp;
+ struct ptksa_cache_entry *entry, *tmp, *tmp2 = NULL;
struct os_reltime now;
if (!ptksa || !ptk || !addr || !life_time || cipher == WPA_CIPHER_NONE)
@@ -296,21 +296,21 @@ struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa,
entry->expiration = now.sec + life_time;
dl_list_for_each(tmp, &ptksa->ptksa, struct ptksa_cache_entry, list) {
- if (tmp->expiration > entry->expiration)
+ if (tmp->expiration > entry->expiration) {
+ tmp2 = tmp;
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;
+ * If the expiration is later then all other or the list is empty
+ * 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);
+ if (tmp2)
+ dl_list_add(&tmp2->list, &entry->list);
else
- dl_list_add_tail(&tmp->list, &entry->list);
+ dl_list_add_tail(&ptksa->ptksa, &entry->list);
ptksa->n_ptksa++;
wpa_printf(MSG_DEBUG,
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 47666f04ae7c..4dac10ef9724 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -701,6 +701,8 @@ enum qca_radiotap_vendor_ids {
* The host driver selects Tx VDEV, and notifies user. The attributes
* used with this event are defined in enum
* qca_wlan_vendor_attr_mbssid_tx_vdev_status.
+ * This event contains Tx VDEV group information, other VDEVs
+ * interface index, and status information.
*
* @QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY: Vendor command to
* configure the concurrent session policies when multiple STA interfaces
@@ -719,6 +721,40 @@ enum qca_radiotap_vendor_ids {
* to get DFS radar history from the driver to userspace. The driver
* returns QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_ENTRIES attribute with an
* array of nested entries.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD: Userspace can use this command to
+ * enable/disable mDNS offload to the firmware. The attributes used with
+ * this command are defined in enum qca_wlan_vendor_attr_mdns_offload.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE: This vendor subcommand is used
+ * to set packet monitor mode that aims to send the specified set of TX and
+ * RX frames on the current client interface to an active monitor
+ * interface. If this monitor mode is set, the driver will send the
+ * configured frames, from the interface on which the command is issued, to
+ * an active monitor interface. The attributes used with this command are
+ * defined in enum qca_wlan_vendor_attr_set_monitor_mode.
+ *
+ * Though the monitor mode is configured for the respective
+ * Data/Management/Control frames, it is up to the respective WLAN
+ * driver/firmware/hardware designs to consider the possibility of sending
+ * these frames over the monitor interface. For example, the Control frames
+ * are handled within the hardware and thus passing such frames over the
+ * monitor interface is left to the respective designs.
+ *
+ * Also, this monitor mode is governed to behave accordingly in
+ * suspend/resume states. If the firmware handles any of such frames in
+ * suspend state without waking up the host and if the monitor mode is
+ * configured to notify all such frames, the firmware is expected to resume
+ * the host and forward the respective frames to the monitor interface.
+ * Please note that such a request to get the frames over the monitor
+ * interface will have a definite power implication.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS: This vendor subcommand is used both
+ * as a request to set the driver/firmware with the parameters to trigger
+ * the roaming events, and also used by the driver/firmware to pass on the
+ * various roam events to userspace.
+ * Applicable only for the STA mode. The attributes used with this command
+ * are defined in enum qca_wlan_vendor_attr_roam_events.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -908,6 +944,10 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY = 197,
QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS = 198,
QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY = 199,
+ QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD = 200,
+ /* 201 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE = 202,
+ QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS = 203,
};
enum qca_wlan_vendor_attr {
@@ -1146,7 +1186,7 @@ enum qca_roaming_policy {
* @QCA_ROAM_REASON_CONGESTION: Roam triggered considering the connected channel
* or environment being very noisy or congested.
*
- * @QCA_ROAM_REASON_EXPLICIT_REQUEST: Roam triggered due to an explicit request
+ * @QCA_ROAM_REASON_USER_TRIGGER: Roam triggered due to an explicit request
* from the user (user space).
*
* @QCA_ROAM_REASON_BTM: Roam triggered due to BTM Request frame received from
@@ -1154,6 +1194,26 @@ enum qca_roaming_policy {
*
* @QCA_ROAM_REASON_BSS_LOAD: Roam triggered due to the channel utilization
* breaching out the configured threshold.
+ *
+ * @QCA_ROAM_REASON_WTC: Roam triggered due to Wireless to Cellular BSS
+ * transition request.
+ *
+ * @QCA_ROAM_REASON_IDLE: Roam triggered when device is suspended, there is no
+ * data activity with the AP and the current RSSI falls below a certain
+ * threshold.
+ *
+ * @QCA_ROAM_REASON_DISCONNECTION: Roam triggered due to Deauthentication or
+ * Disassociation frames received from the connected AP.
+ *
+ * @QCA_ROAM_REASON_PERIODIC_TIMER: Roam triggered as part of the periodic scan
+ * that happens when there is no candidate AP found during the poor RSSI scan
+ * trigger.
+ *
+ * @QCA_ROAM_REASON_BACKGROUND_SCAN: Roam triggered based on the scan results
+ * obtained from an external scan (not aimed at roaming).
+ *
+ * @QCA_ROAM_REASON_BT_ACTIVITY: Roam triggered due to Bluetooth connection is
+ * established when the station is connected in the 2.4 GHz band.
*/
enum qca_roam_reason {
QCA_ROAM_REASON_UNKNOWN,
@@ -1165,6 +1225,12 @@ enum qca_roam_reason {
QCA_ROAM_REASON_USER_TRIGGER,
QCA_ROAM_REASON_BTM,
QCA_ROAM_REASON_BSS_LOAD,
+ QCA_ROAM_REASON_WTC,
+ QCA_ROAM_REASON_IDLE,
+ QCA_ROAM_REASON_DISCONNECTION,
+ QCA_ROAM_REASON_PERIODIC_TIMER,
+ QCA_ROAM_REASON_BACKGROUND_SCAN,
+ QCA_ROAM_REASON_BT_ACTIVITY,
};
enum qca_wlan_vendor_attr_roam_auth {
@@ -1384,6 +1450,11 @@ enum qca_wlan_vendor_attr_p2p_listen_offload {
* Used with event to notify the EDMG channel number selected in ACS
* operation.
* EDMG primary channel is indicated by QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP: Optional (u16).
+ * Used with event to notify the puncture pattern selected in ACS operation.
+ * Encoding for this attribute will follow the convention used in the Disabled
+ * Subchannel Bitmap field of the EHT Operation IE.
*/
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
@@ -1404,6 +1475,7 @@ enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY = 15,
QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED = 16,
QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL = 17,
+ QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP = 18,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
@@ -1839,6 +1911,23 @@ enum qca_vendor_element_id {
};
/**
+ * enum qca_wlan_vendor_scan_priority - Specifies the valid values that the
+ * vendor scan attribute QCA_WLAN_VENDOR_ATTR_SCAN_PRIORITY can take.
+ * @QCA_WLAN_VENDOR_SCAN_PRIORITY_VERY_LOW: Very low priority
+ * @QCA_WLAN_VENDOR_SCAN_PRIORITY_LOW: Low priority
+ * @QCA_WLAN_VENDOR_SCAN_PRIORITY_MEDIUM: Medium priority
+ * @QCA_WLAN_VENDOR_SCAN_PRIORITY_HIGH: High priority
+ * @QCA_WLAN_VENDOR_SCAN_PRIORITY_VERY_HIGH: Very high priority
+ */
+enum qca_wlan_vendor_scan_priority {
+ QCA_WLAN_VENDOR_SCAN_PRIORITY_VERY_LOW = 0,
+ QCA_WLAN_VENDOR_SCAN_PRIORITY_LOW = 1,
+ QCA_WLAN_VENDOR_SCAN_PRIORITY_MEDIUM = 2,
+ QCA_WLAN_VENDOR_SCAN_PRIORITY_HIGH = 3,
+ QCA_WLAN_VENDOR_SCAN_PRIORITY_VERY_HIGH = 4,
+};
+
+/**
* enum qca_wlan_vendor_attr_scan - Specifies vendor scan attributes
*
* @QCA_WLAN_VENDOR_ATTR_SCAN_IE: IEs that should be included as part of scan
@@ -1863,6 +1952,11 @@ enum qca_vendor_element_id {
* @QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME: Unsigned 64-bit dwell time in
* microseconds. This is a common value which applies across all
* frequencies specified by QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES.
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_PRIORITY: Priority of vendor scan relative to
+ * other scan requests. It is a u32 attribute and takes values from enum
+ * qca_wlan_vendor_scan_priority. This is an optional attribute.
+ * If this attribute is not configured, the driver shall use
+ * QCA_WLAN_VENDOR_SCAN_PRIORITY_HIGH as the priority of vendor scan.
*/
enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
@@ -1878,6 +1972,7 @@ enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK = 10,
QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11,
QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME = 12,
+ QCA_WLAN_VENDOR_ATTR_SCAN_PRIORITY = 13,
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@@ -2459,6 +2554,19 @@ enum qca_wlan_vendor_attr_config {
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_FT_OVER_DS = 80,
+ /*
+ * 8-bit unsigned value. This attribute can be used to configure the
+ * firmware to enable/disable ARP/NS offload feature. Possible values
+ * for this attribute are 0-Disable and 1-Enable.
+ *
+ * This attribute is only applicable for STA/P2P-Client interface,
+ * and is optional, default behavior is ARP/NS offload enabled.
+ *
+ * This attribute can be set in disconnected and connected state, and
+ * will restore to the default behavior if the interface is closed.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ARP_NS_OFFLOAD = 81,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -3882,6 +3990,10 @@ enum qca_wlan_vendor_attr_ll_stats_results {
* are 0-100.
*/
QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE = 86,
+ /* u8 value representing the time slicing duty cycle percentage.
+ * Possible values are 0-100.
+ */
+ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_TS_DUTY_CYCLE = 87,
/* keep last */
QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX =
@@ -4659,6 +4771,44 @@ enum qca_vendor_attr_roam_candidate_selection_criteria {
* threshold value specified by the
* QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD attribute shall be used.
*
+ * @QCA_ATTR_ROAM_CONTROL_BAND_MASK: Unsigned 32-bit value.
+ * Carries bitmask value of bits from &enum qca_set_band and represents
+ * all the bands in which roaming is allowed. The configuration is valid
+ * until next disconnection. If this attribute is not present, the
+ * existing configuration shall be used. By default, roaming is allowed on
+ * all bands supported by the local device. When the value is set to
+ * %QCA_SETBAND_AUTO, all supported bands shall be enabled.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_ACTIVE_CH_DWELL_TIME: u16 value in milliseconds.
+ * Optional parameter. Scan dwell time for active channels in the 2.4/5 GHz
+ * bands. If this attribute is not configured, the driver shall proceed
+ * with default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_PASSIVE_CH_DWELL_TIME: u16 value in milliseconds.
+ * Optional parameter. Scan dwell time for passive channels in the 5 GHz
+ * band. If this attribute is not configured, the driver shall proceed with
+ * default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_HOME_CHANNEL_TIME: u16 value in milliseconds.
+ * Optional parameter. The minimum duration to stay on the connected AP
+ * channel during the channel scanning. If this attribute is not
+ * configured, the driver shall proceed with default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_MAXIMUM_AWAY_TIME: u16 value in milliseconds.
+ * Optional parameter. The maximum duration for which the radio can scan
+ * foreign channels consecutively without coming back to home channel. If
+ * this attribute is not configured, the driver shall proceed with default
+ * behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_6G_PSC_DWELL_TIME: u16 value in milliseconds.
+ * Optional parameter. Scan dwell time for 6G Preferred Scanning Channels.
+ * If this attribute is not configured, the driver shall proceed with
+ * default behavior.
+ *
+ * @QCA_ATTR_ROAM_CONTROL_SCAN_6G_NON_PSC_DWELL_TIME: u16 value in milliseconds.
+ * Optional parameter. Scan dwell time for 6G Non Preferred Scanning
+ * Channels. If this attribute is not configured, the driver shall proceed
+ * with default behavior.
*/
enum qca_vendor_attr_roam_control {
QCA_ATTR_ROAM_CONTROL_ENABLE = 1,
@@ -4677,6 +4827,13 @@ enum qca_vendor_attr_roam_control {
QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_2P4GHZ = 14,
QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_5GHZ = 15,
QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_6GHZ = 16,
+ QCA_ATTR_ROAM_CONTROL_BAND_MASK = 17,
+ QCA_ATTR_ROAM_CONTROL_ACTIVE_CH_DWELL_TIME = 18,
+ QCA_ATTR_ROAM_CONTROL_PASSIVE_CH_DWELL_TIME = 19,
+ QCA_ATTR_ROAM_CONTROL_HOME_CHANNEL_TIME = 20,
+ QCA_ATTR_ROAM_CONTROL_MAXIMUM_AWAY_TIME = 21,
+ QCA_ATTR_ROAM_CONTROL_SCAN_6G_PSC_DWELL_TIME = 22,
+ QCA_ATTR_ROAM_CONTROL_SCAN_6G_NON_PSC_DWELL_TIME = 23,
/* keep last */
QCA_ATTR_ROAM_CONTROL_AFTER_LAST,
@@ -6284,6 +6441,14 @@ enum qca_wlan_vendor_attr_spectral_scan {
* u32 attribute.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY_2 = 29,
+ /* This attribute specifies the bandwidth to be used for spectral scan
+ * operation. This is an u8 attribute and uses the values in enum
+ * nl80211_chan_width. This is an optional attribute.
+ * If this attribute is not populated, the driver should configure the
+ * spectral scan bandwidth to the maximum value supported by the target
+ * for the current operating bandwidth.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BANDWIDTH = 30,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
@@ -6394,6 +6559,14 @@ enum qca_wlan_vendor_attr_spectral_cap {
* u32 attribute.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_80P80_MHZ = 18,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 320 MHz mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_320 = 19,
+ /* Number of spectral detectors used for scan in 320 MHz.
+ * u32 attribute.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_NUM_DETECTORS_320_MHZ = 20,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
@@ -7303,6 +7476,15 @@ enum qca_wlan_vendor_attr_thermal_cmd {
* there is any critical ongoing operation.
*/
QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW = 3,
+ /* Nested attribute, the driver/firmware uses this attribute to report
+ * thermal statistics of different thermal levels to userspace when
+ * requested using the
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_THERMAL_STATS command
+ * type. This attribute contains a nested array of records of thermal
+ * statistics of multiple levels. The attributes used inside this nested
+ * attribute are defined in enum qca_wlan_vendor_attr_thermal_stats.
+ */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_STATS = 4,
/* keep last */
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST,
@@ -7331,6 +7513,13 @@ enum qca_wlan_vendor_attr_thermal_cmd {
* @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL: Request to get the current
* thermal level from the driver/firmware. The driver should respond with a
* thermal level defined in enum qca_wlan_vendor_thermal_level.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_THERMAL_STATS: Request to get the
+ * current thermal statistics from the driver/firmware. The driver should
+ * respond with statistics of all thermal levels encapsulated in the attribute
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_STATS.
+ * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_CLEAR_THERMAL_STATS: Request to clear
+ * the current thermal statistics for all thermal levels maintained in the
+ * driver/firmware and start counting from zero again.
*/
enum qca_wlan_vendor_attr_thermal_cmd_type {
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS,
@@ -7339,6 +7528,8 @@ enum qca_wlan_vendor_attr_thermal_cmd_type {
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL,
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_THERMAL_STATS,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_CLEAR_THERMAL_STATS,
};
/**
@@ -7434,6 +7625,35 @@ enum qca_wlan_vendor_attr_thermal_event {
};
/**
+ * enum qca_wlan_vendor_attr_thermal_stats - vendor subcmd attributes
+ * to get thermal status from the driver/firmware.
+ * enum values are used for NL attributes encapsulated inside the
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_STATS nested attribute.
+ *
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MIN_TEMPERATURE: Minimum temperature
+ * of a thermal level in Celsius. u32 size.
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MAX_TEMPERATURE: Maximum temperature
+ * of a thermal level in Celsius. u32 size.
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_DWELL_TIME: The total time spent on each
+ * thermal level in milliseconds. u32 size.
+ * QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_TEMP_LEVEL_COUNTER: Indicates the number
+ * of times the temperature crossed into the temperature range defined by the
+ * thermal level from both higher and lower directions. u32 size.
+ */
+enum qca_wlan_vendor_attr_thermal_stats {
+ QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MIN_TEMPERATURE,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MAX_TEMPERATURE,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_DWELL_TIME,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_TEMP_LEVEL_COUNTER,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MAX =
+ QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_AFTER_LAST - 1,
+};
+
+/**
* enum he_fragmentation_val - HE fragmentation support values
* Indicates level of dynamic fragmentation that is supported by
* a STA as a recipient.
@@ -8158,6 +8378,24 @@ enum qca_wlan_vendor_attr_wifi_test_config {
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD_ENABLE = 55,
+ /* 8-bit unsigned value to configure the driver/firmware to enable or
+ * disable Rx control frame to MultiBSS subfield in the HE MAC
+ * capabilities information field.
+ * 0 - Disable Rx control frame to MultiBSS subfield
+ * 1 - Enable Rx control frame to MultiBSS subfield
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RX_CTRL_FRAME_TO_MBSS = 56,
+
+ /* 8-bit unsigned value to configure the driver/firmware to enable or
+ * disable Broadcast TWT support subfield in the HE MAC capabilities
+ * information field.
+ * 0 - Disable Broadcast TWT support subfield
+ * 1 - Enable Broadcast TWT support subfield
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BCAST_TWT_SUPPORT = 57,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -8230,6 +8468,10 @@ enum qca_wlan_vendor_attr_wifi_test_config {
*
* @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.
+ *
+ * @QCA_WLAN_TWT_SET_PARAM: Configure TWT related parameters. Required
+ * parameters are obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refer
+ * the enum qca_wlan_vendor_attr_twt_set_param.
*/
enum qca_wlan_twt_operation {
QCA_WLAN_TWT_SET = 0,
@@ -8242,6 +8484,7 @@ enum qca_wlan_twt_operation {
QCA_WLAN_TWT_CLEAR_STATS = 7,
QCA_WLAN_TWT_GET_CAPABILITIES = 8,
QCA_WLAN_TWT_SETUP_READY_NOTIFY = 9,
+ QCA_WLAN_TWT_SET_PARAM = 10,
};
/**
@@ -8256,7 +8499,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, enum qca_wlan_vendor_attr_twt_resume,
- * or enum qca_wlan_vendor_attr_twt_stats based on the operation.
+ * enum qca_wlan_vendor_attr_twt_set_param, 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,
@@ -8547,9 +8791,13 @@ enum qca_wlan_twt_setup_state {
* response.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF: Required (u64)
- * This field is applicable for TWT response only.
- * This field contains absolute TSF value of the wake time received
- * from the TWT responder and is passed to the userspace.
+ * In TWT setup command this field contains absolute TSF that will
+ * be used by TWT requester during setup.
+ * In TWT response this field contains absolute TSF value of the
+ * wake time received from the TWT responder and is passed to
+ * the userspace.
+ * This is an optional parameter for
+ * 1. TWT SET Request
* This is a required parameter for
* 1. TWT SET Response
* 2. TWT GET Response
@@ -8630,6 +8878,23 @@ enum qca_wlan_twt_setup_state {
* indicates that the Broadcast TWT SPs are present until explicitly terminated.
* This parameter is used for
* 1. TWT SET Request
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE: Optional (u8)
+ * This attribute contains the value of the Responder PM Mode subfield (0 or 1)
+ * from TWT response frame.
+ * This parameter is used for
+ * 1. TWT SET Response
+ * 2. TWT GET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT: Optional (u32)
+ * This attribute is used to configure the announce timeout value (in us) in
+ * the firmware. This timeout value is only applicable for the announced TWT. If
+ * the timeout value is non-zero the firmware waits up to the timeout value to
+ * use Data frame as an announcement frame. If the timeout value is 0 the
+ * firmware sends an explicit QoS NULL frame as the announcement frame on SP
+ * start. The default value in the firmware is 0.
+ * This parameter is used for
+ * 1. TWT SET Request
*/
enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
@@ -8663,6 +8928,9 @@ enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION = 23,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE = 24,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE = 25,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT = 26,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX =
@@ -8710,6 +8978,9 @@ enum qca_wlan_vendor_attr_twt_setup {
* setup request due to channel switch in progress.
* @QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS: FW rejected the TWT setup
* request due to scan in progress.
+ * QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE: The driver requested to
+ * terminate an existing TWT session on power save exit request from userspace.
+ * Used on the TWT_TERMINATE notification from the driver/firmware.
*/
enum qca_wlan_vendor_twt_status {
QCA_WLAN_VENDOR_TWT_STATUS_OK = 0,
@@ -8734,6 +9005,7 @@ enum qca_wlan_vendor_twt_status {
QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS = 19,
QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS = 20,
QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS = 21,
+ QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE = 22,
};
/**
@@ -8990,6 +9262,27 @@ enum qca_wlan_vendor_attr_twt_capability {
};
/**
+ * enum qca_wlan_vendor_attr_twt_set_param: Represents attributes for
+ * TWT (Target Wake Time) related parameters. It is used when
+ * %QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION is set to %QCA_WLAN_TWT_SET_PARAM.
+ * These attributes are sent as part of %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE: Optional (u8)
+ * This attribute configures AC parameters to be used for all TWT
+ * sessions in AP mode.
+ * Uses the enum qca_wlan_ac_type values.
+ */
+enum qca_wlan_vendor_attr_twt_set_param {
+ QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE = 1,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AFTER_LAST - 1,
+};
+
+/**
* enum qca_wlan_vendor_twt_setup_resp_type - Represents the response type by
* the TWT responder
*
@@ -10903,10 +11196,25 @@ enum qca_wlan_vendor_attr_medium_assess {
* u8 attribute. Notify the TX VDEV status. Possible values 0, 1
* belonging to MBSSID/EMA_AP configuration. 0 means Non-Tx VDEV,
* 1 means Tx VDEV. Mandatory attribute for all MBSSID VDEV status events.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_EVENT:
+ * u8 attribute, required. 1 means Tx VDEV up event. 0 means Tx VDEV down event.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_ID:
+ * u8 attribute, required. Indicates group id of Tx VDEV.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO:
+ * Nested attribute. This attribute shall be used by the driver to send
+ * group information. The attributes defined in enum
+ * qca_wlan_vendor_attr_mbssid_tx_vdev_group_info
+ * are nested in this attribute.
*/
enum qca_wlan_vendor_attr_mbssid_tx_vdev_status {
QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_VAL = 1,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_EVENT = 2,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_ID = 3,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO = 4,
/* keep last */
QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_STATUS_AFTER_LAST,
@@ -10915,6 +11223,27 @@ enum qca_wlan_vendor_attr_mbssid_tx_vdev_status {
};
/**
+ * enum qca_wlan_vendor_attr_mbssid_tx_vdev_group_info - Attributes used
+ * inside %QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO nested attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO_IF_INDEX:
+ * u32 attribute, required. Contains interface index.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO_STATUS:
+ * u8 attribute, required. 0 - means vdev is in down state.
+ * 1 - means vdev is in up state.
+ */
+enum qca_wlan_vendor_attr_mbssid_tx_vdev_group_info {
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO_IF_INDEX = 1,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO_STATUS = 2,
+
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_MBSSID_TX_VDEV_GROUP_INFO - 1,
+};
+
+/**
* enum qca_wlan_concurrent_sta_policy_config - Concurrent STA policies
*
* @QCA_WLAN_CONCURRENT_STA_POLICY_PREFER_PRIMARY: Preference to the primary
@@ -11129,4 +11458,330 @@ enum qca_wlan_vendor_attr_radar_history {
QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_attr_mdns_offload - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ENABLE: Required (flag)
+ * Enable mDNS offload. This attribute is mandatory to enable
+ * mDNS offload feature. If this attribute is not present, mDNS offload
+ * is disabled.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_TABLE: Nested attribute containing
+ * one or more %QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ENTRY attributes. This
+ * attribute is mandatory when enabling the feature, and not required when
+ * disabling the feature.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ENTRY: Nested attribute containing
+ * the following attributes:
+ * %QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_FQDN
+ * %QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_RESOURCE_RECORDS_COUNT
+ * %QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_PAYLOAD
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_FQDN: Required string attribute.
+ * It consists of a hostname and ".local" as the domain name. The character
+ * set is limited to UTF-8 encoding. The maximum allowed size is 63 bytes.
+ * It is used to compare the domain in the "QU" query. Only 1 FQDN is
+ * supported per vdev.
+ * For example: myphone.local
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_RESOURCE_RECORDS_COUNT: Required
+ * u16 attribute. It specifies the total number of resource records present
+ * in the answer section of the answer payload. This attribute is needed by the
+ * firmware to populate the mDNS response frame for mDNS queries without having
+ * to parse the answer payload.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_PAYLOAD: Required binary blob
+ * attribute sent by the mdnsResponder from userspace. It contains resource
+ * records of various types (e.g., A, AAAA, PTR, TXT) and service list. This
+ * payload is passed down to the firmware and is transmitted in response to
+ * mDNS queries.
+ * The maximum supported size of the answer payload is 512 bytes.
+ */
+enum qca_wlan_vendor_attr_mdns_offload {
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ENABLE = 1,
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_TABLE = 2,
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ENTRY = 3,
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_FQDN = 4,
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_RESOURCE_RECORDS_COUNT = 5,
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_PAYLOAD = 6,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX =
+ QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_AFTER_LAST - 1,
+};
+
+/**
+ * qca_wlan_vendor_monitor_data_frame_type - Represent the various
+ * Data frame types to be sent over the monitor interface.
+ */
+enum qca_wlan_vendor_monitor_data_frame_type {
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_ALL = BIT(0),
+ /* valid only if QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_ALL is not set
+ */
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_ARP = BIT(1),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_DHCPV4 = BIT(2),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_DHCPV6 = BIT(3),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_EAPOL = BIT(4),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_DNSV4 = BIT(5),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_DNSV6 = BIT(6),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_TCP_SYN = BIT(7),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_TCP_SYNACK = BIT(8),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_TCP_FIN = BIT(9),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_TCP_FINACK = BIT(10),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_TCP_ACK = BIT(11),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_TCP_RST = BIT(12),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_ICMPV4 = BIT(13),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_ICMPV6 = BIT(14),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_RTP = BIT(15),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_SIP = BIT(16),
+ QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_QOS_NULL = BIT(17),
+};
+
+/**
+ * qca_wlan_vendor_monitor_mgmt_frame_type - Represent the various
+ * Management frame types to be sent over the monitor interface.
+ * @QCA_WLAN_VENDOR_MONITOR_MGMT_FRAME_TYPE_ALL: All the Management Frames.
+ * @QCA_WLAN_VENDOR_MONITOR_MGMT_CONNECT_NO_BEACON: All the Management frames
+ * except the Beacon frame.
+ * @QCA_WLAN_VENDOR_MONITOR_MGMT_CONNECT_BEACON: Only the connected
+ * BSSID Beacon frames. Valid only in the connected state.
+ * @QCA_WLAN_VENDOR_MONITOR_MGMT_CONNECT_SCAN_BEACON: Represents
+ * the Beacon frames obtained during the scan (off channel and connected
+ * channel), when in connected state.
+ */
+
+enum qca_wlan_vendor_monitor_mgmt_frame_type {
+ QCA_WLAN_VENDOR_MONITOR_MGMT_FRAME_TYPE_ALL = BIT(0),
+ /* valid only if QCA_WLAN_VENDOR_MONITOR_MGMT_FRAME_TYPE_ALL is not set
+ */
+ QCA_WLAN_VENDOR_MONITOR_MGMT_NO_BEACON = BIT(1),
+ QCA_WLAN_VENDOR_MONITOR_MGMT_CONNECT_BEACON = BIT(2),
+ QCA_WLAN_VENDOR_MONITOR_MGMT_CONNECT_SCAN_BEACON = BIT(3),
+};
+
+/**
+ * qca_wlan_vendor_monitor_ctrl_frame_type - Represent the various
+ * Control frame types to be sent over the monitor interface.
+ * @QCA_WLAN_VENDOR_MONITOR_CTRL_FRAME_TYPE_ALL: All the Control frames
+ * @QCA_WLAN_VENDOR_MONITOR_CTRL_TRIGGER_FRAME: Trigger frame
+ */
+enum qca_wlan_vendor_monitor_ctrl_frame_type {
+ QCA_WLAN_VENDOR_MONITOR_CTRL_FRAME_TYPE_ALL = BIT(0),
+ /* valid only if QCA_WLAN_VENDOR_MONITOR_CTRL_FRAME_TYPE_ALL is not set
+ */
+ QCA_WLAN_VENDOR_MONITOR_CTRL_TRIGGER_FRAME = BIT(1),
+};
+
+/**
+ * enum qca_wlan_vendor_attr_set_monitor_mode - Used by the
+ * vendor command QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE to set the
+ * monitor mode.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_TX_FRAME_TYPE: u32 attribute.
+ * Represents the TX Data frame types to be monitored (u32). These Data frames
+ * are represented by enum qca_wlan_vendor_monitor_data_frame_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_RX_FRAME_TYPE: u32 attribute.
+ * Represents the RX Data frame types to be monitored (u32). These Data frames
+ * are represented by enum qca_wlan_vendor_monitor_data_frame_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE: u32 attribute.
+ * Represents the TX Management frame types to be monitored (u32). These
+ * Management frames are represented by
+ * enum qca_wlan_vendor_monitor_mgmt_frame_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE: u32 attribute.
+ * Represents the RX Management frame types to be monitored (u32). These
+ * Management frames are represented by
+ * enum qca_wlan_vendor_monitor_mgmt_frame_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE: u32 attribute.
+ * Represents the TX Control frame types to be monitored (u32). These Control
+ * frames are represented by enum qca_wlan_vendor_monitor_ctrl_frame_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE: u32 attribute.
+ * Represents the RX Control frame types to be monitored (u32). These Control
+ * frames are represented by enum qca_wlan_vendor_monitor_ctrl_frame_type.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL: u32
+ * attribute.
+ * Represents the interval in milliseconds only for the connected Beacon frames,
+ * expecting the connected BSS's Beacon frames to be sent on the monitor
+ * interface at this specific interval.
+ */
+enum qca_wlan_vendor_attr_set_monitor_mode
+{
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_TX_FRAME_TYPE = 1,
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_RX_FRAME_TYPE = 2,
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE = 3,
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE = 4,
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE = 5,
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE = 6,
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL = 7,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MAX =
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_roam_scan_state - Roam scan state flags.
+ * Bits will be set to 1 if the corresponding state is enabled.
+ *
+ * @QCA_VENDOR_WLAN_ROAM_SCAN_STATE_START: Scan Start.
+ * @QCA_VENDOR_WLAN_ROAM_SCAN_STATE_END: Scan end.
+ */
+enum qca_wlan_vendor_roam_scan_state {
+ QCA_WLAN_VENDOR_ROAM_SCAN_STATE_START = BIT(0),
+ QCA_WLAN_VENDOR_ROAM_SCAN_STATE_END = BIT(1),
+};
+
+/**
+ * enum qca_wlan_vendor_roam_event_type - Roam event type flags.
+ * Bits will be set to 1 if the corresponding event is notified.
+ *
+ * @QCA_WLAN_VENDOR_ROAM_EVENT_TRIGGER_REASON: Represents that the roam event
+ * carries the trigger reason. When set, it is expected that the roam event
+ * carries the respective reason via the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON. This event also carries
+ * the BSSID, RSSI, frequency info of the AP to which the roam is attempted.
+ *
+ * @QCA_WLAN_VENDOR_ROAM_EVENT_FAIL_REASON: Represents that the roam event
+ * carries the roam fail reason. When set, it is expected that the roam event
+ * carries the respective reason via the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_FAIL_REASON. This event also carries the
+ * BSSID, RSSI, frequency info of the AP to which the roam was attempted.
+ *
+ * @QCA_WLAN_VENDOR_ROAM_EVENT_INVOKE_FAIL_REASON: Represents that the roam
+ * event carries the roam invoke fail reason. When set, it is expected that
+ * the roam event carries the respective reason via the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON.
+ *
+ * @QCA_WLAN_VENDOR_ROAM_EVENT_SCAN_STATE: Represents that the roam event
+ * carries the roam scan state. When set, it is expected that the roam event
+ * carries the respective scan state via the attribute
+ * QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE and the corresponding
+ * frequency info via QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST.
+ */
+enum qca_wlan_vendor_roam_event_type {
+ QCA_WLAN_VENDOR_ROAM_EVENT_TRIGGER_REASON = BIT(0),
+ QCA_WLAN_VENDOR_ROAM_EVENT_FAIL_REASON = BIT(1),
+ QCA_WLAN_VENDOR_ROAM_EVENT_INVOKE_FAIL_REASON = BIT(2),
+ QCA_WLAN_VENDOR_ROAM_EVENT_ROAM_SCAN_STATE = BIT(3),
+};
+
+/**
+ * enum qca_wlan_vendor_attr_roam_events_candidate_info: Roam candidate info.
+ * Referred by QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID: 6-byte MAC address
+ * representing the BSSID of the AP to which the roam is attempted.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI: Signed 32-bit value
+ * in dBm, signifying the RSSI of the candidate BSSID to which the Roaming is
+ * attempted.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ: u32, frequency in MHz
+ * on which the roam is attempted.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON: u32, used in
+ * STA mode only. This represents the roam fail reason for the last failed
+ * roaming attempt by the firmware for the specific BSSID. Different roam
+ * failure reason codes are specified in enum qca_vendor_roam_fail_reasons.
+ */
+enum qca_wlan_vendor_attr_roam_events_candidate_info {
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID = 1,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI = 2,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ = 3,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON = 4,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_roam_events - Used by the
+ * vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS to either configure the
+ * roam events to the driver or notify these events from the driver.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CONFIGURE: u8 attribute. Configures the
+ * driver/firmware to enable/disable the notification of roam events. It's a
+ * mandatory attribute and used only in the request from the userspace to the
+ * host driver. 1-Enable, 0-Disable.
+ * If the roaming is totally offloaded to the firmware, this request when
+ * enabled shall mandate the firmware to notify all the relevant roam events
+ * represented by the below attributes. If the host is in the suspend mode,
+ * the behavior of the firmware to notify these events is guided by
+ * QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_DEVICE_STATE, and if the request is to get
+ * these events in the suspend state, the firmware is expected to wake up the
+ * host before the respective events are notified. Please note that such a
+ * request to get the events in the suspend state will have a definite power
+ * implication.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_SUSPEND_STATE: flag attribute. Represents
+ * that the roam events need to be notified in the suspend state too. By
+ * default, these roam events are notified in the resume state. With this flag,
+ * the roam events are notified in both resume and suspend states.
+ * This attribute is used in the request from the userspace to the host driver.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE: u32, used in STA mode only.
+ * Represents the different roam event types, signified by the enum
+ * qca_wlan_vendor_roam_event_type.
+ * Each bit of this attribute represents the different roam even types reported
+ * through QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS.
+ * This is sent as an event through QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON: u32, used in STA
+ * mode only. This represents the roam trigger reason for the last roaming
+ * attempted by the firmware. Each bit of this attribute represents the
+ * different roam trigger reason code which are defined in enum
+ * qca_vendor_roam_triggers.
+ * This is sent as an event through QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_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.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO: Array of candidates info
+ * for which the roam is attempted. Each entry is a nested attribute defined
+ * by enum qca_wlan_vendor_attr_roam_events_candidate_info.
+ * This is sent as an event through QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE: u8 attribute. Represents
+ * the scan state on which the roam events need to be notified. The values for
+ * this attribute are referred from enum qca_wlan_vendor_roam_scan_state.
+ * This is sent as an event through QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST: Nested attribute of
+ * u32 values. List of frequencies in MHz considered for a roam scan.
+ * This is sent as an event through QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS.
+ */
+
+enum qca_wlan_vendor_attr_roam_events
+{
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CONFIGURE = 1,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_SUSPEND_STATE = 2,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE = 3,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON = 4,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON = 5,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO = 6,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE = 7,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST = 8,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_MAX =
+ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_AFTER_LAST -1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 74920a78e46a..b768c22faa9d 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -286,7 +286,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
u8 addrs[2 * ETH_ALEN];
const u8 *addr[2];
size_t len[2];
- u8 *dummy_password, *tmp_password;
+ u8 *stub_password, *tmp_password;
int pwd_seed_odd = 0;
u8 prime[SAE_MAX_ECC_PRIME_LEN];
size_t prime_len;
@@ -301,10 +301,10 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
os_memset(x_bin, 0, sizeof(x_bin));
- dummy_password = os_malloc(password_len);
+ stub_password = os_malloc(password_len);
tmp_password = os_malloc(password_len);
- if (!dummy_password || !tmp_password ||
- random_get_bytes(dummy_password, password_len) < 0)
+ if (!stub_password || !tmp_password ||
+ random_get_bytes(stub_password, password_len) < 0)
goto fail;
prime_len = sae->tmp->prime_len;
@@ -354,7 +354,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
}
wpa_printf(MSG_DEBUG, "SAE: counter = %03u", counter);
- const_time_select_bin(found, dummy_password, password,
+ const_time_select_bin(found, stub_password, password,
password_len, tmp_password);
if (hmac_sha256_vector(addrs, sizeof(addrs), 2,
addr, len, pwd_seed) < 0)
@@ -415,7 +415,7 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
fail:
crypto_bignum_deinit(qr, 0);
crypto_bignum_deinit(qnr, 0);
- os_free(dummy_password);
+ os_free(stub_password);
bin_clear_free(tmp_password, password_len);
crypto_bignum_deinit(x, 1);
os_memset(x_bin, 0, sizeof(x_bin));
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 04461516f138..b78db05a1430 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -3231,6 +3231,11 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
pos[2] == WLAN_EID_EXT_HE_CAPABILITIES) {
ie->he_capabilities = pos + 3;
ie->he_capab_len = pos[1] - 1;
+ } else if (*pos == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 +
+ sizeof(struct ieee80211_he_6ghz_band_cap) &&
+ pos[2] == WLAN_EID_EXT_HE_6GHZ_BAND_CAP) {
+ ie->he_6ghz_capabilities = pos + 3;
} else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
ie->qosinfo = pos[2];
} else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index a1ff895659cb..c28c55d3aab6 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -599,6 +599,7 @@ struct wpa_eapol_ie_parse {
const u8 *vht_capabilities;
const u8 *he_capabilities;
size_t he_capab_len;
+ const u8 *he_6ghz_capabilities;
const u8 *supp_channels;
size_t supp_channels_len;
const u8 *supp_oper_classes;
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 126a7892c8a8..2c7ec043d409 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -126,6 +126,10 @@ extern "C" {
#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
/** Frequency ranges that the driver recommends to avoid */
#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ "
+/** A new network profile was added (followed by network entry id) */
+#define WPA_EVENT_NETWORK_ADDED "CTRL-EVENT-NETWORK-ADDED "
+/** A network profile was removed (followed by prior network entry id) */
+#define WPA_EVENT_NETWORK_REMOVED "CTRL-EVENT-NETWORK-REMOVED "
/** Result of MSCS setup */
#define WPA_EVENT_MSCS_RESULT "CTRL-EVENT-MSCS-RESULT "
/** WPS overlap detected in PBC mode */
@@ -157,6 +161,10 @@ extern "C" {
#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
+/** Result of SCS setup */
+#define WPA_EVENT_SCS_RESULT "CTRL-EVENT-SCS-RESULT "
+/* Event indicating DSCP policy */
+#define WPA_EVENT_DSCP_POLICY "CTRL-EVENT-DSCP-POLICY "
/* WPS ER events */
#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 7d2ebd61caea..eb600699d3d0 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -495,6 +495,13 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip,
*/
int crypto_get_random(void *buf, size_t len);
+/**
+ * crypto_pkcs7_get_certificates - Extract X.509 certificates from PKCS#7 data
+ * @pkcs7: DER encoded PKCS#7 data
+ * Returns: Buffer of the extracted PEM X.509 certificates or %NULL on failure
+ */
+struct wpabuf * crypto_pkcs7_get_certificates(const struct wpabuf *pkcs7);
+
/**
* struct crypto_bignum - bignum
@@ -714,6 +721,14 @@ int crypto_bignum_legendre(const struct crypto_bignum *a,
struct crypto_ec;
/**
+ * struct crypto_ec_point - Elliptic curve point
+ *
+ * Internal data structure for EC implementation to represent a point. The
+ * contents is specific to the used crypto library.
+ */
+struct crypto_ec_point;
+
+/**
* crypto_ec_init - Initialize elliptic curve context
* @group: Identifying number for the ECC group (IANA "Group Description"
* attribute registrty for RFC 2409)
@@ -762,16 +777,26 @@ const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e);
*/
const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
+/**
+ * crypto_ec_get_a - Get 'a' coefficient of an EC group's curve
+ * @e: EC context from crypto_ec_init()
+ * Returns: 'a' coefficient (bignum) of the group
+ */
const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e);
+
+/**
+ * crypto_ec_get_b - Get 'b' coeffiecient of an EC group's curve
+ * @e: EC context from crypto_ec_init()
+ * Returns: 'b' coefficient (bignum) of the group
+ */
const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e);
/**
- * struct crypto_ec_point - Elliptic curve point
- *
- * Internal data structure for EC implementation to represent a point. The
- * contents is specific to the used crypto library.
+ * crypto_ec_get_generator - Get generator point of the EC group's curve
+ * @e: EC context from crypto_ec_init()
+ * Returns: Pointer to generator point
*/
-struct crypto_ec_point;
+const struct crypto_ec_point * crypto_ec_get_generator(struct crypto_ec *e);
/**
* crypto_ec_point_init - Initialize data for an EC point
@@ -909,25 +934,357 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
const struct crypto_ec_point *a,
const struct crypto_ec_point *b);
+/**
+ * crypto_ec_point_debug_print - Dump EC point to debug log
+ * @e: EC context from crypto_ec_init()
+ * @p: EC point
+ * @title: Name of the EC point in the trace
+ */
+void crypto_ec_point_debug_print(const struct crypto_ec *e,
+ const struct crypto_ec_point *p,
+ const char *title);
+
+/**
+ * struct crypto_ec_key - Elliptic curve key pair
+ *
+ * Internal data structure for EC key pair. The contents is specific to the used
+ * crypto library.
+ */
+struct crypto_ec_key;
+
+/**
+ * struct crypto_ecdh - Elliptic Curve Diffie–Hellman context
+ *
+ * Internal data structure for ECDH. The contents is specific to the used
+ * crypto library.
+ */
struct crypto_ecdh;
+/**
+ * crypto_ecdh_init - Initialize elliptic curve Diffie–Hellman context
+ * @group: Identifying number for the ECC group (IANA "Group Description"
+ * attribute registry for RFC 2409)
+ * This function generates an ephemeral key pair.
+ * Returns: Pointer to ECDH context or %NULL on failure
+ */
struct crypto_ecdh * crypto_ecdh_init(int group);
+
+/**
+ * crypto_ecdh_init2 - Initialize elliptic curve Diffie–Hellman context with a
+ * given EC key
+ * @group: Identifying number for the ECC group (IANA "Group Description"
+ * attribute registry for RFC 2409)
+ * @own_key: Our own EC Key
+ * Returns: Pointer to ECDH context or %NULL on failure
+ */
+struct crypto_ecdh * crypto_ecdh_init2(int group,
+ struct crypto_ec_key *own_key);
+
+/**
+ * crypto_ecdh_get_pubkey - Retrieve public key from ECDH context
+ * @ecdh: ECDH context from crypto_ecdh_init() or crypto_ecdh_init2()
+ * @inc_y: Whether public key should include y coordinate (explicit form)
+ * or not (compressed form)
+ * Returns: Binary data f the public key or %NULL on failure
+ */
struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y);
+
+/**
+ * crypto_ecdh_set_peerkey - Compute ECDH secret
+ * @ecdh: ECDH context from crypto_ecdh_init() or crypto_ecdh_init2()
+ * @inc_y: Whether peer's public key includes y coordinate (explicit form)
+ * or not (compressed form)
+ * @key: Binary data of the peer's public key
+ * @len: Length of the @key buffer
+ * Returns: Binary data with the EDCH secret or %NULL on failure
+ */
struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
const u8 *key, size_t len);
+
+/**
+ * crypto_ecdh_deinit - Free ECDH context
+ * @ecdh: ECDH context from crypto_ecdh_init() or crypto_ecdh_init2()
+ */
void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
-size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
-struct crypto_ec_key;
+/**
+ * crypto_ecdh_prime_len - Get length of the prime in octets
+ * @e: ECDH context from crypto_ecdh_init()
+ * Returns: Length of the prime defining the group
+ */
+size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
+/**
+ * crypto_ec_key_parse_priv - Initialize EC key pair from ECPrivateKey ASN.1
+ * @der: DER encoding of ASN.1 ECPrivateKey
+ * @der_len: Length of @der buffer
+ * Returns: EC key or %NULL on failure
+ */
struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len);
+
+/**
+ * crypto_ec_key_parse_pub - Initialize EC key pair from SubjectPublicKeyInfo ASN.1
+ * @der: DER encoding of ASN.1 SubjectPublicKeyInfo
+ * @der_len: Length of @der buffer
+ * Returns: EC key or %NULL on failure
+ */
struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len);
+
+/**
+ * crypto_ec_key_set_pub - Initialize an EC public key from EC point coordinates
+ * @group: Identifying number for the ECC group
+ * @x: X coordinate of the public key
+ * @y: Y coordinate of the public key
+ * @len: Length of @x and @y buffer
+ * Returns: EC key or %NULL on failure
+ *
+ * This function initialize an EC key from public key coordinates, in big endian
+ * byte order padded to the length of the prime defining the group.
+ */
+struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *x,
+ const u8 *y, size_t len);
+
+/**
+ * crypto_ec_key_set_pub_point - Initialize an EC public key from EC point
+ * @e: EC context from crypto_ec_init()
+ * @pub: Public key point
+ * Returns: EC key or %NULL on failure
+ */
+struct crypto_ec_key *
+crypto_ec_key_set_pub_point(struct crypto_ec *e,
+ const struct crypto_ec_point *pub);
+
+/**
+ * crypto_ec_key_gen - Generate EC key pair
+ * @group: Identifying number for the ECC group
+ * Returns: EC key or %NULL on failure
+ */
+struct crypto_ec_key * crypto_ec_key_gen(int group);
+
+/**
+ * crypto_ec_key_deinit - Free EC key
+ * @key: EC key from crypto_ec_key_parse_pub/priv() or crypto_ec_key_gen()
+ */
void crypto_ec_key_deinit(struct crypto_ec_key *key);
+
+/**
+ * crypto_ec_key_get_subject_public_key - Get SubjectPublicKeyInfo ASN.1 for an EC key
+ * @key: EC key from crypto_ec_key_parse/set_pub/priv() or crypto_ec_key_gen()
+ * Returns: Buffer with DER encoding of ASN.1 SubjectPublicKeyInfo or %NULL on failure
+ */
struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key);
+
+/**
+ * crypto_ec_key_get_ecprivate_key - Get ECPrivateKey ASN.1 for a EC key
+ * @key: EC key from crypto_ec_key_parse_priv() or crypto_ec_key_gen()
+ * @include_pub: Whether to include public key in the ASN.1 sequence
+ * Returns: Buffer with DER encoding of ASN.1 ECPrivateKey or %NULL on failure
+ */
+struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key,
+ bool include_pub);
+
+/**
+ * crypto_ec_key_get_pubkey_point - Get public key point coordinates
+ * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_parse_priv()
+ * @prefix: Whether output buffer should include the octet to indicate
+ * coordinate form (as defined for SubjectPublicKeyInfo)
+ * Returns: Buffer with coordinates of public key in uncompressed form or %NULL
+ * on failure
+ */
+struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key,
+ int prefix);
+
+/**
+ * crypto_ec_key_get_public_key - Get EC public key as an EC point
+ * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_parse_priv()
+ * Returns: Public key as an EC point or %NULL on failure
+ */
+const struct crypto_ec_point *
+crypto_ec_key_get_public_key(struct crypto_ec_key *key);
+
+/**
+ * crypto_ec_key_get_private_key - Get EC private key as a bignum
+ * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_parse_priv()
+ * Returns: Private key as a bignum or %NULL on failure
+ */
+const struct crypto_bignum *
+crypto_ec_key_get_private_key(struct crypto_ec_key *key);
+
+/**
+ * crypto_ec_key_sign - Sign a buffer with an EC key
+ * @key: EC key from crypto_ec_key_parse_priv() or crypto_ec_key_gen()
+ * @data: Data to sign
+ * @len: Length of @data buffer
+ * Returns: Buffer with DER encoding of ASN.1 Ecdsa-Sig-Value or %NULL on failure
+ */
struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
size_t len);
+
+/**
+ * crypto_ec_key_sign_r_s - Sign a buffer with an EC key
+ * @key: EC key from crypto_ec_key_parse_priv() or crypto_ec_key_gen()
+ * @data: Data to sign
+ * @len: Length of @data buffer
+ * Returns: Buffer with the concatenated r and s values. Each value is in big
+ * endian byte order padded to the length of the prime defining the group of
+ * the key.
+ */
+struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
+ const u8 *data, size_t len);
+
+/**
+ * crypto_ec_key_verify_signature - Verify ECDSA signature
+ * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_gen()
+ * @data: Data to be signed
+ * @len: Length of @data buffer
+ * @sig: DER encoding of ASN.1 Ecdsa-Sig-Value
+ * @sig_len: Length of @sig buffer
+ * Returns: 1 if signature is valid, 0 if signature is invalid and -1 on failure
+ */
int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
size_t len, const u8 *sig, size_t sig_len);
+
+/**
+ * crypto_ec_key_verify_signature_r_s - Verify signature
+ * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_gen()
+ * @data: Data to signed
+ * @len: Length of @data buffer
+ * @r: Binary data, in big endian byte order, of the 'r' field of the ECDSA
+ * signature.
+ * @s: Binary data, in big endian byte order, of the 's' field of the ECDSA
+ * signature.
+ * @r_len: Length of @r buffer
+ * @s_len: Length of @s buffer
+ * Returns: 1 if signature is valid, 0 if signature is invalid, or -1 on failure
+ */
+int crypto_ec_key_verify_signature_r_s(struct crypto_ec_key *key,
+ const u8 *data, size_t len,
+ const u8 *r, size_t r_len,
+ const u8 *s, size_t s_len);
+
+/**
+ * crypto_ec_key_group - Get IANA group identifier for an EC key
+ * @key: EC key from crypto_ec_key_parse/set_pub/priv() or crypto_ec_key_gen()
+ * Returns: IANA group identifier and -1 on failure
+ */
int crypto_ec_key_group(struct crypto_ec_key *key);
+/**
+ * crypto_ec_key_cmp - Compare two EC public keys
+ * @key1: Key 1
+ * @key2: Key 2
+ * Returns: 0 if public keys are identical, -1 otherwise
+ */
+int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2);
+
+/**
+ * crypto_ec_key_debug_print - Dump EC key to debug log
+ * @key: EC key from crypto_ec_key_parse/set_pub/priv() or crypto_ec_key_gen()
+ * @title: Name of the EC point in the trace
+ */
+void crypto_ec_key_debug_print(const struct crypto_ec_key *key,
+ const char *title);
+
+/**
+ * struct crypto_csr - Certification Signing Request
+ *
+ * Internal data structure for CSR. The contents is specific to the used
+ * crypto library.
+ * For now it is assumed that only an EC public key can be used
+ */
+struct crypto_csr;
+
+/**
+ * enum crypto_csr_name - CSR name type
+ */
+enum crypto_csr_name {
+ CSR_NAME_CN,
+ CSR_NAME_SN,
+ CSR_NAME_C,
+ CSR_NAME_O,
+ CSR_NAME_OU,
+};
+
+/**
+ * enum crypto_csr_attr - CSR attribute
+ */
+enum crypto_csr_attr {
+ CSR_ATTR_CHALLENGE_PASSWORD,
+};
+
+/**
+ * crypto_csr_init - Initialize empty CSR
+ * Returns: Pointer to CSR data or %NULL on failure
+ */
+struct crypto_csr * crypto_csr_init(void);
+
+/**
+ * crypto_csr_verify - Initialize CSR from CertificationRequest
+ * @req: DER encoding of ASN.1 CertificationRequest
+ *
+ * Returns: Pointer to CSR data or %NULL on failure or if signature is invalid
+ */
+struct crypto_csr * crypto_csr_verify(const struct wpabuf *req);
+
+/**
+ * crypto_csr_deinit - Free CSR structure
+ * @csr: CSR structure from @crypto_csr_init() or crypto_csr_verify()
+ */
+void crypto_csr_deinit(struct crypto_csr *csr);
+
+/**
+ * crypto_csr_set_ec_public_key - Set public key in CSR
+ * @csr: CSR structure from @crypto_csr_init()
+ * @key: EC public key to set as public key in the CSR
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_csr_set_ec_public_key(struct crypto_csr *csr,
+ struct crypto_ec_key *key);
+
+/**
+ * crypto_csr_set_name - Set name entry in CSR SubjectName
+ * @csr: CSR structure from @crypto_csr_init()
+ * @type: Name type to add into the CSR SubjectName
+ * @name: UTF-8 string to write in the CSR SubjectName
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_csr_set_name(struct crypto_csr *csr, enum crypto_csr_name type,
+ const char *name);
+
+/**
+ * crypto_csr_set_attribute - Set attribute in CSR
+ * @csr: CSR structure from @crypto_csr_init()
+ * @attr: Attribute identifier
+ * @attr_type: ASN.1 type of @value buffer
+ * @value: Attribute value
+ * @len: length of @value buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_csr_set_attribute(struct crypto_csr *csr, enum crypto_csr_attr attr,
+ int attr_type, const u8 *value, size_t len);
+
+/**
+ * crypto_csr_get_attribute - Get attribute from CSR
+ * @csr: CSR structure from @crypto_csr_verify()
+ * @attr: Updated with atribute identifier
+ * @len: Updated with length of returned buffer
+ * @type: ASN.1 type of the attribute buffer
+ * Returns: Type, length, and pointer on attribute value or %NULL on failure
+ */
+const u8 * crypto_csr_get_attribute(struct crypto_csr *csr,
+ enum crypto_csr_attr attr,
+ size_t *len, int *type);
+
+/**
+ * crypto_csr_sign - Sign CSR and return ASN.1 CertificationRequest
+ * @csr: CSR structure from @crypto_csr_init()
+ * @key: Private key to sign the CSR (for now ony EC key are supported)
+ * @algo: Hash algorithm to use for the signature
+ * Returns: DER encoding of ASN.1 CertificationRequest for the CSR or %NULL on
+ * failure
+ */
+struct wpabuf * crypto_csr_sign(struct crypto_csr *csr,
+ struct crypto_ec_key *key,
+ enum crypto_hash_alg algo);
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_internal-rsa.c b/src/crypto/crypto_internal-rsa.c
index dc7f350af057..0c5ceadb805a 100644
--- a/src/crypto/crypto_internal-rsa.c
+++ b/src/crypto/crypto_internal-rsa.c
@@ -14,7 +14,7 @@
#include "tls/pkcs1.h"
#include "tls/pkcs8.h"
-/* Dummy structures; these are just typecast to struct crypto_rsa_key */
+/* Stub structures; these are just typecast to struct crypto_rsa_key */
struct crypto_public_key;
struct crypto_private_key;
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index a4b1083bb4c1..ef669c408474 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -22,6 +22,7 @@
#ifdef CONFIG_ECC
#include <openssl/ec.h>
#include <openssl/x509.h>
+#include <openssl/pem.h>
#endif /* CONFIG_ECC */
#include "common.h"
@@ -82,14 +83,38 @@ static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
#ifdef CONFIG_ECC
+
static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
{
if (pkey->type != EVP_PKEY_EC)
return NULL;
return pkey->pkey.ec;
}
+
+
+static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+ sig->r = r;
+ sig->s = s;
+ return 1;
+}
+
+
+static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr,
+ const BIGNUM **ps)
+{
+ if (pr)
+ *pr = sig->r;
+ if (ps)
+ *ps = sig->s;
+}
+
#endif /* CONFIG_ECC */
+static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
+{
+ return ASN1_STRING_data((ASN1_STRING *) x);
+}
#endif /* OpenSSL version < 1.1.0 */
static BIGNUM * get_group5_prime(void)
@@ -206,8 +231,8 @@ int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
- int i;
- DES_key_schedule ks;
+ int i, plen, ret = -1;
+ EVP_CIPHER_CTX *ctx;
/* Add parity bits to the key */
next = 0;
@@ -218,10 +243,19 @@ int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
}
pkey[i] = next | 1;
- DES_set_key((DES_cblock *) &pkey, &ks);
- DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
- DES_ENCRYPT);
- return 0;
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx &&
+ EVP_EncryptInit_ex(ctx, EVP_des_ecb(), NULL, pkey, NULL) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_EncryptUpdate(ctx, cypher, &plen, clear, 8) == 1 &&
+ EVP_EncryptFinal_ex(ctx, &cypher[plen], &plen) == 1)
+ ret = 0;
+ else
+ wpa_printf(MSG_ERROR, "OpenSSL: DES encrypt failed");
+
+ if (ctx)
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
}
@@ -239,8 +273,8 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip,
ctx = EVP_CIPHER_CTX_new();
if (!ctx ||
- !EVP_CIPHER_CTX_set_padding(ctx, 0) ||
!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
+ !EVP_CIPHER_CTX_set_padding(ctx, 0) ||
!EVP_CIPHER_CTX_set_key_length(ctx, keylen) ||
!EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, 1))
goto out;
@@ -700,8 +734,8 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
}
if (!(ctx->enc = EVP_CIPHER_CTX_new()) ||
- !EVP_CIPHER_CTX_set_padding(ctx->enc, 0) ||
!EVP_EncryptInit_ex(ctx->enc, cipher, NULL, NULL, NULL) ||
+ !EVP_CIPHER_CTX_set_padding(ctx->enc, 0) ||
!EVP_CIPHER_CTX_set_key_length(ctx->enc, key_len) ||
!EVP_EncryptInit_ex(ctx->enc, NULL, NULL, key, iv)) {
if (ctx->enc)
@@ -711,8 +745,8 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
}
if (!(ctx->dec = EVP_CIPHER_CTX_new()) ||
- !EVP_CIPHER_CTX_set_padding(ctx->dec, 0) ||
!EVP_DecryptInit_ex(ctx->dec, cipher, NULL, NULL, NULL) ||
+ !EVP_CIPHER_CTX_set_padding(ctx->dec, 0) ||
!EVP_CIPHER_CTX_set_key_length(ctx->dec, key_len) ||
!EVP_DecryptInit_ex(ctx->dec, NULL, NULL, key, iv)) {
EVP_CIPHER_CTX_free(ctx->enc);
@@ -1631,51 +1665,51 @@ struct crypto_ec {
BIGNUM *b;
};
-struct crypto_ec * crypto_ec_init(int group)
-{
- struct crypto_ec *e;
- int nid;
+static int crypto_ec_group_2_nid(int group)
+{
/* Map from IANA registry for IKE D-H groups to OpenSSL NID */
switch (group) {
case 19:
- nid = NID_X9_62_prime256v1;
- break;
+ return NID_X9_62_prime256v1;
case 20:
- nid = NID_secp384r1;
- break;
+ return NID_secp384r1;
case 21:
- nid = NID_secp521r1;
- break;
+ return NID_secp521r1;
case 25:
- nid = NID_X9_62_prime192v1;
- break;
+ return NID_X9_62_prime192v1;
case 26:
- nid = NID_secp224r1;
- break;
+ return NID_secp224r1;
#ifdef NID_brainpoolP224r1
case 27:
- nid = NID_brainpoolP224r1;
- break;
+ return NID_brainpoolP224r1;
#endif /* NID_brainpoolP224r1 */
#ifdef NID_brainpoolP256r1
case 28:
- nid = NID_brainpoolP256r1;
- break;
+ return NID_brainpoolP256r1;
#endif /* NID_brainpoolP256r1 */
#ifdef NID_brainpoolP384r1
case 29:
- nid = NID_brainpoolP384r1;
- break;
+ return NID_brainpoolP384r1;
#endif /* NID_brainpoolP384r1 */
#ifdef NID_brainpoolP512r1
case 30:
- nid = NID_brainpoolP512r1;
- break;
+ return NID_brainpoolP512r1;
#endif /* NID_brainpoolP512r1 */
default:
- return NULL;
+ return -1;
}
+}
+
+
+struct crypto_ec * crypto_ec_init(int group)
+{
+ struct crypto_ec *e;
+ int nid;
+
+ nid = crypto_ec_group_2_nid(group);
+ if (nid < 0)
+ return NULL;
e = os_zalloc(sizeof(*e));
if (e == NULL)
@@ -1766,6 +1800,13 @@ const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
}
+const struct crypto_ec_point * crypto_ec_get_generator(struct crypto_ec *e)
+{
+ return (const struct crypto_ec_point *)
+ EC_GROUP_get0_generator(e->group);
+}
+
+
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
{
if (clear)
@@ -1951,6 +1992,35 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
}
+void crypto_ec_point_debug_print(const struct crypto_ec *e,
+ const struct crypto_ec_point *p,
+ const char *title)
+{
+ BIGNUM *x, *y;
+ char *x_str = NULL, *y_str = NULL;
+
+ x = BN_new();
+ y = BN_new();
+ if (!x || !y ||
+ EC_POINT_get_affine_coordinates_GFp(e->group, (const EC_POINT *) p,
+ x, y, e->bnctx) != 1)
+ goto fail;
+
+ x_str = BN_bn2hex(x);
+ y_str = BN_bn2hex(y);
+ if (!x_str || !y_str)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "%s (%s,%s)", title, x_str, y_str);
+
+fail:
+ OPENSSL_free(x_str);
+ OPENSSL_free(y_str);
+ BN_free(x);
+ BN_free(y);
+}
+
+
struct crypto_ecdh {
struct crypto_ec *ec;
EVP_PKEY *pkey;
@@ -2015,6 +2085,32 @@ fail:
}
+struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key)
+{
+ struct crypto_ecdh *ecdh;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ ecdh->pkey = EVP_PKEY_new();
+ if (!ecdh->pkey ||
+ EVP_PKEY_assign_EC_KEY(ecdh->pkey,
+ EVP_PKEY_get1_EC_KEY((EVP_PKEY *) own_key))
+ != 1)
+ goto fail;
+
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ return NULL;
+}
+
+
struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
{
struct wpabuf *buf = NULL;
@@ -2186,83 +2282,325 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
}
-struct crypto_ec_key {
- EVP_PKEY *pkey;
- EC_KEY *eckey;
-};
-
-
struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
{
- struct crypto_ec_key *key;
-
- key = os_zalloc(sizeof(*key));
- if (!key)
- return NULL;
+ EVP_PKEY *pkey = NULL;
+ EC_KEY *eckey;
- key->eckey = d2i_ECPrivateKey(NULL, &der, der_len);
- if (!key->eckey) {
+ eckey = d2i_ECPrivateKey(NULL, &der, der_len);
+ if (!eckey) {
wpa_printf(MSG_INFO, "OpenSSL: d2i_ECPrivateKey() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
- EC_KEY_set_conv_form(key->eckey, POINT_CONVERSION_COMPRESSED);
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
- key->pkey = EVP_PKEY_new();
- if (!key->pkey || EVP_PKEY_assign_EC_KEY(key->pkey, key->eckey) != 1) {
- EC_KEY_free(key->eckey);
- key->eckey = NULL;
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
+ EC_KEY_free(eckey);
goto fail;
}
- return key;
+ return (struct crypto_ec_key *) pkey;
fail:
- crypto_ec_key_deinit(key);
+ crypto_ec_key_deinit((struct crypto_ec_key *) pkey);
return NULL;
}
struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
{
- struct crypto_ec_key *key;
-
- key = os_zalloc(sizeof(*key));
- if (!key)
- return NULL;
+ EVP_PKEY *pkey;
- key->pkey = d2i_PUBKEY(NULL, &der, der_len);
- if (!key->pkey) {
+ pkey = d2i_PUBKEY(NULL, &der, der_len);
+ if (!pkey) {
wpa_printf(MSG_INFO, "OpenSSL: d2i_PUBKEY() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
- key->eckey = EVP_PKEY_get0_EC_KEY(key->pkey);
- if (!key->eckey)
+ /* Ensure this is an EC key */
+ if (!EVP_PKEY_get0_EC_KEY(pkey))
goto fail;
- return key;
+ return (struct crypto_ec_key *) pkey;
fail:
- crypto_ec_key_deinit(key);
+ crypto_ec_key_deinit((struct crypto_ec_key *) pkey);
return NULL;
}
-void crypto_ec_key_deinit(struct crypto_ec_key *key)
+struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *buf_x,
+ const u8 *buf_y, size_t len)
{
- if (key) {
- EVP_PKEY_free(key->pkey);
- os_free(key);
+ EC_KEY *eckey = NULL;
+ EVP_PKEY *pkey = NULL;
+ EC_GROUP *ec_group = NULL;
+ BN_CTX *ctx;
+ EC_POINT *point = NULL;
+ BIGNUM *x = NULL, *y = NULL;
+ int nid;
+
+ if (!buf_x || !buf_y)
+ return NULL;
+
+ nid = crypto_ec_group_2_nid(group);
+ if (nid < 0) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Unsupported group %d", group);
+ return NULL;
+ }
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ goto fail;
+
+ ec_group = EC_GROUP_new_by_curve_name(nid);
+ if (!ec_group)
+ goto fail;
+
+ x = BN_bin2bn(buf_x, len, NULL);
+ y = BN_bin2bn(buf_y, len, NULL);
+ point = EC_POINT_new(ec_group);
+ if (!x || !y || !point)
+ goto fail;
+
+ if (!EC_POINT_set_affine_coordinates_GFp(ec_group, point, x, y, ctx)) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ if (!EC_POINT_is_on_curve(ec_group, point, ctx) ||
+ EC_POINT_is_at_infinity(ec_group, point)) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Invalid point");
+ goto fail;
}
+
+ eckey = EC_KEY_new();
+ if (!eckey ||
+ EC_KEY_set_group(eckey, ec_group) != 1 ||
+ EC_KEY_set_public_key(eckey, point) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to set EC_KEY: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Could not create EVP_PKEY");
+ goto fail;
+ }
+
+out:
+ EC_GROUP_free(ec_group);
+ BN_free(x);
+ BN_free(y);
+ EC_POINT_free(point);
+ BN_CTX_free(ctx);
+ return (struct crypto_ec_key *) pkey;
+
+fail:
+ EC_KEY_free(eckey);
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ goto out;
+}
+
+
+struct crypto_ec_key *
+crypto_ec_key_set_pub_point(struct crypto_ec *ec,
+ const struct crypto_ec_point *pub)
+{
+ EC_KEY *eckey;
+ EVP_PKEY *pkey = NULL;
+
+ eckey = EC_KEY_new();
+ if (!eckey ||
+ EC_KEY_set_group(eckey, ec->group) != 1 ||
+ EC_KEY_set_public_key(eckey, (const EC_POINT *) pub) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to set EC_KEY: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
+
+ pkey = EVP_PKEY_new();
+ if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Could not create EVP_PKEY");
+ goto fail;
+ }
+
+out:
+ return (struct crypto_ec_key *) pkey;
+
+fail:
+ EVP_PKEY_free(pkey);
+ EC_KEY_free(eckey);
+ pkey = NULL;
+ goto out;
+}
+
+
+struct crypto_ec_key * crypto_ec_key_gen(int group)
+{
+ EVP_PKEY_CTX *kctx = NULL;
+ EC_KEY *ec_params = NULL, *eckey;
+ EVP_PKEY *params = NULL, *key = NULL;
+ int nid;
+
+ nid = crypto_ec_group_2_nid(group);
+ if (nid < 0) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Unsupported group %d", group);
+ return NULL;
+ }
+
+ ec_params = EC_KEY_new_by_curve_name(nid);
+ if (!ec_params) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to generate EC_KEY parameters");
+ goto fail;
+ }
+ EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE);
+ params = EVP_PKEY_new();
+ if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to generate EVP_PKEY parameters");
+ goto fail;
+ }
+
+ kctx = EVP_PKEY_CTX_new(params, NULL);
+ if (!kctx ||
+ EVP_PKEY_keygen_init(kctx) != 1 ||
+ EVP_PKEY_keygen(kctx, &key) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Failed to generate EC key");
+ key = NULL;
+ goto fail;
+ }
+
+ eckey = EVP_PKEY_get0_EC_KEY(key);
+ if (!eckey) {
+ key = NULL;
+ goto fail;
+ }
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
+
+fail:
+ EC_KEY_free(ec_params);
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(kctx);
+ return (struct crypto_ec_key *) key;
+}
+
+
+void crypto_ec_key_deinit(struct crypto_ec_key *key)
+{
+ EVP_PKEY_free((EVP_PKEY *) key);
}
+#ifdef OPENSSL_IS_BORINGSSL
+
+/* BoringSSL version of i2d_PUBKEY() always outputs public EC key using
+ * uncompressed form so define a custom function to export EC pubkey using
+ * the compressed format that is explicitly required for some protocols. */
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+
+typedef struct {
+ /* AlgorithmIdentifier ecPublicKey with optional parameters present
+ * as an OID identifying the curve */
+ X509_ALGOR *alg;
+ /* Compressed format public key per ANSI X9.63 */
+ ASN1_BIT_STRING *pub_key;
+} EC_COMP_PUBKEY;
+
+ASN1_SEQUENCE(EC_COMP_PUBKEY) = {
+ ASN1_SIMPLE(EC_COMP_PUBKEY, alg, X509_ALGOR),
+ ASN1_SIMPLE(EC_COMP_PUBKEY, pub_key, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(EC_COMP_PUBKEY);
+
+IMPLEMENT_ASN1_FUNCTIONS(EC_COMP_PUBKEY);
+
+#endif /* OPENSSL_IS_BORINGSSL */
+
+
struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
{
+#ifdef OPENSSL_IS_BORINGSSL
+ unsigned char *der = NULL;
+ int der_len;
+ const EC_KEY *eckey;
+ struct wpabuf *ret = NULL;
+ size_t len;
+ const EC_GROUP *group;
+ const EC_POINT *point;
+ BN_CTX *ctx;
+ EC_COMP_PUBKEY *pubkey = NULL;
+ int nid;
+
+ ctx = BN_CTX_new();
+ eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!ctx || !eckey)
+ goto fail;
+
+ group = EC_KEY_get0_group(eckey);
+ point = EC_KEY_get0_public_key(eckey);
+ if (!group || !point)
+ goto fail;
+ nid = EC_GROUP_get_curve_name(group);
+
+ pubkey = EC_COMP_PUBKEY_new();
+ if (!pubkey ||
+ X509_ALGOR_set0(pubkey->alg, OBJ_nid2obj(EVP_PKEY_EC),
+ V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
+ goto fail;
+
+ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+ NULL, 0, ctx);
+ if (len == 0)
+ goto fail;
+
+ der = OPENSSL_malloc(len);
+ if (!der)
+ goto fail;
+ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
+ der, len, ctx);
+
+ OPENSSL_free(pubkey->pub_key->data);
+ pubkey->pub_key->data = der;
+ der = NULL;
+ pubkey->pub_key->length = len;
+ /* No unused bits */
+ pubkey->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
+ pubkey->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
+
+ der_len = i2d_EC_COMP_PUBKEY(pubkey, &der);
+ if (der_len <= 0) {
+ wpa_printf(MSG_ERROR,
+ "BoringSSL: Failed to build DER encoded public key");
+ goto fail;
+ }
+
+ ret = wpabuf_alloc_copy(der, der_len);
+fail:
+ EC_COMP_PUBKEY_free(pubkey);
+ OPENSSL_free(der);
+ BN_CTX_free(ctx);
+ return ret;
+#else /* OPENSSL_IS_BORINGSSL */
unsigned char *der = NULL;
int der_len;
struct wpabuf *buf;
- der_len = i2d_PUBKEY(key->pkey, &der);
+ /* For now, all users expect COMPRESSED form */
+ EC_KEY_set_conv_form(EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key),
+ POINT_CONVERSION_COMPRESSED);
+
+ der_len = i2d_PUBKEY((EVP_PKEY *) key, &der);
if (der_len <= 0) {
wpa_printf(MSG_INFO, "OpenSSL: i2d_PUBKEY() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -2272,6 +2610,111 @@ struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
buf = wpabuf_alloc_copy(der, der_len);
OPENSSL_free(der);
return buf;
+#endif /* OPENSSL_IS_BORINGSSL */
+}
+
+
+struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key,
+ bool include_pub)
+{
+ EC_KEY *eckey;
+ unsigned char *der = NULL;
+ int der_len;
+ struct wpabuf *buf;
+ unsigned int key_flags;
+
+ eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!eckey)
+ return NULL;
+
+ key_flags = EC_KEY_get_enc_flags(eckey);
+ if (include_pub)
+ key_flags &= ~EC_PKEY_NO_PUBKEY;
+ else
+ key_flags |= EC_PKEY_NO_PUBKEY;
+ EC_KEY_set_enc_flags(eckey, key_flags);
+
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
+
+ der_len = i2d_ECPrivateKey(eckey, &der);
+ if (der_len <= 0)
+ return NULL;
+ buf = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+
+ return buf;
+}
+
+
+struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key,
+ int prefix)
+{
+ int len, res;
+ EC_KEY *eckey;
+ struct wpabuf *buf;
+ unsigned char *pos;
+
+ eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+ if (!eckey)
+ return NULL;
+ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
+ len = i2o_ECPublicKey(eckey, NULL);
+ if (len <= 0) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to determine public key encoding length");
+ EC_KEY_free(eckey);
+ return NULL;
+ }
+
+ buf = wpabuf_alloc(len);
+ if (!buf) {
+ EC_KEY_free(eckey);
+ return NULL;
+ }
+
+ pos = wpabuf_put(buf, len);
+ res = i2o_ECPublicKey(eckey, &pos);
+ EC_KEY_free(eckey);
+ if (res != len) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to encode public key (res=%d/%d)",
+ res, len);
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ if (!prefix) {
+ /* Remove 0x04 prefix if requested */
+ pos = wpabuf_mhead(buf);
+ os_memmove(pos, pos + 1, len - 1);
+ buf->used--;
+ }
+
+ return buf;
+}
+
+
+const struct crypto_ec_point *
+crypto_ec_key_get_public_key(struct crypto_ec_key *key)
+{
+ EC_KEY *eckey;
+
+ eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!eckey)
+ return NULL;
+ return (const struct crypto_ec_point *) EC_KEY_get0_public_key(eckey);
+}
+
+
+const struct crypto_bignum *
+crypto_ec_key_get_private_key(struct crypto_ec_key *key)
+{
+ EC_KEY *eckey;
+
+ eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!eckey)
+ return NULL;
+ return (const struct crypto_bignum *) EC_KEY_get0_private_key(eckey);
}
@@ -2282,12 +2725,12 @@ struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
struct wpabuf *sig_der;
size_t sig_len;
- sig_len = EVP_PKEY_size(key->pkey);
+ sig_len = EVP_PKEY_size((EVP_PKEY *) key);
sig_der = wpabuf_alloc(sig_len);
if (!sig_der)
return NULL;
- pkctx = EVP_PKEY_CTX_new(key->pkey, NULL);
+ pkctx = EVP_PKEY_CTX_new((EVP_PKEY *) key, NULL);
if (!pkctx ||
EVP_PKEY_sign_init(pkctx) <= 0 ||
EVP_PKEY_sign(pkctx, wpabuf_put(sig_der, 0), &sig_len,
@@ -2303,13 +2746,68 @@ struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
}
+struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
+ const u8 *data, size_t len)
+{
+ const EC_GROUP *group;
+ const EC_KEY *eckey;
+ BIGNUM *prime = NULL;
+ ECDSA_SIG *sig = NULL;
+ const BIGNUM *r, *s;
+ u8 *r_buf, *s_buf;
+ struct wpabuf *buf;
+ const unsigned char *p;
+ int prime_len;
+
+ buf = crypto_ec_key_sign(key, data, len);
+ if (!buf)
+ return NULL;
+
+ /* Extract (r,s) from Ecdsa-Sig-Value */
+ eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!eckey)
+ goto fail;
+ group = EC_KEY_get0_group(eckey);
+ prime = BN_new();
+ if (!prime || !group ||
+ !EC_GROUP_get_curve_GFp(group, prime, NULL, NULL, NULL))
+ goto fail;
+ prime_len = BN_num_bytes(prime);
+
+ p = wpabuf_head(buf);
+ sig = d2i_ECDSA_SIG(NULL, &p, wpabuf_len(buf));
+ if (!sig)
+ goto fail;
+ ECDSA_SIG_get0(sig, &r, &s);
+
+ /* Re-use wpabuf returned by crypto_ec_key_sign() */
+ buf->used = 0;
+ r_buf = wpabuf_put(buf, prime_len);
+ s_buf = wpabuf_put(buf, prime_len);
+ if (crypto_bignum_to_bin((const struct crypto_bignum *) r, r_buf,
+ prime_len, prime_len) < 0 ||
+ crypto_bignum_to_bin((const struct crypto_bignum *) s, s_buf,
+ prime_len, prime_len) < 0)
+ goto fail;
+
+out:
+ BN_free(prime);
+ ECDSA_SIG_free(sig);
+ return buf;
+fail:
+ wpabuf_clear_free(buf);
+ buf = NULL;
+ goto out;
+}
+
+
int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
size_t len, const u8 *sig, size_t sig_len)
{
EVP_PKEY_CTX *pkctx;
int ret;
- pkctx = EVP_PKEY_CTX_new(key->pkey, NULL);
+ pkctx = EVP_PKEY_CTX_new((EVP_PKEY *) key, NULL);
if (!pkctx || EVP_PKEY_verify_init(pkctx) <= 0) {
EVP_PKEY_CTX_free(pkctx);
return -1;
@@ -2325,12 +2823,53 @@ int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
}
+int crypto_ec_key_verify_signature_r_s(struct crypto_ec_key *key,
+ const u8 *data, size_t len,
+ const u8 *r, size_t r_len,
+ const u8 *s, size_t s_len)
+{
+ ECDSA_SIG *sig;
+ BIGNUM *r_bn, *s_bn;
+ unsigned char *der = NULL;
+ int der_len;
+ int ret = -1;
+
+ r_bn = BN_bin2bn(r, r_len, NULL);
+ s_bn = BN_bin2bn(s, s_len, NULL);
+ sig = ECDSA_SIG_new();
+ if (!r_bn || !s_bn || !sig || ECDSA_SIG_set0(sig, r_bn, s_bn) != 1)
+ goto fail;
+ r_bn = NULL;
+ s_bn = NULL;
+
+ der_len = i2d_ECDSA_SIG(sig, &der);
+ if (der_len <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Could not DER encode signature");
+ goto fail;
+ }
+
+ ret = crypto_ec_key_verify_signature(key, data, len, der, der_len);
+
+fail:
+ OPENSSL_free(der);
+ BN_free(r_bn);
+ BN_free(s_bn);
+ ECDSA_SIG_free(sig);
+ return ret;
+}
+
+
int crypto_ec_key_group(struct crypto_ec_key *key)
{
+ const EC_KEY *eckey;
const EC_GROUP *group;
int nid;
- group = EC_KEY_get0_group(key->eckey);
+ eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!eckey)
+ return -1;
+ group = EC_KEY_get0_group(eckey);
if (!group)
return -1;
nid = EC_GROUP_get_curve_name(group);
@@ -2341,8 +2880,334 @@ int crypto_ec_key_group(struct crypto_ec_key *key)
return 20;
case NID_secp521r1:
return 21;
+#ifdef NID_brainpoolP256r1
+ case NID_brainpoolP256r1:
+ return 28;
+#endif /* NID_brainpoolP256r1 */
+#ifdef NID_brainpoolP384r1
+ case NID_brainpoolP384r1:
+ return 29;
+#endif /* NID_brainpoolP384r1 */
+#ifdef NID_brainpoolP512r1
+ case NID_brainpoolP512r1:
+ return 30;
+#endif /* NID_brainpoolP512r1 */
}
+ wpa_printf(MSG_ERROR, "OpenSSL: Unsupported curve (nid=%d) in EC key",
+ nid);
return -1;
}
+
+int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2)
+{
+ if (EVP_PKEY_cmp((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1)
+ return -1;
+ return 0;
+}
+
+
+void crypto_ec_key_debug_print(const struct crypto_ec_key *key,
+ const char *title)
+{
+ BIO *out;
+ size_t rlen;
+ char *txt;
+ int res;
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ return;
+
+ EVP_PKEY_print_private(out, (EVP_PKEY *) key, 0, NULL);
+ rlen = BIO_ctrl_pending(out);
+ txt = os_malloc(rlen + 1);
+ if (txt) {
+ res = BIO_read(out, txt, rlen);
+ if (res > 0) {
+ txt[res] = '\0';
+ wpa_printf(MSG_DEBUG, "%s: %s", title, txt);
+ }
+ os_free(txt);
+ }
+ BIO_free(out);
+}
+
+
+struct wpabuf * crypto_pkcs7_get_certificates(const struct wpabuf *pkcs7)
+{
+#ifdef OPENSSL_IS_BORINGSSL
+ CBS pkcs7_cbs;
+#else /* OPENSSL_IS_BORINGSSL */
+ PKCS7 *p7 = NULL;
+ const unsigned char *p = wpabuf_head(pkcs7);
+#endif /* OPENSSL_IS_BORINGSSL */
+ STACK_OF(X509) *certs;
+ int i, num;
+ BIO *out = NULL;
+ size_t rlen;
+ struct wpabuf *pem = NULL;
+ int res;
+
+#ifdef OPENSSL_IS_BORINGSSL
+ certs = sk_X509_new_null();
+ if (!certs)
+ goto fail;
+ CBS_init(&pkcs7_cbs, wpabuf_head(pkcs7), wpabuf_len(pkcs7));
+ if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+#else /* OPENSSL_IS_BORINGSSL */
+ p7 = d2i_PKCS7(NULL, &p, wpabuf_len(pkcs7));
+ if (!p7) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Could not parse PKCS#7 object: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto fail;
+ }
+
+ switch (OBJ_obj2nid(p7->type)) {
+ case NID_pkcs7_signed:
+ certs = p7->d.sign->cert;
+ break;
+ case NID_pkcs7_signedAndEnveloped:
+ certs = p7->d.signed_and_enveloped->cert;
+ break;
+ default:
+ certs = NULL;
+ break;
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+
+ if (!certs || ((num = sk_X509_num(certs)) == 0)) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: No certificates found in PKCS#7 object");
+ goto fail;
+ }
+
+ out = BIO_new(BIO_s_mem());
+ if (!out)
+ goto fail;
+
+ for (i = 0; i < num; i++) {
+ X509 *cert = sk_X509_value(certs, i);
+
+ PEM_write_bio_X509(out, cert);
+ }
+
+ rlen = BIO_ctrl_pending(out);
+ pem = wpabuf_alloc(rlen);
+ if (!pem)
+ goto fail;
+ res = BIO_read(out, wpabuf_put(pem, 0), rlen);
+ if (res <= 0) {
+ wpabuf_free(pem);
+ pem = NULL;
+ goto fail;
+ }
+ wpabuf_put(pem, res);
+
+fail:
+#ifdef OPENSSL_IS_BORINGSSL
+ if (certs)
+ sk_X509_pop_free(certs, X509_free);
+#else /* OPENSSL_IS_BORINGSSL */
+ PKCS7_free(p7);
+#endif /* OPENSSL_IS_BORINGSSL */
+ if (out)
+ BIO_free_all(out);
+
+ return pem;
+}
+
+
+struct crypto_csr * crypto_csr_init()
+{
+ return (struct crypto_csr *)X509_REQ_new();
+}
+
+
+struct crypto_csr * crypto_csr_verify(const struct wpabuf *req)
+{
+ X509_REQ *csr;
+ EVP_PKEY *pkey = NULL;
+ const u8 *der = wpabuf_head(req);
+
+ csr = d2i_X509_REQ(NULL, &der, wpabuf_len(req));
+ if (!csr)
+ return NULL;
+
+ pkey = X509_REQ_get_pubkey((X509_REQ *)csr);
+ if (!pkey)
+ goto fail;
+
+ if (X509_REQ_verify((X509_REQ *)csr, pkey) != 1)
+ goto fail;
+
+ return (struct crypto_csr *)csr;
+fail:
+ X509_REQ_free(csr);
+ return NULL;
+}
+
+
+void crypto_csr_deinit(struct crypto_csr *csr)
+{
+ X509_REQ_free((X509_REQ *)csr);
+}
+
+
+int crypto_csr_set_ec_public_key(struct crypto_csr *csr, struct crypto_ec_key *key)
+{
+ if (!X509_REQ_set_pubkey((X509_REQ *)csr, (EVP_PKEY *)key))
+ return -1;
+
+ return 0;
+}
+
+
+int crypto_csr_set_name(struct crypto_csr *csr, enum crypto_csr_name type,
+ const char *name)
+{
+ X509_NAME *n;
+ int nid;
+
+ switch (type) {
+ case CSR_NAME_CN:
+ nid = NID_commonName;
+ break;
+ case CSR_NAME_SN:
+ nid = NID_surname;
+ break;
+ case CSR_NAME_C:
+ nid = NID_countryName;
+ break;
+ case CSR_NAME_O:
+ nid = NID_organizationName;
+ break;
+ case CSR_NAME_OU:
+ nid = NID_organizationalUnitName;
+ break;
+ default:
+ return -1;
+ }
+
+ n = X509_REQ_get_subject_name((X509_REQ *) csr);
+ if (!n)
+ return -1;
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_UTF8,
+ (unsigned char *) name,
+ os_strlen(name), -1, 0))
+ return -1;
+#else
+ if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_UTF8,
+ (const unsigned char *) name,
+ os_strlen(name), -1, 0))
+ return -1;
+#endif
+
+ return 0;
+}
+
+
+int crypto_csr_set_attribute(struct crypto_csr *csr, enum crypto_csr_attr attr,
+ int attr_type, const u8 *value, size_t len)
+{
+ int nid;
+
+ switch (attr) {
+ case CSR_ATTR_CHALLENGE_PASSWORD:
+ nid = NID_pkcs9_challengePassword;
+ break;
+ default:
+ return -1;
+ }
+
+ if (!X509_REQ_add1_attr_by_NID((X509_REQ *) csr, nid, attr_type, value,
+ len))
+ return -1;
+
+ return 0;
+}
+
+
+const u8 * crypto_csr_get_attribute(struct crypto_csr *csr,
+ enum crypto_csr_attr attr,
+ size_t *len, int *type)
+{
+ X509_ATTRIBUTE *attrib;
+ ASN1_TYPE *attrib_type;
+ ASN1_STRING *data;
+ int loc;
+ int nid;
+
+ switch (attr) {
+ case CSR_ATTR_CHALLENGE_PASSWORD:
+ nid = NID_pkcs9_challengePassword;
+ break;
+ default:
+ return NULL;
+ }
+
+ loc = X509_REQ_get_attr_by_NID((X509_REQ *) csr, nid, -1);
+ if (loc < 0)
+ return NULL;
+
+ attrib = X509_REQ_get_attr((X509_REQ *) csr, loc);
+ if (!attrib)
+ return NULL;
+
+ attrib_type = X509_ATTRIBUTE_get0_type(attrib, 0);
+ if (!attrib_type)
+ return NULL;
+ *type = ASN1_TYPE_get(attrib_type);
+ data = X509_ATTRIBUTE_get0_data(attrib, 0, *type, NULL);
+ if (!data)
+ return NULL;
+ *len = ASN1_STRING_length(data);
+ return ASN1_STRING_get0_data(data);
+}
+
+
+struct wpabuf * crypto_csr_sign(struct crypto_csr *csr,
+ struct crypto_ec_key *key,
+ enum crypto_hash_alg algo)
+{
+ const EVP_MD *sign_md;
+ struct wpabuf *buf;
+ unsigned char *der = NULL;
+ int der_len;
+
+ switch (algo) {
+ case CRYPTO_HASH_ALG_SHA256:
+ sign_md = EVP_sha256();
+ break;
+ case CRYPTO_HASH_ALG_SHA384:
+ sign_md = EVP_sha384();
+ break;
+ case CRYPTO_HASH_ALG_SHA512:
+ sign_md = EVP_sha512();
+ break;
+ default:
+ return NULL;
+ }
+
+ if (!X509_REQ_sign((X509_REQ *) csr, (EVP_PKEY *) key, sign_md))
+ return NULL;
+
+ der_len = i2d_X509_REQ((X509_REQ *) csr, &der);
+ if (der_len < 0)
+ return NULL;
+
+ buf = wpabuf_alloc_copy(der, der_len);
+ OPENSSL_free(der);
+
+ return buf;
+}
+
#endif /* CONFIG_ECC */
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 2e4bf8962b55..6f116eb62f53 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -609,7 +609,7 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx)
#endif
-#ifdef CONFIG_WPS_NFC
+#ifdef CONFIG_WPS
static const unsigned char RFC3526_PRIME_1536[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
@@ -695,6 +695,8 @@ done:
}
+#ifdef CONFIG_WPS_NFC
+
void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
{
DhKey *ret = NULL;
@@ -736,6 +738,8 @@ done:
return ret;
}
+#endif /* CONFIG_WPS_NFC */
+
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private)
@@ -772,7 +776,7 @@ void dh5_free(void *ctx)
XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
-#endif /* CONFIG_WPS_NFC */
+#endif /* CONFIG_WPS */
int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey,
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 1cabf3f4b9a4..548b60dba267 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -49,9 +49,9 @@
static u32 pool[POOL_WORDS];
static unsigned int input_rotate = 0;
static unsigned int pool_pos = 0;
-static u8 dummy_key[20];
+static u8 stub_key[20];
#ifdef __linux__
-static size_t dummy_key_avail = 0;
+static size_t stub_key_avail = 0;
static int random_fd = -1;
#endif /* __linux__ */
static unsigned int own_pool_ready = 0;
@@ -109,13 +109,13 @@ static void random_extract(u8 *out)
u32 buf[POOL_WORDS / 2];
/* First, add hash back to pool to make backtracking more difficult. */
- hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) pool,
+ hmac_sha1(stub_key, sizeof(stub_key), (const u8 *) pool,
sizeof(pool), hash);
random_mix_pool(hash, sizeof(hash));
/* Hash half the pool to extra data */
for (i = 0; i < POOL_WORDS / 2; i++)
buf[i] = pool[(pool_pos - i) & POOL_WORDS_MASK];
- hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) buf,
+ hmac_sha1(stub_key, sizeof(stub_key), (const u8 *) buf,
sizeof(buf), hash);
/*
* Fold the hash to further reduce any potential output pattern.
@@ -227,7 +227,7 @@ int random_pool_ready(void)
* some key derivation operations to proceed.
*/
- if (dummy_key_avail == sizeof(dummy_key))
+ if (stub_key_avail == sizeof(stub_key))
return 1; /* Already initialized - good to continue */
/*
@@ -238,8 +238,8 @@ int random_pool_ready(void)
*/
#ifdef CONFIG_GETRANDOM
- res = getrandom(dummy_key + dummy_key_avail,
- sizeof(dummy_key) - dummy_key_avail, GRND_NONBLOCK);
+ res = getrandom(stub_key + stub_key_avail,
+ sizeof(stub_key) - stub_key_avail, GRND_NONBLOCK);
if (res < 0) {
if (errno == ENOSYS) {
wpa_printf(MSG_DEBUG,
@@ -263,8 +263,8 @@ int random_pool_ready(void)
return -1;
}
- res = read(fd, dummy_key + dummy_key_avail,
- sizeof(dummy_key) - dummy_key_avail);
+ res = read(fd, stub_key + stub_key_avail,
+ sizeof(stub_key) - stub_key_avail);
if (res < 0) {
wpa_printf(MSG_ERROR,
"random: Cannot read from /dev/random: %s",
@@ -275,10 +275,10 @@ int random_pool_ready(void)
}
wpa_printf(MSG_DEBUG, "random: Got %u/%u random bytes", (unsigned) res,
- (unsigned) (sizeof(dummy_key) - dummy_key_avail));
- dummy_key_avail += res;
+ (unsigned) (sizeof(stub_key) - stub_key_avail));
+ stub_key_avail += res;
- if (dummy_key_avail == sizeof(dummy_key)) {
+ if (stub_key_avail == sizeof(stub_key)) {
if (own_pool_ready < MIN_READY_MARK)
own_pool_ready = MIN_READY_MARK;
random_write_entropy();
@@ -287,7 +287,7 @@ int random_pool_ready(void)
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
"random data available",
- (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
+ (unsigned) stub_key_avail, (unsigned) sizeof(stub_key));
if (own_pool_ready >= MIN_READY_MARK ||
total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) {
@@ -331,13 +331,13 @@ static void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx)
{
ssize_t res;
- if (dummy_key_avail == sizeof(dummy_key)) {
+ if (stub_key_avail == sizeof(stub_key)) {
random_close_fd();
return;
}
- res = read(sock, dummy_key + dummy_key_avail,
- sizeof(dummy_key) - dummy_key_avail);
+ res = read(sock, stub_key + stub_key_avail,
+ sizeof(stub_key) - stub_key_avail);
if (res < 0) {
wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
"%s", strerror(errno));
@@ -346,10 +346,10 @@ static void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx)
wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from /dev/random",
(unsigned) res,
- (unsigned) (sizeof(dummy_key) - dummy_key_avail));
- dummy_key_avail += res;
+ (unsigned) (sizeof(stub_key) - stub_key_avail));
+ stub_key_avail += res;
- if (dummy_key_avail == sizeof(dummy_key)) {
+ if (stub_key_avail == sizeof(stub_key)) {
random_close_fd();
if (own_pool_ready < MIN_READY_MARK)
own_pool_ready = MIN_READY_MARK;
@@ -440,9 +440,9 @@ void random_init(const char *entropy_file)
#ifdef CONFIG_GETRANDOM
{
- u8 dummy;
+ u8 stub;
- if (getrandom(&dummy, 0, GRND_NONBLOCK) == 0 ||
+ if (getrandom(&stub, 0, GRND_NONBLOCK) == 0 ||
errno != ENOSYS) {
wpa_printf(MSG_DEBUG,
"random: getrandom() support available");
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 345a35ee16f4..203b0f781ff5 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -3773,6 +3773,7 @@ static int tls_connection_private_key(struct tls_data *data,
const u8 *private_key_blob,
size_t private_key_blob_len)
{
+ BIO *bio;
int ok;
if (private_key == NULL && private_key_blob == NULL)
@@ -3818,6 +3819,28 @@ static int tls_connection_private_key(struct tls_data *data,
break;
}
+ bio = BIO_new_mem_buf((u8 *) private_key_blob,
+ private_key_blob_len);
+ if (bio) {
+ EVP_PKEY *pkey;
+
+ pkey = PEM_read_bio_PrivateKey(
+ bio, NULL, tls_passwd_cb,
+ (void *) private_key_passwd);
+ if (pkey) {
+ if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: SSL_use_PrivateKey --> OK");
+ ok = 1;
+ EVP_PKEY_free(pkey);
+ BIO_free(bio);
+ break;
+ }
+ EVP_PKEY_free(pkey);
+ }
+ BIO_free(bio);
+ }
+
if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
private_key_blob_len,
private_key_passwd) == 0) {
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 804ac6806f61..2020184c5f94 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1894,11 +1894,11 @@ struct wpa_driver_capa {
*/
#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P 0x00002000
/**
- * Driver is known to use sane error codes, i.e., when it indicates that
+ * Driver is known to use valid error codes, i.e., when it indicates that
* something (e.g., association) fails, there was indeed a failure and the
* operation does not end up getting completed successfully later.
*/
-#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000
+#define WPA_DRIVER_FLAGS_VALID_ERROR_CODES 0x00004000
/** Driver supports off-channel TX */
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
/** Driver indicates TX status events for EAPOL Data frames */
@@ -2151,6 +2151,7 @@ struct hostapd_data;
#define STA_DRV_DATA_TX_SHORT_GI BIT(6)
#define STA_DRV_DATA_RX_SHORT_GI BIT(7)
#define STA_DRV_DATA_LAST_ACK_RSSI BIT(8)
+#define STA_DRV_DATA_CONN_TIME BIT(9)
struct hostap_sta_driver_data {
unsigned long rx_packets, tx_packets;
@@ -2160,6 +2161,7 @@ struct hostap_sta_driver_data {
unsigned long current_tx_rate;
unsigned long current_rx_rate;
unsigned long inactive_msec;
+ unsigned long connected_sec;
unsigned long flags; /* bitfield of STA_DRV_DATA_* */
unsigned long num_ps_buf_frames;
unsigned long tx_retry_failed;
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index a7ebe956680b..1cb976011d2b 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -268,7 +268,7 @@ const char * driver_flag_to_string(u64 flag)
DF2S(P2P_CAPABLE);
DF2S(AP_TEARDOWN_SUPPORT);
DF2S(P2P_MGMT_AND_NON_P2P);
- DF2S(SANE_ERROR_CODES);
+ DF2S(VALID_ERROR_CODES);
DF2S(OFFCHANNEL_TX);
DF2S(EAPOL_TX_STATUS);
DF2S(DEAUTH_TX_STATUS);
diff --git a/src/drivers/driver_hostap.h b/src/drivers/driver_hostap.h
index 4c1e6d69f0a7..ac0b83ad24d1 100644
--- a/src/drivers/driver_hostap.h
+++ b/src/drivers/driver_hostap.h
@@ -55,8 +55,6 @@ enum {
PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
PRISM2_PARAM_HOST_ENCRYPT = 17,
PRISM2_PARAM_HOST_DECRYPT = 18,
- PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
- PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
PRISM2_PARAM_HOST_ROAMING = 21,
PRISM2_PARAM_BCRX_STA_KEY = 22,
PRISM2_PARAM_IEEE_802_1X = 23,
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index 928f02499510..54964f37e3ed 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -257,6 +257,33 @@ static int macsec_qca_init_sockets(struct macsec_qca_data *drv, u8 *own_addr)
}
+static int macsec_qca_secy_id_get(const char *ifname, u32 *secy_id)
+{
+#ifdef NSS_MACSEC_SECY_ID_GET_FUNC
+ /* Get secy id from nss macsec driver */
+ return nss_macsec_secy_id_get((u8 *) ifname, secy_id);
+#else /* NSS_MACSEC_SECY_ID_GET_FUNC */
+ /* Board specific settings */
+ if (os_strcmp(ifname, "eth2") == 0) {
+ *secy_id = 1;
+ } else if (os_strcmp(ifname, "eth3") == 0) {
+ *secy_id = 2;
+ } else if (os_strcmp(ifname, "eth4") == 0 ||
+ os_strcmp(ifname, "eth0") == 0) {
+ *secy_id = 0;
+ } else if (os_strcmp(ifname, "eth5") == 0 ||
+ os_strcmp(ifname, "eth1") == 0) {
+ *secy_id = 1;
+ } else {
+ *secy_id = -1;
+ return -1;
+ }
+
+ return 0;
+#endif /* NSS_MACSEC_SECY_ID_GET_FUNC */
+}
+
+
static void * macsec_qca_init(void *ctx, const char *ifname)
{
struct macsec_qca_data *drv;
@@ -265,13 +292,12 @@ static void * macsec_qca_init(void *ctx, const char *ifname)
if (drv == NULL)
return NULL;
- /* Board specific settings */
- if (os_memcmp("eth2", ifname, 4) == 0)
- drv->secy_id = 1;
- else if (os_memcmp("eth3", ifname, 4) == 0)
- drv->secy_id = 2;
- else
- drv->secy_id = -1;
+ if (macsec_qca_secy_id_get(ifname, &drv->secy_id)) {
+ wpa_printf(MSG_ERROR,
+ "macsec_qca: Failed to get secy_id for %s", ifname);
+ os_free(drv);
+ return NULL;
+ }
if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
os_free(drv);
@@ -303,17 +329,13 @@ static void * macsec_qca_hapd_init(struct hostapd_data *hapd,
return NULL;
}
- /* Board specific settings */
- if (os_memcmp("eth2", params->ifname, 4) == 0)
- drv->secy_id = 1;
- else if (os_memcmp("eth3", params->ifname, 4) == 0)
- drv->secy_id = 2;
- else if (os_memcmp("eth4", params->ifname, 4) == 0)
- drv->secy_id = 0;
- else if (os_memcmp("eth5", params->ifname, 4) == 0)
- drv->secy_id = 1;
- else
- drv->secy_id = -1;
+ if (macsec_qca_secy_id_get(params->ifname, &drv->secy_id)) {
+ wpa_printf(MSG_ERROR,
+ "macsec_qca: Failed to get secy_id for %s",
+ params->ifname);
+ os_free(drv);
+ return NULL;
+ }
drv->common.ctx = hapd;
os_strlcpy(drv->common.ifname, params->ifname,
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index b5fff483e78b..b32e009679dc 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -1111,20 +1111,20 @@ wpa_driver_ndis_associate(void *priv,
auth_mode = Ndis802_11AuthModeOpen;
priv_mode = Ndis802_11PrivFilterAcceptAll;
if (params->wps == WPS_MODE_PRIVACY) {
- u8 dummy_key[5] = { 0x11, 0x22, 0x33, 0x44, 0x55 };
+ u8 stub_key[5] = { 0x11, 0x22, 0x33, 0x44, 0x55 };
/*
* Some NDIS drivers refuse to associate in open mode
* configuration due to Privacy field mismatch, so use
* a workaround to make the configuration look like
* matching one for WPS provisioning.
*/
- wpa_printf(MSG_DEBUG, "NDIS: Set dummy WEP key as a "
+ wpa_printf(MSG_DEBUG, "NDIS: Set stub WEP key as a "
"workaround to allow driver to associate "
"for WPS");
wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
bcast, 0, 1,
- NULL, 0, dummy_key,
- sizeof(dummy_key));
+ NULL, 0, stub_key,
+ sizeof(stub_key));
}
#endif /* CONFIG_WPS */
} else {
@@ -2233,10 +2233,10 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
/*
* Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
- * descriptions. Fill in dummy descriptors to work around this.
+ * descriptions. Fill in stub descriptors to work around this.
*/
while (num_desc < num_name)
- desc[num_desc++] = "dummy description";
+ desc[num_desc++] = "stub description";
if (num_name != num_desc) {
wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
@@ -3164,10 +3164,10 @@ wpa_driver_ndis_get_interfaces(void *global_priv)
/*
* Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
- * descriptions. Fill in dummy descriptors to work around this.
+ * descriptions. Fill in stub descriptors to work around this.
*/
while (num_desc < num_name)
- desc[num_desc++] = "dummy description";
+ desc[num_desc++] = "stub description";
if (num_name != num_desc) {
wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 8eb033c78cf9..9a9a146f7ea1 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -604,7 +604,7 @@ static int nl_get_multicast_id(struct nl80211_global *global,
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
- if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
+ if (!genlmsg_put(msg, 0, 0, global->nlctrl_id,
0, 0, CTRL_CMD_GETFAMILY, 0) ||
nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
nlmsg_free(msg);
@@ -1883,6 +1883,13 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
goto err;
}
+ global->nlctrl_id = genl_ctrl_resolve(global->nl, "nlctrl");
+ if (global->nlctrl_id < 0) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: 'nlctrl' generic netlink not found");
+ goto err;
+ }
+
global->nl_event = nl_create_handle(global->nl_cb, "event");
if (global->nl_event == NULL)
goto err;
@@ -2505,10 +2512,19 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
(nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
ret = -1;
+ /* Robust AV SCS Response */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x13\x01", 2) < 0)
+ ret = -1;
+
/* Robust AV MSCS Response */
if (nl80211_register_action_frame(bss, (u8 *) "\x13\x05", 2) < 0)
ret = -1;
+ /* Protected QoS Management Action frame */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x7e\x50\x6f\x9a\x1a",
+ 5) < 0)
+ ret = -1;
+
nl80211_mgmt_handle_register_eloop(bss);
return ret;
@@ -4072,7 +4088,7 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
freq = bss->freq;
}
- if (drv->use_monitor) {
+ if (drv->use_monitor && is_ap_interface(drv->nlmode)) {
wpa_printf(MSG_DEBUG,
"nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
freq, bss->freq);
@@ -5144,7 +5160,7 @@ static int wpa_driver_nl80211_sta_add(void *priv,
/*
* cfg80211 validates that AID is non-zero, so we have
* to make this a non-zero value for the TDLS case where
- * a dummy STA entry is used for now and for a station
+ * a stub STA entry is used for now and for a station
* that is still not associated.
*/
wpa_printf(MSG_DEBUG, " * aid=1 (%s workaround)",
@@ -7024,6 +7040,7 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
[NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 },
[NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 },
[NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 },
+ [NL80211_STA_INFO_CONNECTED_TIME] = { .type = NLA_U32 },
};
struct nlattr *rate[NL80211_RATE_INFO_MAX + 1];
static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -7098,6 +7115,12 @@ static int get_sta_handler(struct nl_msg *msg, void *arg)
data->flags |= STA_DRV_DATA_LAST_ACK_RSSI;
}
+ if (stats[NL80211_STA_INFO_CONNECTED_TIME]) {
+ data->connected_sec =
+ nla_get_u32(stats[NL80211_STA_INFO_CONNECTED_TIME]);
+ data->flags |= STA_DRV_DATA_CONN_TIME;
+ }
+
if (stats[NL80211_STA_INFO_TX_BITRATE] &&
nla_parse_nested(rate, NL80211_RATE_INFO_MAX,
stats[NL80211_STA_INFO_TX_BITRATE],
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 9d61c1d6930f..80d4564721ad 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -32,6 +32,7 @@ struct nl80211_global {
struct nl_cb *nl_cb;
struct nl_sock *nl;
int nl80211_id;
+ int nlctrl_id;
int ioctl_sock; /* socket for ioctl() use */
struct nl_sock *nl_event;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index cd596e311e59..83868b78e6f0 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1389,7 +1389,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
- drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
+ drv->capa.flags |= WPA_DRIVER_FLAGS_VALID_ERROR_CODES;
drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
diff --git a/src/eap_peer/eap_proxy_dummy.c b/src/eap_peer/eap_proxy_dummy.c
index 2cc05c92cdfc..181e8cc74e8c 100644
--- a/src/eap_peer/eap_proxy_dummy.c
+++ b/src/eap_peer/eap_proxy_dummy.c
@@ -1,5 +1,5 @@
/*
- * EAP proxy - dummy implementation for build testing
+ * EAP proxy - stub implementation for build testing
* Copyright (c) 2013 Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
diff --git a/src/eap_peer/eap_teap.c b/src/eap_peer/eap_teap.c
index e8cc7844ce5f..bc7f6f4f5abe 100644
--- a/src/eap_peer/eap_teap.c
+++ b/src/eap_peer/eap_teap.c
@@ -1760,8 +1760,8 @@ static int eap_teap_process_start(struct eap_sm *sm,
#ifdef CONFIG_TESTING_OPTIONS
-static struct wpabuf * eap_teap_add_dummy_outer_tlvs(struct eap_teap_data *data,
- struct wpabuf *resp)
+static struct wpabuf * eap_teap_add_stub_outer_tlvs(struct eap_teap_data *data,
+ struct wpabuf *resp)
{
struct wpabuf *resp2;
u16 len;
@@ -1775,11 +1775,11 @@ static struct wpabuf * eap_teap_add_dummy_outer_tlvs(struct eap_teap_data *data,
return NULL;
}
- /* Outer TLVs (dummy Vendor-Specific TLV for testing) */
+ /* Outer TLVs (stub Vendor-Specific TLV for testing) */
wpabuf_put_be16(data->peer_outer_tlvs, TEAP_TLV_VENDOR_SPECIFIC);
wpabuf_put_be16(data->peer_outer_tlvs, 4);
wpabuf_put_be32(data->peer_outer_tlvs, EAP_VENDOR_HOSTAP);
- wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: TESTING - Add dummy Outer TLVs",
+ wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: TESTING - Add stub Outer TLVs",
data->peer_outer_tlvs);
wpa_hexdump_buf(MSG_DEBUG,
@@ -1986,7 +1986,7 @@ static struct wpabuf * eap_teap_process(struct eap_sm *sm, void *priv,
#ifdef CONFIG_TESTING_OPTIONS
if (data->test_outer_tlvs && res == 0 && resp &&
(flags & EAP_TLS_FLAGS_START) && wpabuf_len(resp) >= 6)
- resp = eap_teap_add_dummy_outer_tlvs(data, resp);
+ resp = eap_teap_add_stub_outer_tlvs(data, resp);
#endif /* CONFIG_TESTING_OPTIONS */
return resp;
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 183b7de00ae5..9ac00121f664 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -92,7 +92,7 @@ struct eap_ssl_data {
/* could be up to 128 bytes, but only the first 64 bytes are used */
#define EAP_TLS_KEY_LEN 64
-/* dummy type used as a flag for UNAUTH-TLS */
+/* stub type used as a flag for UNAUTH-TLS */
#define EAP_UNAUTH_TLS_TYPE 255
#define EAP_WFA_UNAUTH_TLS_TYPE 254
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index b0b736123016..b0723a1fa492 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -68,7 +68,7 @@ struct eap_ssl_data {
/* could be up to 128 bytes, but only the first 64 bytes are used */
#define EAP_TLS_KEY_LEN 64
-/* dummy type used as a flag for UNAUTH-TLS */
+/* stub type used as a flag for UNAUTH-TLS */
#define EAP_UNAUTH_TLS_TYPE 255
#define EAP_WFA_UNAUTH_TLS_TYPE 254
diff --git a/src/l2_packet/l2_packet_none.c b/src/l2_packet/l2_packet_none.c
index bc7a4e82d672..6783d7391cb0 100644
--- a/src/l2_packet/l2_packet_none.c
+++ b/src/l2_packet/l2_packet_none.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant - Layer2 packet handling example with dummy functions
+ * WPA Supplicant - Layer2 packet handling example with stub functions
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 9ac505735cbb..598a449c11b2 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1326,7 +1326,9 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq)
{
- if (freq > 0 && p2p->drv_in_listen == freq && p2p->in_listen) {
+ if (freq > 0 &&
+ ((p2p->drv_in_listen == freq && p2p->in_listen) ||
+ p2p->pending_listen_freq == (unsigned int) freq)) {
p2p_dbg(p2p, "Skip stop_listen since we are on correct channel for response");
return;
}
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 63eb2e84c376..4229d9b34873 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -111,7 +111,7 @@ void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country,
void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
- const u32 *preferred_freq_list,
+ const unsigned int *preferred_freq_list,
unsigned int size)
{
unsigned int i, count = 0;
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 113346141986..1d53d52f1f8e 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -582,8 +582,8 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go,
&op_channel) < 0)
continue; /* cannot happen due to earlier check */
for (j = 0; j < msg->channel_list_len; j++) {
-
- if (op_channel != msg->channel_list[j])
+ if (!msg->channel_list ||
+ op_channel != msg->channel_list[j])
continue;
p2p->op_reg_class = op_class;
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 8220e85506a3..aa147c614fc5 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -789,7 +789,8 @@ void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
int all_attr);
void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
- const u32 *preferred_freq_list, u32 size);
+ const unsigned int *preferred_freq_list,
+ unsigned int size);
/* p2p_sd.c */
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 05fd593494ef..338b47e4e36b 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -1425,7 +1425,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
* Save the reported channel list and operating frequency.
* Note that the specification mandates that the responder
* should include in the channel list only channels reported by
- * the initiator, so this is only a sanity check, and if this
+ * the initiator, so this is only a validity check, and if this
* fails the flow would continue, although it would probably
* fail. Same is true for the operating channel.
*/
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 2fe88ac0c5f2..657de93ae748 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -3057,12 +3057,12 @@ int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay)
/**
- * ieee802_1x_kay_mkpdu_sanity_check -
- * Sanity checks specified in IEEE Std 802.1X-2010, 11.11.2 (Validation of
+ * ieee802_1x_kay_mkpdu_validity_check -
+ * Validity checks specified in IEEE Std 802.1X-2010, 11.11.2 (Validation of
* MKPDUs)
*/
-static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay,
- const u8 *buf, size_t len)
+static int ieee802_1x_kay_mkpdu_validity_check(struct ieee802_1x_kay *kay,
+ const u8 *buf, size_t len)
{
struct ieee8023_hdr *eth_hdr;
struct ieee802_1x_hdr *eapol_hdr;
@@ -3215,7 +3215,7 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay,
wpa_printf(MSG_DEBUG, "KaY: Decode received MKPDU (ifname=%s)",
kay->if_name);
- if (ieee802_1x_kay_mkpdu_sanity_check(kay, buf, len))
+ if (ieee802_1x_kay_mkpdu_validity_check(kay, buf, len))
return -1;
/* handle basic parameter set */
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 4f0ff07547da..ee9e46d2aa01 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -815,7 +815,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
struct radius_client_data *radius = eloop_ctx;
struct hostapd_radius_servers *conf = radius->conf;
- RadiusType msg_type = (RadiusType) sock_ctx;
+ RadiusType msg_type = (uintptr_t) sock_ctx;
int len, roundtrip;
unsigned char buf[RADIUS_MAX_MSG_LEN];
struct msghdr msghdr = {0};
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 97a01a2f81e8..0cd5159821bb 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -26,6 +26,8 @@ struct rsn_pmksa_cache {
void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
enum pmksa_free_reason reason);
+ bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry,
+ void *ctx);
void *ctx;
};
@@ -57,14 +59,35 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
struct os_reltime now;
+ struct rsn_pmksa_cache_entry *prev = NULL, *tmp;
+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
os_get_reltime(&now);
- while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
- struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
- pmksa->pmksa = entry->next;
+ while (entry && entry->expiration <= now.sec) {
+ if (wpa_key_mgmt_sae(entry->akmp) &&
+ pmksa->is_current_cb(entry, pmksa->ctx)) {
+ /* Do not expire the currently used PMKSA entry for SAE
+ * since there is no convenient mechanism for
+ * reauthenticating during an association with SAE. The
+ * expired entry will be removed after this association
+ * has been lost. */
+ wpa_printf(MSG_DEBUG,
+ "RSN: postpone PMKSA cache entry expiration for SAE with "
+ MACSTR, MAC2STR(entry->aa));
+ prev = entry;
+ entry = entry->next;
+ continue;
+ }
+
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
MACSTR, MAC2STR(entry->aa));
- pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
+ if (prev)
+ prev->next = entry->next;
+ else
+ pmksa->pmksa = entry->next;
+ tmp = entry;
+ entry = entry->next;
+ pmksa_cache_free_entry(pmksa, tmp, PMKSA_EXPIRE);
}
pmksa_cache_set_expiration(pmksa);
@@ -91,13 +114,32 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
return;
os_get_reltime(&now);
sec = pmksa->pmksa->expiration - now.sec;
- if (sec < 0)
+ if (sec < 0) {
sec = 0;
+ if (wpa_key_mgmt_sae(pmksa->pmksa->akmp) &&
+ pmksa->is_current_cb(pmksa->pmksa, pmksa->ctx)) {
+ /* Do not continue polling for the current PMKSA entry
+ * from SAE to expire every second. Use the expiration
+ * time to the following entry, if any, and wait at
+ * maximum 10 minutes to check again.
+ */
+ entry = pmksa->pmksa->next;
+ if (entry) {
+ sec = entry->expiration - now.sec;
+ if (sec < 0)
+ sec = 0;
+ else if (sec > 600)
+ sec = 600;
+ } else {
+ sec = 600;
+ }
+ }
+ }
eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, 0);
- if (entry) {
+ if (entry && !wpa_key_mgmt_sae(entry->akmp)) {
sec = pmksa->pmksa->reauth_time - now.sec;
if (sec < 0)
sec = 0;
@@ -378,6 +420,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
{
struct rsn_pmksa_cache_entry *new_entry;
os_time_t old_expiration = old_entry->expiration;
+ os_time_t old_reauth_time = old_entry->reauth_time;
const u8 *pmkid = NULL;
if (wpa_key_mgmt_sae(old_entry->akmp) ||
@@ -394,6 +437,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
/* TODO: reorder entries based on expiration time? */
new_entry->expiration = old_expiration;
+ new_entry->reauth_time = old_reauth_time;
new_entry->opportunistic = 1;
return new_entry;
@@ -651,6 +695,8 @@ struct rsn_pmksa_cache_entry * pmksa_cache_head(struct rsn_pmksa_cache *pmksa)
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx, enum pmksa_free_reason reason),
+ bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry,
+ void *ctx),
void *ctx, struct wpa_sm *sm)
{
struct rsn_pmksa_cache *pmksa;
@@ -658,6 +704,7 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
pmksa = os_zalloc(sizeof(*pmksa));
if (pmksa) {
pmksa->free_cb = free_cb;
+ pmksa->is_current_cb = is_current_cb;
pmksa->ctx = ctx;
pmksa->sm = sm;
}
@@ -665,4 +712,37 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
return pmksa;
}
+
+void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa)
+{
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ if (!pmksa || !pmksa->pmksa)
+ return;
+
+ os_get_reltime(&now);
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
+ u32 life_time;
+ u8 reauth_threshold;
+
+ if (entry->expiration - now.sec < 1 ||
+ entry->reauth_time - now.sec < 1)
+ continue;
+
+ life_time = entry->expiration - now.sec;
+ reauth_threshold = (entry->reauth_time - now.sec) * 100 /
+ life_time;
+ if (!reauth_threshold)
+ continue;
+
+ wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa,
+ entry->pmkid,
+ entry->fils_cache_id_set ?
+ entry->fils_cache_id : NULL,
+ entry->pmk, entry->pmk_len, life_time,
+ reauth_threshold, entry->akmp);
+ }
+}
+
#endif /* IEEE8021X_EAPOL */
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index ae7bc13fa118..b801268599a9 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -59,6 +59,8 @@ enum pmksa_free_reason {
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx, enum pmksa_free_reason reason),
+ bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry,
+ void *ctx),
void *ctx, struct wpa_sm *sm);
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
@@ -86,12 +88,15 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
void *network_ctx, const u8 *aa, int akmp);
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
const u8 *pmk, size_t pmk_len, bool external_only);
+void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa);
#else /* IEEE8021X_EAPOL */
static inline struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx, enum pmksa_free_reason reason),
+ bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry,
+ void *ctx),
void *ctx, struct wpa_sm *sm)
{
return (void *) -1;
@@ -163,6 +168,10 @@ static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
{
}
+static inline void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa)
+{
+}
+
#endif /* IEEE8021X_EAPOL */
#endif /* PMKSA_CACHE_H */
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 411cbf46a40d..c26a63d822af 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -138,6 +138,7 @@ struct wpa_tdls_peer {
struct ieee80211_vht_capabilities *vht_capabilities;
struct ieee80211_he_capabilities *he_capabilities;
size_t he_capab_len;
+ struct ieee80211_he_6ghz_band_cap *he_6ghz_band_capabilities;
u8 qos_info;
@@ -707,6 +708,8 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
peer->vht_capabilities = NULL;
os_free(peer->he_capabilities);
peer->he_capabilities = NULL;
+ os_free(peer->he_6ghz_band_capabilities);
+ peer->he_6ghz_band_capabilities = NULL;
os_free(peer->ext_capab);
peer->ext_capab = NULL;
os_free(peer->supp_channels);
@@ -1681,6 +1684,33 @@ static int copy_peer_he_capab(const struct wpa_eapol_ie_parse *kde,
}
+static int copy_peer_he_6ghz_band_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->he_6ghz_capabilities) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: No HE 6 GHz band capabilities received");
+ return 0;
+ }
+
+ if (!peer->he_6ghz_band_capabilities) {
+ peer->he_6ghz_band_capabilities =
+ os_zalloc(sizeof(struct ieee80211_he_6ghz_band_cap));
+ if (peer->he_6ghz_band_capabilities == NULL)
+ return -1;
+ }
+
+ os_memcpy(peer->he_6ghz_band_capabilities, kde->he_6ghz_capabilities,
+ sizeof(struct ieee80211_he_6ghz_band_cap));
+
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer 6 GHz band HE capabilities",
+ peer->he_6ghz_band_capabilities,
+ sizeof(struct ieee80211_he_6ghz_band_cap));
+
+ return 0;
+}
+
+
static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde,
struct wpa_tdls_peer *peer)
{
@@ -1792,6 +1822,7 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
peer->vht_capabilities,
peer->he_capabilities,
peer->he_capab_len,
+ peer->he_6ghz_band_capabilities,
peer->qos_info, peer->wmm_capable,
peer->ext_capab, peer->ext_capab_len,
peer->supp_channels,
@@ -1928,7 +1959,8 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
goto error;
if (copy_peer_vht_capab(&kde, peer) < 0 ||
- copy_peer_he_capab(&kde, peer) < 0)
+ copy_peer_he_capab(&kde, peer) < 0 ||
+ copy_peer_he_6ghz_band_capab(&kde, peer) < 0)
goto error;
if (copy_peer_ext_capab(&kde, peer) < 0)
@@ -1957,8 +1989,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, NULL, 0, 0, 0, NULL, 0, NULL, 0,
- NULL, 0);
+ NULL, NULL, 0, NULL, 0, 0, NULL, 0,
+ NULL, 0, NULL, 0);
if (wpa_tdls_send_tpk_m1(sm, peer) == -2) {
peer = NULL;
goto error;
@@ -2337,7 +2369,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
goto error;
if (copy_peer_vht_capab(&kde, peer) < 0 ||
- copy_peer_he_capab(&kde, peer) < 0)
+ copy_peer_he_capab(&kde, peer) < 0 ||
+ copy_peer_he_6ghz_band_capab(&kde, peer) < 0)
goto error;
if (copy_peer_ext_capab(&kde, peer) < 0)
@@ -2724,7 +2757,7 @@ 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, NULL, 0, 0, 0, NULL, 0, NULL, 0,
+ NULL, NULL, 0, NULL, 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 e01cd52177d2..0a2f87787504 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -2903,6 +2903,15 @@ static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
}
+static bool wpa_sm_pmksa_is_current_cb(struct rsn_pmksa_cache_entry *entry,
+ void *ctx)
+{
+ struct wpa_sm *sm = ctx;
+
+ return sm->cur_pmksa == entry;
+}
+
+
/**
* wpa_sm_init - Initialize WPA state machine
* @ctx: Context pointer for callbacks; this needs to be an allocated buffer
@@ -2926,7 +2935,8 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
sm->dot11RSNAConfigPMKReauthThreshold = 70;
sm->dot11RSNAConfigSATimeout = 60;
- sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
+ sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb,
+ wpa_sm_pmksa_is_current_cb, sm, sm);
if (sm->pmksa == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"RSN: PMKSA cache initialization failed");
@@ -3122,9 +3132,11 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
#endif /* CONFIG_IEEE80211R */
if (bssid) {
- pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0,
- bssid, sm->own_addr,
- sm->network_ctx, sm->key_mgmt, NULL);
+ sm->cur_pmksa = pmksa_cache_add(sm->pmksa, pmk, pmk_len,
+ pmkid, NULL, 0, bssid,
+ sm->own_addr,
+ sm->network_ctx, sm->key_mgmt,
+ NULL);
}
}
@@ -5246,3 +5258,10 @@ void wpa_pasn_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
key_mgmt, 0);
}
#endif /* CONFIG_PASN */
+
+
+void wpa_sm_pmksa_cache_reconfig(struct wpa_sm *sm)
+{
+ if (sm)
+ pmksa_cache_reconfig(sm->pmksa);
+}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index ff8a85b6e29b..41daaae2cf72 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -71,6 +71,7 @@ struct wpa_sm_ctx {
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u8 qosinfo, int wmm, const u8 *ext_capab,
size_t ext_capab_len, const u8 *supp_channels,
size_t supp_channels_len,
@@ -215,6 +216,7 @@ void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
const u8 *ptk_kck, size_t ptk_kck_len,
const u8 *ptk_kek, size_t ptk_kek_len);
int wpa_fils_is_completed(struct wpa_sm *sm);
+void wpa_sm_pmksa_cache_reconfig(struct wpa_sm *sm);
#else /* CONFIG_NO_WPA */
@@ -424,6 +426,10 @@ static inline int wpa_fils_is_completed(struct wpa_sm *sm)
return 0;
}
+static inline void wpa_sm_pmksa_cache_reconfig(struct wpa_sm *sm)
+{
+}
+
#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_IEEE80211R
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index e7281bf3b1d8..6cdce321da3b 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -400,6 +400,7 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
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,
@@ -411,7 +412,7 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
supp_rates_len, ht_capab,
vht_capab,
he_capab, he_capab_len,
- qosinfo, wmm,
+ he_6ghz_capab, qosinfo, wmm,
ext_capab, ext_capab_len,
supp_channels,
supp_channels_len,
diff --git a/src/utils/config.c b/src/utils/config.c
index 22aa2216eb3f..ba26c2c9a71c 100644
--- a/src/utils/config.c
+++ b/src/utils/config.c
@@ -66,12 +66,20 @@ char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
* 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;
+ sstart = pos;
end = os_strchr(sstart, '#');
+ while (end) {
+ sstart = os_strchr(sstart, '"');
+ if (!sstart || sstart > end)
+ break;
+ sstart = os_strchr(sstart + 1, '"');
+ if (!sstart)
+ break;
+ sstart++;
+ if (sstart > end)
+ end = os_strchr(sstart, '#');
+ }
+
if (end)
*end-- = '\0';
else
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index b353ab0e467f..00b0beff0b78 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -785,21 +785,15 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
}
now_sec = timeout->time.sec;
timeout->time.sec += secs;
- if (timeout->time.sec < now_sec) {
- /*
- * Integer overflow - assume long enough timeout to be assumed
- * to be infinite, i.e., the timeout would never happen.
- */
- wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
- "ever happen - ignore it", secs);
- os_free(timeout);
- return 0;
- }
+ if (timeout->time.sec < now_sec)
+ goto overflow;
timeout->time.usec += usecs;
while (timeout->time.usec >= 1000000) {
timeout->time.sec++;
timeout->time.usec -= 1000000;
}
+ if (timeout->time.sec < now_sec)
+ goto overflow;
timeout->eloop_data = eloop_data;
timeout->user_data = user_data;
timeout->handler = handler;
@@ -817,6 +811,17 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
dl_list_add_tail(&eloop.timeout, &timeout->list);
return 0;
+
+overflow:
+ /*
+ * Integer overflow - assume long enough timeout to be assumed
+ * to be infinite, i.e., the timeout would never happen.
+ */
+ wpa_printf(MSG_DEBUG,
+ "ELOOP: Too long timeout (secs=%u usecs=%u) to ever happen - ignore it",
+ secs,usecs);
+ os_free(timeout);
+ return 0;
}
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 1de37204d710..258deef9dd55 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -464,9 +464,9 @@ int os_file_exists(const char *fname)
int os_fdatasync(FILE *stream)
{
if (!fflush(stream)) {
-#ifdef __linux__
+#if defined __FreeBSD__ || defined __linux__
return fdatasync(fileno(stream));
-#else /* !__linux__ */
+#else /* !__linux__ && !__FreeBSD__ */
#ifdef F_FULLFSYNC
/* OS X does not implement fdatasync(). */
return fcntl(fileno(stream), F_FULLFSYNC);
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 484df262c3ca..1fe38063b253 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -17,7 +17,7 @@
#ifdef CONFIG_WPS_TESTING
int wps_version_number = 0x20;
-int wps_testing_dummy_cred = 0;
+int wps_testing_stub_cred = 0;
int wps_corrupt_pkhash = 0;
int wps_force_auth_types_in_use = 0;
u16 wps_force_auth_types = 0;
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index 9fccb4eeb5c1..ddaeda56d317 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -12,7 +12,7 @@
#ifdef CONFIG_WPS_TESTING
extern int wps_version_number;
-extern int wps_testing_dummy_cred;
+extern int wps_testing_stub_cred;
extern int wps_corrupt_pkhash;
extern int wps_force_auth_types_in_use;
extern u16 wps_force_auth_types;
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 173fbbd68aa0..9587293d0f88 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -1785,23 +1785,23 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
use_provided:
#ifdef CONFIG_WPS_TESTING
- if (wps_testing_dummy_cred)
+ if (wps_testing_stub_cred)
cred = wpabuf_alloc(200);
else
cred = NULL;
if (cred) {
- struct wps_credential dummy;
- wpa_printf(MSG_DEBUG, "WPS: Add dummy credential");
- os_memset(&dummy, 0, sizeof(dummy));
- os_memcpy(dummy.ssid, "dummy", 5);
- dummy.ssid_len = 5;
- dummy.auth_type = WPS_AUTH_WPA2PSK;
- dummy.encr_type = WPS_ENCR_AES;
- os_memcpy(dummy.key, "dummy psk", 9);
- dummy.key_len = 9;
- os_memcpy(dummy.mac_addr, wps->mac_addr_e, ETH_ALEN);
- wps_build_credential(cred, &dummy);
- wpa_hexdump_buf(MSG_DEBUG, "WPS: Dummy Credential", cred);
+ struct wps_credential stub;
+ wpa_printf(MSG_DEBUG, "WPS: Add stub credential");
+ os_memset(&stub, 0, sizeof(stub));
+ os_memcpy(stub.ssid, "stub", 5);
+ stub.ssid_len = 5;
+ stub.auth_type = WPS_AUTH_WPA2PSK;
+ stub.encr_type = WPS_ENCR_AES;
+ os_memcpy(stub.key, "stub psk", 9);
+ stub.key_len = 9;
+ os_memcpy(stub.mac_addr, wps->mac_addr_e, ETH_ALEN);
+ wps_build_credential(cred, &stub);
+ wpa_hexdump_buf(MSG_DEBUG, "WPS: Stub Credential", cred);
wpabuf_put_be16(msg, ATTR_CRED);
wpabuf_put_be16(msg, wpabuf_len(cred));
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index ff58cb938a9c..05bb9c5853d6 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -658,7 +658,7 @@ static int subscription_first_event(struct subscription *s)
/*
* There has been no events before the subscription. However,
* UPnP device architecture specification requires all the
- * evented variables to be included, so generate a dummy event
+ * evented variables to be included, so generate a stub event
* for this particular case using a WSC_ACK and all-zeros
* nonces. The ER (UPnP control point) will ignore this, but at
* least it will learn that WLANEvent variable will be used in
diff --git a/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db b/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db
index 1c494f77309f..fefe5145ff0b 100644
--- a/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db
+++ b/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db
@@ -3,7 +3,7 @@
# 4.3.20 Test Set 20. SQN is the last used SQN value.
# These values can be used for both UMTS (EAP-AKA) and GSM (EAP-SIM)
# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
-# dummy values will need to be included in this file.
+# stub values will need to be included in this file.
# IMSI Ki OPc AMF SQN
232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
diff --git a/tests/hwsim/auth_serv/rsa3072-server.pem b/tests/hwsim/auth_serv/rsa3072-server.pem
index 546361dff4ab..39e022130ba8 100644
--- a/tests/hwsim/auth_serv/rsa3072-server.pem
+++ b/tests/hwsim/auth_serv/rsa3072-server.pem
@@ -2,12 +2,12 @@ Certificate:
Data:
Version: 3 (0x2)
Serial Number:
- ad:8c:09:e8:fb:a2:88:cb
+ ad:8c:09:e8:fb:a2:88:ce
Signature Algorithm: sha384WithRSAEncryption
Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B RSA 3k Root CA
Validity
- Not Before: Aug 16 13:19:41 2019 GMT
- Not After : Aug 15 13:19:41 2021 GMT
+ Not Before: Aug 19 10:56:47 2021 GMT
+ Not After : Aug 19 10:56:47 2023 GMT
Subject: C=FI, O=w1.fi, CN=rsa3072.server.w1.fi
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
@@ -55,33 +55,33 @@ Certificate:
X509v3 Key Usage:
Digital Signature, Key Encipherment
Signature Algorithm: sha384WithRSAEncryption
- 39:6b:3b:eb:37:00:5d:71:35:15:bd:9d:59:7b:10:f5:57:51:
- bf:e7:40:69:4d:05:f5:64:d0:42:d2:7e:74:12:bf:dc:20:13:
- f5:24:1f:84:18:5c:75:18:34:f6:b3:57:a1:32:de:13:ef:d9:
- 79:6d:7a:9c:3a:3d:b0:3b:74:44:e8:9e:fc:19:6b:fa:55:74:
- c8:e1:a1:2e:a9:ce:73:4c:7f:4d:0b:fd:33:33:10:c3:21:f1:
- d1:80:31:ca:33:77:23:91:1d:11:b1:60:c9:ec:51:4c:70:31:
- 3c:b6:8a:8e:e3:42:d4:e7:e1:1c:11:a7:13:99:76:3c:25:55:
- 04:c2:e6:45:e5:21:39:5d:9f:e1:f2:35:84:ad:dd:3b:69:ab:
- ca:f6:88:9a:4c:cc:cf:6a:82:b8:54:5a:60:40:aa:20:05:c3:
- 39:c1:46:11:8d:e4:cb:b1:7c:ee:48:cf:31:18:89:7a:5c:f7:
- f9:51:18:65:e1:25:28:cb:49:1c:f5:5e:f6:68:d9:8e:c5:01:
- cb:4f:da:7e:7a:54:f5:b4:4d:0a:e8:3f:6d:26:a1:72:c8:07:
- 50:ee:bf:64:01:8f:12:19:6d:ad:c0:6d:fa:29:ff:ab:31:9c:
- fa:d4:55:46:83:a3:3b:53:cc:26:53:3f:b4:85:2f:90:76:6b:
- 39:4a:06:22:72:c0:0e:45:0d:3f:80:41:03:d7:65:89:fd:01:
- 3a:8c:8f:9c:af:77:93:ec:c0:fb:2e:f2:b0:db:ac:07:ac:e2:
- 0f:c8:af:24:0b:57:69:9f:bb:cb:e0:d7:bc:c2:c7:6f:3f:f3:
- 30:aa:42:88:7d:45:02:1e:ad:ac:da:89:8b:43:d9:80:0e:ab:
- 79:c5:c4:21:97:3b:e0:99:ef:9b:50:4a:86:62:e4:af:18:ed:
- 70:5b:e8:f8:87:9e:0c:c4:f0:6a:f4:1e:ce:05:f0:15:3f:68:
- 02:33:1d:9d:05:e4:d8:2f:20:38:33:1a:4e:46:7e:4b:10:b2:
- 6c:55:04:21:38:36
+ 8c:3a:e4:8b:4f:42:ae:13:a4:c5:1e:eb:72:0d:15:c0:59:aa:
+ 09:e9:ee:b4:97:94:ab:1a:fc:b1:b0:48:39:90:35:45:8b:40:
+ 59:7b:51:d3:be:b1:ac:9c:90:9d:5c:0a:1c:34:41:d7:74:5f:
+ 5a:84:a2:11:f6:66:ef:ae:22:66:1f:76:fb:c3:e0:65:3f:12:
+ 59:6b:4b:84:6a:dd:58:ab:3d:1b:3f:d3:c8:51:84:72:7f:c1:
+ 92:e5:d1:79:b4:62:9d:55:e1:6f:fa:c2:30:6c:6e:0d:ae:1c:
+ 8b:d5:e5:02:99:c0:c2:95:ac:d5:d6:9a:2d:9d:a3:20:56:f4:
+ e7:60:0a:03:08:85:98:27:df:97:48:a6:92:6e:b4:fa:a5:e0:
+ 46:0b:85:b7:6c:07:73:c5:59:a4:a9:db:3a:42:6c:1a:25:af:
+ 4a:70:39:1d:5c:d7:08:41:57:b0:d7:59:66:c2:97:a5:09:4a:
+ 11:1f:a5:f7:23:cb:c4:2c:d3:9e:ae:4a:86:56:e1:1a:e7:f3:
+ 7c:c4:5c:b1:ae:c2:ea:1f:67:5a:10:e4:02:01:bd:92:b8:0f:
+ 56:26:e3:27:24:6e:53:94:c0:16:fe:fa:e2:ed:4f:42:8d:dc:
+ 23:9b:96:2e:5b:a5:47:56:a0:0d:09:17:28:3a:f2:a4:2e:71:
+ 65:93:88:3c:ff:61:92:04:75:59:96:5f:40:85:e1:be:1d:59:
+ ec:8d:4b:b7:82:3b:bb:a1:06:c2:c4:44:7a:de:3e:fe:68:e8:
+ a3:43:a5:50:80:fd:11:1d:2c:ff:27:8d:e9:71:6d:c6:01:20:
+ 0d:9a:5e:6c:c6:11:83:da:cc:fd:dd:a3:59:5c:b1:64:e1:81:
+ b4:6f:34:60:df:b5:bb:3d:5f:2b:f8:ef:73:d0:54:39:e4:dd:
+ 4b:c9:5f:87:e9:1f:fb:c4:e2:f7:f6:6e:21:70:14:3b:0e:6e:
+ 2d:11:e5:db:b8:18:d3:d2:9f:1b:a5:85:ae:89:f6:55:33:13:
+ e6:da:b4:1b:10:bc
-----BEGIN CERTIFICATE-----
-MIIEqzCCAxOgAwIBAgIJAK2MCej7oojLMA0GCSqGSIb3DQEBDAUAMFExCzAJBgNV
+MIIEqzCCAxOgAwIBAgIJAK2MCej7oojOMA0GCSqGSIb3DQEBDAUAMFExCzAJBgNV
BAYTAkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxHzAdBgNV
-BAMMFlN1aXRlIEIgUlNBIDNrIFJvb3QgQ0EwHhcNMTkwODE2MTMxOTQxWhcNMjEw
-ODE1MTMxOTQxWjA8MQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxHTAbBgNV
+BAMMFlN1aXRlIEIgUlNBIDNrIFJvb3QgQ0EwHhcNMjEwODE5MTA1NjQ3WhcNMjMw
+ODE5MTA1NjQ3WjA8MQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxHTAbBgNV
BAMMFHJzYTMwNzIuc2VydmVyLncxLmZpMIIBojANBgkqhkiG9w0BAQEFAAOCAY8A
MIIBigKCAYEA/qlcWY+qgMu4Son5Ouh9JFG48gXGQuBotaTxfooxouAMWMWAIMsg
8A7Ba03h1+vMRUjJsA+P74DbG2ACr+/oCinIBN9wkunx3GpHO1pvEOYZTZOS0AqO
@@ -94,13 +94,13 @@ gTF4oMl9bdlrB/rISmdXLIymzuV+NpXxCb3fv8hTPSFn/ZPLsnq1VmGeL85p+vpW
CmucaXj3TlRzAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUgtd1
lZSeNfcfkW03nyZPPZ3BbpYwHwYDVR0jBBgwFoAUIffv2sM0Ou3N1VDAs7oJ7j+A
13AwIgYDVR0RAQH/BBgwFoIUcnNhMzA3Mi5zZXJ2ZXIudzEuZmkwFgYDVR0lAQH/
-BAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBDAUAA4IBgQA5
-azvrNwBdcTUVvZ1ZexD1V1G/50BpTQX1ZNBC0n50Er/cIBP1JB+EGFx1GDT2s1eh
-Mt4T79l5bXqcOj2wO3RE6J78GWv6VXTI4aEuqc5zTH9NC/0zMxDDIfHRgDHKM3cj
-kR0RsWDJ7FFMcDE8toqO40LU5+EcEacTmXY8JVUEwuZF5SE5XZ/h8jWErd07aavK
-9oiaTMzPaoK4VFpgQKogBcM5wUYRjeTLsXzuSM8xGIl6XPf5URhl4SUoy0kc9V72
-aNmOxQHLT9p+elT1tE0K6D9tJqFyyAdQ7r9kAY8SGW2twG36Kf+rMZz61FVGg6M7
-U8wmUz+0hS+Qdms5SgYicsAORQ0/gEED12WJ/QE6jI+cr3eT7MD7LvKw26wHrOIP
-yK8kC1dpn7vL4Ne8wsdvP/MwqkKIfUUCHq2s2omLQ9mADqt5xcQhlzvgme+bUEqG
-YuSvGO1wW+j4h54MxPBq9B7OBfAVP2gCMx2dBeTYLyA4MxpORn5LELJsVQQhODY=
+BAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMA0GCSqGSIb3DQEBDAUAA4IBgQCM
+OuSLT0KuE6TFHutyDRXAWaoJ6e60l5SrGvyxsEg5kDVFi0BZe1HTvrGsnJCdXAoc
+NEHXdF9ahKIR9mbvriJmH3b7w+BlPxJZa0uEat1Yqz0bP9PIUYRyf8GS5dF5tGKd
+VeFv+sIwbG4NrhyL1eUCmcDClazV1potnaMgVvTnYAoDCIWYJ9+XSKaSbrT6peBG
+C4W3bAdzxVmkqds6QmwaJa9KcDkdXNcIQVew11lmwpelCUoRH6X3I8vELNOerkqG
+VuEa5/N8xFyxrsLqH2daEOQCAb2SuA9WJuMnJG5TlMAW/vri7U9Cjdwjm5YuW6VH
+VqANCRcoOvKkLnFlk4g8/2GSBHVZll9AheG+HVnsjUu3gju7oQbCxER63j7+aOij
+Q6VQgP0RHSz/J43pcW3GASANml5sxhGD2sz93aNZXLFk4YG0bzRg37W7PV8r+O9z
+0FQ55N1LyV+H6R/7xOL39m4hcBQ7Dm4tEeXbuBjT0p8bpYWuifZVMxPm2rQbELw=
-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/rsa3072-user-rsa2048.pem b/tests/hwsim/auth_serv/rsa3072-user-rsa2048.pem
index 56b4a5994fa7..f5a4d632831c 100644
--- a/tests/hwsim/auth_serv/rsa3072-user-rsa2048.pem
+++ b/tests/hwsim/auth_serv/rsa3072-user-rsa2048.pem
@@ -2,12 +2,12 @@ Certificate:
Data:
Version: 3 (0x2)
Serial Number:
- ad:8c:09:e8:fb:a2:88:cd
+ ad:8c:09:e8:fb:a2:88:d0
Signature Algorithm: sha384WithRSAEncryption
Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B RSA 3k Root CA
Validity
- Not Before: Aug 16 13:19:41 2019 GMT
- Not After : Aug 15 13:19:41 2021 GMT
+ Not Before: Aug 19 10:56:47 2021 GMT
+ Not After : Aug 19 10:56:47 2023 GMT
Subject: C=FI, O=w1.fi, CN=user-rsa3072-rsa2048
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
@@ -47,33 +47,33 @@ Certificate:
X509v3 Key Usage:
Digital Signature, Key Encipherment
Signature Algorithm: sha384WithRSAEncryption
- 56:58:31:e4:90:41:01:ca:19:97:06:e0:5a:74:a4:a6:1d:1d:
- e4:71:bf:dc:cd:94:99:5c:20:24:73:7f:42:6e:1e:d0:4b:89:
- 6f:e3:1e:fa:16:7d:1e:b6:92:5f:e2:f8:66:3f:9f:fe:4b:0c:
- 39:c0:c1:bf:e3:8b:e9:cd:25:39:f6:50:4f:2a:a0:8c:1d:0c:
- 26:6a:3a:65:42:ee:4e:2a:23:5d:54:79:ca:9e:57:9b:c0:c0:
- 04:55:d4:ad:4f:06:88:71:f7:d8:6f:cd:7d:8e:92:a9:85:aa:
- a0:3c:0d:47:af:f9:cd:db:d6:41:f7:e1:a2:2d:b6:4d:70:78:
- 9f:08:07:dd:9b:27:bf:cb:85:07:55:0d:bc:55:1c:84:04:84:
- 98:9e:62:80:ca:93:b8:16:5b:74:fe:a1:cf:d7:59:99:be:23:
- f4:e3:a3:5f:2b:22:a5:38:09:c0:04:89:2e:f4:64:fe:b9:90:
- 17:38:02:2c:6b:ae:ca:36:f1:3a:e0:e1:db:47:99:78:59:ed:
- 98:b7:95:f9:06:5a:37:03:9f:96:bd:87:cd:8d:f9:5c:3b:22:
- b2:ca:f6:b0:e6:b9:70:4e:70:ea:ab:25:bd:f7:4f:1a:5d:7b:
- d2:36:aa:30:c1:95:cb:e5:71:3a:51:6e:e5:b4:b6:e2:19:55:
- 05:50:e5:4d:88:8d:fd:0e:0e:e3:5b:86:61:cf:10:b7:dd:7f:
- 12:01:b8:bf:2c:a6:86:7b:86:ff:b3:cc:b0:c7:ca:2a:c6:33:
- 2e:81:f8:bc:19:e0:da:b4:d5:6a:69:dd:cb:c6:5d:41:7b:d0:
- d1:02:67:7f:c0:39:e2:7c:60:9a:8b:ce:c9:1f:2a:0c:69:04:
- 22:36:4d:50:20:bc:cd:6a:fa:5e:c2:96:ef:d0:82:55:ea:2c:
- 64:87:59:36:f3:db:06:80:41:1b:8d:75:6e:db:bc:66:d5:15:
- a3:72:89:d0:ee:ed:e4:37:b1:68:40:7c:9e:da:5d:01:12:91:
- f3:bb:39:45:57:26
+ cf:0f:89:a8:6e:1e:ca:36:a7:35:90:60:66:0a:d3:ae:59:00:
+ 10:18:e7:33:26:96:df:36:81:0e:43:bd:e2:f9:38:ee:6f:9a:
+ 9f:a2:f4:a2:75:58:ef:47:83:64:1b:aa:61:99:f9:49:53:5d:
+ cf:ab:e1:79:33:ad:d0:87:3e:b7:0b:8a:8e:aa:a2:0f:e1:be:
+ c9:91:c1:e7:d6:0d:e0:16:3d:4c:01:62:eb:c0:d5:7c:7b:94:
+ d5:6b:7b:0c:c0:d8:bd:0f:b6:b4:1c:7f:c7:77:40:e3:d1:c8:
+ d8:df:36:56:01:69:c6:10:20:c0:88:57:a4:cf:4b:99:1a:ba:
+ 1b:4c:d3:06:1a:ce:b7:92:3d:71:47:5a:66:c0:84:a3:b3:92:
+ 01:62:b8:8d:c0:b4:c3:f5:07:a3:93:38:94:e8:d5:76:04:19:
+ 68:8b:11:5e:2e:03:64:8e:a9:ad:29:8b:45:a2:0d:4e:a3:c1:
+ 33:a5:5c:5e:a4:7d:9e:7f:13:96:b6:f0:18:3b:8b:03:9c:fa:
+ 2a:03:02:17:ef:6f:23:fe:a0:6d:b1:52:32:64:da:ac:d9:f8:
+ aa:bc:d4:8b:50:a7:3c:b4:ca:b5:62:5e:ce:87:f1:85:4e:a7:
+ 98:85:ea:17:6e:3a:ef:5e:74:4e:13:7c:17:5b:72:92:aa:bf:
+ dc:b3:03:28:79:83:89:e5:b2:f9:85:64:f2:d1:7a:cb:cb:22:
+ 87:1a:ce:34:c7:a3:8d:06:04:3d:ad:f8:f1:af:0b:d0:2a:06:
+ 26:de:8d:fc:7a:07:0a:82:98:0b:2f:40:bb:d8:36:d7:7f:df:
+ ba:f3:b7:5d:5b:9b:8f:4f:48:71:b6:cf:05:e7:a3:6c:e8:37:
+ 3a:f1:23:73:da:00:c3:b5:99:b1:eb:24:7f:57:8d:71:f4:37:
+ 11:c3:61:19:3c:70:8b:9b:2a:cb:6f:5e:25:33:99:0f:d2:a4:
+ 68:35:b5:2a:fb:8b:d4:9f:04:3f:58:e0:f4:d5:dd:a5:ca:d8:
+ 55:00:50:db:51:ce
-----BEGIN CERTIFICATE-----
-MIIEKDCCApCgAwIBAgIJAK2MCej7oojNMA0GCSqGSIb3DQEBDAUAMFExCzAJBgNV
+MIIEKDCCApCgAwIBAgIJAK2MCej7oojQMA0GCSqGSIb3DQEBDAUAMFExCzAJBgNV
BAYTAkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxHzAdBgNV
-BAMMFlN1aXRlIEIgUlNBIDNrIFJvb3QgQ0EwHhcNMTkwODE2MTMxOTQxWhcNMjEw
-ODE1MTMxOTQxWjA8MQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxHTAbBgNV
+BAMMFlN1aXRlIEIgUlNBIDNrIFJvb3QgQ0EwHhcNMjEwODE5MTA1NjQ3WhcNMjMw
+ODE5MTA1NjQ3WjA8MQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxHTAbBgNV
BAMMFHVzZXItcnNhMzA3Mi1yc2EyMDQ4MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA22b/i5Vmli5KdAKAQ/wJ+rZBeAn46b9rQf1bv8xm2AfDDexIl40s
T1j1tScH7kh8a5iiduiLlBF3aDZDHyyIn9ZA3+wnFmOuNBzV7CbF2a13qXMUhqOk
@@ -84,13 +84,13 @@ SaiVAkmoZyp487QOq2kF6dkwrbC9JvCNMwIDAQABo4GXMIGUMAkGA1UdEwQCMAAw
HQYDVR0OBBYEFMyFqj3kN1E+cEaWjgBlw4Eg4OSHMB8GA1UdIwQYMBaAFCH379rD
NDrtzdVQwLO6Ce4/gNdwMCUGA1UdEQQeMByBGnVzZXItcnNhMzA3Mi1yc2EyMDQ4
QHcxLmZpMBMGA1UdJQQMMAoGCCsGAQUFBwMCMAsGA1UdDwQEAwIFoDANBgkqhkiG
-9w0BAQwFAAOCAYEAVlgx5JBBAcoZlwbgWnSkph0d5HG/3M2UmVwgJHN/Qm4e0EuJ
-b+Me+hZ9HraSX+L4Zj+f/ksMOcDBv+OL6c0lOfZQTyqgjB0MJmo6ZULuTiojXVR5
-yp5Xm8DABFXUrU8GiHH32G/NfY6SqYWqoDwNR6/5zdvWQffhoi22TXB4nwgH3Zsn
-v8uFB1UNvFUchASEmJ5igMqTuBZbdP6hz9dZmb4j9OOjXysipTgJwASJLvRk/rmQ
-FzgCLGuuyjbxOuDh20eZeFntmLeV+QZaNwOflr2HzY35XDsissr2sOa5cE5w6qsl
-vfdPGl170jaqMMGVy+VxOlFu5bS24hlVBVDlTYiN/Q4O41uGYc8Qt91/EgG4vyym
-hnuG/7PMsMfKKsYzLoH4vBng2rTVamndy8ZdQXvQ0QJnf8A54nxgmovOyR8qDGkE
-IjZNUCC8zWr6XsKW79CCVeosZIdZNvPbBoBBG411btu8ZtUVo3KJ0O7t5DexaEB8
-ntpdARKR87s5RVcm
+9w0BAQwFAAOCAYEAzw+JqG4eyjanNZBgZgrTrlkAEBjnMyaW3zaBDkO94vk47m+a
+n6L0onVY70eDZBuqYZn5SVNdz6vheTOt0Ic+twuKjqqiD+G+yZHB59YN4BY9TAFi
+68DVfHuU1Wt7DMDYvQ+2tBx/x3dA49HI2N82VgFpxhAgwIhXpM9LmRq6G0zTBhrO
+t5I9cUdaZsCEo7OSAWK4jcC0w/UHo5M4lOjVdgQZaIsRXi4DZI6prSmLRaINTqPB
+M6VcXqR9nn8TlrbwGDuLA5z6KgMCF+9vI/6gbbFSMmTarNn4qrzUi1CnPLTKtWJe
+zofxhU6nmIXqF2467150ThN8F1tykqq/3LMDKHmDieWy+YVk8tF6y8sihxrONMej
+jQYEPa348a8L0CoGJt6N/HoHCoKYCy9Au9g213/fuvO3XVubj09IcbbPBeejbOg3
+OvEjc9oAw7WZseskf1eNcfQ3EcNhGTxwi5sqy29eJTOZD9KkaDW1KvuL1J8EP1jg
+9NXdpcrYVQBQ21HO
-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/rsa3072-user.pem b/tests/hwsim/auth_serv/rsa3072-user.pem
index fef367b07f93..dff6581f629a 100644
--- a/tests/hwsim/auth_serv/rsa3072-user.pem
+++ b/tests/hwsim/auth_serv/rsa3072-user.pem
@@ -2,12 +2,12 @@ Certificate:
Data:
Version: 3 (0x2)
Serial Number:
- ad:8c:09:e8:fb:a2:88:cc
+ ad:8c:09:e8:fb:a2:88:cf
Signature Algorithm: sha384WithRSAEncryption
Issuer: C=FI, L=Helsinki, O=w1.fi, CN=Suite B RSA 3k Root CA
Validity
- Not Before: Aug 16 13:19:41 2019 GMT
- Not After : Aug 15 13:19:41 2021 GMT
+ Not Before: Aug 19 10:56:47 2021 GMT
+ Not After : Aug 19 10:56:47 2023 GMT
Subject: C=FI, O=w1.fi, CN=user-rsa3072
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
@@ -55,33 +55,33 @@ Certificate:
X509v3 Key Usage:
Digital Signature, Key Encipherment
Signature Algorithm: sha384WithRSAEncryption
- b8:51:21:70:fc:ce:a2:a6:43:db:b1:54:c6:51:ee:a9:77:dd:
- ad:3f:75:fc:23:0c:be:a5:e7:ec:f4:2d:33:04:08:48:45:58:
- 5d:1f:83:57:57:43:b0:be:81:69:d7:51:65:f8:24:97:8e:3c:
- 01:60:a3:b3:0a:11:43:94:2c:68:f0:a1:28:63:e4:ce:a8:27:
- 2d:74:6f:8f:e4:10:8e:9a:56:91:72:61:fd:85:82:8a:48:dd:
- d6:f3:40:97:de:6d:8b:51:ef:e8:a0:a5:65:45:96:aa:85:d1:
- b6:86:8e:53:68:2d:d0:c3:6b:11:ba:8e:15:3c:a4:b7:38:fe:
- 9f:1c:57:b8:58:a3:f6:ff:31:e4:95:f9:d8:52:80:66:b1:c4:
- f9:ce:95:01:30:89:7b:e7:ec:86:b5:c6:95:46:55:5f:ce:36:
- 43:8f:9c:ca:48:86:20:d0:60:89:c8:03:d0:25:1e:38:25:bb:
- d8:b1:e1:72:9a:f5:f3:97:e6:76:41:80:0e:00:47:06:59:46:
- 2b:37:57:07:77:e4:5e:9c:38:0e:80:81:61:ab:89:ef:43:99:
- 7a:2c:24:b5:60:c2:5e:a8:2b:59:03:1d:e3:ab:b9:0b:02:3f:
- 16:90:57:70:56:d7:40:42:70:0e:de:27:9e:f1:27:30:e0:2c:
- 56:5c:bf:56:43:db:fb:a6:14:ba:0a:ef:87:d5:a4:00:73:59:
- 8b:a0:10:1d:b1:8a:31:a8:ef:ae:c7:c5:25:65:b5:05:a0:df:
- 16:63:0e:58:f4:0e:5f:9c:e8:95:ea:b5:18:63:6e:ae:5a:dc:
- c5:d5:95:c7:f9:23:46:76:96:d6:d2:ec:a0:63:01:3c:63:f1:
- 99:6e:b1:f2:3c:e7:08:ff:67:53:dd:b7:6e:83:91:cb:32:e9:
- 5e:64:8b:5f:46:6c:80:02:a8:37:3c:a3:17:ad:33:5f:dc:75:
- e6:41:dc:db:19:26:c0:34:76:5d:19:a5:10:89:ad:59:5e:5d:
- 69:41:2d:3f:64:d0
+ 46:8b:f8:99:9e:59:45:06:16:c4:09:52:4e:06:63:25:55:9f:
+ e7:4b:65:41:b3:af:64:1f:ff:70:17:18:a4:0f:d7:95:97:bd:
+ 81:2a:f7:df:8f:c5:76:ec:f0:95:4d:c2:17:3f:54:7d:63:1a:
+ 82:3c:22:7b:49:55:6c:c0:9b:a2:66:fe:9c:d5:ce:ee:9c:f0:
+ f3:17:32:84:09:0d:e6:a9:13:a5:af:94:95:ed:8c:85:cd:c9:
+ 65:ed:6a:05:3f:56:8d:07:1e:be:b4:eb:5b:92:d3:bb:90:4f:
+ 1c:e7:3b:bc:b0:9a:da:c9:d7:14:55:de:a7:68:d0:c7:58:7e:
+ 73:21:4b:9c:9e:37:38:d3:e2:77:ec:56:8e:b7:43:01:4a:7c:
+ 15:0e:ed:b9:e5:fe:28:b9:df:f4:4f:96:43:2d:9c:d3:7f:dc:
+ 46:37:8e:3a:60:47:1b:24:b6:a5:df:34:7b:b5:32:6a:1c:f0:
+ 37:3c:10:0a:5c:53:6b:11:11:aa:1c:4b:da:d2:b5:e0:59:ee:
+ f1:0f:0c:f5:ec:49:14:24:a1:68:39:b2:85:c6:30:79:e1:ac:
+ 5e:08:1a:93:ba:fc:97:1c:aa:e2:1f:99:2c:ca:0b:3f:7a:ab:
+ 9e:35:ab:b7:78:f5:a0:d2:38:f8:ed:91:e7:9e:0c:b7:fc:ce:
+ d9:bc:f6:f5:cc:6b:a2:0a:78:94:ac:16:aa:f5:b3:8b:7e:e8:
+ 3d:67:4d:e8:5d:fc:6a:f1:a4:0f:7d:20:f0:e7:7f:af:f4:71:
+ 73:e5:77:e3:6b:41:9b:25:fb:65:4a:96:60:ac:58:18:27:21:
+ a3:aa:89:fb:c3:e6:e5:bf:ad:89:92:ae:9e:66:18:49:6f:16:
+ 01:2c:05:76:17:92:34:9a:dc:ed:d8:e0:f6:20:37:29:ef:4b:
+ 6c:6e:23:94:67:3d:c8:04:39:46:10:c5:bf:02:cf:1a:52:b6:
+ 43:35:84:aa:b1:0e:0b:d7:cb:4c:89:bc:43:f8:84:3f:39:8f:
+ 6e:ea:28:e6:d9:a6
-----BEGIN CERTIFICATE-----
-MIIEmDCCAwCgAwIBAgIJAK2MCej7oojMMA0GCSqGSIb3DQEBDAUAMFExCzAJBgNV
+MIIEmDCCAwCgAwIBAgIJAK2MCej7oojPMA0GCSqGSIb3DQEBDAUAMFExCzAJBgNV
BAYTAkZJMREwDwYDVQQHDAhIZWxzaW5raTEOMAwGA1UECgwFdzEuZmkxHzAdBgNV
-BAMMFlN1aXRlIEIgUlNBIDNrIFJvb3QgQ0EwHhcNMTkwODE2MTMxOTQxWhcNMjEw
-ODE1MTMxOTQxWjA0MQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxFTATBgNV
+BAMMFlN1aXRlIEIgUlNBIDNrIFJvb3QgQ0EwHhcNMjEwODE5MTA1NjQ3WhcNMjMw
+ODE5MTA1NjQ3WjA0MQswCQYDVQQGEwJGSTEOMAwGA1UECgwFdzEuZmkxFTATBgNV
BAMMDHVzZXItcnNhMzA3MjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGB
AJJ3Z45ENIOoN/mpxHJccXKdNR09jDQiXCT4h4He3qylk3fFOKSCnIwGmxSLUgky
TDHF+OkvZIo5CnCeToqcvKWreBhSRHX+wwBh5x9FwBJy5DieKJ32dmBws3sRypCY
@@ -94,13 +94,13 @@ E/lTNzqoITjnX3T7hVNrIWuCyaVBLKM5dBSgXAPIExdVphVFUjy5uT/+2agUbyDF
IQIDAQABo4GPMIGMMAkGA1UdEwQCMAAwHQYDVR0OBBYEFLFPNhckQK1rBTOHxK1P
SlOv9dYjMB8GA1UdIwQYMBaAFCH379rDNDrtzdVQwLO6Ce4/gNdwMB0GA1UdEQQW
MBSBEnVzZXItcnNhMzA3MkB3MS5maTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNV
-HQ8EBAMCBaAwDQYJKoZIhvcNAQEMBQADggGBALhRIXD8zqKmQ9uxVMZR7ql33a0/
-dfwjDL6l5+z0LTMECEhFWF0fg1dXQ7C+gWnXUWX4JJeOPAFgo7MKEUOULGjwoShj
-5M6oJy10b4/kEI6aVpFyYf2FgopI3dbzQJfebYtR7+igpWVFlqqF0baGjlNoLdDD
-axG6jhU8pLc4/p8cV7hYo/b/MeSV+dhSgGaxxPnOlQEwiXvn7Ia1xpVGVV/ONkOP
-nMpIhiDQYInIA9AlHjglu9ix4XKa9fOX5nZBgA4ARwZZRis3Vwd35F6cOA6AgWGr
-ie9DmXosJLVgwl6oK1kDHeOruQsCPxaQV3BW10BCcA7eJ57xJzDgLFZcv1ZD2/um
-FLoK74fVpABzWYugEB2xijGo767HxSVltQWg3xZjDlj0Dl+c6JXqtRhjbq5a3MXV
-lcf5I0Z2ltbS7KBjATxj8ZlusfI85wj/Z1Pdt26Dkcsy6V5ki19GbIACqDc8oxet
-M1/cdeZB3NsZJsA0dl0ZpRCJrVleXWlBLT9k0A==
+HQ8EBAMCBaAwDQYJKoZIhvcNAQEMBQADggGBAEaL+JmeWUUGFsQJUk4GYyVVn+dL
+ZUGzr2Qf/3AXGKQP15WXvYEq99+PxXbs8JVNwhc/VH1jGoI8IntJVWzAm6Jm/pzV
+zu6c8PMXMoQJDeapE6WvlJXtjIXNyWXtagU/Vo0HHr6061uS07uQTxznO7ywmtrJ
+1xRV3qdo0MdYfnMhS5yeNzjT4nfsVo63QwFKfBUO7bnl/ii53/RPlkMtnNN/3EY3
+jjpgRxsktqXfNHu1Mmoc8Dc8EApcU2sREaocS9rSteBZ7vEPDPXsSRQkoWg5soXG
+MHnhrF4IGpO6/JccquIfmSzKCz96q541q7d49aDSOPjtkeeeDLf8ztm89vXMa6IK
+eJSsFqr1s4t+6D1nTehd/GrxpA99IPDnf6/0cXPld+NrQZsl+2VKlmCsWBgnIaOq
+ifvD5uW/rYmSrp5mGElvFgEsBXYXkjSa3O3Y4PYgNynvS2xuI5RnPcgEOUYQxb8C
+zxpStkM1hKqxDgvXy0yJvEP4hD85j27qKObZpg==
-----END CERTIFICATE-----
diff --git a/tests/hwsim/fst_test_common.py b/tests/hwsim/fst_test_common.py
index 4b6bab07d780..440d65f9f3fd 100644
--- a/tests/hwsim/fst_test_common.py
+++ b/tests/hwsim/fst_test_common.py
@@ -24,14 +24,9 @@ fst_test_def_reg_domain = '00'
class HapdRegCtrl:
def __init__(self):
- self.refcnt = 0
self.ifname = None
self.changed = False
- def __del__(self):
- if self.refcnt != 0 and self.changed == True:
- self.restore_reg_domain()
-
def start(self):
if self.ifname != None:
hapd = hostapd.Hostapd(self.ifname)
diff --git a/tests/hwsim/multi-bss-iface-per_sta_vif.conf b/tests/hwsim/multi-bss-iface-per_sta_vif.conf
index f07c13b212ea..874cb0771c81 100644
--- a/tests/hwsim/multi-bss-iface-per_sta_vif.conf
+++ b/tests/hwsim/multi-bss-iface-per_sta_vif.conf
@@ -9,7 +9,7 @@ ctrl_interface=/var/run/hostapd
ssid=bss-1
dynamic_vlan=1
-vlan_tagged_interface=dummy0
+vlan_tagged_interface=stub0
vlan_bridge=brvlan
wpa=2
wpa_key_mgmt=WPA-EAP
@@ -28,7 +28,7 @@ ctrl_interface=/var/run/hostapd
ssid=bss-2
dynamic_vlan=1
-vlan_tagged_interface=dummy0
+vlan_tagged_interface=stub0
vlan_bridge=brvlan
wpa=2
wpa_key_mgmt=WPA-EAP
diff --git a/tests/hwsim/multi-bss-iface.conf b/tests/hwsim/multi-bss-iface.conf
index 6b6167f51cc1..5370352c920e 100644
--- a/tests/hwsim/multi-bss-iface.conf
+++ b/tests/hwsim/multi-bss-iface.conf
@@ -9,7 +9,7 @@ ctrl_interface=/var/run/hostapd
ssid=bss-1
dynamic_vlan=1
-vlan_tagged_interface=dummy0
+vlan_tagged_interface=stub0
vlan_bridge=brvlan
wpa=2
wpa_key_mgmt=WPA-EAP
@@ -27,7 +27,7 @@ ctrl_interface=/var/run/hostapd
ssid=bss-2
dynamic_vlan=1
-vlan_tagged_interface=dummy0
+vlan_tagged_interface=stub0
vlan_bridge=brvlan
wpa=2
wpa_key_mgmt=WPA-EAP
diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py
index c53ce75ca826..269500a93a69 100644
--- a/tests/hwsim/test_ap_eap.py
+++ b/tests/hwsim/test_ap_eap.py
@@ -124,19 +124,25 @@ def check_ec_support(dev):
if tls.startswith("internal"):
raise HwsimSkip("EC not supported with this TLS library: " + tls)
-def read_pem(fname):
+def read_pem(fname, decode=True):
with open(fname, "r") as f:
lines = f.readlines()
copy = False
cert = ""
for l in lines:
if "-----END" in l:
+ if not decode:
+ cert = cert + l
break
if copy:
cert = cert + l
if "-----BEGIN" in l:
copy = True
- return base64.b64decode(cert)
+ if not decode:
+ cert = cert + l
+ if decode:
+ return base64.b64decode(cert)
+ return cert.encode()
def eap_connect(dev, hapd, method, identity,
sha256=False, expect_failure=False, local_error_report=False,
@@ -2244,6 +2250,24 @@ def test_ap_wpa2_eap_tls_blob(dev, apdev):
client_cert="blob://usercert",
private_key="blob://userkey")
+def test_ap_wpa2_eap_tls_blob_pem(dev, apdev):
+ """WPA2-Enterprise connection using EAP-TLS and config blobs (PEM)"""
+ params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
+ hapd = hostapd.add_ap(apdev[0], params)
+ cert = read_pem("auth_serv/ca.pem", decode=False)
+ if "OK" not in dev[0].request("SET blob cacert " + binascii.hexlify(cert).decode()):
+ raise Exception("Could not set cacert blob")
+ cert = read_pem("auth_serv/user.pem", decode=False)
+ if "OK" not in dev[0].request("SET blob usercert " + binascii.hexlify(cert).decode()):
+ raise Exception("Could not set usercert blob")
+ key = read_pem("auth_serv/user.key.pkcs8", decode=False)
+ if "OK" not in dev[0].request("SET blob userkey " + binascii.hexlify(key).decode()):
+ raise Exception("Could not set cacert blob")
+ eap_connect(dev[0], hapd, "TLS", "tls user", ca_cert="blob://cacert",
+ client_cert="blob://usercert",
+ private_key="blob://userkey",
+ private_key_passwd="whatever")
+
def test_ap_wpa2_eap_tls_blob_missing(dev, apdev):
"""EAP-TLS and config blob missing"""
params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
diff --git a/tests/hwsim/test_ap_vlan.py b/tests/hwsim/test_ap_vlan.py
index 29f8f53225ef..e4bfd68693b2 100644
--- a/tests/hwsim/test_ap_vlan.py
+++ b/tests/hwsim/test_ap_vlan.py
@@ -378,41 +378,41 @@ def test_ap_vlan_tagged(dev, apdev):
os.unlink(filename)
def ap_vlan_iface_cleanup_multibss_cleanup():
- subprocess.call(['ifconfig', 'dummy0', 'down'],
+ subprocess.call(['ifconfig', 'stub0', 'down'],
stderr=open('/dev/null', 'w'))
- ifnames = ['wlan3.1', 'wlan3.2', 'wlan3-2.1', 'wlan3-2.2', 'dummy0.2',
- 'dummy0.1', 'dummy0', 'brvlan1', 'brvlan2']
+ ifnames = ['wlan3.1', 'wlan3.2', 'wlan3-2.1', 'wlan3-2.2', 'stub0.2',
+ 'stub0.1', 'stub0', 'brvlan1', 'brvlan2']
for ifname in ifnames:
subprocess.call(['ip', 'link', 'del', ifname],
stderr=open('/dev/null', 'w'))
def ap_vlan_iface_test_and_prepare_environ():
ifaces = netifaces.interfaces()
- if "dummy0" in ifaces:
- raise Exception("dummy0 already exists before")
+ if "stub0" in ifaces:
+ raise Exception("stub0 already exists before")
ifaces = netifaces.interfaces()
- if "dummy0.1" in ifaces:
- raise Exception("dummy0.1 already exists before")
+ if "stub0.1" in ifaces:
+ raise Exception("stub0.1 already exists before")
- subprocess.call(['ip', 'link', 'add', 'dummy0', 'type', 'dummy'])
- subprocess.call(['ifconfig', 'dummy0', 'up'])
+ subprocess.call(['ip', 'link', 'add', 'stub0', 'type', 'dummy'])
+ subprocess.call(['ifconfig', 'stub0', 'up'])
ifaces = netifaces.interfaces()
- if "dummy0" not in ifaces:
- raise HwsimSkip("failed to add dummy0 - missing kernel config DUMMY ?")
+ if "stub0" not in ifaces:
+ raise HwsimSkip("failed to add stub0 - missing kernel config DUMMY ?")
- subprocess.call(['ip', 'link', 'add', 'link', 'dummy0', 'name', 'dummy0.1',
+ subprocess.call(['ip', 'link', 'add', 'link', 'stub0', 'name', 'stub0.1',
'type', 'vlan', 'id', '1'])
ifaces = netifaces.interfaces()
- if "dummy0.1" not in ifaces:
- raise HwsimSkip("failed to add dummy0.1 - missing kernel config VLAN_8021Q ?")
+ if "stub0.1" not in ifaces:
+ raise HwsimSkip("failed to add stub0.1 - missing kernel config VLAN_8021Q ?")
- subprocess.call(['ip', 'link', 'del', 'dummy0.1'])
+ subprocess.call(['ip', 'link', 'del', 'stub0.1'])
ifaces = netifaces.interfaces()
- if "dummy0.1" in ifaces:
- raise Exception("dummy0.1 was not removed before testing")
+ if "stub0.1" in ifaces:
+ raise Exception("stub0.1 was not removed before testing")
def test_ap_vlan_iface_cleanup_multibss(dev, apdev):
"""AP VLAN operation in multi-BSS multi-VLAN case"""
@@ -464,8 +464,8 @@ def ap_vlan_iface_cleanup_multibss(dev, apdev, cfgfile):
raise Exception("bridge brvlan1 was not created")
hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan1")
- if not iface_is_in_bridge("brvlan1", "dummy0.1"):
- raise Exception("dummy0.1 not in brvlan1")
+ if not iface_is_in_bridge("brvlan1", "stub0.1"):
+ raise Exception("stub0.1 not in brvlan1")
dev[1].connect("bss-2", key_mgmt="WPA-EAP", eap="PAX",
identity="vlan1",
@@ -474,8 +474,8 @@ def ap_vlan_iface_cleanup_multibss(dev, apdev, cfgfile):
hapd1.wait_sta()
hwsim_utils.test_connectivity_iface(dev[1], hapd1, "brvlan1")
- if not iface_is_in_bridge("brvlan1", "dummy0.1"):
- raise Exception("dummy0.1 not in brvlan1")
+ if not iface_is_in_bridge("brvlan1", "stub0.1"):
+ raise Exception("stub0.1 not in brvlan1")
authserv.disable()
authserv.set('eap_user_file', "auth_serv/eap_user_vlan.conf")
@@ -502,13 +502,13 @@ def ap_vlan_iface_cleanup_multibss(dev, apdev, cfgfile):
hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan2",
max_tries=5)
- if not iface_is_in_bridge("brvlan2", "dummy0.2"):
- raise Exception("dummy0.2 not in brvlan2")
+ if not iface_is_in_bridge("brvlan2", "stub0.2"):
+ raise Exception("stub0.2 not in brvlan2")
logger.info("test wlan1 == VLAN 1")
hwsim_utils.test_connectivity_iface(dev[1], hapd1, "brvlan1")
- if not iface_is_in_bridge("brvlan1", "dummy0.1"):
- raise Exception("dummy0.1 not in brvlan1")
+ if not iface_is_in_bridge("brvlan1", "stub0.1"):
+ raise Exception("stub0.1 not in brvlan1")
logger.info("wlan1 -> VLAN 2")
@@ -530,8 +530,8 @@ def ap_vlan_iface_cleanup_multibss(dev, apdev, cfgfile):
logger.info("test wlan0 == VLAN 2")
hwsim_utils.test_connectivity_iface(dev[0], hapd, "brvlan2")
- if not iface_is_in_bridge("brvlan2", "dummy0.2"):
- raise Exception("dummy0.2 not in brvlan2")
+ if not iface_is_in_bridge("brvlan2", "stub0.2"):
+ raise Exception("stub0.2 not in brvlan2")
ifaces = netifaces.interfaces()
if "brvlan1" in ifaces:
diff --git a/tests/hwsim/test_ap_wps.py b/tests/hwsim/test_ap_wps.py
index a07ed60b8218..62972ac703fd 100644
--- a/tests/hwsim/test_ap_wps.py
+++ b/tests/hwsim/test_ap_wps.py
@@ -5066,14 +5066,14 @@ def _test_ap_wps_http_timeout(dev, apdev):
sock.connect(addr)
sock.send(b"G")
- class DummyServer(StreamRequestHandler):
+ class StubServer(StreamRequestHandler):
def handle(self):
- logger.debug("DummyServer - start 31 sec wait")
+ logger.debug("StubServer - start 31 sec wait")
time.sleep(31)
- logger.debug("DummyServer - wait done")
+ logger.debug("StubServer - wait done")
logger.debug("Start WPS ER")
- server, sock2 = wps_er_start(dev[0], DummyServer, max_age=40,
+ server, sock2 = wps_er_start(dev[0], StubServer, max_age=40,
wait_m_search=True)
logger.debug("Start server to accept, but not complete, HTTP connection from WPS ER")
@@ -10131,8 +10131,8 @@ def test_ap_wps_tkip(dev, apdev):
if "FAIL" not in hapd.request("WPS_PBC"):
raise Exception("WPS unexpectedly enabled")
-def test_ap_wps_conf_dummy_cred(dev, apdev):
- """WPS PIN provisioning with configured AP using dummy cred"""
+def test_ap_wps_conf_stub_cred(dev, apdev):
+ """WPS PIN provisioning with configured AP using stub cred"""
ssid = "test-wps-conf"
hapd = hostapd.add_ap(apdev[0],
{"ssid": ssid, "eap_server": "1", "wps_state": "2",
@@ -10142,7 +10142,7 @@ def test_ap_wps_conf_dummy_cred(dev, apdev):
dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
dev[0].dump_monitor()
try:
- hapd.set("wps_testing_dummy_cred", "1")
+ hapd.set("wps_testing_stub_cred", "1")
dev[0].request("WPS_PIN " + apdev[0]['bssid'] + " 12345670")
for i in range(1, 3):
ev = dev[0].wait_event(["WPS-CRED-RECEIVED"], timeout=15)
@@ -10150,7 +10150,7 @@ def test_ap_wps_conf_dummy_cred(dev, apdev):
raise Exception("WPS credential %d not received" % i)
dev[0].wait_connected(timeout=30)
finally:
- hapd.set("wps_testing_dummy_cred", "0")
+ hapd.set("wps_testing_stub_cred", "0")
def test_ap_wps_rf_bands(dev, apdev):
"""WPS and wps_rf_bands configuration"""
@@ -10429,6 +10429,39 @@ def run_ap_wps_conf_and_sae(dev, apdev):
dev[1].connect(ssid, psk="12345678", scan_freq="2412", proto="WPA2",
key_mgmt="WPA-PSK", ieee80211w="0")
+def test_ap_wps_conf_and_sae_h2e(dev, apdev):
+ """WPS PIN provisioning with configured AP using PSK+SAE(H2E)"""
+ try:
+ run_ap_wps_conf_and_sae_h2e(dev, apdev)
+ finally:
+ dev[0].set("wps_cred_add_sae", "0")
+ dev[0].set("sae_pwe", "0")
+
+def run_ap_wps_conf_and_sae_h2e(dev, apdev):
+ check_sae_capab(dev[0])
+ ssid = "test-wps-conf-sae"
+ hapd = hostapd.add_ap(apdev[0],
+ {"ssid": ssid, "eap_server": "1", "wps_state": "2",
+ "wpa_passphrase": "12345678", "wpa": "2",
+ "ieee80211w": "1", "sae_require_mfp": "1",
+ "sae_pwe": "1",
+ "wpa_key_mgmt": "WPA-PSK SAE",
+ "rsn_pairwise": "CCMP"})
+
+ dev[0].set("wps_cred_add_sae", "1")
+ dev[0].set("sae_pwe", "1")
+ dev[0].request("SET sae_groups ")
+ dev[0].scan_for_bss(apdev[0]['bssid'], freq="2412")
+ pin = dev[0].wps_read_pin()
+ hapd.request("WPS_PIN any " + pin)
+ dev[0].request("WPS_PIN " + apdev[0]['bssid'] + " " + pin)
+ dev[0].wait_connected(timeout=30)
+ status = dev[0].get_status()
+ if status['key_mgmt'] != "SAE":
+ raise Exception("SAE not used")
+ if 'pmf' not in status or status['pmf'] != "1":
+ raise Exception("PMF not enabled")
+
def test_ap_wps_reg_config_and_sae(dev, apdev):
"""WPS registrar configuring an AP using AP PIN and using PSK+SAE"""
try:
@@ -10566,3 +10599,10 @@ def test_ap_wps_registrar_init_errors(dev, apdev):
with alloc_fail(hapd, count, func):
if "FAIL" not in hapd.request("ENABLE"):
raise Exception("ENABLE succeeded unexpectedly")
+
+def test_ap_wps_config_without_wps(dev, apdev):
+ """AP configuration attempt using wps_config when WPS is disabled"""
+ ssid = "test-wps-init-config"
+ hapd = hostapd.add_ap(apdev[0], {"ssid": ssid})
+ if "FAIL" not in hapd.request("WPS_CONFIG " + binascii.hexlify(ssid.encode()).decode() + " WPA2PSK CCMP " + binascii.hexlify(b"12345678").decode()):
+ raise Exception("WPS_CONFIG command succeeded unexpectedly")
diff --git a/tests/hwsim/test_connect_cmd.py b/tests/hwsim/test_connect_cmd.py
index 3c0985137d41..d101ee7052fc 100644
--- a/tests/hwsim/test_connect_cmd.py
+++ b/tests/hwsim/test_connect_cmd.py
@@ -191,6 +191,25 @@ def test_connect_cmd_roam(dev, apdev):
wpas.wait_disconnected()
wpas.dump_monitor()
+def test_connect_cmd_wpa_psk_roam(dev, apdev):
+ """WPA2/WPA-PSK connection using cfg80211 connect command to trigger roam"""
+ params = hostapd.wpa2_params(ssid="sta-connect", passphrase="12345678")
+ hostapd.add_ap(apdev[0], params)
+
+ wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+ wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
+ wpas.connect("sta-connect", psk="12345678", scan_freq="2412")
+ wpas.dump_monitor()
+
+ params = hostapd.wpa_params(ssid="sta-connect", passphrase="12345678")
+ hostapd.add_ap(apdev[1], params)
+ wpas.scan_for_bss(apdev[1]['bssid'], freq=2412, force_scan=True)
+ wpas.roam(apdev[1]['bssid'])
+ time.sleep(0.1)
+ wpas.request("DISCONNECT")
+ wpas.wait_disconnected()
+ wpas.dump_monitor()
+
def test_connect_cmd_bssid_hint(dev, apdev):
"""cfg80211 connect command with bssid_hint"""
params = {"ssid": "sta-connect"}
diff --git a/tests/hwsim/test_dpp.py b/tests/hwsim/test_dpp.py
index 71df7fc64148..4ed2652ef5df 100644
--- a/tests/hwsim/test_dpp.py
+++ b/tests/hwsim/test_dpp.py
@@ -214,7 +214,8 @@ def test_dpp_qr_code_keygen_fail(dev, apdev):
"""DPP QR Code and keygen failure"""
check_dpp_capab(dev[0])
- with alloc_fail(dev[0], 1, "dpp_bootstrap_key_der;dpp_keygen"):
+ with alloc_fail(dev[0], 1,
+ "crypto_ec_key_get_subject_public_key;dpp_keygen"):
if "FAIL" not in dev[0].request("DPP_BOOTSTRAP_GEN type=qrcode"):
raise Exception("Failure not reported")
@@ -369,8 +370,10 @@ def run_dpp_qr_code_auth_unicast(dev, apdev, curve, netrole=None, key=None,
require_conf_failure=False,
configurator=False, conf_curve=None,
conf=None, qr=None, stop_responder=True):
- check_dpp_capab(dev[0], curve and "brainpool" in curve)
- check_dpp_capab(dev[1], curve and "brainpool" in curve)
+ brainpool = (curve and "brainpool" in curve) or \
+ (conf_curve and "brainpool" in conf_curve)
+ check_dpp_capab(dev[0], brainpool)
+ check_dpp_capab(dev[1], brainpool)
if configurator:
conf_id = dev[1].dpp_configurator_add(curve=conf_curve)
else:
@@ -1751,8 +1754,10 @@ def update_hapd_config(hapd):
def run_dpp_ap_config(dev, apdev, curve=None, conf_curve=None,
reconf_configurator=False):
- check_dpp_capab(dev[0])
- check_dpp_capab(dev[1])
+ brainpool = (curve and "BP-" in curve) or \
+ (conf_curve and "BP-" in conf_curve)
+ check_dpp_capab(dev[0], brainpool)
+ check_dpp_capab(dev[1], brainpool)
hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured"})
check_dpp_capab(hapd)
@@ -2214,7 +2219,7 @@ def test_dpp_test_vector_p_256_b(dev, apdev):
def der_priv_key_p_521(priv):
if len(priv) != 2 * 66:
raise Exception("Unexpected der_priv_key_p_521 parameter: " + priv)
- der_prefix = "3081500201010442"
+ der_prefix = "30500201010442"
der_postfix = "a00706052b81040023"
return der_prefix + priv + der_postfix
@@ -2482,7 +2487,7 @@ def test_dpp_pkex_commit_reveal_req_processing_failure(dev, apdev):
dev[0].dpp_pkex_resp(2437, identifier="test", code="secret")
with alloc_fail(dev[0], 1,
- "dpp_get_pubkey_point;dpp_pkex_rx_commit_reveal_req"):
+ "crypto_ec_key_get_pubkey_point;dpp_pkex_rx_commit_reveal_req"):
dev[1].dpp_pkex_init(identifier="test", code="secret")
wait_fail_trigger(dev[0], "GET_ALLOC_FAIL")
@@ -4138,7 +4143,7 @@ def test_dpp_pkex_alloc_fail(dev, apdev):
id1 = None
# Local error cases on the Initiator
- tests = [(1, "dpp_get_pubkey_point"),
+ tests = [(1, "crypto_ec_key_get_pubkey_point"),
(1, "dpp_alloc_msg;dpp_pkex_build_exchange_req"),
(1, "dpp_alloc_msg;dpp_pkex_build_commit_reveal_req"),
(1, "dpp_alloc_msg;dpp_auth_build_req"),
@@ -4168,9 +4173,9 @@ def test_dpp_pkex_alloc_fail(dev, apdev):
(3, "dpp_pkex_init"),
(1, "dpp_pkex_derive_z"),
(1, "=dpp_pkex_rx_commit_reveal_resp"),
- (1, "dpp_get_pubkey_point;dpp_build_jwk"),
- (2, "dpp_get_pubkey_point;dpp_build_jwk"),
- (1, "dpp_get_pubkey_point;dpp_auth_init")]
+ (1, "crypto_ec_key_get_pubkey_point;dpp_build_jwk"),
+ (2, "crypto_ec_key_get_pubkey_point;dpp_build_jwk"),
+ (1, "crypto_ec_key_get_pubkey_point;dpp_auth_init")]
for count, func in tests:
dev[0].request("DPP_STOP_LISTEN")
dev[1].request("DPP_STOP_LISTEN")
@@ -4191,11 +4196,11 @@ def test_dpp_pkex_alloc_fail(dev, apdev):
dev[0].wait_event(["GAS-QUERY-DONE"], timeout=3)
# Local error cases on the Responder
- tests = [(1, "dpp_get_pubkey_point"),
+ tests = [(1, "crypto_ec_key_get_pubkey_point"),
(1, "dpp_alloc_msg;dpp_pkex_build_exchange_resp"),
(1, "dpp_alloc_msg;dpp_pkex_build_commit_reveal_resp"),
(1, "dpp_alloc_msg;dpp_auth_build_resp"),
- (1, "dpp_get_pubkey_point;dpp_auth_build_resp_ok"),
+ (1, "crypto_ec_key_get_pubkey_point;dpp_auth_build_resp_ok"),
(1, "dpp_alloc_auth"),
(1, "=dpp_auth_req_rx"),
(1, "=dpp_auth_conf_rx"),
@@ -4206,7 +4211,7 @@ def test_dpp_pkex_alloc_fail(dev, apdev):
(1, "json_parse;dpp_parse_connector"),
(1, "dpp_parse_jwk;dpp_parse_connector"),
(1, "dpp_parse_jwk;dpp_parse_cred_dpp"),
- (1, "dpp_get_pubkey_point;dpp_check_pubkey_match"),
+ (1, "crypto_ec_key_get_pubkey_point;dpp_check_pubkey_match"),
(1, "base64_gen_decode;dpp_process_signed_connector"),
(1, "dpp_parse_jws_prot_hdr;dpp_process_signed_connector"),
(2, "base64_gen_decode;dpp_process_signed_connector"),
@@ -4219,7 +4224,7 @@ def test_dpp_pkex_alloc_fail(dev, apdev):
(2, "=dpp_pkex_rx_exchange_req"),
(3, "=dpp_pkex_rx_exchange_req"),
(1, "=dpp_pkex_rx_commit_reveal_req"),
- (1, "dpp_get_pubkey_point;dpp_pkex_rx_commit_reveal_req"),
+ (1, "crypto_ec_key_get_pubkey_point;dpp_pkex_rx_commit_reveal_req"),
(1, "dpp_bootstrap_key_hash")]
for count, func in tests:
dev[0].request("DPP_STOP_LISTEN")
@@ -4650,7 +4655,8 @@ def test_dpp_invalid_configurator_key(dev, apdev):
if "FAIL" not in dev[0].request("DPP_CONFIGURATOR_ADD key=" + dpp_key_p256):
raise Exception("Error not reported")
- with alloc_fail(dev[0], 1, "dpp_get_pubkey_point;dpp_keygen_configurator"):
+ with alloc_fail(dev[0], 1,
+ "crypto_ec_key_get_pubkey_point;dpp_keygen_configurator"):
if "FAIL" not in dev[0].request("DPP_CONFIGURATOR_ADD key=" + dpp_key_p256):
raise Exception("Error not reported")
@@ -5490,6 +5496,37 @@ def test_dpp_tcp_controller_management_hostapd(dev, apdev, params):
if "FAIL" not in hapd.request("DPP_CONFIGURATOR_REMOVE %d" % conf_id):
raise Exception("Removal of unknown Configurator accepted")
+def test_dpp_tcp_controller_management_hostapd2(dev, apdev, params):
+ """DPP Controller management in hostapd over interface addition/removal"""
+ check_dpp_capab(dev[0], min_ver=2)
+ hapd = hostapd.add_ap(apdev[0], {"ssid": "unconfigured"})
+ check_dpp_capab(hapd, min_ver=2)
+ hapd2 = hostapd.add_ap(apdev[1], {"ssid": "unconfigured"})
+ check_dpp_capab(hapd2, min_ver=2)
+ id_c = hapd.dpp_bootstrap_gen()
+ uri_c = hapd.request("DPP_BOOTSTRAP_GET_URI %d" % id_c)
+ if "OK" not in hapd.request("DPP_CONTROLLER_START role=enrollee"):
+ raise Exception("Failed to start Controller")
+
+ conf_id = dev[0].dpp_configurator_add()
+ dev[0].dpp_auth_init(uri=uri_c, role="configurator", conf="sta-dpp",
+ configurator=conf_id, tcp_addr="127.0.0.1")
+ ev = dev[0].wait_event(["DPP-AUTH-SUCCESS"], timeout=5)
+ if ev is None:
+ raise Exception("DPP Authentication did not succeed")
+ ev = dev[0].wait_event(["DPP-CONF-SENT"], timeout=5)
+ if ev is None:
+ raise Exception("DPP Configuration did not succeed")
+
+ hapd_global = hostapd.HostapdGlobal(apdev)
+ hapd_global.remove(apdev[0]['ifname'])
+
+ dev[0].dpp_auth_init(uri=uri_c, role="configurator", conf="sta-dpp",
+ configurator=conf_id, tcp_addr="127.0.0.1")
+ ev = dev[0].wait_event(["DPP-AUTH-SUCCESS"], timeout=5)
+ if ev is not None:
+ raise Exception("Unexpected DPP Authentication success")
+
def test_dpp_tcp_controller_start_failure(dev, apdev, params):
"""DPP Controller startup failure"""
check_dpp_capab(dev[0])
diff --git a/tests/hwsim/test_dscp.py b/tests/hwsim/test_dscp.py
new file mode 100644
index 000000000000..e017938bc355
--- /dev/null
+++ b/tests/hwsim/test_dscp.py
@@ -0,0 +1,407 @@
+# Test cases for dscp policy
+# Copyright (c) 2021, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2021, The Linux Foundation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import struct
+import time
+import sys
+import socket
+
+import hostapd
+from wpasupplicant import WpaSupplicant
+from utils import *
+
+def register_dscp_req(hapd):
+ type = 0x00d0
+ match = "7e506f9a1a"
+ if "OK" not in hapd.request("REGISTER_FRAME %04x %s" % (type, match)):
+ raise Exception("Could not register frame reception for Vendor specific protected type")
+
+def send_dscp_req(hapd, da, oui_subtype, dialog_token, req_control, qos_ie,
+ truncate=False):
+ type = 0
+ subtype = 13
+ category = 126
+ oui_type = 0x506f9a1a
+ if truncate:
+ req = struct.pack('>BLBB', category, oui_type, oui_subtype,
+ dialog_token)
+ else:
+ req = struct.pack('>BLBBB', category, oui_type, oui_subtype,
+ dialog_token, req_control)
+ if qos_ie:
+ req += qos_ie
+
+ msg = {}
+ msg['fc'] = 0x00d0
+ msg['sa'] = hapd.own_addr()
+ msg['da'] = da
+ msg['bssid'] = hapd.own_addr()
+ msg['type'] = type
+ msg['subtype'] = subtype
+ msg['payload'] = req
+
+ hapd.mgmt_tx(msg)
+ ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
+ if ev is None or "stype=13 ok=1" not in ev:
+ raise Exception("No DSCP Policy Request sent")
+
+def prepare_qos_ie(policy_id, req_type, dscp, start_port=0, end_port=0,
+ frame_classifier=None, frame_class_len=0, domain_name=None):
+ qos_elem_oui_type = 0x229a6f50
+ qos_elem_id = 221
+
+ if policy_id:
+ qos_attr = struct.pack('BBBBB', 2, 3, policy_id, req_type, dscp)
+ qos_attr_len = 5
+ else:
+ qos_attr = 0
+ qos_attr_len = 0
+
+ if start_port and end_port:
+ port_range_attr = struct.pack('>BBHH', 1, 4, start_port, end_port)
+ if qos_attr:
+ qos_attr += port_range_attr
+ else:
+ qos_attr = port_range_attr
+ qos_attr_len += 6
+
+ if frame_classifier and frame_class_len:
+ tclas_attr = struct.pack('>BB%ds' % (len(frame_classifier),), 3,
+ len(frame_classifier), frame_classifier)
+ if qos_attr:
+ qos_attr += tclas_attr
+ else:
+ qos_attr = tclas_attr
+ qos_attr_len += 2 + len(frame_classifier)
+
+ if domain_name:
+ s = bytes(domain_name, 'utf-8')
+ domain_name_attr = struct.pack('>BB%ds' % (len(s),), 4, len(s), s)
+ if qos_attr:
+ qos_attr += domain_name_attr
+ else:
+ qos_attr = domain_name_attr
+ qos_attr_len += 2 + len(s)
+
+ qos_attr_len += 4
+ qos_ie = struct.pack('<BBL', qos_elem_id, qos_attr_len,
+ qos_elem_oui_type) + qos_attr
+
+ return qos_ie
+
+def validate_dscp_req_event(dev, event):
+ ev = dev.wait_event(["CTRL-EVENT-DSCP-POLICY"], timeout=2)
+ if ev is None:
+ raise Exception("No DSCP request reported")
+ if ev != event:
+ raise Exception("Invalid DSCP event received (%s; expected: %s)" % (ev, event))
+
+def handle_dscp_query(hapd, query):
+ msg = hapd.mgmt_rx()
+ if msg['payload'] != query:
+ raise Exception("Invalid DSCP Query received at AP")
+
+def handle_dscp_response(hapd, response):
+ msg = hapd.mgmt_rx()
+ if msg['payload'] != response:
+ raise Exception("Invalid DSCP Response received at AP")
+
+def ap_sta_connectivity(dev, apdev, params):
+ p = hostapd.wpa2_params(passphrase="12345678")
+ p["wpa_key_mgmt"] = "WPA-PSK"
+ p["ieee80211w"] = "1"
+ p.update(params)
+ hapd = hostapd.add_ap(apdev[0], p)
+ register_dscp_req(hapd)
+
+ dev[0].request("SET enable_dscp_policy_capa 1")
+ dev[0].connect("dscp", psk="12345678", ieee80211w="1",
+ key_mgmt="WPA-PSK WPA-PSK-SHA256", scan_freq="2412")
+ hapd.wait_sta()
+
+ hapd.dump_monitor()
+ hapd.set("ext_mgmt_frame_handling", "1")
+ return hapd
+
+def test_dscp_query(dev, apdev):
+ """DSCP Policy Query"""
+
+ # Positive tests
+ #AP with DSCP Capabilities
+ params = {"ssid": "dscp",
+ "ext_capa": 6*"00" + "40",
+ "assocresp_elements": "dd06506f9a230101",
+ "vendor_elements": "dd06506f9a230101"}
+
+ hapd = ap_sta_connectivity(dev, apdev, params)
+ da = dev[0].own_addr()
+
+ # Query 1
+ cmd = "DSCP_QUERY wildcard"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("Sending DSCP Query failed")
+ query = b'\x7e\x50\x6f\x9a\x1a\x00\x01'
+ handle_dscp_query(hapd, query)
+
+ # Query 2
+ cmd = "DSCP_QUERY domain_name=example.com"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("Sending DSCP Query failed")
+ query = b'\x7e\x50\x6f\x9a\x1a\x00\x02\xdd\x11\x50\x6f\x9a\x22\x04\x0b\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d'
+ handle_dscp_query(hapd, query)
+
+ # Negative tests
+
+ cmd = "DSCP_QUERY domain_name=" + 250*'a' + ".example.com"
+ if "FAIL" not in dev[0].request(cmd):
+ raise Exception("Invalid DSCP_QUERY accepted")
+
+ dev[0].disconnect_and_stop_scan()
+ # AP without DSCP Capabilities
+ params = {"ssid": "dscp",
+ "ext_capa": 6*"00" + "40"}
+ hapd = ap_sta_connectivity(dev, apdev, params)
+
+ # Query 3
+ cmd = "DSCP_QUERY wildcard"
+ if "FAIL" not in dev[0].request(cmd):
+ raise Exception("Able to send invalid DSCP Query")
+
+def test_dscp_request(dev, apdev):
+ """DSCP Policy Request"""
+
+ # Positive tests
+
+ #AP with DSCP Capabilities
+ params = {"ssid": "dscp",
+ "ext_capa": 6*"00" + "40",
+ "assocresp_elements": "dd06506f9a230101",
+ "vendor_elements": "dd06506f9a230101"}
+
+ hapd = ap_sta_connectivity(dev, apdev, params)
+ da = dev[0].own_addr()
+
+ # Request 1
+ dialog_token = 5
+ send_dscp_req(hapd, da, 1, dialog_token, 2, 0)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_start clear_all"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_end"
+ validate_dscp_req_event(dev[0], event)
+
+ # DSCP Request with multiple QoS IEs
+ # QoS IE 1
+ dialog_token = 1
+ domain_name = "example.com"
+ ipv4_src_addr = socket.inet_pton(socket.AF_INET, "192.168.0.1")
+ ipv4_dest_addr = socket.inet_pton(socket.AF_INET, "192.168.0.2")
+ frame_classifier_start = [4, 91, 4]
+ frame_classifier_end = [12, 34, 12, 34, 0, 17, 0]
+ frame_classifier = bytes(frame_classifier_start) + ipv4_src_addr + ipv4_dest_addr + bytes(frame_classifier_end)
+ frame_len = len(frame_classifier)
+ qos_ie = prepare_qos_ie(1, 0, 22, 0, 0, frame_classifier, frame_len, domain_name)
+
+ # QoS IE 2
+ ipv6_src_addr = socket.inet_pton(socket.AF_INET6, "aaaa:bbbb:cccc::1")
+ ipv6_dest_addr = socket.inet_pton(socket.AF_INET6, "aaaa:bbbb:cccc::2")
+ frame_classifier_start = [4, 79, 6]
+ frame_classifier_end = [0, 12, 34, 0, 0, 17, 0, 0, 0]
+ frame_classifier = bytes(frame_classifier_start) + ipv6_src_addr + ipv6_dest_addr + bytes(frame_classifier_end)
+ frame_len = len(frame_classifier)
+ ie = prepare_qos_ie(5, 0, 48, 12345, 23456, frame_classifier, frame_len,
+ None)
+ qos_ie += ie
+
+ # QoS IE 3
+ ie = prepare_qos_ie(4, 0, 32, 12345, 23456, 0, 0, domain_name)
+ qos_ie += ie
+ send_dscp_req(hapd, da, 1, dialog_token, 0, qos_ie)
+
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_start"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY add policy_id=1 dscp=22 ip_version=4 src_ip=192.168.0.1 src_port=3106 dst_port=3106 protocol=17 domain_name=example.com"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY add policy_id=5 dscp=48 ip_version=6 src_ip=aaaa:bbbb:cccc::1 dst_ip=aaaa:bbbb:cccc::2 src_port=12 protocol=17 start_port=12345 end_port=23456"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY add policy_id=4 dscp=32 ip_version=0 start_port=12345 end_port=23456 domain_name=example.com"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_end"
+ validate_dscp_req_event(dev[0], event)
+
+ # Negative Tests
+
+ # No DSCP policy attribute
+ dialog_token = 4
+ domain_name = "example.com"
+ qos_ie = prepare_qos_ie(0, 0, 0, 12345, 23456, frame_classifier, frame_len,
+ domain_name)
+ send_dscp_req(hapd, da, 1, dialog_token, 0, qos_ie)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_start"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_end"
+ validate_dscp_req_event(dev[0], event)
+
+ # No DSCP stream classifier params
+ dialog_token = 6
+ qos_ie = prepare_qos_ie(1, 0, 32, 0, 0, 0, 0, None)
+ send_dscp_req(hapd, da, 1, dialog_token, 0, qos_ie)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_start"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY reject policy_id=1"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_end"
+ validate_dscp_req_event(dev[0], event)
+
+ # DSCP request with both destination and domain name
+ dialog_token = 7
+ domain_name = "example.com"
+ ipv4_src_addr = socket.inet_pton(socket.AF_INET, "192.168.0.1")
+ ipv4_dest_addr = socket.inet_pton(socket.AF_INET, "192.168.0.2")
+ frame_classifier_start = [4, 69, 4]
+ frame_classifier_end = [0, 0, 0, 0, 0, 17, 0]
+ frame_classifier = bytes(frame_classifier_start) + ipv4_src_addr + ipv4_dest_addr + bytes(frame_classifier_end)
+ frame_len = len(frame_classifier)
+ qos_ie = prepare_qos_ie(1, 0, 36, 0, 0, frame_classifier, frame_len,
+ domain_name)
+ send_dscp_req(hapd, da, 1, dialog_token, 0, qos_ie)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_start"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY reject policy_id=1"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_end"
+ validate_dscp_req_event(dev[0], event)
+
+ # DSCP request with both port range and destination port
+ frame_classifier_start = [4, 81, 4]
+ frame_classifier_end = [0, 0, 23, 45, 0, 17, 0]
+ frame_classifier = bytes(frame_classifier_start) + ipv4_src_addr + ipv4_dest_addr + bytes(frame_classifier_end)
+ frame_len = len(frame_classifier)
+ qos_ie = prepare_qos_ie(1, 0, 36, 12345, 23456, frame_classifier, frame_len,
+ None)
+ send_dscp_req(hapd, da, 1, dialog_token, 0, qos_ie)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_start"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY reject policy_id=1"
+ validate_dscp_req_event(dev[0], event)
+ event = "<3>CTRL-EVENT-DSCP-POLICY request_end"
+ validate_dscp_req_event(dev[0], event)
+
+ # Too short DSCP Policy Request frame
+ dialog_token += 1
+ send_dscp_req(hapd, da, 1, dialog_token, 0, None, truncate=True)
+
+ # Request Type: Remove
+ dialog_token += 1
+ qos_ie = prepare_qos_ie(1, 1, 36)
+ send_dscp_req(hapd, da, 1, dialog_token, 0, qos_ie)
+ validate_dscp_req_event(dev[0], "<3>CTRL-EVENT-DSCP-POLICY request_start")
+ validate_dscp_req_event(dev[0],
+ "<3>CTRL-EVENT-DSCP-POLICY remove policy_id=1")
+ validate_dscp_req_event(dev[0], "<3>CTRL-EVENT-DSCP-POLICY request_end")
+
+ # Request Type: Reserved
+ dialog_token += 1
+ qos_ie = prepare_qos_ie(1, 2, 36)
+ send_dscp_req(hapd, da, 1, dialog_token, 0, qos_ie)
+ validate_dscp_req_event(dev[0], "<3>CTRL-EVENT-DSCP-POLICY request_start")
+ validate_dscp_req_event(dev[0],
+ "<3>CTRL-EVENT-DSCP-POLICY reject policy_id=1")
+ validate_dscp_req_event(dev[0], "<3>CTRL-EVENT-DSCP-POLICY request_end")
+
+def test_dscp_response(dev, apdev):
+ """DSCP Policy Response"""
+
+ # Positive tests
+
+ # AP with DSCP Capabilities
+ params = {"ssid": "dscp",
+ "ext_capa": 6*"00" + "40",
+ "assocresp_elements": "dd06506f9a230101",
+ "vendor_elements": "dd06506f9a230101"}
+ hapd = ap_sta_connectivity(dev, apdev, params)
+ da = dev[0].own_addr()
+
+ # Sending solicited DSCP response after receiving DSCP request
+ dialog_token = 1
+ domain_name = "example.com"
+ ipv4_src_addr = socket.inet_pton(socket.AF_INET, "192.168.0.1")
+ ipv4_dest_addr = socket.inet_pton(socket.AF_INET, "192.168.0.2")
+ frame_classifier_start = [4,91,4]
+ frame_classifier_end = [12,34,12,34,0,17,0]
+ frame_classifier = bytes(frame_classifier_start) + ipv4_src_addr + ipv4_dest_addr + bytes(frame_classifier_end)
+ frame_len = len(frame_classifier)
+ qos_ie = prepare_qos_ie(1, 0, 22, 0, 0, frame_classifier, frame_len,
+ domain_name)
+ ie = prepare_qos_ie(4, 0, 32, 12345, 23456, 0, 0, domain_name)
+ qos_ie += ie
+ send_dscp_req(hapd, da, 1, dialog_token, 0, qos_ie)
+
+ cmd = "DSCP_RESP solicited policy_id=1 status=0 policy_id=4 status=0"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("Sending DSCP Response failed")
+ response = b'\x7e\x50\x6f\x9a\x1a\x02\x01\x00\x02\x01\x00\x04\x00'
+ handle_dscp_response(hapd, response)
+
+ # Unsolicited DSCP Response without status duples
+ cmd = "DSCP_RESP reset more"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("Sending DSCP Response failed")
+ response = b'\x7e\x50\x6f\x9a\x1a\x02\x00\x03\x00'
+ handle_dscp_response(hapd, response)
+
+ # Unsolicited DSCP Response with one status duple
+ cmd = "DSCP_RESP policy_id=2 status=0"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("Sending DSCP Response failed")
+ response = b'\x7e\x50\x6f\x9a\x1a\x02\x00\x00\x01\x02\x00'
+ handle_dscp_response(hapd, response)
+
+ # Negative tests
+
+ # Send solicited DSCP Response without prior DSCP request
+ cmd = "DSCP_RESP solicited policy_id=1 status=0 policy_id=5 status=0"
+ if "FAIL" not in dev[0].request(cmd):
+ raise Exception("Able to send invalid DSCP response")
+
+def test_dscp_unsolicited_req_at_assoc(dev, apdev):
+ """DSCP Policy and unsolicited request at association"""
+ params = {"ssid": "dscp",
+ "ext_capa": 6*"00" + "40",
+ "assocresp_elements": "dd06506f9a230103",
+ "vendor_elements": "dd06506f9a230103"}
+ hapd = ap_sta_connectivity(dev, apdev, params)
+ da = dev[0].own_addr()
+
+ dialog_token = 1
+ qos_ie = prepare_qos_ie(1, 0, 36, 12345, 23456)
+ send_dscp_req(hapd, da, 1, dialog_token, 0, qos_ie)
+ validate_dscp_req_event(dev[0], "<3>CTRL-EVENT-DSCP-POLICY request_start")
+ validate_dscp_req_event(dev[0], "<3>CTRL-EVENT-DSCP-POLICY add policy_id=1 dscp=36 ip_version=0 start_port=12345 end_port=23456")
+ validate_dscp_req_event(dev[0], "<3>CTRL-EVENT-DSCP-POLICY request_end")
+
+ cmd = "DSCP_QUERY wildcard"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("Sending DSCP Query failed")
+
+def test_dscp_missing_unsolicited_req_at_assoc(dev, apdev):
+ """DSCP Policy and missing unsolicited request at association"""
+ params = {"ssid": "dscp",
+ "ext_capa": 6*"00" + "40",
+ "assocresp_elements": "dd06506f9a230103",
+ "vendor_elements": "dd06506f9a230103"}
+ hapd = ap_sta_connectivity(dev, apdev, params)
+ da = dev[0].own_addr()
+
+ cmd = "DSCP_QUERY wildcard"
+ if "FAIL" not in dev[0].request(cmd):
+ raise Exception("DSCP_QUERY accepted during wait for unsolicited requesdt")
+ time.sleep(5)
+ validate_dscp_req_event(dev[0], "<3>CTRL-EVENT-DSCP-POLICY request_wait end")
+
+ cmd = "DSCP_QUERY wildcard"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("Sending DSCP Query failed")
diff --git a/tests/hwsim/test_fst_config.py b/tests/hwsim/test_fst_config.py
index 98134014150f..c28786ded853 100644
--- a/tests/hwsim/test_fst_config.py
+++ b/tests/hwsim/test_fst_config.py
@@ -111,7 +111,10 @@ class FstLauncher:
self.reg_ctrl = fst_test_common.HapdRegCtrl()
self.test_is_supported()
- def __del__(self):
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
self.cleanup()
@staticmethod
@@ -269,7 +272,7 @@ def parse_ies(iehex, el=-1):
iel = [iehex[i:i + 2] for i in range(0, len(iehex), 2)]
for i in range(0, len(iel)):
iel[i] = int(iel[i], 16)
- # Sanity check
+ # Validity check
i = 0
res = []
while i < len(iel):
@@ -303,19 +306,19 @@ def run_test_ap_configuration(apdev, test_params,
0 - no errors discovered, an error otherwise. The function is used for
simplek "bad configuration" tests."""
logdir = test_params['logdir']
- fst_launcher = FstLauncher(logdir)
- ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_goodconf', 'a',
- fst_test_common.fst_test_def_chan_a,
- fst_test_common.fst_test_def_group,
- fst_test_common.fst_test_def_prio_low,
- fst_test_common.fst_test_def_llt)
- ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_badconf', 'b',
- fst_test_common.fst_test_def_chan_g, fst_group,
- fst_pri, fst_llt)
- fst_launcher.add_cfg(ap1)
- fst_launcher.add_cfg(ap2)
- res = fst_launcher.run_hostapd()
- return res
+ with FstLauncher(logdir) as fst_launcher:
+ ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_goodconf', 'a',
+ fst_test_common.fst_test_def_chan_a,
+ fst_test_common.fst_test_def_group,
+ fst_test_common.fst_test_def_prio_low,
+ fst_test_common.fst_test_def_llt)
+ ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_badconf', 'b',
+ fst_test_common.fst_test_def_chan_g, fst_group,
+ fst_pri, fst_llt)
+ fst_launcher.add_cfg(ap1)
+ fst_launcher.add_cfg(ap2)
+ res = fst_launcher.run_hostapd()
+ return res
def run_test_sta_configuration(test_params,
fst_group=fst_test_common.fst_test_def_group,
@@ -326,16 +329,16 @@ def run_test_sta_configuration(test_params,
the run: 0 - no errors discovered, an error otherwise. The function is used
for simple "bad configuration" tests."""
logdir = test_params['logdir']
- fst_launcher = FstLauncher(logdir)
- sta1 = FstLauncherConfigSTA('wlan5',
- fst_test_common.fst_test_def_group,
- fst_test_common.fst_test_def_prio_low,
- fst_test_common.fst_test_def_llt)
- sta2 = FstLauncherConfigSTA('wlan6', fst_group, fst_pri, fst_llt)
- fst_launcher.add_cfg(sta1)
- fst_launcher.add_cfg(sta2)
- res = fst_launcher.run_wpa_supplicant()
- return res
+ with FstLauncher(logdir) as fst_launcher:
+ sta1 = FstLauncherConfigSTA('wlan5',
+ fst_test_common.fst_test_def_group,
+ fst_test_common.fst_test_def_prio_low,
+ fst_test_common.fst_test_def_llt)
+ sta2 = FstLauncherConfigSTA('wlan6', fst_group, fst_pri, fst_llt)
+ fst_launcher.add_cfg(sta1)
+ fst_launcher.add_cfg(sta2)
+ res = fst_launcher.run_wpa_supplicant()
+ return res
def test_fst_ap_config_llt_neg(dev, apdev, test_params):
"""FST AP configuration negative LLT"""
@@ -481,21 +484,21 @@ def test_fst_scan_mb(dev, apdev, test_params):
logdir = test_params['logdir']
# Test valid MB IE in scan results
- fst_launcher = FstLauncher(logdir)
- ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
- fst_test_common.fst_test_def_chan_a,
- fst_test_common.fst_test_def_group,
- fst_test_common.fst_test_def_prio_high)
- ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_11g', 'b',
- fst_test_common.fst_test_def_chan_g,
- fst_test_common.fst_test_def_group,
- fst_test_common.fst_test_def_prio_low)
- fst_launcher.add_cfg(ap1)
- fst_launcher.add_cfg(ap2)
- res = fst_launcher.run_hostapd()
- if res != 0:
- raise Exception("hostapd didn't start properly")
- try:
+ with FstLauncher(logdir) as fst_launcher:
+ ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
+ fst_test_common.fst_test_def_chan_a,
+ fst_test_common.fst_test_def_group,
+ fst_test_common.fst_test_def_prio_high)
+ ap2 = FstLauncherConfigAP(apdev[1]['ifname'], 'fst_11g', 'b',
+ fst_test_common.fst_test_def_chan_g,
+ fst_test_common.fst_test_def_group,
+ fst_test_common.fst_test_def_prio_low)
+ fst_launcher.add_cfg(ap1)
+ fst_launcher.add_cfg(ap2)
+ res = fst_launcher.run_hostapd()
+ if res != 0:
+ raise Exception("hostapd didn't start properly")
+
mbie1 = []
flags1 = ''
mbie2 = []
@@ -514,8 +517,6 @@ def test_fst_scan_mb(dev, apdev, test_params):
mbie2 = parse_ies(vals2['ie'], 0x9e)
if 'flags' in vals2:
flags2 = vals2['flags']
- finally:
- fst_launcher.cleanup()
if len(mbie1) == 0:
raise Exception("No MB IE created by 1st AP")
@@ -527,16 +528,16 @@ def test_fst_scan_nomb(dev, apdev, test_params):
logdir = test_params['logdir']
# Test valid MB IE in scan results
- fst_launcher = FstLauncher(logdir)
- ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
- fst_test_common.fst_test_def_chan_a,
- fst_test_common.fst_test_def_group,
- fst_test_common.fst_test_def_prio_high)
- fst_launcher.add_cfg(ap1)
- res = fst_launcher.run_hostapd()
- if res != 0:
- raise Exception("Hostapd didn't start properly")
- try:
+ with FstLauncher(logdir) as fst_launcher:
+ ap1 = FstLauncherConfigAP(apdev[0]['ifname'], 'fst_11a', 'a',
+ fst_test_common.fst_test_def_chan_a,
+ fst_test_common.fst_test_def_group,
+ fst_test_common.fst_test_def_prio_high)
+ fst_launcher.add_cfg(ap1)
+ res = fst_launcher.run_hostapd()
+ if res != 0:
+ raise Exception("Hostapd didn't start properly")
+
time.sleep(2)
mbie1 = []
flags1 = ''
@@ -546,8 +547,6 @@ def test_fst_scan_nomb(dev, apdev, test_params):
mbie1 = parse_ies(vals1['ie'], 0x9e)
if 'flags' in vals1:
flags1 = vals1['flags']
- finally:
- fst_launcher.cleanup()
if len(mbie1) != 0:
raise Exception("MB IE exists with 1 AP")
diff --git a/tests/hwsim/test_p2p_autogo.py b/tests/hwsim/test_p2p_autogo.py
index 91d68eaf2836..d857c9025b3f 100644
--- a/tests/hwsim/test_p2p_autogo.py
+++ b/tests/hwsim/test_p2p_autogo.py
@@ -378,7 +378,7 @@ def test_autogo_chan_switch_group_iface(dev):
@remote_compatible
def test_autogo_extra_cred(dev):
"""P2P autonomous GO sending two WPS credentials"""
- if "FAIL" in dev[0].request("SET wps_testing_dummy_cred 1"):
+ if "FAIL" in dev[0].request("SET wps_testing_stub_cred 1"):
raise Exception("Failed to enable test mode")
autogo(dev[0], freq=2412)
connect_cli(dev[0], dev[1], social=True, freq=2412)
diff --git a/tests/hwsim/test_rrm.py b/tests/hwsim/test_rrm.py
index 9111a357eaca..db671318381d 100644
--- a/tests/hwsim/test_rrm.py
+++ b/tests/hwsim/test_rrm.py
@@ -241,9 +241,9 @@ def test_rrm_neighbor_rep_req(dev, apdev):
nr2 = "00112233445600000000510107"
nr3 = "dd112233445500000000510107"
- params = {"ssid": "test"}
+ params = {"ssid": "test", "rnr": "1"}
hostapd.add_ap(apdev[0]['ifname'], params)
- params = {"ssid": "test2", "rrm_neighbor_report": "1"}
+ params = {"ssid": "test2", "rrm_neighbor_report": "1", "rnr": "1"}
hapd = hostapd.add_ap(apdev[1]['ifname'], params)
bssid1 = apdev[1]['bssid']
@@ -337,6 +337,11 @@ def test_rrm_neighbor_rep_req(dev, apdev):
raise Exception("Request failed")
check_nr_results(dev[0], ["dd:11:22:33:44:55"], lci=True)
+ if "OK" not in hapd.request("UPDATE_BEACON"):
+ raise Exception("UPDATE_BEACON failed")
+ time.sleep(0.2)
+ dev[1].connect("test2", key_mgmt="NONE", scan_freq="2412")
+
def test_rrm_neighbor_rep_oom(dev, apdev):
"""hostapd neighbor report OOM"""
check_rrm_support(dev[0])
diff --git a/tests/hwsim/test_sae.py b/tests/hwsim/test_sae.py
index 9925d98f3a7c..a8a4ac00c856 100644
--- a/tests/hwsim/test_sae.py
+++ b/tests/hwsim/test_sae.py
@@ -2588,7 +2588,7 @@ def test_sae_okc_pmk_lifetime(dev, apdev):
raise Exception("SAE authentication not used during roam to AP2 after reauth threshold")
def test_sae_pmk_lifetime(dev, apdev):
- """SAE and opportunistic key caching and PMK lifetime"""
+ """SAE and PMK lifetime"""
check_sae_capab(dev[0])
params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
params['wpa_key_mgmt'] = 'SAE'
@@ -2632,19 +2632,8 @@ def test_sae_pmk_lifetime(dev, apdev):
ev = dev[0].wait_event(["PMKSA-CACHE-REMOVED"], 11)
if ev is None:
raise Exception("PMKSA cache entry did not expire")
- if bssid2 not in ev:
- ev = dev[0].wait_event(["PMKSA-CACHE-REMOVED"], 11)
- if ev is None:
- raise Exception("PMKSA cache entry did not expire")
- if bssid2 not in ev:
- raise Exception("PMKSA cache entry for the current AP did not expire")
- ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], 1)
- if ev is None:
- raise Exception("Disconnection not reported after PMKSA cache entry expiration")
-
- dev[0].wait_connected()
- if "sae_group" not in dev[0].get_status():
- raise Exception("SAE authentication not used after PMKSA cache entry expiration")
+ if bssid2 in ev:
+ raise Exception("Unexpected expiration of the current SAE PMKSA cache entry")
def test_sae_and_psk_multiple_passwords(dev, apdev, params):
"""SAE and PSK with multiple passwords/passphrases"""
diff --git a/tests/hwsim/test_scs.py b/tests/hwsim/test_scs.py
new file mode 100644
index 000000000000..df63cbfdff47
--- /dev/null
+++ b/tests/hwsim/test_scs.py
@@ -0,0 +1,196 @@
+# Test cases for SCS
+# Copyright (c) 2021, Jouni Malinen <j@w1.fi>
+# Copyright (c) 2021, The Linux Foundation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import struct
+import time
+
+import hostapd
+from utils import *
+
+def register_scs_req(hapd):
+ type = 0x00d0
+ match = "1300"
+ if "OK" not in hapd.request("REGISTER_FRAME %04x %s" % (type, match)):
+ raise Exception("Could not register frame reception for Robust AV Streaming")
+
+def handle_scs_req(hapd, wrong_dialog=False, status_code=0, twice=False,
+ short=False, scsid=1):
+ msg = hapd.mgmt_rx()
+ if msg['subtype'] != 13:
+ logger.info("RX:" + str(msg))
+ raise Exception("Received unexpected Management frame")
+ categ, act, dialog_token = struct.unpack('BBB', msg['payload'][0:3])
+ if categ != 19 or act != 0:
+ logger.info("RX:" + str(msg))
+ raise Exception("Received unexpected Action frame")
+
+ if wrong_dialog:
+ dialog_token = (dialog_token + 1) % 256
+ msg['da'] = msg['sa']
+ msg['sa'] = hapd.own_addr()
+ count = 1
+ if short:
+ resp = struct.pack('BBB', 19, 1, dialog_token)
+ else:
+ resp = struct.pack('BBBB', 19, 1, dialog_token, count)
+ resp += struct.pack('<BH', scsid, status_code)
+ msg['payload'] = resp
+ hapd.mgmt_tx(msg)
+ ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
+ if ev is None or "stype=13 ok=1" not in ev:
+ raise Exception("No TX status reported")
+ if twice:
+ hapd.mgmt_tx(msg)
+ ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
+ if ev is None or "stype=13 ok=1" not in ev:
+ raise Exception("No TX status reported")
+
+def wait_scs_result(dev, expect_status="0"):
+ ev = dev.wait_event(["CTRL-EVENT-SCS-RESULT"], timeout=2)
+ if ev is None:
+ raise Exception("No SCS result reported")
+ if "status_code=%s" % expect_status not in ev:
+ raise Exception("Unexpected SCS result: " + ev)
+
+def test_scs_invalid_params(dev, apdev):
+ """SCS command invalid parameters"""
+ tests = ["",
+ "scs_id=1",
+ "scs_id=1 foo",
+ "scs_id=1 add ",
+ "scs_id=1 add scs_up=8",
+ "scs_id=1 add scs_up=7",
+ "scs_id=1 add scs_up=7 classifier_type=1",
+ "scs_id=1 add scs_up=7 classifier_type=4",
+ "scs_id=1 add scs_up=7 classifier_type=4 ip_version=ipv4",
+ "scs_id=1 add scs_up=7 classifier_type=4 ip_version=ipv4 src_ip=q",
+ "scs_id=1 add scs_up=7 classifier_type=4 ip_version=ipv4 dst_ip=q",
+ "scs_id=1 add scs_up=7 classifier_type=4 ip_version=ipv4 src_port=q",
+ "scs_id=1 add scs_up=7 classifier_type=4 ip_version=ipv4 dst_port=q",
+ "scs_id=1 add scs_up=7 classifier_type=4 ip_version=ipv4 protocol=foo",
+ "scs_id=1 add scs_up=7 classifier_type=4 ip_version=ipv6 protocol=foo",
+ "scs_id=1 add scs_up=7 classifier_type=4 ip_version=ipv6 next_header=foo",
+ "scs_id=1 add scs_up=7 classifier_type=4 ip_version=ipv6 flow_label=ffffff",
+ "scs_id=1 add scs_up=7 classifier_type=10",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11223344",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=qq",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11223344 filter_mask=ffffff",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11223344 filter_mask=qqqqqqqq",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11223344 filter_mask=ffffffff",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=foo filter_value=11223344 filter_mask=ffffffff",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11 filter_mask=ee classifier_type=10 prot_instance=2 prot_number=udp filter_value=22 filter_mask=ff",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11 filter_mask=ee classifier_type=10 prot_instance=2 prot_number=udp filter_value=22 filter_mask=ff tclas_processing=2",
+ "scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11 filter_mask=ee classifier_type=10 prot_instance=2 prot_number=udp filter_value=22 filter_mask=ff tclas_processing=0",
+ "scs_id=1 add scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=udp scs_id=1 add scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=tcp"
+ "scs_id=1 remove",
+ "scs_id=1 change "]
+ for t in tests:
+ if "FAIL" not in dev[0].request("SCS " + t):
+ raise Exception("Invalid SCS parameters accepted: " + t)
+
+def test_scs_request(dev, apdev):
+ """SCS Request"""
+ params = {"ssid": "scs",
+ "ext_capa": 6*"00" + "40"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ register_scs_req(hapd)
+
+ dev[0].connect("scs", key_mgmt="NONE", scan_freq="2412")
+
+ hapd.dump_monitor()
+ hapd.set("ext_mgmt_frame_handling", "1")
+
+ cmd = "SCS scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11223344 filter_mask=ffffffff"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("SCS add failed")
+
+ handle_scs_req(hapd)
+ wait_scs_result(dev[0])
+
+ cmd = "SCS scs_id=2 add scs_up=5 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11223344 filter_mask=ffffffff"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("SCS add failed")
+
+ handle_scs_req(hapd, wrong_dialog=True)
+ ev = dev[0].wait_event(["CTRL-EVENT-SCS-RESULT"], timeout=2)
+ if ev is None:
+ raise Exception("No SCS result reported")
+ if "status_code=timedout" not in ev:
+ raise Exception("Timeout not reported: " + ev)
+
+ cmd = "SCS scs_id=1 add scs_up=5 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11223344 filter_mask=ffffffff"
+ if "FAIL" not in dev[0].request(cmd):
+ raise Exception("SCS add for already configured scs_id did not fail")
+
+ cmd = "SCS scs_id=1 remove"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("SCS remove failed")
+ handle_scs_req(hapd)
+ wait_scs_result(dev[0])
+
+ tests = ["scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=udp",
+ "scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=tcp",
+ "scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=esp",
+ "scs_up=6 classifier_type=4 ip_version=ipv6 src_ip=::1 dst_ip=::1 src_port=12345 dst_port=23456 dscp=5 next_header=udp",
+ "scs_up=6 classifier_type=4 ip_version=ipv6 src_ip=::1 dst_ip=::1 src_port=12345 dst_port=23456 dscp=5 next_header=tcp",
+ "scs_up=6 classifier_type=4 ip_version=ipv6 src_ip=::1 dst_ip=::1 src_port=12345 dst_port=23456 dscp=5 next_header=esp flow_label=012345",
+ "scs_up=6 classifier_type=10 prot_instance=1 prot_number=tcp filter_value=11223344 filter_mask=ffffffff",
+ "scs_up=6 classifier_type=10 prot_instance=1 prot_number=esp filter_value=11223344 filter_mask=ffffffff",
+ "scs_up=6 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11223344 filter_mask=ffffffff",
+ "scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=udp classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=tcp tclas_processing=1",
+ "scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=udp scs_id=10 add scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=tcp"]
+ for t in tests:
+ cmd = "SCS scs_id=1 change " + t
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("SCS change failed: " + t)
+ handle_scs_req(hapd)
+ wait_scs_result(dev[0])
+ if "scs_id=" in t:
+ wait_scs_result(dev[0], expect_status="response_not_received")
+
+ cmd = "SCS scs_id=1 change scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=udp"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("SCS change failed: " + t)
+ if "FAIL" not in dev[0].request(cmd):
+ raise Exception("SCS change failed: " + t)
+ handle_scs_req(hapd, twice=True)
+ wait_scs_result(dev[0])
+ ev = dev[0].wait_event(["CTRL-EVENT-SCS-RESULT"], timeout=0.1)
+ if ev is not None:
+ raise Exception("Unexpected SCS result reported(1)")
+
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("SCS change failed: " + t)
+ handle_scs_req(hapd, short=True)
+ ev = dev[0].wait_event(["CTRL-EVENT-SCS-RESULT"], timeout=3)
+ if ev is not None:
+ raise Exception("Unexpected SCS result reported(2)")
+
+ cmd = "SCS scs_id=123 add scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=udp"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("SCS add failed: " + t)
+ handle_scs_req(hapd, scsid=34)
+ wait_scs_result(dev[0], expect_status="response_not_received")
+
+ cmd = "SCS scs_id=33 add scs_up=6 classifier_type=4 ip_version=ipv4 src_ip=1.2.3.4 dst_ip=5.6.7.8 src_port=12345 dst_port=23456 dscp=5 protocol=udp"
+ if "OK" not in dev[0].request(cmd):
+ raise Exception("SCS add failed: " + t)
+ handle_scs_req(hapd, scsid=33, status_code=123)
+ wait_scs_result(dev[0], expect_status="123")
+
+def test_scs_request_without_ap_capa(dev, apdev):
+ """SCS Request without AP capability"""
+ params = {"ssid": "scs"}
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[0].connect("scs", key_mgmt="NONE", scan_freq="2412")
+
+ cmd = "SCS scs_id=1 add scs_up=7 classifier_type=10 prot_instance=1 prot_number=udp filter_value=11223344 filter_mask=ffffffff"
+ if "FAIL" not in dev[0].request(cmd):
+ raise Exception("SCS add accepted")
diff --git a/tests/hwsim/test_wmediumd.py b/tests/hwsim/test_wmediumd.py
index ad38f03ced82..8243e7ce37d7 100644
--- a/tests/hwsim/test_wmediumd.py
+++ b/tests/hwsim/test_wmediumd.py
@@ -1,4 +1,4 @@
-# wmediumd sanity checks
+# wmediumd validity checks
# Copyright (c) 2015, Intel Deutschland GmbH
#
# This software may be distributed under the terms of the BSD license.
diff --git a/tests/hwsim/test_wnm.py b/tests/hwsim/test_wnm.py
index 354822327210..88cb0820b634 100644
--- a/tests/hwsim/test_wnm.py
+++ b/tests/hwsim/test_wnm.py
@@ -797,7 +797,7 @@ def test_wnm_bss_tm(dev, apdev):
dev[0].dump_monitor()
logger.info("Neighbor list entry, but not claimed as Preferred Candidate List")
- if "OK" not in hapd.request("BSS_TM_REQ " + addr + " neighbor=11:22:33:44:55:66,0x0000,81,3,7"):
+ if "OK" not in hapd.request("BSS_TM_REQ " + addr + " dialog_token=123 neighbor=11:22:33:44:55:66,0x0000,81,3,7"):
raise Exception("BSS_TM_REQ command failed")
ev = hapd.wait_event(['BSS-TM-RESP'], timeout=10)
if ev is None:
diff --git a/tests/hwsim/test_wpas_ap.py b/tests/hwsim/test_wpas_ap.py
index b5b43114a12b..fb70cd3bb49f 100644
--- a/tests/hwsim/test_wpas_ap.py
+++ b/tests/hwsim/test_wpas_ap.py
@@ -903,3 +903,25 @@ def test_wpas_ap_sae_and_psk_transition_disable(dev):
dev[1].wait_disconnected()
dev[1].request("RECONNECT")
dev[1].wait_connected()
+
+def test_wpas_ap_vendor_elems(dev):
+ """wpa_supplicant AP mode - vendor elements"""
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "2")
+ dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
+ dev[0].set_network(id, "key_mgmt", "NONE")
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].set_network(id, "scan_freq", "2412")
+ dev[0].select_network(id)
+ wait_ap_ready(dev[0])
+
+ beacon_elems = "dd0411223301"
+ dev[0].set("ap_vendor_elements", beacon_elems)
+ dev[0].set("ap_assocresp_elements", "dd0411223302")
+ if "OK" not in dev[0].request("UPDATE_BEACON"):
+ raise Exception("UPDATE_BEACON failed")
+
+ dev[1].connect("wpas-ap-open", key_mgmt="NONE", scan_freq="2412")
+ bss = dev[1].get_bss(dev[0].own_addr())
+ if beacon_elems not in bss['ie']:
+ raise Exception("Vendor element not visible in scan results")
diff --git a/tests/hwsim/test_wpas_config.py b/tests/hwsim/test_wpas_config.py
index d105fed0dc36..3cd7dfcf3bcf 100644
--- a/tests/hwsim/test_wpas_config.py
+++ b/tests/hwsim/test_wpas_config.py
@@ -191,6 +191,11 @@ def test_wpas_config_file(dev, apdev, params):
f.write(" ")
f.write("foo\n")
f.write("device_name=name#foo\n")
+ f.write("network={\n")
+ f.write("\tkey_mgmt=NONE\n")
+ f.write('\tssid="hello"\n')
+ f.write('\tgroup=GCMP # "foo"\n')
+ f.write("}\n")
wpas.interface_add("wlan5", config=config)
capa = {}
@@ -242,9 +247,11 @@ def test_wpas_config_file(dev, apdev, params):
wpas.interface_remove("wlan5")
data1 = check_config(capa, config)
+ if "group=GCMP" not in data1:
+ raise Exception("Network block group parameter with a comment not present")
wpas.interface_add("wlan5", config=config)
- if len(wpas.list_networks()) != 1:
+ if len(wpas.list_networks()) != 2:
raise Exception("Unexpected number of networks")
if len(wpas.request("LIST_CREDS").splitlines()) != 2:
raise Exception("Unexpected number of credentials")
diff --git a/tests/hwsim/test_wpas_mesh.py b/tests/hwsim/test_wpas_mesh.py
index 75bc02146eb8..0caed771edad 100644
--- a/tests/hwsim/test_wpas_mesh.py
+++ b/tests/hwsim/test_wpas_mesh.py
@@ -270,6 +270,9 @@ def test_wpas_mesh_open(dev, apdev):
if mode != "mesh":
raise Exception("Unexpected mode: " + mode)
+ peer = dev[1].own_addr()
+ sta1 = dev[0].get_sta(peer)
+
dev[0].scan(freq="2462")
bss = dev[0].get_bss(dev[1].own_addr())
if bss and 'ie' in bss and "ff0724" in bss['ie']:
@@ -280,6 +283,15 @@ def test_wpas_mesh_open(dev, apdev):
if "[VHT]" in sta:
raise Exception("Unexpected STA VHT flag")
+ time.sleep(1.1)
+ sta2 = dev[0].get_sta(peer)
+ if 'connected_time' not in sta1 or 'connected_time' not in sta2:
+ raise Exception("connected_time not reported for peer")
+ ct1 = int(sta1['connected_time'])
+ ct2 = int(sta2['connected_time'])
+ if ct2 <= ct1:
+ raise Exception("connected_time did not increment")
+
def test_wpas_mesh_open_no_auto(dev, apdev):
"""wpa_supplicant open MESH network connectivity"""
check_mesh_support(dev[0])
diff --git a/tests/hwsim/vm/inside.sh b/tests/hwsim/vm/inside.sh
index 9d4a933fe729..bfcbda631e4f 100755
--- a/tests/hwsim/vm/inside.sh
+++ b/tests/hwsim/vm/inside.sh
@@ -38,6 +38,8 @@ TELNET=$(sed 's/.*TELNET=\([^ ]*\) .*/\1/' /proc/cmdline)
ARGS=$(sed 's/.*ARGS=\([^ ]*\)\( \|$\).*/\1/' /proc/cmdline)
LOGDIR=$(sed 's/.*LOGDIR=\([^ ]*\)\( \|$\).*/\1/' /proc/cmdline)
+mount --bind "$TESTDIR/vm/regdb/" /lib/firmware
+
# create /dev entries we need
mknod -m 660 /dev/ttyS0 c 4 64
mknod -m 666 /dev/ptmx c 5 2
@@ -53,7 +55,7 @@ ln -s /proc/self/fd/2 /dev/stderr
echo "VM has started up" > /dev/ttyS0
-# create dummy sudo - everything runs as uid 0
+# create stub sudo - everything runs as uid 0
mkdir /tmp/bin
cat > /tmp/bin/sudo << EOF
#!/bin/bash
diff --git a/tests/hwsim/vm/regdb/regulatory.db b/tests/hwsim/vm/regdb/regulatory.db
new file mode 100644
index 000000000000..e0db5f8be0f4
--- /dev/null
+++ b/tests/hwsim/vm/regdb/regulatory.db
Binary files differ
diff --git a/tests/hwsim/vm/regdb/regulatory.db.p7s b/tests/hwsim/vm/regdb/regulatory.db.p7s
new file mode 100644
index 000000000000..730aef4f364c
--- /dev/null
+++ b/tests/hwsim/vm/regdb/regulatory.db.p7s
Binary files differ
diff --git a/wlantest/bss.c b/wlantest/bss.c
index 1834aecba199..4fc0b17a7bdd 100644
--- a/wlantest/bss.c
+++ b/wlantest/bss.c
@@ -102,6 +102,7 @@ int bss_add_pmk_from_passphrase(struct wlantest_bss *bss,
" based on passphrase '%s'",
MAC2STR(bss->bssid), passphrase);
wpa_hexdump(MSG_DEBUG, "Possible PMK", pmk->pmk, PMK_LEN);
+ pmk->pmk_len = PMK_LEN;
dl_list_add(&bss->pmk, &pmk->list);
return 0;
diff --git a/wlantest/inject.c b/wlantest/inject.c
index 399f1a3c0707..b177bcfd9301 100644
--- a/wlantest/inject.c
+++ b/wlantest/inject.c
@@ -83,17 +83,17 @@ static int wlantest_inject_bip(struct wlantest *wt, struct wlantest_bss *bss,
u8 *frame, size_t len, int incorrect_key)
{
u8 *prot;
- u8 dummy[32];
+ u8 stub[32];
int ret;
size_t plen;
if (!bss->igtk_len[bss->igtk_idx])
return -1;
- os_memset(dummy, 0x11, sizeof(dummy));
+ os_memset(stub, 0x11, sizeof(stub));
inc_byte_array(bss->ipn[bss->igtk_idx], 6);
- prot = bip_protect(incorrect_key ? dummy : bss->igtk[bss->igtk_idx],
+ prot = bip_protect(incorrect_key ? stub : bss->igtk[bss->igtk_idx],
bss->igtk_len[bss->igtk_idx],
frame, len, bss->ipn[bss->igtk_idx],
bss->igtk_idx, &plen);
@@ -115,7 +115,7 @@ static int wlantest_inject_prot_bc(struct wlantest *wt,
u8 *crypt;
size_t crypt_len;
int ret;
- u8 dummy[64];
+ u8 stub[64];
u8 *pn;
struct ieee80211_hdr *hdr;
u16 fc;
@@ -134,14 +134,14 @@ static int wlantest_inject_prot_bc(struct wlantest *wt,
pn = bss->rsc[bss->gtk_idx];
inc_byte_array(pn, 6);
- os_memset(dummy, 0x11, sizeof(dummy));
+ os_memset(stub, 0x11, sizeof(stub));
if (bss->group_cipher == WPA_CIPHER_TKIP)
- crypt = tkip_encrypt(incorrect_key ? dummy :
+ crypt = tkip_encrypt(incorrect_key ? stub :
bss->gtk[bss->gtk_idx],
frame, len, hdrlen, NULL, pn,
bss->gtk_idx, &crypt_len);
else
- crypt = ccmp_encrypt(incorrect_key ? dummy :
+ crypt = ccmp_encrypt(incorrect_key ? stub :
bss->gtk[bss->gtk_idx],
frame, len, hdrlen, NULL, pn,
bss->gtk_idx, &crypt_len);
@@ -163,7 +163,7 @@ static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss,
u8 *crypt;
size_t crypt_len;
int ret;
- u8 dummy[64];
+ u8 stub[64];
u8 *pn;
struct ieee80211_hdr *hdr;
u16 fc;
@@ -243,17 +243,17 @@ static int wlantest_inject_prot(struct wlantest *wt, struct wlantest_bss *bss,
pn = sta->rsc_tods[tid];
inc_byte_array(pn, 6);
- os_memset(dummy, 0x11, sizeof(dummy));
+ os_memset(stub, 0x11, sizeof(stub));
if (tk)
- crypt = ccmp_encrypt(incorrect_key ? dummy : tk,
+ crypt = ccmp_encrypt(incorrect_key ? stub : tk,
frame, len, hdrlen, qos, pn, 0,
&crypt_len);
else if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
- crypt = tkip_encrypt(incorrect_key ? dummy : sta->ptk.tk,
+ crypt = tkip_encrypt(incorrect_key ? stub : sta->ptk.tk,
frame, len, hdrlen, qos, pn, 0,
&crypt_len);
else
- crypt = ccmp_encrypt(incorrect_key ? dummy : sta->ptk.tk,
+ crypt = ccmp_encrypt(incorrect_key ? stub : sta->ptk.tk,
frame, len, hdrlen, qos, pn, 0,
&crypt_len);
diff --git a/wlantest/rx_eapol.c b/wlantest/rx_eapol.c
index d5e10debf3e0..967d52199561 100644
--- a/wlantest/rx_eapol.c
+++ b/wlantest/rx_eapol.c
@@ -124,7 +124,7 @@ static int try_pmk(struct wlantest *wt, struct wlantest_bss *bss,
check_mic(ptk.kck, ptk.kck_len, sta->key_mgmt, ver, data,
len) < 0)
return -1;
- } else if (wpa_pmk_to_ptk(pmk->pmk, PMK_LEN,
+ } else if (wpa_pmk_to_ptk(pmk->pmk, pmk->pmk_len,
"Pairwise key expansion",
bss->bssid, sta->addr, sta->anonce,
sta->snonce, &ptk, sta->key_mgmt,
@@ -703,7 +703,7 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
decrypted, decrypted_len);
}
if ((wt->write_pcap_dumper || wt->pcapng) && decrypted != key_data) {
- /* Fill in a dummy Data frame header */
+ /* Fill in a stub Data frame header */
u8 buf[24 + 8 + sizeof(*eapol) + sizeof(*hdr) + 64];
struct ieee80211_hdr *h;
struct wpa_eapol_key *k;
@@ -926,7 +926,7 @@ static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst,
wpa_hexdump(MSG_DEBUG, "Decrypted EAPOL-Key Key Data",
decrypted, decrypted_len);
if (wt->write_pcap_dumper || wt->pcapng) {
- /* Fill in a dummy Data frame header */
+ /* Fill in a stub Data frame header */
u8 buf[24 + 8 + sizeof(*eapol) + sizeof(*hdr) + 64];
struct ieee80211_hdr *h;
struct wpa_eapol_key *k;
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index f539ce1348ec..0aacafd4ab96 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -366,12 +366,11 @@ CONFIG_AP=y
ifdef CONFIG_P2P_STRICT
L_CFLAGS += -DCONFIG_P2P_STRICT
endif
-endif
-
ifdef CONFIG_WIFI_DISPLAY
L_CFLAGS += -DCONFIG_WIFI_DISPLAY
OBJS += wifi_display.c
endif
+endif
ifdef CONFIG_PASN
L_CFLAGS += -DCONFIG_PASN
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index a06a93b22175..5ca82457ad1b 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1864,7 +1864,8 @@ ChangeLog for wpa_supplicant
generate, e.g., man pages
* l2_packet_linux: use socket type SOCK_DGRAM instead of SOCK_RAW for
PF_PACKET in order to prepare for network devices that do not use
- Ethernet headers (e.g., network stack with native IEEE 802.11 frames)
+ Ethernet headers (e.g., network stack that includes IEEE 802.11
+ header in the frames)
* use receipt of EAPOL-Key frame as a lower layer success indication
for EAP state machine to allow recovery from dropped EAP-Success
frame
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 271f2aab3118..ce1c8b2e3366 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -30,9 +30,9 @@ LIBS_p := $(LIBS)
endif
endif
-export LIBDIR ?= /usr/local/lib/
-export INCDIR ?= /usr/local/include/
-export BINDIR ?= /usr/local/sbin/
+export LIBDIR ?= /usr/local/lib
+export INCDIR ?= /usr/local/include
+export BINDIR ?= /usr/local/sbin
PKG_CONFIG ?= pkg-config
CFLAGS += $(EXTRA_CFLAGS)
@@ -389,12 +389,11 @@ CONFIG_AP=y
ifdef CONFIG_P2P_STRICT
CFLAGS += -DCONFIG_P2P_STRICT
endif
-endif
-
ifdef CONFIG_WIFI_DISPLAY
CFLAGS += -DCONFIG_WIFI_DISPLAY
OBJS += wifi_display.o
endif
+endif
ifdef CONFIG_PASN
CFLAGS += -DCONFIG_PASN
@@ -1011,7 +1010,6 @@ ifdef CONFIG_PCSC
# PC/SC interface for smartcards (USIM, GSM SIM)
CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
OBJS += ../src/utils/pcsc_funcs.o
-# -lpthread may not be needed depending on how pcsc-lite was configured
ifdef CONFIG_NATIVE_WINDOWS
#Once MinGW gets support for WinScard, -lwinscard could be used instead of the
#dynamic symbol loading that is now used in pcsc_funcs.c
@@ -1020,7 +1018,7 @@ else
ifdef CONFIG_OSX
LIBS += -framework PCSC
else
-LIBS += -lpcsclite -lpthread
+LIBS += $(shell $(PKG_CONFIG) --libs libpcsclite)
endif
endif
endif
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 391912e9b6c5..05f15ff46bda 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -1077,3 +1077,87 @@ ext:test4@wlan0:0:0:9.679895
OK
<3>EXT-RADIO-WORK-START 7
<3>EXT-RADIO-WORK-TIMEOUT 7
+
+
+DSCP policy procedures
+----------------------
+
+DSCP policy procedures defined in WFA QoS Management-R2 program
+facilitates AP devices to configure DSCP settings for specific uplink
+data streams.
+
+An AP may transmit a DSCP Policy Request frame containing zero or more
+QoS Management IEs to an associated STA which supports DSCP policy
+procedures. Each QoS Management element in a DSCP Policy Request frame
+represents one DSCP policy, and shall include one DSCP Policy attribute
+including a DSCP Policy ID, Request type, and a DSCP value.
+
+wpa_supplicant sends control interface event messages consisting details
+of DSCP policies requested by the AP through a DSCP Policy Request frame
+to external programs. The format of the control interface event messages
+is as shown below:
+
+- Control interface event message format to indicate DSCP request start
+
+ <3>CTRL-EVENT-DSCP-POLICY request_start [clear_all] [more]
+
+ clear_all - AP requested to clear all DSCP policies configured earlier
+ more - AP may request to configure more DSCP policies with new DSCP
+ request
+
+- Control interface event message format to add new policy
+
+ <3>CTRL-EVENT-DSCP-POLICY add <policy_id> <dscp_value> <ip_version=0|4|6>
+ [protocol] [source ip] [destination_ip]/[domain name] [source port]
+ [[<start_port> <end_port>]/destination port]
+
+ ip_version = 0: Both IPv4 and IPv6
+ = 4: IPv4
+ = 6: IPv6
+ protocol: Internet Protocol Numbers as per IETF RFCs
+ = 6: TCP
+ = 17: UDP
+ = 50: ESP
+
+- Control interface event message format to remove a particular policy,
+ identified by the policy_id attribute.
+
+ <3>CTRL-EVENT-DSCP-POLICY remove <policy_id>
+
+- DSCP policy may get rejected due to invalid policy parameters. Ccontrol
+ interface event message format for rejected policy.
+
+ <3>CTRL-EVENT-DSCP-POLICY reject <policy_id>
+
+- Control interface event message format to indicate end of DSCP request.
+
+ <3>CTRL-EVENT-DSCP-POLICY request_end
+
+- External applications shall clear active DSCP policies upon receiving
+ "CTRL-EVENT-DISCONNECTED" or "CTRL-EVENT-DSCP-POLICY clear_all" events.
+
+- Control interface event message format to indicate wpa_supplicant started
+ a timer to wait until the unsolicited DSCP request from the AP.
+
+ <3>CTRL-EVENT-DSCP-POLICY request_wait start
+
+- Control interface event message format to indicate timeout to receive the
+ unsolicited DSCP request. This event is expected only when an unsolicited
+ DSCP request is not received from the AP before timeout.
+
+ <3>CTRL-EVENT-DSCP-POLICY request_wait end
+
+DSCP Response:
+A QoS Management STA that enables DSCP Policy capability shall respond
+with DSCP response on receipt of a successful DSCP request from its
+associated AP. wpa_supplicant sends DSCP policy response based on the
+control interface command received from the user is as below:
+
+DSCP_RESP <[reset]>/<[solicited] [policy_id=1 status=0...]> [more]
+
+DSCP Query:
+DSCP Policy Query enables a STA to query its associated AP for DSCP
+policies applicable to the STA. Currently, this includes support to send
+a wildcard DSCP query or a DSCP query with a single domain name
+attribute. The command format for the DSCP query command is as follows:
+DSCP_QUERY <wildcard>/<domain_name=<string>>
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index cdf0ed5c7b5f..6a0a69e68ee6 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -84,6 +84,11 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
/* Use the maximum oper channel width if it's given. */
if (ssid->max_oper_chwidth)
hostapd_set_oper_chwidth(conf, ssid->max_oper_chwidth);
+ if (hostapd_get_oper_chwidth(conf))
+ ieee80211_freq_to_channel_ext(ssid->frequency, 0,
+ hostapd_get_oper_chwidth(conf),
+ &conf->op_class,
+ &conf->channel);
if (hostapd_get_oper_chwidth(conf) == CHANWIDTH_80P80MHZ) {
ieee80211_freq_to_chan(ssid->vht_center_freq2,
@@ -191,19 +196,79 @@ wpa_supplicant_find_hw_mode(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_P2P
+
+static int get_max_oper_chwidth_6ghz(int chwidth)
+{
+ switch (chwidth) {
+ case CHANWIDTH_USE_HT:
+ return 20;
+ case CHANWIDTH_40MHZ_6GHZ:
+ return 40;
+ case CHANWIDTH_80MHZ:
+ return 80;
+ case CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_160MHZ:
+ return 160;
+ default:
+ return 0;
+ }
+}
+
+
+static void wpas_conf_ap_he_6ghz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ struct wpa_ssid *ssid,
+ struct hostapd_config *conf)
+{
+ bool is_chanwidth_40_80, is_chanwidth_160;
+ int he_chanwidth;
+
+ he_chanwidth =
+ mode->he_capab[wpas_mode_to_ieee80211_mode(
+ ssid->mode)].phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX];
+ is_chanwidth_40_80 = he_chanwidth &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
+ is_chanwidth_160 = he_chanwidth &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+
+ wpa_printf(MSG_DEBUG,
+ "Enable HE support (p2p_group=%d he_chwidth_cap=%d)",
+ ssid->p2p_group, he_chanwidth);
+
+ if (mode->he_capab[wpas_mode_to_ieee80211_mode(
+ ssid->mode)].he_supported &&
+ ssid->he)
+ conf->ieee80211ax = 1;
+
+ if (is_chanwidth_40_80 && ssid->p2p_group &&
+ get_max_oper_chwidth_6ghz(ssid->max_oper_chwidth) >= 40) {
+ conf->secondary_channel =
+ wpas_p2p_get_sec_channel_offset_40mhz(
+ wpa_s, mode, conf->channel);
+ wpa_printf(MSG_DEBUG,
+ "Secondary channel offset %d for P2P group",
+ conf->secondary_channel);
+ if (ssid->max_oper_chwidth == CHANWIDTH_40MHZ_6GHZ)
+ ssid->max_oper_chwidth = CHANWIDTH_USE_HT;
+ }
+
+ if ((is_chanwidth_40_80 || is_chanwidth_160) && ssid->p2p_group &&
+ get_max_oper_chwidth_6ghz(ssid->max_oper_chwidth) >= 80)
+ wpas_conf_ap_vht(wpa_s, ssid, conf, mode);
+}
+
+#endif /* CONFIG_P2P */
+
+
int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_config *conf)
{
conf->hw_mode = ieee80211_freq_to_channel_ext(ssid->frequency, 0,
- ssid->max_oper_chwidth,
+ CHANWIDTH_USE_HT,
&conf->op_class,
&conf->channel);
- /* ssid->max_oper_chwidth is not valid in all cases, so fall back to the
- * less specific mechanism, if needed, at least for now */
- if (conf->hw_mode == NUM_HOSTAPD_MODES)
- conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
- &conf->channel);
if (conf->hw_mode == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
ssid->frequency);
@@ -224,7 +289,8 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
"Determining HT/VHT options based on driver capabilities (freq=%u chan=%u)",
ssid->frequency, conf->channel);
- mode = wpa_supplicant_find_hw_mode(wpa_s, conf->hw_mode);
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+ conf->hw_mode, is_6ghz_freq(ssid->frequency));
/* May drop to IEEE 802.11b if the driver does not support IEEE
* 802.11g */
@@ -255,7 +321,12 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
no_ht = 1;
}
- if (!no_ht && mode && mode->ht_capab) {
+ if (mode && is_6ghz_freq(ssid->frequency) &&
+ conf->hw_mode == HOSTAPD_MODE_IEEE80211A) {
+#ifdef CONFIG_P2P
+ wpas_conf_ap_he_6ghz(wpa_s, mode, ssid, conf);
+#endif /* CONFIG_P2P */
+ } else if (!no_ht && mode && mode->ht_capab) {
wpa_printf(MSG_DEBUG,
"Enable HT support (p2p_group=%d 11a=%d ht40_hw_capab=%d ssid->ht40=%d)",
ssid->p2p_group,
@@ -279,8 +350,8 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
ssid->ht40) {
conf->secondary_channel =
- wpas_p2p_get_ht40_mode(wpa_s, mode,
- conf->channel);
+ wpas_p2p_get_sec_channel_offset_40mhz(
+ wpa_s, mode, conf->channel);
wpa_printf(MSG_DEBUG,
"HT secondary channel offset %d for P2P group",
conf->secondary_channel);
@@ -530,7 +601,10 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
bss->sae_passwords = pw;
}
- bss->sae_pwe = wpa_s->conf->sae_pwe;
+ if (ssid->sae_pwe != DEFAULT_SAE_PWE)
+ bss->sae_pwe = ssid->sae_pwe;
+ else
+ bss->sae_pwe = wpa_s->conf->sae_pwe;
#endif /* CONFIG_SAE */
if (wpa_s->conf->go_interworking) {
@@ -698,6 +772,10 @@ no_wps:
bss->vendor_elements =
wpabuf_dup(wpa_s->conf->ap_vendor_elements);
}
+ if (wpa_s->conf->ap_assocresp_elements) {
+ bss->assocresp_elements =
+ wpabuf_dup(wpa_s->conf->ap_assocresp_elements);
+ }
bss->ftm_responder = wpa_s->conf->ftm_responder;
bss->ftm_initiator = wpa_s->conf->ftm_initiator;
@@ -1748,6 +1826,32 @@ int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd)
#endif /* CONFIG_MESH */
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+int wpas_ap_update_beacon(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (!wpa_s->ap_iface)
+ return -1;
+ hapd = wpa_s->ap_iface->bss[0];
+
+ wpabuf_free(hapd->conf->assocresp_elements);
+ hapd->conf->assocresp_elements = NULL;
+ if (wpa_s->conf->ap_assocresp_elements) {
+ hapd->conf->assocresp_elements =
+ wpabuf_dup(wpa_s->conf->ap_assocresp_elements);
+ }
+
+ wpabuf_free(hapd->conf->vendor_elements);
+ hapd->conf->vendor_elements = NULL;
+ if (wpa_s->conf->ap_vendor_elements) {
+ hapd->conf->vendor_elements =
+ wpabuf_dup(wpa_s->conf->ap_vendor_elements);
+ }
+
+ return ieee802_11_set_beacon(hapd);
+}
+
#endif /* CONFIG_CTRL_IFACE */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 6c6e94cdf6a2..7bc1b781e3ac 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -88,6 +88,7 @@ void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
int wpas_ap_pmksa_cache_list_mesh(struct wpa_supplicant *wpa_s, const u8 *addr,
char *buf, size_t len);
int wpas_ap_pmksa_cache_add_external(struct wpa_supplicant *wpa_s, char *cmd);
+int wpas_ap_update_beacon(struct wpa_supplicant *wpa_s);
void wpas_ap_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
struct dfs_event *radar);
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index e8e9fd432618..c5177d915524 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2951,6 +2951,7 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->ext_password_backend);
os_free(config->sae_groups);
wpabuf_free(config->ap_vendor_elements);
+ wpabuf_free(config->ap_assocresp_elements);
os_free(config->osu_dir);
os_free(config->bgscan);
os_free(config->wowlan_triggers);
@@ -3139,6 +3140,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
#endif /* CONFIG_VHT_OVERRIDES */
ssid->proactive_key_caching = -1;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+ ssid->sae_pwe = DEFAULT_SAE_PWE;
#ifdef CONFIG_MACSEC
ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
#endif /* CONFIG_MACSEC */
@@ -4909,33 +4911,46 @@ static int wpa_config_process_ap_vendor_elements(
struct wpa_config *config, int line, const char *pos)
{
struct wpabuf *tmp;
- int len = os_strlen(pos) / 2;
- u8 *p;
- if (!len) {
+ if (!*pos) {
+ wpabuf_free(config->ap_vendor_elements);
+ config->ap_vendor_elements = NULL;
+ return 0;
+ }
+
+ tmp = wpabuf_parse_bin(pos);
+ if (!tmp) {
wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements",
line);
return -1;
}
+ wpabuf_free(config->ap_vendor_elements);
+ config->ap_vendor_elements = tmp;
- tmp = wpabuf_alloc(len);
- if (tmp) {
- p = wpabuf_put(tmp, len);
+ return 0;
+}
- if (hexstr2bin(pos, p, len)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "ap_vendor_elements", line);
- wpabuf_free(tmp);
- return -1;
- }
- wpabuf_free(config->ap_vendor_elements);
- config->ap_vendor_elements = tmp;
- } else {
- wpa_printf(MSG_ERROR, "Cannot allocate memory for "
- "ap_vendor_elements");
+static int wpa_config_process_ap_assocresp_elements(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ struct wpabuf *tmp;
+
+ if (!*pos) {
+ wpabuf_free(config->ap_assocresp_elements);
+ config->ap_assocresp_elements = NULL;
+ return 0;
+ }
+
+ tmp = wpabuf_parse_bin(pos);
+ if (!tmp) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid ap_assocresp_elements",
+ line);
return -1;
}
+ wpabuf_free(config->ap_assocresp_elements);
+ config->ap_assocresp_elements = tmp;
return 0;
}
@@ -5155,6 +5170,7 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
{ INT(dtim_period), 0 },
{ INT(beacon_int), 0 },
+ { FUNC(ap_assocresp_elements), 0 },
{ FUNC(ap_vendor_elements), 0 },
{ INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
{ FUNC(freq_list), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 68679c6e380a..0320d9eebb57 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1242,6 +1242,17 @@ struct wpa_config {
struct wpabuf *ap_vendor_elements;
/**
+ * ap_assocresp_elements: Vendor specific elements for (Re)Association
+ * Response frames
+ *
+ * This parameter can be used to define additional vendor specific
+ * elements for (Re)Association Response frames in AP/P2P GO mode. The
+ * format for these element(s) is a hexdump of the raw information
+ * elements (id+len+payload for one or more elements).
+ */
+ struct wpabuf *ap_assocresp_elements;
+
+ /**
* ignore_old_scan_res - Ignore scan results older than request
*
* The driver may have a cache of scan results that makes it return
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index a535e3f08aad..54fb72d8c1f7 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -675,6 +675,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(mem_only_psk);
STR(sae_password);
STR(sae_password_id);
+ write_int(f, "sae_pwe", ssid->sae_pwe, DEFAULT_SAE_PWE);
write_proto(f, ssid);
write_key_mgmt(f, ssid);
INT_DEF(bg_scan_period, DEFAULT_BG_SCAN_PERIOD);
@@ -1364,6 +1365,18 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
}
}
+ if (config->ap_assocresp_elements) {
+ int i, len = wpabuf_len(config->ap_assocresp_elements);
+ const u8 *p = wpabuf_head_u8(config->ap_assocresp_elements);
+
+ if (len > 0) {
+ fprintf(f, "ap_assocresp_elements=");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", *p++);
+ fprintf(f, "\n");
+ }
+ }
+
if (config->ignore_old_scan_res)
fprintf(f, "ignore_old_scan_res=%d\n",
config->ignore_old_scan_res);
diff --git a/wpa_supplicant/config_none.c b/wpa_supplicant/config_none.c
index 2aac28fa3d17..0bc977e3961b 100644
--- a/wpa_supplicant/config_none.c
+++ b/wpa_supplicant/config_none.c
@@ -5,7 +5,7 @@
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*
- * This file implements dummy example of a configuration backend. None of the
+ * This file implements stub example of a configuration backend. None of the
* functions are actually implemented so this can be used as a simple
* compilation test or a starting point for a new configuration backend.
*/
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 3f7b31480765..339eead1c333 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -46,6 +46,9 @@
#define DEFAULT_USER_SELECTED_SIM 1
#define DEFAULT_MAX_OPER_CHWIDTH -1
+/* Consider global sae_pwe for SAE mechanism for PWE derivation */
+#define DEFAULT_SAE_PWE 4
+
struct psk_list_entry {
struct dl_list list;
u8 addr[ETH_ALEN];
@@ -1156,6 +1159,19 @@ struct wpa_ssid {
* configuration.
*/
bool was_recently_reconfigured;
+
+ /**
+ * sae_pwe - SAE mechanism for PWE derivation
+ *
+ * Internally, special value 4 (DEFAULT_SAE_PWE) is used to indicate
+ * that the parameter is not set and the global sae_pwe value needs to
+ * be considered.
+ *
+ * 0 = hunting-and-pecking loop only
+ * 1 = hash-to-element only
+ * 2 = both hunting-and-pecking loop and hash-to-element enabled
+ */
+ int sae_pwe;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 8a6a829b6665..9dc17f5eef85 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -568,10 +568,10 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
(wps_version_number & 0xf0) >> 4,
wps_version_number & 0x0f);
}
- } else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
- wps_testing_dummy_cred = atoi(value);
- wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
- wps_testing_dummy_cred);
+ } else if (os_strcasecmp(cmd, "wps_testing_stub_cred") == 0) {
+ wps_testing_stub_cred = atoi(value);
+ wpa_printf(MSG_DEBUG, "WPS: Testing - stub_cred=%d",
+ wps_testing_stub_cred);
} else if (os_strcasecmp(cmd, "wps_corrupt_pkhash") == 0) {
wps_corrupt_pkhash = atoi(value);
wpa_printf(MSG_DEBUG, "WPS: Testing - wps_corrupt_pkhash=%d",
@@ -830,6 +830,10 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
wpa_s->sae_commit_override = wpabuf_parse_bin(value);
} else if (os_strcasecmp(cmd, "driver_signal_override") == 0) {
ret = wpas_ctrl_iface_set_dso(wpa_s, value);
+ } else if (os_strcasecmp(cmd, "disable_scs_support") == 0) {
+ wpa_s->disable_scs_support = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "disable_mscs_support") == 0) {
+ wpa_s->disable_mscs_support = !!atoi(value);
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(wpa_s->dpp_config_obj_override);
@@ -918,6 +922,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
return -1;
wnm_set_coloc_intf_elems(wpa_s, elems);
#endif /* CONFIG_WNM */
+ } else if (os_strcasecmp(cmd, "enable_dscp_policy_capa") == 0) {
+ wpa_s->enable_dscp_policy_capa = !!atoi(value);
} else {
value[-1] = '=';
ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -5918,7 +5924,7 @@ static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
for (i = 0; p2ps_prov->cpt_priority[i]; i++)
p2ps_prov->cpt_mask |= p2ps_prov->cpt_priority[i];
- /* force conncap with tstCap (no sanity checks) */
+ /* force conncap with tstCap (no validity checks) */
pos = os_strstr(cmd, "tstCap=");
if (pos) {
role = strtol(pos + 7, NULL, 16);
@@ -6122,6 +6128,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
if (max_oper_chwidth < 0)
return -1;
+ if (allow_6ghz && chwidth == 40)
+ max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
+
pos2 = os_strstr(pos, " ssid=");
if (pos2) {
char *end;
@@ -6775,6 +6784,9 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
allow_6ghz = os_strstr(cmd, " allow_6ghz") != NULL;
+ if (allow_6ghz && chwidth == 40)
+ max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
+
return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
max_oper_chwidth, pref_freq, he, edmg,
allow_6ghz);
@@ -6918,6 +6930,13 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
if (max_oper_chwidth < 0)
return -1;
+ if (allow_6ghz && chwidth == 40)
+ max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
+
+ /* Allow DFS to be used for Autonomous GO */
+ wpa_s->p2p_go_allow_dfs = !!(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_DFS_OFFLOAD);
+
if (group_id >= 0)
return p2p_ctrl_group_add_persistent(wpa_s, group_id,
freq, freq2, ht40, vht,
@@ -8428,7 +8447,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_WPS_TESTING
wps_version_number = 0x20;
- wps_testing_dummy_cred = 0;
+ wps_testing_stub_cred = 0;
wps_corrupt_pkhash = 0;
wps_force_auth_types_in_use = 0;
wps_force_encr_types_in_use = 0;
@@ -8551,6 +8570,9 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpabuf_free(wpa_s->rsnxe_override_eapol);
wpa_s->rsnxe_override_eapol = NULL;
wpas_clear_driver_signal_override(wpa_s);
+ wpa_s->disable_scs_support = 0;
+ wpa_s->disable_mscs_support = 0;
+ wpa_s->enable_dscp_policy_capa = 0;
wpa_s->oci_freq_override_eapol = 0;
wpa_s->oci_freq_override_saquery_req = 0;
wpa_s->oci_freq_override_saquery_resp = 0;
@@ -10602,6 +10624,8 @@ static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s,
if (sscanf(pos, "%d %d %d %d", &reauth_time, &expiration,
&entry->akmp, &entry->opportunistic) != 4)
goto fail;
+ if (reauth_time > expiration)
+ goto fail;
for (i = 0; i < 4; i++) {
pos = os_strchr(pos, ' ');
if (!pos) {
@@ -10887,6 +10911,581 @@ static int wpas_ctrl_iface_pasn_deauthenticate(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_PASN */
+static int set_type4_frame_classifier(const char *cmd,
+ struct type4_params *param)
+{
+ const char *pos, *end;
+ u8 classifier_mask = 0;
+ int ret;
+ char addr[INET6_ADDRSTRLEN];
+ size_t alen;
+
+ if (os_strstr(cmd, "ip_version=ipv4")) {
+ param->ip_version = IPV4;
+ } else if (os_strstr(cmd, "ip_version=ipv6")) {
+ param->ip_version = IPV6;
+ } else {
+ wpa_printf(MSG_ERROR, "IP version missing/invalid");
+ return -1;
+ }
+
+ classifier_mask |= BIT(0);
+
+ pos = os_strstr(cmd, "src_ip=");
+ if (pos) {
+ pos += 7;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+
+ alen = end - pos;
+ if (alen >= INET6_ADDRSTRLEN)
+ return -1;
+ os_memcpy(addr, pos, alen);
+ addr[alen] = '\0';
+ if (param->ip_version == IPV4)
+ ret = inet_pton(AF_INET, addr,
+ &param->ip_params.v4.src_ip);
+ else
+ ret = inet_pton(AF_INET6, addr,
+ &param->ip_params.v6.src_ip);
+
+ if (ret != 1) {
+ wpa_printf(MSG_ERROR,
+ "Error converting src IP address to binary ret=%d",
+ ret);
+ return -1;
+ }
+
+ classifier_mask |= BIT(1);
+ }
+
+ pos = os_strstr(cmd, "dst_ip=");
+ if (pos) {
+ pos += 7;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+
+ alen = end - pos;
+ if (alen >= INET6_ADDRSTRLEN)
+ return -1;
+ os_memcpy(addr, pos, alen);
+ addr[alen] = '\0';
+ if (param->ip_version == IPV4)
+ ret = inet_pton(AF_INET, addr,
+ &param->ip_params.v4.dst_ip);
+ else
+ ret = inet_pton(AF_INET6, addr,
+ &param->ip_params.v6.dst_ip);
+
+ if (ret != 1) {
+ wpa_printf(MSG_ERROR,
+ "Error converting dst IP address to binary ret=%d",
+ ret);
+ return -1;
+ }
+
+ classifier_mask |= BIT(2);
+ }
+
+ pos = os_strstr(cmd, "src_port=");
+ if (pos && atoi(pos + 9) > 0) {
+ if (param->ip_version == IPV4)
+ param->ip_params.v4.src_port = atoi(pos + 9);
+ else
+ param->ip_params.v6.src_port = atoi(pos + 9);
+ classifier_mask |= BIT(3);
+ }
+
+ pos = os_strstr(cmd, "dst_port=");
+ if (pos && atoi(pos + 9) > 0) {
+ if (param->ip_version == IPV4)
+ param->ip_params.v4.dst_port = atoi(pos + 9);
+ else
+ param->ip_params.v6.dst_port = atoi(pos + 9);
+ classifier_mask |= BIT(4);
+ }
+
+ pos = os_strstr(cmd, "dscp=");
+ if (pos && atoi(pos + 5) > 0) {
+ if (param->ip_version == IPV4)
+ param->ip_params.v4.dscp = atoi(pos + 5);
+ else
+ param->ip_params.v6.dscp = atoi(pos + 5);
+ classifier_mask |= BIT(5);
+ }
+
+ if (param->ip_version == IPV4) {
+ pos = os_strstr(cmd, "protocol=");
+ if (pos) {
+ if (os_strstr(pos, "udp")) {
+ param->ip_params.v4.protocol = 17;
+ } else if (os_strstr(pos, "tcp")) {
+ param->ip_params.v4.protocol = 6;
+ } else if (os_strstr(pos, "esp")) {
+ param->ip_params.v4.protocol = 50;
+ } else {
+ wpa_printf(MSG_ERROR, "Invalid protocol");
+ return -1;
+ }
+ classifier_mask |= BIT(6);
+ }
+ } else {
+ pos = os_strstr(cmd, "next_header=");
+ if (pos) {
+ if (os_strstr(pos, "udp")) {
+ param->ip_params.v6.next_header = 17;
+ } else if (os_strstr(pos, "tcp")) {
+ param->ip_params.v6.next_header = 6;
+ } else if (os_strstr(pos, "esp")) {
+ param->ip_params.v6.next_header = 50;
+ } else {
+ wpa_printf(MSG_ERROR, "Invalid next header");
+ return -1;
+ }
+
+ classifier_mask |= BIT(6);
+ }
+
+ pos = os_strstr(cmd, "flow_label=");
+ if (pos) {
+ pos += 11;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+
+ if (end - pos != 6 ||
+ hexstr2bin(pos, param->ip_params.v6.flow_label,
+ 3) ||
+ param->ip_params.v6.flow_label[0] > 0x0F) {
+ wpa_printf(MSG_ERROR, "Invalid flow label");
+ return -1;
+ }
+
+ classifier_mask |= BIT(7);
+ }
+ }
+
+ param->classifier_mask = classifier_mask;
+ return 0;
+}
+
+
+static int set_type10_frame_classifier(const char *cmd,
+ struct type10_params *param)
+{
+ const char *pos, *end;
+ size_t filter_len;
+
+ pos = os_strstr(cmd, "prot_instance=");
+ if (!pos) {
+ wpa_printf(MSG_ERROR, "Protocol instance missing");
+ return -1;
+ }
+ param->prot_instance = atoi(pos + 14);
+
+ pos = os_strstr(cmd, "prot_number=");
+ if (!pos) {
+ wpa_printf(MSG_ERROR, "Protocol number missing");
+ return -1;
+ }
+ if (os_strstr(pos, "udp")) {
+ param->prot_number = 17;
+ } else if (os_strstr(pos, "tcp")) {
+ param->prot_number = 6;
+ } else if (os_strstr(pos, "esp")) {
+ param->prot_number = 50;
+ } else {
+ wpa_printf(MSG_ERROR, "Invalid protocol number");
+ return -1;
+ }
+
+ pos = os_strstr(cmd, "filter_value=");
+ if (!pos) {
+ wpa_printf(MSG_ERROR,
+ "Classifier parameter filter_value missing");
+ return -1;
+ }
+
+ pos += 13;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+
+ filter_len = (end - pos) / 2;
+ param->filter_value = os_malloc(filter_len);
+ if (!param->filter_value)
+ return -1;
+
+ if (hexstr2bin(pos, param->filter_value, filter_len)) {
+ wpa_printf(MSG_ERROR, "Invalid filter_value %s", pos);
+ goto free;
+ }
+
+ pos = os_strstr(cmd, "filter_mask=");
+ if (!pos) {
+ wpa_printf(MSG_ERROR,
+ "Classifier parameter filter_mask missing");
+ goto free;
+ }
+
+ pos += 12;
+ end = os_strchr(pos, ' ');
+ if (!end)
+ end = pos + os_strlen(pos);
+
+ if (filter_len != (size_t) (end - pos) / 2) {
+ wpa_printf(MSG_ERROR,
+ "Filter mask length mismatch expected=%zu received=%zu",
+ filter_len, (size_t) (end - pos) / 2);
+ goto free;
+ }
+
+ param->filter_mask = os_malloc(filter_len);
+ if (!param->filter_mask)
+ goto free;
+
+ if (hexstr2bin(pos, param->filter_mask, filter_len)) {
+ wpa_printf(MSG_ERROR, "Invalid filter mask %s", pos);
+ os_free(param->filter_mask);
+ param->filter_mask = NULL;
+ goto free;
+ }
+
+ param->filter_len = filter_len;
+ return 0;
+free:
+ os_free(param->filter_value);
+ param->filter_value = NULL;
+ return -1;
+}
+
+
+static int scs_parse_type4(struct tclas_element *elem, const char *pos)
+{
+ struct type4_params type4_param = { 0 };
+
+ if (set_type4_frame_classifier(pos, &type4_param) == -1) {
+ wpa_printf(MSG_ERROR, "Failed to set frame_classifier 4");
+ return -1;
+ }
+
+ os_memcpy(&elem->frame_classifier.type4_param,
+ &type4_param, sizeof(struct type4_params));
+ return 0;
+}
+
+
+static int scs_parse_type10(struct tclas_element *elem, const char *pos)
+{
+ struct type10_params type10_param = { 0 };
+
+ if (set_type10_frame_classifier(pos, &type10_param) == -1) {
+ wpa_printf(MSG_ERROR, "Failed to set frame_classifier 10");
+ return -1;
+ }
+
+ os_memcpy(&elem->frame_classifier.type10_param,
+ &type10_param, sizeof(struct type10_params));
+ return 0;
+}
+
+
+static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *pos1, *pos;
+ struct scs_robust_av_data *scs_data = &wpa_s->scs_robust_av_req;
+ struct scs_desc_elem desc_elem = { 0 };
+ int val;
+ unsigned int num_scs_desc = 0;
+
+ if (wpa_s->ongoing_scs_req) {
+ wpa_printf(MSG_ERROR, "%s: SCS Request already in queue",
+ __func__);
+ return -1;
+ }
+
+ /**
+ * format:
+ * [scs_id=<decimal number>] <add|remove|change> [scs_up=<0-7>]
+ * [classifier_type=<4|10>]
+ * [classifier params based on classifier type]
+ * [tclas_processing=<0|1>] [scs_id=<decimal number>] ...
+ */
+ pos1 = os_strstr(cmd, "scs_id=");
+ if (!pos1) {
+ wpa_printf(MSG_ERROR, "SCSID not present");
+ return -1;
+ }
+
+ free_up_scs_desc(scs_data);
+
+ while (pos1) {
+ struct scs_desc_elem *n1;
+ struct active_scs_elem *active_scs_desc;
+ char *next_scs_desc;
+ unsigned int num_tclas_elem = 0;
+ bool scsid_active = false;
+
+ desc_elem.scs_id = atoi(pos1 + 7);
+ pos1 += 7;
+
+ next_scs_desc = os_strstr(pos1, "scs_id=");
+ if (next_scs_desc) {
+ char temp[20];
+
+ os_snprintf(temp, sizeof(temp), "scs_id=%d ",
+ desc_elem.scs_id);
+ if (os_strstr(next_scs_desc, temp)) {
+ wpa_printf(MSG_ERROR,
+ "Multiple SCS descriptors configured with same SCSID(=%d)",
+ desc_elem.scs_id);
+ goto free_scs_desc;
+ }
+ pos1[next_scs_desc - pos1 - 1] = '\0';
+ }
+
+ dl_list_for_each(active_scs_desc, &wpa_s->active_scs_ids,
+ struct active_scs_elem, list) {
+ if (desc_elem.scs_id == active_scs_desc->scs_id) {
+ scsid_active = true;
+ break;
+ }
+ }
+
+ if (os_strstr(pos1, "add ")) {
+ desc_elem.request_type = SCS_REQ_ADD;
+ if (scsid_active) {
+ wpa_printf(MSG_ERROR, "SCSID %d already active",
+ desc_elem.scs_id);
+ return -1;
+ }
+ } else if (os_strstr(pos1, "remove")) {
+ desc_elem.request_type = SCS_REQ_REMOVE;
+ if (!scsid_active) {
+ wpa_printf(MSG_ERROR, "SCSID %d not active",
+ desc_elem.scs_id);
+ return -1;
+ }
+ goto scs_desc_end;
+ } else if (os_strstr(pos1, "change ")) {
+ desc_elem.request_type = SCS_REQ_CHANGE;
+ if (!scsid_active) {
+ wpa_printf(MSG_ERROR, "SCSID %d not active",
+ desc_elem.scs_id);
+ return -1;
+ }
+ } else {
+ wpa_printf(MSG_ERROR, "SCS Request type invalid");
+ goto free_scs_desc;
+ }
+
+ pos1 = os_strstr(pos1, "scs_up=");
+ if (!pos1) {
+ wpa_printf(MSG_ERROR,
+ "Intra-Access user priority not present");
+ goto free_scs_desc;
+ }
+
+ val = atoi(pos1 + 7);
+ if (val < 0 || val > 7) {
+ wpa_printf(MSG_ERROR,
+ "Intra-Access user priority invalid %d",
+ val);
+ goto free_scs_desc;
+ }
+
+ desc_elem.intra_access_priority = val;
+ desc_elem.scs_up_avail = true;
+
+ pos = os_strstr(pos1, "classifier_type=");
+ if (!pos) {
+ wpa_printf(MSG_ERROR, "classifier type empty");
+ goto free_scs_desc;
+ }
+
+ while (pos) {
+ struct tclas_element elem = { 0 }, *n;
+ char *next_tclas_elem;
+
+ val = atoi(pos + 16);
+ if (val != 4 && val != 10) {
+ wpa_printf(MSG_ERROR,
+ "classifier type invalid %d", val);
+ goto free_scs_desc;
+ }
+
+ elem.classifier_type = val;
+ pos += 16;
+
+ next_tclas_elem = os_strstr(pos, "classifier_type=");
+ if (next_tclas_elem) {
+ pos1 = next_tclas_elem;
+ pos[next_tclas_elem - pos - 1] = '\0';
+ }
+
+ switch (val) {
+ case 4:
+ if (scs_parse_type4(&elem, pos) < 0)
+ goto free_scs_desc;
+ break;
+ case 10:
+ if (scs_parse_type10(&elem, pos) < 0)
+ goto free_scs_desc;
+ break;
+ }
+
+ n = os_realloc(desc_elem.tclas_elems,
+ (num_tclas_elem + 1) * sizeof(elem));
+ if (!n)
+ goto free_scs_desc;
+
+ desc_elem.tclas_elems = n;
+ os_memcpy((u8 *) desc_elem.tclas_elems +
+ num_tclas_elem * sizeof(elem),
+ &elem, sizeof(elem));
+ num_tclas_elem++;
+ desc_elem.num_tclas_elem = num_tclas_elem;
+ pos = next_tclas_elem;
+ }
+
+ if (desc_elem.num_tclas_elem > 1) {
+ pos1 = os_strstr(pos1, "tclas_processing=");
+ if (!pos1) {
+ wpa_printf(MSG_ERROR, "tclas_processing empty");
+ goto free_scs_desc;
+ }
+
+ val = atoi(pos1 + 17);
+ if (val != 0 && val != 1) {
+ wpa_printf(MSG_ERROR,
+ "tclas_processing invalid");
+ goto free_scs_desc;
+ }
+
+ desc_elem.tclas_processing = val;
+ }
+
+scs_desc_end:
+ n1 = os_realloc(scs_data->scs_desc_elems, (num_scs_desc + 1) *
+ sizeof(struct scs_desc_elem));
+ if (!n1)
+ goto free_scs_desc;
+
+ scs_data->scs_desc_elems = n1;
+ os_memcpy((u8 *) scs_data->scs_desc_elems + num_scs_desc *
+ sizeof(desc_elem), &desc_elem, sizeof(desc_elem));
+ num_scs_desc++;
+ scs_data->num_scs_desc = num_scs_desc;
+ pos1 = next_scs_desc;
+ os_memset(&desc_elem, 0, sizeof(desc_elem));
+ }
+
+ return wpas_send_scs_req(wpa_s);
+
+free_scs_desc:
+ free_up_tclas_elem(&desc_elem);
+ free_up_scs_desc(scs_data);
+ return -1;
+}
+
+
+static int wpas_ctrl_iface_send_dscp_resp(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ char *pos;
+ struct dscp_policy_status *policy = NULL, *n;
+ int num_policies = 0, ret = -1;
+ struct dscp_resp_data resp_data;
+
+ /*
+ * format:
+ * <[reset]>/<[solicited] [policy_id=1 status=0...]> [more]
+ */
+
+ os_memset(&resp_data, 0, sizeof(resp_data));
+
+ resp_data.more = os_strstr(cmd, "more") != NULL;
+
+ if (os_strstr(cmd, "reset")) {
+ resp_data.reset = true;
+ resp_data.solicited = false;
+ goto send_resp;
+ }
+
+ resp_data.solicited = os_strstr(cmd, "solicited") != NULL;
+
+ pos = os_strstr(cmd, "policy_id=");
+ while (pos) {
+ n = os_realloc(policy, (num_policies + 1) * sizeof(*policy));
+ if (!n)
+ goto fail;
+
+ policy = n;
+ pos += 10;
+ policy[num_policies].id = atoi(pos);
+ if (policy[num_policies].id == 0) {
+ wpa_printf(MSG_ERROR, "DSCP: Invalid policy id");
+ goto fail;
+ }
+
+ pos = os_strstr(pos, "status=");
+ if (!pos) {
+ wpa_printf(MSG_ERROR,
+ "DSCP: Status is not found for a policy");
+ goto fail;
+ }
+
+ pos += 7;
+ policy[num_policies].status = atoi(pos);
+ num_policies++;
+
+ pos = os_strstr(pos, "policy_id");
+ }
+
+ resp_data.policy = policy;
+ resp_data.num_policies = num_policies;
+send_resp:
+ ret = wpas_send_dscp_response(wpa_s, &resp_data);
+ if (ret)
+ wpa_printf(MSG_ERROR, "DSCP: Failed to send DSCP response");
+fail:
+ os_free(policy);
+ return ret;
+}
+
+
+static int wpas_ctrl_iface_send_dscp_query(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ char *pos;
+
+ /*
+ * format:
+ * Wildcard DSCP query
+ * <wildcard>
+ *
+ * DSCP query with a domain name attribute:
+ * [domain_name=<string>]
+ */
+
+ if (os_strstr(cmd, "wildcard")) {
+ wpa_printf(MSG_DEBUG, "QM: Send wildcard DSCP policy query");
+ return wpas_send_dscp_query(wpa_s, NULL, 0);
+ }
+
+ pos = os_strstr(cmd, "domain_name=");
+ if (!pos || !os_strlen(pos + 12)) {
+ wpa_printf(MSG_ERROR, "QM: Domain name not preset");
+ return -1;
+ }
+
+ return wpas_send_dscp_query(wpa_s, pos + 12, os_strlen(pos + 12));
+}
+
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -11458,6 +12057,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strcmp(buf, "STOP_AP") == 0) {
if (wpas_ap_stop_ap(wpa_s))
reply_len = -1;
+ } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
+ if (wpas_ap_update_beacon(wpa_s))
+ reply_len = -1;
#endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
@@ -11812,6 +12414,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_ctrl_iface_pasn_deauthenticate(wpa_s, buf + 12) < 0)
reply_len = -1;
#endif /* CONFIG_PASN */
+ } else if (os_strncmp(buf, "SCS ", 4) == 0) {
+ if (wpas_ctrl_iface_configure_scs(wpa_s, buf + 4))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DSCP_RESP ", 10) == 0) {
+ if (wpas_ctrl_iface_send_dscp_resp(wpa_s, buf + 10))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DSCP_QUERY ", 11) == 0) {
+ if (wpas_ctrl_iface_send_dscp_query(wpa_s, buf + 11))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 144654aac684..e4a83698393a 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -46,7 +46,7 @@
can be used to improve the network security, but even that has inherited
security issues due to the use of WEP for encryption. Wi-Fi Protected
Access and IEEE 802.11i amendment to the wireless LAN standard introduce
- a much improvement mechanism for securing wireless networks. IEEE 802.11i
+ a much improved mechanism for securing wireless networks. IEEE 802.11i
enabled networks that are using CCMP (encryption mechanism based on strong
cryptographic algorithm AES) can finally be called secure used for
applications which require efficient protection against unauthorized
diff --git a/wpa_supplicant/eapol_test.py b/wpa_supplicant/eapol_test.py
index 734428d29e66..88c83f343597 100755
--- a/wpa_supplicant/eapol_test.py
+++ b/wpa_supplicant/eapol_test.py
@@ -72,7 +72,7 @@ class eapol_test:
break
return None
-def run(ifname, count, no_fast_reauth, res):
+def run(ifname, count, no_fast_reauth, res, conf):
et = eapol_test(ifname)
et.request("AP_SCAN 0")
@@ -81,14 +81,20 @@ def run(ifname, count, no_fast_reauth, res):
else:
et.request("SET fast_reauth 1")
id = et.add_network()
- et.set_network(id, "key_mgmt", "IEEE8021X")
- et.set_network(id, "eapol_flags", "0")
- et.set_network(id, "eap", "TLS")
- et.set_network_quoted(id, "identity", "user")
- et.set_network_quoted(id, "ca_cert", 'ca.pem')
- et.set_network_quoted(id, "client_cert", 'client.pem')
- et.set_network_quoted(id, "private_key", 'client.key')
- et.set_network_quoted(id, "private_key_passwd", 'whatever')
+
+ if len(conf):
+ for item in conf:
+ et.set_network(id, item, conf[item])
+ else:
+ et.set_network(id, "key_mgmt", "IEEE8021X")
+ et.set_network(id, "eapol_flags", "0")
+ et.set_network(id, "eap", "TLS")
+ et.set_network_quoted(id, "identity", "user")
+ et.set_network_quoted(id, "ca_cert", 'ca.pem')
+ et.set_network_quoted(id, "client_cert", 'client.pem')
+ et.set_network_quoted(id, "private_key", 'client.key')
+ et.set_network_quoted(id, "private_key_passwd", 'whatever')
+
et.set_network(id, "disabled", "0")
fail = False
@@ -114,6 +120,7 @@ def main():
parser.add_argument('--no-fast-reauth', action='store_true',
dest='no_fast_reauth',
help='disable TLS session resumption')
+ parser.add_argument('--conf', help='file of network conf items')
args = parser.parse_args()
num = int(args.num)
@@ -122,12 +129,22 @@ def main():
global wpas_ctrl
wpas_ctrl = args.ctrl
+ conf = {}
+ if args.conf:
+ f = open(args.conf, "r")
+ for line in f:
+ confitem = line.split("=")
+ if len(confitem) == 2:
+ conf[confitem[0].strip()] = confitem[1].strip()
+ f.close()
+
t = {}
res = {}
for i in range(num):
res[i] = Queue.Queue()
t[i] = threading.Thread(target=run, args=(str(i), iter,
- args.no_fast_reauth, res[i]))
+ args.no_fast_reauth, res[i],
+ conf))
for i in range(num):
t[i].start()
for i in range(num):
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index a565e658f33d..5f5c50ba9754 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -356,9 +356,14 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
struct wpa_ie_data ie;
int pmksa_set = -1;
size_t i;
+ struct rsn_pmksa_cache_entry *cur_pmksa;
- /* Start with assumption of no PMKSA cache entry match */
- pmksa_cache_clear_current(wpa_s->wpa);
+ /* Start with assumption of no PMKSA cache entry match for cases other
+ * than SAE. In particular, this is needed to generate the PMKSA cache
+ * entries for Suite B cases with driver-based roaming indication. */
+ cur_pmksa = pmksa_cache_get_current(wpa_s->wpa);
+ if (cur_pmksa && !wpa_key_mgmt_sae(cur_pmksa->akmp))
+ pmksa_cache_clear_current(wpa_s->wpa);
if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
ie.pmkid == NULL)
@@ -2680,6 +2685,205 @@ static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_FST */
+static int wpa_supplicant_use_own_rsne_params(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ int sel;
+ const u8 *p;
+ int l, len;
+ bool found = false;
+ struct wpa_ie_data ie;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct wpa_bss *bss = wpa_s->current_bss;
+ int pmf;
+
+ if (!ssid)
+ return 0;
+
+ p = data->assoc_info.req_ies;
+ l = data->assoc_info.req_ies_len;
+
+ while (p && l >= 2) {
+ len = p[1] + 2;
+ if (len > l) {
+ wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
+ p, l);
+ break;
+ }
+ if (((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
+ (p[0] == WLAN_EID_RSN && p[1] >= 2))) {
+ found = true;
+ break;
+ }
+ l -= len;
+ p += len;
+ }
+
+ if (!found || wpa_parse_wpa_ie(p, len, &ie) < 0)
+ return 0;
+
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Update cipher suite selection based on IEs in driver-generated WPA/RSNE in AssocReq",
+ p, l);
+
+ /* Update proto from (Re)Association Request frame info */
+ wpa_s->wpa_proto = ie.proto;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, wpa_s->wpa_proto);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
+ !!(wpa_s->wpa_proto &
+ (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
+
+ /* Update AKMP suite from (Re)Association Request frame info */
+ sel = ie.key_mgmt;
+ if (ssid->key_mgmt)
+ sel &= ssid->key_mgmt;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP key_mgmt 0x%x network key_mgmt 0x%x; available key_mgmt 0x%x",
+ ie.key_mgmt, ssid->key_mgmt, sel);
+ if (ie.key_mgmt && !sel) {
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_AKMP_NOT_VALID);
+ return -1;
+ }
+
+ wpa_s->key_mgmt = ie.key_mgmt;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT %s and proto %d",
+ wpa_key_mgmt_txt(wpa_s->key_mgmt, wpa_s->wpa_proto),
+ wpa_s->wpa_proto);
+
+ /* Update pairwise cipher from (Re)Association Request frame info */
+ sel = ie.pairwise_cipher;
+ if (ssid->pairwise_cipher)
+ sel &= ssid->pairwise_cipher;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP pairwise cipher 0x%x network pairwise cipher 0x%x; available pairwise cipher 0x%x",
+ ie.pairwise_cipher, ssid->pairwise_cipher, sel);
+ if (ie.pairwise_cipher && !sel) {
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID);
+ return -1;
+ }
+
+ wpa_s->pairwise_cipher = ie.pairwise_cipher;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
+ wpa_s->pairwise_cipher);
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
+ wpa_cipher_txt(wpa_s->pairwise_cipher));
+
+ /* Update other parameters based on AP's WPA IE/RSNE, if available */
+ if (!bss) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: current_bss == NULL - skip AP IE check");
+ return 0;
+ }
+
+ /* Update GTK and IGTK from AP's RSNE */
+ found = false;
+
+ if (wpa_s->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) {
+ const u8 *bss_rsn;
+
+ bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (bss_rsn) {
+ p = bss_rsn;
+ len = 2 + bss_rsn[1];
+ found = true;
+ }
+ } else if (wpa_s->wpa_proto & WPA_PROTO_WPA) {
+ const u8 *bss_wpa;
+
+ bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ if (bss_wpa) {
+ p = bss_wpa;
+ len = 2 + bss_wpa[1];
+ found = true;
+ }
+ }
+
+ if (!found || wpa_parse_wpa_ie(p, len, &ie) < 0)
+ return 0;
+
+ pmf = wpas_get_ssid_pmf(wpa_s, ssid);
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+ pmf == MGMT_FRAME_PROTECTION_REQUIRED) {
+ /* AP does not support MFP, local configuration requires it */
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_INVALID_RSN_IE_CAPAB);
+ return -1;
+ }
+ if ((ie.capabilities & WPA_CAPABILITY_MFPR) &&
+ pmf == NO_MGMT_FRAME_PROTECTION) {
+ /* AP requires MFP, local configuration disables it */
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_INVALID_RSN_IE_CAPAB);
+ return -1;
+ }
+
+ /* Update PMF from local configuration now that MFP validation was done
+ * above */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, pmf);
+
+ /* Update GTK from AP's RSNE */
+ sel = ie.group_cipher;
+ if (ssid->group_cipher)
+ sel &= ssid->group_cipher;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP group cipher 0x%x network group cipher 0x%x; available group cipher 0x%x",
+ ie.group_cipher, ssid->group_cipher, sel);
+ if (ie.group_cipher && !sel) {
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_GROUP_CIPHER_NOT_VALID);
+ return -1;
+ }
+
+ wpa_s->group_cipher = ie.group_cipher;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s",
+ wpa_cipher_txt(wpa_s->group_cipher));
+
+ /* Update IGTK from AP RSN IE */
+ sel = ie.mgmt_group_cipher;
+ if (ssid->group_mgmt_cipher)
+ sel &= ssid->group_mgmt_cipher;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP mgmt_group_cipher 0x%x network mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
+ ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
+
+ if (pmf == NO_MGMT_FRAME_PROTECTION ||
+ !(ie.capabilities & WPA_CAPABILITY_MFPC)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: STA/AP is not MFP capable; AP RSNE caps 0x%x",
+ ie.capabilities);
+ ie.mgmt_group_cipher = 0;
+ }
+
+ if (ie.mgmt_group_cipher && !sel) {
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_CIPHER_SUITE_REJECTED);
+ return -1;
+ }
+
+ wpa_s->mgmt_group_cipher = ie.mgmt_group_cipher;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
+ wpa_s->mgmt_group_cipher);
+ if (wpa_s->mgmt_group_cipher)
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher %s",
+ wpa_cipher_txt(wpa_s->mgmt_group_cipher));
+ else
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
+
+ return 0;
+}
+
+
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -2977,6 +3181,9 @@ no_pfs:
wpa_s->assoc_freq = data->assoc_info.freq;
+ wpas_handle_assoc_resp_qos_mgmt(wpa_s, data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+
return 0;
}
@@ -3121,6 +3328,10 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
}
}
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+ data && wpa_supplicant_use_own_rsne_params(wpa_s, data) < 0)
+ return;
+
multi_ap_set_4addr_mode(wpa_s);
if (wpa_s->conf->ap_scan == 1 &&
@@ -4260,12 +4471,26 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_DPP */
if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
+ payload[0] == ROBUST_AV_SCS_RESP) {
+ wpas_handle_robust_av_scs_recv_action(wpa_s, mgmt->sa,
+ payload + 1, plen - 1);
+ return;
+ }
+
+ if (category == WLAN_ACTION_ROBUST_AV_STREAMING &&
payload[0] == ROBUST_AV_MSCS_RESP) {
wpas_handle_robust_av_recv_action(wpa_s, mgmt->sa,
payload + 1, plen - 1);
return;
}
+ if (category == WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED && plen > 4 &&
+ WPA_GET_BE32(payload) == QM_ACTION_VENDOR_TYPE) {
+ wpas_handle_qos_mgmt_recv_action(wpa_s, mgmt->sa,
+ payload + 4, plen - 4);
+ return;
+ }
+
wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
category, payload, plen, freq);
if (wpa_s->ifmsh)
@@ -5238,13 +5463,21 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
case EVENT_INTERFACE_MAC_CHANGED:
wpa_supplicant_update_mac_addr(wpa_s);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
break;
case EVENT_INTERFACE_ENABLED:
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+ u8 addr[ETH_ALEN];
+
eloop_cancel_timeout(wpas_clear_disabled_interface,
wpa_s, NULL);
+ os_memcpy(addr, wpa_s->own_addr, ETH_ALEN);
wpa_supplicant_update_mac_addr(wpa_s);
+ if (os_memcmp(addr, wpa_s->own_addr, ETH_ALEN) != 0)
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+ else
+ wpa_sm_pmksa_cache_reconfig(wpa_s->wpa);
wpa_supplicant_set_default_scan_ies(wpa_s);
if (wpa_s->p2p_mgmt) {
wpa_supplicant_set_state(wpa_s,
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index e60a8c1fe6aa..a6172d69233b 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -273,16 +273,6 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s,
}
-int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
-{
- if (wpa_s->current_ssid == NULL ||
- wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
- os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0)
- return 0;
- return wpa_sm_pmf_enabled(wpa_s->wpa);
-}
-
-
static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
struct wpabuf *req, unsigned int wait_time)
{
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
index f9ce7b680fda..6ccecd4ddbe1 100644
--- a/wpa_supplicant/gas_query.h
+++ b/wpa_supplicant/gas_query.h
@@ -19,7 +19,6 @@ void gas_query_deinit(struct gas_query *gas);
int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
const u8 *bssid, u8 categ, const u8 *data, size_t len,
int freq);
-int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr);
/**
* enum gas_query_result - GAS query result
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 901b49b4d257..7938b8b4903e 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -437,6 +437,37 @@ static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
if (!conf)
goto out_free;
+ if (is_6ghz_freq(freq->freq)) {
+ /*
+ * IEEE Std 802.11ax-2021, 12.12.2:
+ * The STA shall use management frame protection (MFPR=1) when
+ * using RSN.
+ */
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+
+ /* Set mandatory op_class parameter for setting up BSS */
+ switch (freq->bandwidth) {
+ case 20:
+ if (freq->freq == 5935)
+ conf->op_class = 136;
+ else
+ conf->op_class = 131;
+ break;
+ case 40:
+ conf->op_class = 132;
+ break;
+ case 80:
+ conf->op_class = 133;
+ break;
+ case 160:
+ conf->op_class = 134;
+ break;
+ default:
+ conf->op_class = 131;
+ break;
+ }
+ }
+
bss->conf = *conf->bss;
bss->conf->start_disabled = 1;
bss->conf->mesh = MESH_ENABLED;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index b6a5e8857db9..38f0d641a03b 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -251,6 +251,9 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
HE_MAX_MCS_CAPAB_SIZE +
HE_MAX_PPET_CAPAB_SIZE;
buf_len += 3 + sizeof(struct ieee80211_he_operation);
+ if (is_6ghz_op_class(bss->iconf->op_class))
+ buf_len += sizeof(struct ieee80211_he_6ghz_oper_info) +
+ 3 + sizeof(struct ieee80211_he_6ghz_band_cap);
}
#endif /* CONFIG_IEEE80211AX */
if (type != PLINK_CLOSE)
@@ -375,11 +378,14 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
HE_MAX_PHY_CAPAB_SIZE +
HE_MAX_MCS_CAPAB_SIZE +
HE_MAX_PPET_CAPAB_SIZE +
- 3 + sizeof(struct ieee80211_he_operation)];
+ 3 + sizeof(struct ieee80211_he_operation) +
+ sizeof(struct ieee80211_he_6ghz_oper_info) +
+ 3 + sizeof(struct ieee80211_he_6ghz_band_cap)];
pos = hostapd_eid_he_capab(bss, he_capa_oper,
IEEE80211_MODE_MESH);
pos = hostapd_eid_he_operation(bss, pos);
+ pos = hostapd_eid_he_6ghz_band_cap(bss, pos);
wpabuf_put_data(buf, he_capa_oper, pos - he_capa_oper);
}
#endif /* CONFIG_IEEE80211AX */
@@ -749,6 +755,7 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_IEEE80211AX
copy_sta_he_capab(data, sta, IEEE80211_MODE_MESH,
elems->he_capabilities, elems->he_capabilities_len);
+ copy_sta_he_6ghz_capab(data, sta, elems->he_6ghz_band_cap);
#endif /* CONFIG_IEEE80211AX */
if (hostapd_get_aid(data, sta) < 0) {
@@ -770,6 +777,7 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
params.vht_capabilities = sta->vht_capabilities;
params.he_capab = sta->he_capab;
params.he_capab_len = sta->he_capab_len;
+ params.he_6ghz_capab = sta->he_6ghz_capab;
params.flags |= WPA_STA_WMM;
params.flags_mask |= WPA_STA_AUTHENTICATED;
if (conf->security == MESH_CONF_SEC_NONE) {
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index e0e7e5433d77..fe5e072c24c2 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -350,8 +350,11 @@ void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
* applications since these network objects won't behave like
* regular ones.
*/
- if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s)
+ if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s) {
wpas_dbus_register_network(wpa_s, ssid);
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_NETWORK_ADDED "%d",
+ ssid->id);
+ }
}
@@ -381,8 +384,11 @@ void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa)
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s &&
- !wpa_s->p2p_mgmt)
+ !wpa_s->p2p_mgmt) {
wpas_dbus_unregister_network(wpa_s, ssid->id);
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_NETWORK_REMOVED "%d",
+ ssid->id);
+ }
if (network_is_persistent_group(ssid))
wpas_notify_persistent_group_removed(wpa_s, ssid);
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index a0ad0c2ff572..bd53c5ceceaf 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -207,11 +207,15 @@ enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
return NOT_ALLOWED;
res2 = allow_channel(mode, op_class, channel - 4, NULL);
- } else if (bw == BW40PLUS ||
- (bw == BW40 && !(((channel - 1) / 4) % 2))) {
+ } else if (bw == BW40PLUS) {
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
return NOT_ALLOWED;
res2 = allow_channel(mode, op_class, channel + 4, NULL);
+ } else if (is_6ghz_op_class(op_class) && bw == BW40) {
+ if (get_6ghz_sec_channel(channel) < 0)
+ res2 = allow_channel(mode, op_class, channel - 4, NULL);
+ else
+ res2 = allow_channel(mode, op_class, channel + 4, NULL);
} else if (bw == BW80) {
/*
* channel is a center channel and as such, not necessarily a
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 62c9a26a3490..ce44dfb9e053 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -164,6 +164,17 @@ wpas_p2p_consider_moving_gos(struct wpa_supplicant *wpa_s,
static void wpas_p2p_reconsider_moving_go(void *eloop_ctx, void *timeout_ctx);
+static int wpas_get_6ghz_he_chwidth_capab(struct hostapd_hw_modes *mode)
+{
+ int he_capab = 0;
+
+ if (mode)
+ he_capab = mode->he_capab[WPAS_MODE_INFRA].phy_cap[
+ HE_PHYCAP_CHANNEL_WIDTH_SET_IDX];
+ return he_capab;
+}
+
+
/*
* Get the number of concurrent channels that the HW can operate, but that are
* currently not in use by any of the wpa_supplicant interfaces.
@@ -1027,6 +1038,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
wpa_s->p2p_group_common_freqs = NULL;
wpa_s->p2p_group_common_freqs_num = 0;
wpa_s->p2p_go_do_acs = 0;
+ wpa_s->p2p_go_allow_dfs = 0;
wpa_s->waiting_presence_resp = 0;
@@ -2069,6 +2081,8 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
is_p2p_6ghz_capable(wpa_s->global->p2p)) {
ssid->auth_alg |= WPA_AUTH_ALG_SAE;
ssid->key_mgmt = WPA_KEY_MGMT_SAE;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ ssid->sae_pwe = 1;
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use SAE auth_alg and key_mgmt");
} else {
p2p_set_6ghz_dev_capab(wpa_s->global->p2p, false);
@@ -2157,6 +2171,8 @@ do { \
d->disassoc_low_ack = s->disassoc_low_ack;
d->disable_scan_offload = s->disable_scan_offload;
d->passive_scan = s->passive_scan;
+ d->pmf = s->pmf;
+ d->p2p_6ghz_disable = s->p2p_6ghz_disable;
if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
!d->wps_nfc_pw_from_config) {
@@ -3571,12 +3587,12 @@ static enum chan_allowed has_channel(struct wpa_global *global,
if ((unsigned int) mode->channels[i].freq == freq) {
if (flags)
*flags = mode->channels[i].flag;
- if (mode->channels[i].flag &
- (HOSTAPD_CHAN_DISABLED |
- HOSTAPD_CHAN_RADAR))
+ if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
return NOT_ALLOWED;
if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
return NO_IR;
+ if (mode->channels[i].flag & HOSTAPD_CHAN_RADAR)
+ return RADAR;
return ALLOWED;
}
}
@@ -3636,7 +3652,8 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
chans, num_chans);
if (!center_chan)
return NOT_ALLOWED;
- if (!is_6ghz && center_chan >= 58 && center_chan <= 138)
+ if (!wpa_s->p2p_go_allow_dfs &&
+ !is_6ghz && center_chan >= 58 && center_chan <= 138)
return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
/* check all the channels are available */
@@ -3647,17 +3664,24 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
&flags);
if (res == NOT_ALLOWED)
return NOT_ALLOWED;
+ if (res == RADAR)
+ ret = RADAR;
if (res == NO_IR)
ret = NO_IR;
-
- if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
- return NOT_ALLOWED;
- if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50))
- return NOT_ALLOWED;
- if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30))
- return NOT_ALLOWED;
- if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10))
+ if (!is_6ghz) {
+ if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
+ return NOT_ALLOWED;
+ if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50))
+ return NOT_ALLOWED;
+ if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30))
+ return NOT_ALLOWED;
+ if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10))
+ return NOT_ALLOWED;
+ } else if (is_6ghz &&
+ (!(wpas_get_6ghz_he_chwidth_capab(mode) &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G))) {
return NOT_ALLOWED;
+ }
}
return ret;
@@ -3723,25 +3747,33 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
if (res == NOT_ALLOWED)
return NOT_ALLOWED;
+ if (res == RADAR)
+ ret = RADAR;
if (res == NO_IR)
ret = NO_IR;
- if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150))
- return NOT_ALLOWED;
- if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130))
- return NOT_ALLOWED;
- if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110))
- return NOT_ALLOWED;
- if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90))
- return NOT_ALLOWED;
- if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70))
- return NOT_ALLOWED;
- if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50))
- return NOT_ALLOWED;
- if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30))
- return NOT_ALLOWED;
- if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10))
+ if (!is_6ghz_op_class(op_class)) {
+ if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150))
+ return NOT_ALLOWED;
+ if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130))
+ return NOT_ALLOWED;
+ if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110))
+ return NOT_ALLOWED;
+ if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90))
+ return NOT_ALLOWED;
+ if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70))
+ return NOT_ALLOWED;
+ if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50))
+ return NOT_ALLOWED;
+ if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30))
+ return NOT_ALLOWED;
+ if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10))
+ return NOT_ALLOWED;
+ } else if (is_6ghz_op_class(op_class) &&
+ (!(wpas_get_6ghz_he_chwidth_capab(mode) &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G))) {
return NOT_ALLOWED;
+ }
}
return ret;
@@ -3780,6 +3812,15 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
return NOT_ALLOWED;
res2 = has_channel(wpa_s->global, mode, op_class, channel + 4,
NULL);
+ } else if (is_6ghz_op_class(op_class) && bw == BW40) {
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return NOT_ALLOWED;
+ if (get_6ghz_sec_channel(channel) < 0)
+ res2 = has_channel(wpa_s->global, mode, op_class,
+ channel - 4, NULL);
+ else
+ res2 = has_channel(wpa_s->global, mode, op_class,
+ channel + 4, NULL);
} else if (bw == BW80) {
res2 = wpas_p2p_verify_80mhz(wpa_s, mode, op_class, channel,
bw);
@@ -3794,6 +3835,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
return NOT_ALLOWED;
if (res == NO_IR || res2 == NO_IR)
return NO_IR;
+ if (res == RADAR || res2 == RADAR)
+ return RADAR;
return res;
}
@@ -3817,7 +3860,7 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
for (op = 0; global_op_class[op].op_class; op++) {
const struct oper_class_map *o = &global_op_class[op];
- u8 ch;
+ unsigned int ch;
struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
if (o->p2p == NO_P2P_SUPP ||
@@ -3890,30 +3933,50 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
}
-int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
- struct hostapd_hw_modes *mode, u8 channel)
+int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel)
{
int op;
enum chan_allowed ret;
for (op = 0; global_op_class[op].op_class; op++) {
const struct oper_class_map *o = &global_op_class[op];
- u8 ch;
-
- if (o->p2p == NO_P2P_SUPP ||
+ u16 ch;
+ int chan = channel;
+
+ /* Allow DFS channels marked as NO_P2P_SUPP to be used with
+ * driver offloaded DFS. */
+ if ((o->p2p == NO_P2P_SUPP &&
+ (!is_dfs_global_op_class(o->op_class) ||
+ !wpa_s->p2p_go_allow_dfs)) ||
(is_6ghz_op_class(o->op_class) &&
wpa_s->conf->p2p_6ghz_disable))
continue;
+ if (is_6ghz_op_class(o->op_class) && o->bw == BW40 &&
+ get_6ghz_sec_channel(channel) < 0)
+ chan = channel - 4;
+
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
if (o->mode != HOSTAPD_MODE_IEEE80211A ||
- (o->bw != BW40PLUS && o->bw != BW40MINUS) ||
- ch != channel)
+ (o->bw != BW40PLUS && o->bw != BW40MINUS &&
+ o->bw != BW40) ||
+ ch != chan)
continue;
ret = wpas_p2p_verify_channel(wpa_s, mode, o->op_class,
ch, o->bw);
- if (ret == ALLOWED)
+ if (ret == ALLOWED) {
+ if (is_6ghz_op_class(o->op_class) &&
+ o->bw == BW40)
+ return get_6ghz_sec_channel(channel);
+ return (o->bw == BW40MINUS) ? -1 : 1;
+ }
+ if (ret == RADAR && wpa_s->p2p_go_allow_dfs) {
+ /* Allow RADAR channels used for driver
+ * offloaded DFS */
return (o->bw == BW40MINUS) ? -1 : 1;
+ }
}
}
return 0;
@@ -3926,8 +3989,10 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
{
const u8 *chans;
size_t num_chans;
+ enum chan_allowed ret;
- if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW80))
+ ret = wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW80);
+ if (!(ret == ALLOWED || (ret == RADAR && wpa_s->p2p_go_allow_dfs)))
return 0;
if (is_6ghz_op_class(op_class)) {
@@ -3948,8 +4013,10 @@ int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
{
const u8 *chans;
size_t num_chans;
+ enum chan_allowed ret;
- if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW160))
+ ret = wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW160);
+ if (!(ret == ALLOWED || (ret == RADAR && wpa_s->p2p_go_allow_dfs)))
return 0;
if (is_6ghz_op_class(op_class)) {
chans = center_channels_6ghz_160mhz;
@@ -6267,34 +6334,26 @@ static void wpas_p2p_select_go_freq_no_pref(struct wpa_supplicant *wpa_s,
/* try all channels in operating class 115 */
for (i = 0; i < 4; i++) {
params->freq = 5180 + i * 20;
- if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
- freq_included(wpa_s, channels, params->freq) &&
- p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
goto out;
}
/* try all channels in operating class 124 */
for (i = 0; i < 4; i++) {
params->freq = 5745 + i * 20;
- if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
- freq_included(wpa_s, channels, params->freq) &&
- p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
goto out;
}
/* try social channel class 180 channel 2 */
params->freq = 58320 + 1 * 2160;
- if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
- freq_included(wpa_s, channels, params->freq) &&
- p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
goto out;
/* try all channels in reg. class 180 */
for (i = 0; i < 4; i++) {
params->freq = 58320 + i * 2160;
- if (!wpas_p2p_disallowed_freq(wpa_s->global, params->freq) &&
- freq_included(wpa_s, channels, params->freq) &&
- p2p_supported_freq(wpa_s->global->p2p, params->freq))
+ if (wpas_p2p_supported_freq_go(wpa_s, channels, params->freq))
goto out;
}
@@ -6729,6 +6788,11 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
wpa_s->p2p_go_do_acs = 0;
}
+ if (go && wpa_s->p2p_go_allow_dfs) {
+ group_wpa_s->p2p_go_allow_dfs = wpa_s->p2p_go_allow_dfs;
+ wpa_s->p2p_go_allow_dfs = 0;
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
group_wpa_s->ifname);
group_wpa_s->p2p_first_connection_timeout = 0;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index dee9c1bcc1e1..5a869e7309a3 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -146,8 +146,9 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr);
int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
-int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
- struct hostapd_hw_modes *mode, u8 channel);
+int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel);
int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel,
u8 op_class);
diff --git a/wpa_supplicant/p2p_supplicant_sd.c b/wpa_supplicant/p2p_supplicant_sd.c
index f8675e68bec4..b400cbacae61 100644
--- a/wpa_supplicant/p2p_supplicant_sd.c
+++ b/wpa_supplicant/p2p_supplicant_sd.c
@@ -826,7 +826,7 @@ static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
size_t buf_len;
u8 svc_len;
- /* Sanity check fixed length+svc_str */
+ /* Validity check fixed length+svc_str */
if (6 >= tlv_end - pos)
break;
svc_len = pos[6];
@@ -854,7 +854,7 @@ static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
buf_len = WPA_GET_LE16(pos);
pos += sizeof(u16);
- /* Sanity check buffer length */
+ /* Validity check buffer length */
if (buf_len > (unsigned int) (tlv_end - pos))
break;
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 97c16fb80d27..31b55325f7f7 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -220,7 +220,7 @@ static void eapol_test_poll(void *eloop_ctx, void *timeout_ctx)
}
-static struct wpa_driver_ops dummy_driver;
+static struct wpa_driver_ops stub_driver;
static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
@@ -228,8 +228,8 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
struct l2_packet_data *l2;
struct wpa_sm_ctx *ctx;
- os_memset(&dummy_driver, 0, sizeof(dummy_driver));
- wpa_s->driver = &dummy_driver;
+ os_memset(&stub_driver, 0, sizeof(stub_driver));
+ wpa_s->driver = &stub_driver;
ctx = os_zalloc(sizeof(*ctx));
assert(ctx != NULL);
diff --git a/wpa_supplicant/robust_av.c b/wpa_supplicant/robust_av.c
index 39d282f0870d..770c8fcab189 100644
--- a/wpa_supplicant/robust_av.c
+++ b/wpa_supplicant/robust_av.c
@@ -8,6 +8,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_common.h"
#include "wpa_supplicant_i.h"
@@ -15,6 +16,10 @@
#include "bss.h"
+#define SCS_RESP_TIMEOUT 1
+#define DSCP_REQ_TIMEOUT 5
+
+
void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
struct wpabuf *buf)
{
@@ -45,6 +50,126 @@ void wpas_populate_mscs_descriptor_ie(struct robust_av_data *robust_av,
}
+static int wpas_populate_type4_classifier(struct type4_params *type4_param,
+ struct wpabuf *buf)
+{
+ /* classifier parameters */
+ wpabuf_put_u8(buf, type4_param->classifier_mask);
+ if (type4_param->ip_version == IPV4) {
+ wpabuf_put_u8(buf, IPV4); /* IP version */
+ wpabuf_put_data(buf, &type4_param->ip_params.v4.src_ip.s_addr,
+ 4);
+ wpabuf_put_data(buf, &type4_param->ip_params.v4.dst_ip.s_addr,
+ 4);
+ wpabuf_put_be16(buf, type4_param->ip_params.v4.src_port);
+ wpabuf_put_be16(buf, type4_param->ip_params.v4.dst_port);
+ wpabuf_put_u8(buf, type4_param->ip_params.v4.dscp);
+ wpabuf_put_u8(buf, type4_param->ip_params.v4.protocol);
+ wpabuf_put_u8(buf, 0); /* Reserved octet */
+ } else {
+ wpabuf_put_u8(buf, IPV6);
+ wpabuf_put_data(buf, &type4_param->ip_params.v6.src_ip.s6_addr,
+ 16);
+ wpabuf_put_data(buf, &type4_param->ip_params.v6.dst_ip.s6_addr,
+ 16);
+ wpabuf_put_be16(buf, type4_param->ip_params.v6.src_port);
+ wpabuf_put_be16(buf, type4_param->ip_params.v6.dst_port);
+ wpabuf_put_u8(buf, type4_param->ip_params.v6.dscp);
+ wpabuf_put_u8(buf, type4_param->ip_params.v6.next_header);
+ wpabuf_put_data(buf, type4_param->ip_params.v6.flow_label, 3);
+ }
+
+ return 0;
+}
+
+
+static int wpas_populate_type10_classifier(struct type10_params *type10_param,
+ struct wpabuf *buf)
+{
+ /* classifier parameters */
+ wpabuf_put_u8(buf, type10_param->prot_instance);
+ wpabuf_put_u8(buf, type10_param->prot_number);
+ wpabuf_put_data(buf, type10_param->filter_value,
+ type10_param->filter_len);
+ wpabuf_put_data(buf, type10_param->filter_mask,
+ type10_param->filter_len);
+ return 0;
+}
+
+
+static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem,
+ struct wpabuf *buf)
+{
+ u8 *len, *len1;
+ struct tclas_element *tclas_elem;
+ unsigned int i;
+
+ /* SCS Descriptor element */
+ wpabuf_put_u8(buf, WLAN_EID_SCS_DESCRIPTOR);
+ len = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, desc_elem->scs_id);
+ wpabuf_put_u8(buf, desc_elem->request_type);
+ if (desc_elem->request_type == SCS_REQ_REMOVE)
+ goto end;
+
+ if (desc_elem->intra_access_priority || desc_elem->scs_up_avail) {
+ wpabuf_put_u8(buf, WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY);
+ wpabuf_put_u8(buf, 1);
+ wpabuf_put_u8(buf, desc_elem->intra_access_priority);
+ }
+
+ tclas_elem = desc_elem->tclas_elems;
+
+ if (!tclas_elem)
+ return -1;
+
+ for (i = 0; i < desc_elem->num_tclas_elem; i++, tclas_elem++) {
+ int ret;
+
+ /* TCLAS element */
+ wpabuf_put_u8(buf, WLAN_EID_TCLAS);
+ len1 = wpabuf_put(buf, 1);
+ wpabuf_put_u8(buf, 255); /* User Priority: not compared */
+ /* Frame Classifier */
+ wpabuf_put_u8(buf, tclas_elem->classifier_type);
+ /* Frame classifier parameters */
+ switch (tclas_elem->classifier_type) {
+ case 4:
+ ret = wpas_populate_type4_classifier(
+ &tclas_elem->frame_classifier.type4_param,
+ buf);
+ break;
+ case 10:
+ ret = wpas_populate_type10_classifier(
+ &tclas_elem->frame_classifier.type10_param,
+ buf);
+ break;
+ default:
+ return -1;
+ }
+
+ if (ret == -1) {
+ wpa_printf(MSG_ERROR,
+ "Failed to populate frame classifier");
+ return -1;
+ }
+
+ *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1;
+ }
+
+ if (desc_elem->num_tclas_elem > 1) {
+ /* TCLAS Processing element */
+ wpabuf_put_u8(buf, WLAN_EID_TCLAS_PROCESSING);
+ wpabuf_put_u8(buf, 1);
+ wpabuf_put_u8(buf, desc_elem->tclas_processing);
+ }
+
+end:
+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+ return 0;
+}
+
+
int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
{
struct wpabuf *buf;
@@ -101,6 +226,277 @@ int wpas_send_mscs_req(struct wpa_supplicant *wpa_s)
}
+static size_t tclas_elem_len(const struct tclas_element *elem)
+{
+ size_t buf_len = 0;
+
+ buf_len += 2 + /* TCLAS element header */
+ 1 + /* User Priority */
+ 1 ; /* Classifier Type */
+
+ if (elem->classifier_type == 4) {
+ enum ip_version ip_ver;
+
+ buf_len += 1 + /* Classifier mask */
+ 1 + /* IP version */
+ 1 + /* user priority */
+ 2 + /* src_port */
+ 2 + /* dst_port */
+ 1 ; /* dscp */
+ ip_ver = elem->frame_classifier.type4_param.ip_version;
+ if (ip_ver == IPV4) {
+ buf_len += 4 + /* src_ip */
+ 4 + /* dst_ip */
+ 1 + /* protocol */
+ 1 ; /* Reserved */
+ } else if (ip_ver == IPV6) {
+ buf_len += 16 + /* src_ip */
+ 16 + /* dst_ip */
+ 1 + /* next_header */
+ 3 ; /* flow_label */
+ } else {
+ wpa_printf(MSG_ERROR, "%s: Incorrect IP version %d",
+ __func__, ip_ver);
+ return 0;
+ }
+ } else if (elem->classifier_type == 10) {
+ buf_len += 1 + /* protocol instance */
+ 1 + /* protocol number */
+ 2 * elem->frame_classifier.type10_param.filter_len;
+ } else {
+ wpa_printf(MSG_ERROR, "%s: Incorrect classifier type %u",
+ __func__, elem->classifier_type);
+ return 0;
+ }
+
+ return buf_len;
+}
+
+
+static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem,
+ unsigned int num_scs_desc)
+{
+ struct wpabuf *buf;
+ size_t buf_len = 0;
+ unsigned int i, j;
+
+ buf_len = 3; /* Action frame header */
+
+ for (i = 0; i < num_scs_desc; i++, desc_elem++) {
+ struct tclas_element *tclas_elem;
+
+ buf_len += 2 + /* SCS descriptor IE header */
+ 1 + /* SCSID */
+ 1 ; /* Request type */
+
+ if (desc_elem->request_type == SCS_REQ_REMOVE)
+ continue;
+
+ if (desc_elem->intra_access_priority || desc_elem->scs_up_avail)
+ buf_len += 3;
+
+ tclas_elem = desc_elem->tclas_elems;
+ if (!tclas_elem) {
+ wpa_printf(MSG_ERROR, "%s: TCLAS element null",
+ __func__);
+ return NULL;
+ }
+
+ for (j = 0; j < desc_elem->num_tclas_elem; j++, tclas_elem++) {
+ size_t elen;
+
+ elen = tclas_elem_len(tclas_elem);
+ if (elen == 0)
+ return NULL;
+ buf_len += elen;
+ }
+
+ if (desc_elem->num_tclas_elem > 1) {
+ buf_len += 1 + /* TCLAS Processing eid */
+ 1 + /* length */
+ 1 ; /* processing */
+ }
+ }
+
+ buf = wpabuf_alloc(buf_len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "Failed to allocate SCS req");
+ return NULL;
+ }
+
+ return buf;
+}
+
+
+static void scs_request_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct active_scs_elem *scs_desc, *prev;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+ return;
+
+ /* Once timeout is over, remove all SCS descriptors with no response */
+ dl_list_for_each_safe(scs_desc, prev, &wpa_s->active_scs_ids,
+ struct active_scs_elem, list) {
+ u8 bssid[ETH_ALEN] = { 0 };
+ const u8 *src;
+
+ if (scs_desc->status == SCS_DESC_SUCCESS)
+ continue;
+
+ if (wpa_s->current_bss)
+ src = wpa_s->current_bss->bssid;
+ else
+ src = bssid;
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR
+ " SCSID=%u status_code=timedout", MAC2STR(src),
+ scs_desc->scs_id);
+
+ dl_list_del(&scs_desc->list);
+ wpa_printf(MSG_INFO, "%s: SCSID %d removed after timeout",
+ __func__, scs_desc->scs_id);
+ os_free(scs_desc);
+ }
+
+ eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
+ wpa_s->ongoing_scs_req = false;
+}
+
+
+int wpas_send_scs_req(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *buf = NULL;
+ struct scs_desc_elem *desc_elem = NULL;
+ int ret = -1;
+ unsigned int i;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+ return -1;
+
+ if (!wpa_bss_ext_capab(wpa_s->current_bss, WLAN_EXT_CAPAB_SCS)) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "AP does not support SCS - could not send SCS Request");
+ return -1;
+ }
+
+ desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems;
+ if (!desc_elem)
+ return -1;
+
+ buf = allocate_scs_buf(desc_elem,
+ wpa_s->scs_robust_av_req.num_scs_desc);
+ if (!buf)
+ return -1;
+
+ wpabuf_put_u8(buf, WLAN_ACTION_ROBUST_AV_STREAMING);
+ wpabuf_put_u8(buf, ROBUST_AV_SCS_REQ);
+ wpa_s->scs_dialog_token++;
+ if (wpa_s->scs_dialog_token == 0)
+ wpa_s->scs_dialog_token++;
+ wpabuf_put_u8(buf, wpa_s->scs_dialog_token);
+
+ for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc;
+ i++, desc_elem++) {
+ /* SCS Descriptor element */
+ if (wpas_populate_scs_descriptor_ie(desc_elem, buf) < 0)
+ goto end;
+ }
+
+ wpa_hexdump_buf(MSG_DEBUG, "SCS Request", buf);
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret < 0) {
+ wpa_dbg(wpa_s, MSG_ERROR, "SCS: Failed to send SCS Request");
+ wpa_s->scs_dialog_token--;
+ goto end;
+ }
+
+ desc_elem = wpa_s->scs_robust_av_req.scs_desc_elems;
+ for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc;
+ i++, desc_elem++) {
+ struct active_scs_elem *active_scs_elem;
+
+ if (desc_elem->request_type != SCS_REQ_ADD)
+ continue;
+
+ active_scs_elem = os_malloc(sizeof(struct active_scs_elem));
+ if (!active_scs_elem)
+ break;
+ active_scs_elem->scs_id = desc_elem->scs_id;
+ active_scs_elem->status = SCS_DESC_SENT;
+ dl_list_add(&wpa_s->active_scs_ids, &active_scs_elem->list);
+ }
+
+ /*
+ * Register a timeout after which this request will be removed from
+ * the cache.
+ */
+ eloop_register_timeout(SCS_RESP_TIMEOUT, 0, scs_request_timer, wpa_s,
+ NULL);
+ wpa_s->ongoing_scs_req = true;
+
+end:
+ wpabuf_free(buf);
+ free_up_scs_desc(&wpa_s->scs_robust_av_req);
+
+ return ret;
+}
+
+
+void free_up_tclas_elem(struct scs_desc_elem *elem)
+{
+ struct tclas_element *tclas_elems = elem->tclas_elems;
+ unsigned int num_tclas_elem = elem->num_tclas_elem;
+ struct tclas_element *tclas_data;
+ unsigned int j;
+
+ elem->tclas_elems = NULL;
+ elem->num_tclas_elem = 0;
+
+ if (!tclas_elems)
+ return;
+
+ tclas_data = tclas_elems;
+ for (j = 0; j < num_tclas_elem; j++, tclas_data++) {
+ if (tclas_data->classifier_type != 10)
+ continue;
+
+ os_free(tclas_data->frame_classifier.type10_param.filter_value);
+ os_free(tclas_data->frame_classifier.type10_param.filter_mask);
+ }
+
+ os_free(tclas_elems);
+}
+
+
+void free_up_scs_desc(struct scs_robust_av_data *data)
+{
+ struct scs_desc_elem *desc_elems = data->scs_desc_elems;
+ unsigned int num_scs_desc = data->num_scs_desc;
+ struct scs_desc_elem *desc_data;
+ unsigned int i;
+
+ data->scs_desc_elems = NULL;
+ data->num_scs_desc = 0;
+
+ if (!desc_elems)
+ return;
+
+ desc_data = desc_elems;
+ for (i = 0; i < num_scs_desc; i++, desc_data++) {
+ if (desc_data->request_type == SCS_REQ_REMOVE ||
+ !desc_data->tclas_elems)
+ continue;
+
+ free_up_tclas_elem(desc_data);
+ }
+ os_free(desc_elems);
+}
+
+
void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
const u8 *src, const u8 *buf, size_t len)
{
@@ -153,3 +549,939 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
" status_code=%u", MAC2STR(bssid), status);
wpa_s->mscs_setup_done = status == WLAN_STATUS_SUCCESS;
}
+
+
+static void wpas_wait_for_dscp_req_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ /* Once timeout is over, reset wait flag and allow sending DSCP query */
+ wpa_printf(MSG_DEBUG,
+ "QM: Wait time over for sending DSCP request - allow DSCP query");
+ wpa_s->wait_for_dscp_req = 0;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_wait end");
+}
+
+
+void wpas_handle_assoc_resp_qos_mgmt(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len)
+{
+ const u8 *wfa_capa;
+
+ wpa_s->connection_dscp = 0;
+ if (wpa_s->wait_for_dscp_req)
+ eloop_cancel_timeout(wpas_wait_for_dscp_req_timer, wpa_s, NULL);
+
+ if (!ies || ies_len == 0 || !wpa_s->enable_dscp_policy_capa)
+ return;
+
+ wfa_capa = get_vendor_ie(ies, ies_len, WFA_CAPA_IE_VENDOR_TYPE);
+ if (!wfa_capa || wfa_capa[1] < 6 || wfa_capa[6] < 1 ||
+ !(wfa_capa[7] & WFA_CAPA_QM_DSCP_POLICY))
+ return; /* AP does not enable QM DSCP Policy */
+
+ wpa_s->connection_dscp = 1;
+ wpa_s->wait_for_dscp_req = !!(wfa_capa[7] &
+ WFA_CAPA_QM_UNSOLIC_DSCP);
+ if (!wpa_s->wait_for_dscp_req)
+ return;
+
+ /* Register a timeout after which dscp query can be sent to AP. */
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_wait start");
+ eloop_register_timeout(DSCP_REQ_TIMEOUT, 0,
+ wpas_wait_for_dscp_req_timer, wpa_s, NULL);
+}
+
+
+void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf,
+ size_t len)
+{
+ u8 dialog_token;
+ unsigned int i, count;
+ struct active_scs_elem *scs_desc, *prev;
+
+ if (len < 2)
+ return;
+ if (!wpa_s->ongoing_scs_req) {
+ wpa_printf(MSG_INFO,
+ "SCS: Drop received response due to no ongoing request");
+ return;
+ }
+
+ dialog_token = *buf++;
+ len--;
+ if (dialog_token != wpa_s->scs_dialog_token) {
+ wpa_printf(MSG_INFO,
+ "SCS: Drop received frame due to dialog token mismatch: received:%u expected:%u",
+ dialog_token, wpa_s->scs_dialog_token);
+ return;
+ }
+
+ /* This Count field does not exist in the IEEE Std 802.11-2020
+ * definition of the SCS Response frame. However, it was accepted to
+ * be added into REVme per REVme/D0.0 CC35 CID 49 (edits in document
+ * 11-21-0688-07). */
+ count = *buf++;
+ len--;
+ if (count == 0 || count * 3 > len) {
+ wpa_printf(MSG_INFO,
+ "SCS: Drop received frame due to invalid count: %u (remaining %zu octets)",
+ count, len);
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ u8 id;
+ u16 status;
+ bool scs_desc_found = false;
+
+ id = *buf++;
+ status = WPA_GET_LE16(buf);
+ buf += 2;
+ len -= 3;
+
+ dl_list_for_each(scs_desc, &wpa_s->active_scs_ids,
+ struct active_scs_elem, list) {
+ if (id == scs_desc->scs_id) {
+ scs_desc_found = true;
+ break;
+ }
+ }
+
+ if (!scs_desc_found) {
+ wpa_printf(MSG_INFO, "SCS: SCS ID invalid %u", id);
+ continue;
+ }
+
+ if (status != WLAN_STATUS_SUCCESS) {
+ dl_list_del(&scs_desc->list);
+ os_free(scs_desc);
+ } else if (status == WLAN_STATUS_SUCCESS) {
+ scs_desc->status = SCS_DESC_SUCCESS;
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCS_RESULT "bssid=" MACSTR
+ " SCSID=%u status_code=%u", MAC2STR(src), id, status);
+ }
+
+ eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
+ wpa_s->ongoing_scs_req = false;
+
+ dl_list_for_each_safe(scs_desc, prev, &wpa_s->active_scs_ids,
+ struct active_scs_elem, list) {
+ if (scs_desc->status != SCS_DESC_SUCCESS) {
+ wpa_msg(wpa_s, MSG_INFO,
+ WPA_EVENT_SCS_RESULT "bssid=" MACSTR
+ " SCSID=%u status_code=response_not_received",
+ MAC2STR(src), scs_desc->scs_id);
+ dl_list_del(&scs_desc->list);
+ os_free(scs_desc);
+ }
+ }
+}
+
+
+static void wpas_clear_active_scs_ids(struct wpa_supplicant *wpa_s)
+{
+ struct active_scs_elem *scs_elem;
+
+ while ((scs_elem = dl_list_first(&wpa_s->active_scs_ids,
+ struct active_scs_elem, list))) {
+ dl_list_del(&scs_elem->list);
+ os_free(scs_elem);
+ }
+}
+
+
+void wpas_scs_deinit(struct wpa_supplicant *wpa_s)
+{
+ free_up_scs_desc(&wpa_s->scs_robust_av_req);
+ wpa_s->scs_dialog_token = 0;
+ wpas_clear_active_scs_ids(wpa_s);
+ eloop_cancel_timeout(scs_request_timer, wpa_s, NULL);
+ wpa_s->ongoing_scs_req = false;
+}
+
+
+static int write_ipv4_info(char *pos, int total_len,
+ const struct ipv4_params *v4)
+{
+ int res, rem_len;
+ char addr[INET_ADDRSTRLEN];
+
+ rem_len = total_len;
+
+ if (v4->param_mask & BIT(1)) {
+ if (!inet_ntop(AF_INET, &v4->src_ip, addr, INET_ADDRSTRLEN)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to set IPv4 source address");
+ return -1;
+ }
+
+ res = os_snprintf(pos, rem_len, " src_ip=%s", addr);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ if (v4->param_mask & BIT(2)) {
+ if (!inet_ntop(AF_INET, &v4->dst_ip, addr, INET_ADDRSTRLEN)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to set IPv4 destination address");
+ return -1;
+ }
+
+ res = os_snprintf(pos, rem_len, " dst_ip=%s", addr);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ if (v4->param_mask & BIT(3)) {
+ res = os_snprintf(pos, rem_len, " src_port=%d", v4->src_port);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ if (v4->param_mask & BIT(4)) {
+ res = os_snprintf(pos, rem_len, " dst_port=%d", v4->dst_port);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ if (v4->param_mask & BIT(6)) {
+ res = os_snprintf(pos, rem_len, " protocol=%d", v4->protocol);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ return total_len - rem_len;
+}
+
+
+static int write_ipv6_info(char *pos, int total_len,
+ const struct ipv6_params *v6)
+{
+ int res, rem_len;
+ char addr[INET6_ADDRSTRLEN];
+
+ rem_len = total_len;
+
+ if (v6->param_mask & BIT(1)) {
+ if (!inet_ntop(AF_INET6, &v6->src_ip, addr, INET6_ADDRSTRLEN)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to set IPv6 source addr");
+ return -1;
+ }
+
+ res = os_snprintf(pos, rem_len, " src_ip=%s", addr);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ if (v6->param_mask & BIT(2)) {
+ if (!inet_ntop(AF_INET6, &v6->dst_ip, addr, INET6_ADDRSTRLEN)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to set IPv6 destination addr");
+ return -1;
+ }
+
+ res = os_snprintf(pos, rem_len, " dst_ip=%s", addr);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ if (v6->param_mask & BIT(3)) {
+ res = os_snprintf(pos, rem_len, " src_port=%d", v6->src_port);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ if (v6->param_mask & BIT(4)) {
+ res = os_snprintf(pos, rem_len, " dst_port=%d", v6->dst_port);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ if (v6->param_mask & BIT(6)) {
+ res = os_snprintf(pos, rem_len, " protocol=%d",
+ v6->next_header);
+ if (os_snprintf_error(rem_len, res))
+ return -1;
+
+ pos += res;
+ rem_len -= res;
+ }
+
+ return total_len - rem_len;
+}
+
+
+struct dscp_policy_data {
+ u8 policy_id;
+ u8 req_type;
+ u8 dscp;
+ bool dscp_info;
+ const u8 *frame_classifier;
+ u8 frame_classifier_len;
+ struct type4_params type4_param;
+ const u8 *domain_name;
+ u8 domain_name_len;
+ u16 start_port;
+ u16 end_port;
+ bool port_range_info;
+};
+
+
+static int set_frame_classifier_type4_ipv4(struct dscp_policy_data *policy)
+{
+ u8 classifier_mask;
+ const u8 *frame_classifier = policy->frame_classifier;
+ struct type4_params *type4_param = &policy->type4_param;
+
+ if (policy->frame_classifier_len < 18) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received IPv4 frame classifier with insufficient length %d",
+ policy->frame_classifier_len);
+ return -1;
+ }
+
+ classifier_mask = frame_classifier[1];
+
+ /* Classifier Mask - bit 1 = Source IP Address */
+ if (classifier_mask & BIT(1)) {
+ type4_param->ip_params.v4.param_mask |= BIT(1);
+ os_memcpy(&type4_param->ip_params.v4.src_ip,
+ &frame_classifier[3], 4);
+ }
+
+ /* Classifier Mask - bit 2 = Destination IP Address */
+ if (classifier_mask & BIT(2)) {
+ if (policy->domain_name) {
+ wpa_printf(MSG_ERROR,
+ "QM: IPv4: Both domain name and destination IP address not expected");
+ return -1;
+ }
+
+ type4_param->ip_params.v4.param_mask |= BIT(2);
+ os_memcpy(&type4_param->ip_params.v4.dst_ip,
+ &frame_classifier[7], 4);
+ }
+
+ /* Classifier Mask - bit 3 = Source Port */
+ if (classifier_mask & BIT(3)) {
+ type4_param->ip_params.v4.param_mask |= BIT(3);
+ type4_param->ip_params.v4.src_port =
+ WPA_GET_BE16(&frame_classifier[11]);
+ }
+
+ /* Classifier Mask - bit 4 = Destination Port */
+ if (classifier_mask & BIT(4)) {
+ if (policy->port_range_info) {
+ wpa_printf(MSG_ERROR,
+ "QM: IPv4: Both port range and destination port not expected");
+ return -1;
+ }
+
+ type4_param->ip_params.v4.param_mask |= BIT(4);
+ type4_param->ip_params.v4.dst_port =
+ WPA_GET_BE16(&frame_classifier[13]);
+ }
+
+ /* Classifier Mask - bit 5 = DSCP (ignored) */
+
+ /* Classifier Mask - bit 6 = Protocol */
+ if (classifier_mask & BIT(6)) {
+ type4_param->ip_params.v4.param_mask |= BIT(6);
+ type4_param->ip_params.v4.protocol = frame_classifier[16];
+ }
+
+ return 0;
+}
+
+
+static int set_frame_classifier_type4_ipv6(struct dscp_policy_data *policy)
+{
+ u8 classifier_mask;
+ const u8 *frame_classifier = policy->frame_classifier;
+ struct type4_params *type4_param = &policy->type4_param;
+
+ if (policy->frame_classifier_len < 44) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received IPv6 frame classifier with insufficient length %d",
+ policy->frame_classifier_len);
+ return -1;
+ }
+
+ classifier_mask = frame_classifier[1];
+
+ /* Classifier Mask - bit 1 = Source IP Address */
+ if (classifier_mask & BIT(1)) {
+ type4_param->ip_params.v6.param_mask |= BIT(1);
+ os_memcpy(&type4_param->ip_params.v6.src_ip,
+ &frame_classifier[3], 16);
+ }
+
+ /* Classifier Mask - bit 2 = Destination IP Address */
+ if (classifier_mask & BIT(2)) {
+ if (policy->domain_name) {
+ wpa_printf(MSG_ERROR,
+ "QM: IPv6: Both domain name and destination IP address not expected");
+ return -1;
+ }
+ type4_param->ip_params.v6.param_mask |= BIT(2);
+ os_memcpy(&type4_param->ip_params.v6.dst_ip,
+ &frame_classifier[19], 16);
+ }
+
+ /* Classifier Mask - bit 3 = Source Port */
+ if (classifier_mask & BIT(3)) {
+ type4_param->ip_params.v6.param_mask |= BIT(3);
+ type4_param->ip_params.v6.src_port =
+ WPA_GET_BE16(&frame_classifier[35]);
+ }
+
+ /* Classifier Mask - bit 4 = Destination Port */
+ if (classifier_mask & BIT(4)) {
+ if (policy->port_range_info) {
+ wpa_printf(MSG_ERROR,
+ "IPv6: Both port range and destination port not expected");
+ return -1;
+ }
+
+ type4_param->ip_params.v6.param_mask |= BIT(4);
+ type4_param->ip_params.v6.dst_port =
+ WPA_GET_BE16(&frame_classifier[37]);
+ }
+
+ /* Classifier Mask - bit 5 = DSCP (ignored) */
+
+ /* Classifier Mask - bit 6 = Next Header */
+ if (classifier_mask & BIT(6)) {
+ type4_param->ip_params.v6.param_mask |= BIT(6);
+ type4_param->ip_params.v6.next_header = frame_classifier[40];
+ }
+
+ return 0;
+}
+
+
+static int wpas_set_frame_classifier_params(struct dscp_policy_data *policy)
+{
+ const u8 *frame_classifier = policy->frame_classifier;
+ u8 frame_classifier_len = policy->frame_classifier_len;
+
+ if (frame_classifier_len < 3) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received frame classifier with insufficient length %d",
+ frame_classifier_len);
+ return -1;
+ }
+
+ /* Only allowed Classifier Type: IP and higher layer parameters (4) */
+ if (frame_classifier[0] != 4) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received frame classifier with invalid classifier type %d",
+ frame_classifier[0]);
+ return -1;
+ }
+
+ /* Classifier Mask - bit 0 = Version */
+ if (!(frame_classifier[1] & BIT(0))) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received frame classifier without IP version");
+ return -1;
+ }
+
+ /* Version (4 or 6) */
+ if (frame_classifier[2] == 4) {
+ if (set_frame_classifier_type4_ipv4(policy)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to set IPv4 parameters");
+ return -1;
+ }
+
+ policy->type4_param.ip_version = IPV4;
+ } else if (frame_classifier[2] == 6) {
+ if (set_frame_classifier_type4_ipv6(policy)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to set IPv6 parameters");
+ return -1;
+ }
+
+ policy->type4_param.ip_version = IPV6;
+ } else {
+ wpa_printf(MSG_ERROR,
+ "QM: Received unknown IP version %d",
+ frame_classifier[2]);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static bool dscp_valid_domain_name(const char *str)
+{
+ if (!str[0])
+ return false;
+
+ while (*str) {
+ if (is_ctrl_char(*str) || *str == ' ' || *str == '=')
+ return false;
+ str++;
+ }
+
+ return true;
+}
+
+
+static void wpas_add_dscp_policy(struct wpa_supplicant *wpa_s,
+ struct dscp_policy_data *policy)
+{
+ int ip_ver = 0, res;
+ char policy_str[1000], *pos;
+ int len;
+
+ if (!policy->frame_classifier && !policy->domain_name &&
+ !policy->port_range_info) {
+ wpa_printf(MSG_ERROR,
+ "QM: Invalid DSCP policy - no attributes present");
+ goto fail;
+ }
+
+ policy_str[0] = '\0';
+ pos = policy_str;
+ len = sizeof(policy_str);
+
+ if (policy->frame_classifier) {
+ struct type4_params *type4 = &policy->type4_param;
+
+ if (wpas_set_frame_classifier_params(policy)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to set frame classifier parameters");
+ goto fail;
+ }
+
+ if (type4->ip_version == IPV4)
+ res = write_ipv4_info(pos, len, &type4->ip_params.v4);
+ else
+ res = write_ipv6_info(pos, len, &type4->ip_params.v6);
+
+ if (res <= 0) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to write IP parameters");
+ goto fail;
+ }
+
+ ip_ver = type4->ip_version;
+
+ pos += res;
+ len -= res;
+ }
+
+ if (policy->port_range_info) {
+ res = os_snprintf(pos, len, " start_port=%u end_port=%u",
+ policy->start_port, policy->end_port);
+ if (os_snprintf_error(len, res)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to write port range attributes for policy id = %d",
+ policy->policy_id);
+ goto fail;
+ }
+
+ pos += res;
+ len -= res;
+ }
+
+ if (policy->domain_name) {
+ char domain_name_str[250];
+
+ if (policy->domain_name_len >= sizeof(domain_name_str)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Domain name length higher than max expected");
+ goto fail;
+ }
+ os_memcpy(domain_name_str, policy->domain_name,
+ policy->domain_name_len);
+ domain_name_str[policy->domain_name_len] = '\0';
+ if (!dscp_valid_domain_name(domain_name_str)) {
+ wpa_printf(MSG_ERROR, "QM: Invalid domain name string");
+ goto fail;
+ }
+ res = os_snprintf(pos, len, " domain_name=%s", domain_name_str);
+ if (os_snprintf_error(len, res)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to write domain name attribute for policy id = %d",
+ policy->policy_id);
+ goto fail;
+ }
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY
+ "add policy_id=%u dscp=%u ip_version=%d%s",
+ policy->policy_id, policy->dscp, ip_ver, policy_str);
+ return;
+fail:
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "reject policy_id=%u",
+ policy->policy_id);
+}
+
+
+void wpas_dscp_deinit(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "QM: Clear all active DSCP policies");
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "clear_all");
+ wpa_s->dscp_req_dialog_token = 0;
+ wpa_s->dscp_query_dialog_token = 0;
+ wpa_s->connection_dscp = 0;
+ if (wpa_s->wait_for_dscp_req) {
+ wpa_s->wait_for_dscp_req = 0;
+ eloop_cancel_timeout(wpas_wait_for_dscp_req_timer, wpa_s, NULL);
+ }
+}
+
+
+static void wpas_fill_dscp_policy(struct dscp_policy_data *policy, u8 attr_id,
+ u8 attr_len, const u8 *attr_data)
+{
+ switch (attr_id) {
+ case QM_ATTR_PORT_RANGE:
+ if (attr_len < 4) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received Port Range attribute with insufficient length %d",
+ attr_len);
+ break;
+ }
+ policy->start_port = WPA_GET_BE16(attr_data);
+ policy->end_port = WPA_GET_BE16(attr_data + 2);
+ policy->port_range_info = true;
+ break;
+ case QM_ATTR_DSCP_POLICY:
+ if (attr_len < 3) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received DSCP Policy attribute with insufficient length %d",
+ attr_len);
+ return;
+ }
+ policy->policy_id = attr_data[0];
+ policy->req_type = attr_data[1];
+ policy->dscp = attr_data[2];
+ policy->dscp_info = true;
+ break;
+ case QM_ATTR_TCLAS:
+ if (attr_len < 1) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received TCLAS attribute with insufficient length %d",
+ attr_len);
+ return;
+ }
+ policy->frame_classifier = attr_data;
+ policy->frame_classifier_len = attr_len;
+ break;
+ case QM_ATTR_DOMAIN_NAME:
+ if (attr_len < 1) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received domain name attribute with insufficient length %d",
+ attr_len);
+ return;
+ }
+ policy->domain_name = attr_data;
+ policy->domain_name_len = attr_len;
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "QM: Received invalid QoS attribute %d",
+ attr_id);
+ break;
+ }
+}
+
+
+void wpas_handle_qos_mgmt_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *buf, size_t len)
+{
+ int rem_len;
+ const u8 *qos_ie, *attr;
+ int more, reset;
+
+ if (!wpa_s->enable_dscp_policy_capa) {
+ wpa_printf(MSG_ERROR,
+ "QM: Ignore DSCP Policy frame since the capability is not enabled");
+ return;
+ }
+
+ if (!pmf_in_use(wpa_s, src)) {
+ wpa_printf(MSG_ERROR,
+ "QM: Ignore DSCP Policy frame since PMF is not in use");
+ return;
+ }
+
+ if (!wpa_s->connection_dscp) {
+ wpa_printf(MSG_DEBUG,
+ "QM: DSCP Policy capability not enabled for the current association - ignore QoS Management Action frames");
+ return;
+ }
+
+ if (len < 1)
+ return;
+
+ /* Handle only DSCP Policy Request frame */
+ if (buf[0] != QM_DSCP_POLICY_REQ) {
+ wpa_printf(MSG_ERROR, "QM: Received unexpected QoS action frame %d",
+ buf[0]);
+ return;
+ }
+
+ if (len < 3) {
+ wpa_printf(MSG_ERROR,
+ "Received QoS Management DSCP Policy Request frame with invalid length %zu",
+ len);
+ return;
+ }
+
+ /* Clear wait_for_dscp_req on receiving first DSCP request from AP */
+ if (wpa_s->wait_for_dscp_req) {
+ wpa_s->wait_for_dscp_req = 0;
+ eloop_cancel_timeout(wpas_wait_for_dscp_req_timer, wpa_s, NULL);
+ }
+
+ wpa_s->dscp_req_dialog_token = buf[1];
+ more = buf[2] & DSCP_POLICY_CTRL_MORE;
+ reset = buf[2] & DSCP_POLICY_CTRL_RESET;
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_start%s%s",
+ reset ? " clear_all" : "", more ? " more" : "");
+
+ qos_ie = buf + 3;
+ rem_len = len - 3;
+ while (rem_len > 2) {
+ struct dscp_policy_data policy;
+ int rem_attrs_len, ie_len;
+
+ ie_len = 2 + qos_ie[1];
+ if (rem_len < ie_len)
+ break;
+
+ if (rem_len < 6 || qos_ie[0] != WLAN_EID_VENDOR_SPECIFIC ||
+ qos_ie[1] < 4 ||
+ WPA_GET_BE32(&qos_ie[2]) != QM_IE_VENDOR_TYPE) {
+ rem_len -= ie_len;
+ qos_ie += ie_len;
+ continue;
+ }
+
+ os_memset(&policy, 0, sizeof(struct dscp_policy_data));
+ attr = qos_ie + 6;
+ rem_attrs_len = qos_ie[1] - 4;
+
+ while (rem_attrs_len > 2 && rem_attrs_len >= 2 + attr[1]) {
+ wpas_fill_dscp_policy(&policy, attr[0], attr[1],
+ &attr[2]);
+ rem_attrs_len -= 2 + attr[1];
+ attr += 2 + attr[1];
+ }
+
+ rem_len -= ie_len;
+ qos_ie += ie_len;
+
+ if (!policy.dscp_info) {
+ wpa_printf(MSG_ERROR,
+ "QM: Received QoS IE without DSCP Policy attribute");
+ continue;
+ }
+
+ if (policy.req_type == DSCP_POLICY_REQ_ADD)
+ wpas_add_dscp_policy(wpa_s, &policy);
+ else if (policy.req_type == DSCP_POLICY_REQ_REMOVE)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY
+ "remove policy_id=%u", policy.policy_id);
+ else
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY
+ "reject policy_id=%u", policy.policy_id);
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DSCP_POLICY "request_end");
+}
+
+
+int wpas_send_dscp_response(struct wpa_supplicant *wpa_s,
+ struct dscp_resp_data *resp_data)
+{
+ struct wpabuf *buf = NULL;
+ size_t buf_len;
+ int ret = -1, i;
+ u8 resp_control = 0;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to send DSCP response - not connected to AP");
+ return -1;
+ }
+
+ if (resp_data->solicited && !wpa_s->dscp_req_dialog_token) {
+ wpa_printf(MSG_ERROR, "QM: No ongoing DSCP request");
+ return -1;
+ }
+
+ if (!wpa_s->connection_dscp) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to send DSCP response - DSCP capability not enabled for the current association");
+ return -1;
+
+ }
+
+ buf_len = 1 + /* Category */
+ 3 + /* OUI */
+ 1 + /* OUI Type */
+ 1 + /* OUI Subtype */
+ 1 + /* Dialog Token */
+ 1 + /* Response Control */
+ 1 + /* Count */
+ 2 * resp_data->num_policies; /* Status list */
+ buf = wpabuf_alloc(buf_len);
+ if (!buf) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to allocate DSCP policy response");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, QM_ACTION_OUI_TYPE);
+ wpabuf_put_u8(buf, QM_DSCP_POLICY_RESP);
+
+ wpabuf_put_u8(buf, resp_data->solicited ?
+ wpa_s->dscp_req_dialog_token : 0);
+
+ if (resp_data->more)
+ resp_control |= DSCP_POLICY_CTRL_MORE;
+ if (resp_data->reset)
+ resp_control |= DSCP_POLICY_CTRL_RESET;
+ wpabuf_put_u8(buf, resp_control);
+
+ wpabuf_put_u8(buf, resp_data->num_policies);
+ for (i = 0; i < resp_data->num_policies; i++) {
+ wpabuf_put_u8(buf, resp_data->policy[i].id);
+ wpabuf_put_u8(buf, resp_data->policy[i].status);
+ }
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "DSCP response frame: ", buf);
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret < 0) {
+ wpa_msg(wpa_s, MSG_INFO, "QM: Failed to send DSCP response");
+ goto fail;
+ }
+
+ /*
+ * Mark DSCP request complete whether response sent is solicited or
+ * unsolicited
+ */
+ wpa_s->dscp_req_dialog_token = 0;
+
+fail:
+ wpabuf_free(buf);
+ return ret;
+}
+
+
+int wpas_send_dscp_query(struct wpa_supplicant *wpa_s, const char *domain_name,
+ size_t domain_name_length)
+{
+ struct wpabuf *buf = NULL;
+ int ret, dscp_query_size;
+
+ if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid)
+ return -1;
+
+ if (!wpa_s->connection_dscp) {
+ wpa_printf(MSG_ERROR,
+ "QM: Failed to send DSCP query - DSCP capability not enabled for the current association");
+ return -1;
+ }
+
+ if (wpa_s->wait_for_dscp_req) {
+ wpa_printf(MSG_INFO, "QM: Wait until AP sends a DSCP request");
+ return -1;
+ }
+
+#define DOMAIN_NAME_OFFSET (4 /* OUI */ + 1 /* Attr Id */ + 1 /* Attr len */)
+
+ if (domain_name_length > 255 - DOMAIN_NAME_OFFSET) {
+ wpa_printf(MSG_ERROR, "QM: Too long domain name");
+ return -1;
+ }
+
+ dscp_query_size = 1 + /* Category */
+ 4 + /* OUI Type */
+ 1 + /* OUI subtype */
+ 1; /* Dialog Token */
+ if (domain_name && domain_name_length)
+ dscp_query_size += 1 + /* Element ID */
+ 1 + /* IE Length */
+ DOMAIN_NAME_OFFSET + domain_name_length;
+
+ buf = wpabuf_alloc(dscp_query_size);
+ if (!buf) {
+ wpa_printf(MSG_ERROR, "QM: Failed to allocate DSCP query");
+ return -1;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED);
+ wpabuf_put_be32(buf, QM_ACTION_VENDOR_TYPE);
+ wpabuf_put_u8(buf, QM_DSCP_POLICY_QUERY);
+ wpa_s->dscp_query_dialog_token++;
+ if (wpa_s->dscp_query_dialog_token == 0)
+ wpa_s->dscp_query_dialog_token++;
+ wpabuf_put_u8(buf, wpa_s->dscp_query_dialog_token);
+
+ if (domain_name && domain_name_length) {
+ /* Domain Name attribute */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(buf, DOMAIN_NAME_OFFSET + domain_name_length);
+ wpabuf_put_be32(buf, QM_IE_VENDOR_TYPE);
+ wpabuf_put_u8(buf, QM_ATTR_DOMAIN_NAME);
+ wpabuf_put_u8(buf, domain_name_length);
+ wpabuf_put_data(buf, domain_name, domain_name_length);
+ }
+#undef DOMAIN_NAME_OFFSET
+
+ ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0);
+ if (ret < 0) {
+ wpa_dbg(wpa_s, MSG_ERROR, "QM: Failed to send DSCP query");
+ wpa_s->dscp_query_dialog_token--;
+ }
+
+ wpabuf_free(buf);
+ return ret;
+}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 97a8d9a638d6..b0094ca6ca5b 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -392,6 +392,29 @@ wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids)
}
+#ifdef CONFIG_P2P
+static bool is_6ghz_supported(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_channel_data *chnl;
+ int i, j;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211A) {
+ chnl = wpa_s->hw.modes[i].channels;
+ for (j = 0; j < wpa_s->hw.modes[i].num_channels; j++) {
+ if (chnl[j].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+ if (is_6ghz_freq(chnl[j].freq))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+#endif /* CONFIG_P2P */
+
+
static void wpa_supplicant_optimize_freqs(
struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params)
{
@@ -729,13 +752,13 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s,
if (wpa_s->setband_mask & WPA_SETBAND_5G)
wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
- 0);
+ false);
if (wpa_s->setband_mask & WPA_SETBAND_2G)
wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
- 0);
+ false);
if (wpa_s->setband_mask & WPA_SETBAND_6G)
wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
- 1);
+ true);
}
@@ -1337,6 +1360,34 @@ scan:
}
}
}
+
+ if (!params.freqs &&
+ (wpa_s->p2p_in_invitation || wpa_s->p2p_in_provisioning) &&
+ !is_p2p_allow_6ghz(wpa_s->global->p2p) &&
+ is_6ghz_supported(wpa_s)) {
+ int i;
+
+ /* Exclude 5 GHz channels from the full scan for P2P connection
+ * since the 6 GHz band is disabled for P2P uses. */
+ wpa_printf(MSG_DEBUG,
+ "P2P: 6 GHz disabled - update the scan frequency list");
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ if (wpa_s->hw.modes[i].num_channels == 0)
+ continue;
+ if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211G)
+ wpa_add_scan_freqs_list(
+ wpa_s, HOSTAPD_MODE_IEEE80211G,
+ &params, false);
+ if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211A)
+ wpa_add_scan_freqs_list(
+ wpa_s, HOSTAPD_MODE_IEEE80211A,
+ &params, false);
+ if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211AD)
+ wpa_add_scan_freqs_list(
+ wpa_s, HOSTAPD_MODE_IEEE80211AD,
+ &params, false);
+ }
+ }
#endif /* CONFIG_P2P */
ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.in b/wpa_supplicant/systemd/wpa_supplicant.service.in
index 75a37a8cdbd3..58a622887cd9 100644
--- a/wpa_supplicant/systemd/wpa_supplicant.service.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.in
@@ -1,6 +1,7 @@
[Unit]
Description=WPA supplicant
Before=network.target
+After=dbus.service
Wants=network.target
[Service]
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index fea7b85e081d..b72983e9c3f7 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -499,6 +499,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"p2p_search_delay", "mac_addr", "rand_addr_lifetime",
"preassoc_mac_addr", "key_mgmt_offload", "passive_scan",
"reassoc_same_bss_optim", "wps_priority",
+ "ap_assocresp_elements",
#ifdef CONFIG_TESTING_OPTIONS
"ignore_auth_resp",
#endif /* CONFIG_TESTING_OPTIONS */
@@ -2037,6 +2038,13 @@ static int wpa_cli_cmd_chanswitch(struct wpa_ctrl *ctrl, int argc,
return wpa_cli_cmd(ctrl, "CHAN_SWITCH", 2, argc, argv);
}
+
+static int wpa_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "UPDATE_BEACON");
+}
+
#endif /* CONFIG_AP */
@@ -3220,6 +3228,30 @@ static int wpa_cli_cmd_pasn_deauth(struct wpa_ctrl *ctrl, int argc,
#endif /* CONFIG_PASN */
+static int wpa_cli_cmd_mscs(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "MSCS", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_scs(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "SCS", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dscp_resp(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DSCP_RESP", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_dscp_query(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DSCP_QUERY", 1, argc, argv);
+}
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -3563,6 +3595,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
"<cs_count> <freq> [sec_channel_offset=] [center_freq1=]"
" [center_freq2=] [bandwidth=] [blocktx] [ht|vht]"
" = CSA parameters" },
+ { "update_beacon", wpa_cli_cmd_update_beacon, NULL,
+ cli_cmd_flag_none,
+ "= update Beacon frame contents"},
#endif /* CONFIG_AP */
{ "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
"= notification of suspend/hibernate" },
@@ -3924,6 +3959,18 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = {
cli_cmd_flag_none,
"bssid=<BSSID> = Remove PASN PTKSA state" },
#endif /* CONFIG_PASN */
+ { "mscs", wpa_cli_cmd_mscs, NULL,
+ cli_cmd_flag_none,
+ "<add|remove|change> [up_bitmap=<hex byte>] [up_limit=<integer>] [stream_timeout=<in TUs>] [frame_classifier=<hex bytes>] = Configure MSCS request" },
+ { "scs", wpa_cli_cmd_scs, NULL,
+ cli_cmd_flag_none,
+ "[scs_id=<decimal number>] <add|remove|change> [scs_up=<0-7>] [classifier_type=<4|10>] [classifier params based on classifier type] [tclas_processing=<0|1>] [scs_id=<decimal number>] ... = Send SCS request" },
+ { "dscp_resp", wpa_cli_cmd_dscp_resp, NULL,
+ cli_cmd_flag_none,
+ "<[reset]>/<[solicited] [policy_id=1 status=0...]> [more] = Send DSCP response" },
+ { "dscp_query", wpa_cli_cmd_dscp_query, NULL,
+ cli_cmd_flag_none,
+ "wildcard/domain_name=<string> = Send DSCP Query" },
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index cc184dba5feb..b80f1d4f0b38 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -743,6 +743,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
#ifdef CONFIG_PASN
wpas_pasn_auth_stop(wpa_s);
#endif /* CONFIG_PASN */
+ wpas_scs_deinit(wpa_s);
+ wpas_dscp_deinit(wpa_s);
}
@@ -1295,6 +1297,47 @@ static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie,
}
+void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct wpa_ie_data *ie)
+{
+ int sel;
+
+ sel = ie->mgmt_group_cipher;
+ if (ssid->group_mgmt_cipher)
+ sel &= ssid->group_mgmt_cipher;
+ if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
+ !(ie->capabilities & WPA_CAPABILITY_MFPC))
+ sel = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
+ ie->mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
+ if (sel & WPA_CIPHER_AES_128_CMAC) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using MGMT group cipher AES-128-CMAC");
+ } else if (sel & WPA_CIPHER_BIP_GMAC_128) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using MGMT group cipher BIP-GMAC-128");
+ } else if (sel & WPA_CIPHER_BIP_GMAC_256) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using MGMT group cipher BIP-GMAC-256");
+ } else if (sel & WPA_CIPHER_BIP_CMAC_256) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "WPA: using MGMT group cipher BIP-CMAC-256");
+ } else {
+ wpa_s->mgmt_group_cipher = 0;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
+ }
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
+ wpa_s->mgmt_group_cipher);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+ wpas_get_ssid_pmf(wpa_s, ssid));
+}
+
+
/**
* wpa_supplicant_set_suites - Set authentication and encryption parameters
* @wpa_s: Pointer to wpa_supplicant data
@@ -1628,39 +1671,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
return -1;
}
- sel = ie.mgmt_group_cipher;
- if (ssid->group_mgmt_cipher)
- sel &= ssid->group_mgmt_cipher;
- if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
- !(ie.capabilities & WPA_CAPABILITY_MFPC))
- sel = 0;
- wpa_dbg(wpa_s, MSG_DEBUG,
- "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
- ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
- if (sel & WPA_CIPHER_AES_128_CMAC) {
- wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
- "AES-128-CMAC");
- } else if (sel & WPA_CIPHER_BIP_GMAC_128) {
- wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
- "BIP-GMAC-128");
- } else if (sel & WPA_CIPHER_BIP_GMAC_256) {
- wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
- "BIP-GMAC-256");
- } else if (sel & WPA_CIPHER_BIP_CMAC_256) {
- wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
- "BIP-CMAC-256");
- } else {
- wpa_s->mgmt_group_cipher = 0;
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
- }
- wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
- wpa_s->mgmt_group_cipher);
- wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
- wpas_get_ssid_pmf(wpa_s, ssid));
+ wpas_set_mgmt_group_cipher(wpa_s, ssid, &ie);
#ifdef CONFIG_OCV
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV))
@@ -1872,6 +1883,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
{
+ bool scs = true, mscs = true;
+
*pos = 0x00;
switch (idx) {
@@ -1915,6 +1928,12 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
#endif /* CONFIG_MBO */
break;
case 6: /* Bits 48-55 */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->disable_scs_support)
+ scs = false;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (scs)
+ *pos |= 0x40; /* Bit 54 - SCS */
break;
case 7: /* Bits 56-63 */
break;
@@ -1931,7 +1950,12 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
#endif /* CONFIG_FILS */
break;
case 10: /* Bits 80-87 */
- *pos |= 0x20; /* Bit 85 - Mirrored SCS */
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->disable_mscs_support)
+ mscs = false;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (mscs)
+ *pos |= 0x20; /* Bit 85 - Mirrored SCS */
break;
}
}
@@ -2220,9 +2244,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
} else {
#ifdef CONFIG_SAE
wpa_s_clear_sae_rejected(wpa_s);
- wpa_s_setup_sae_pt(wpa_s->conf, ssid);
#endif /* CONFIG_SAE */
}
+#ifdef CONFIG_SAE
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+#endif /* CONFIG_SAE */
if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
if (wpas_update_random_addr(wpa_s, rand_style) < 0)
@@ -2383,6 +2409,23 @@ static int drv_supports_vht(struct wpa_supplicant *wpa_s,
}
+static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode)
+{
+ int i;
+
+ for (i = channel; i < channel + 16; i += 4) {
+ struct hostapd_channel_data *chan;
+
+ chan = hw_get_channel_chan(mode, i, NULL);
+ if (!chan ||
+ chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+ return false;
+ }
+
+ return true;
+}
+
+
void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
const struct wpa_ssid *ssid,
struct hostapd_freq_params *freq)
@@ -2392,7 +2435,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode = NULL;
int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
184, 192 };
- int vht80[] = { 36, 52, 100, 116, 132, 149 };
+ int bw80[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955,
+ 6035, 6115, 6195, 6275, 6355, 6435, 6515,
+ 6595, 6675, 6755, 6835, 6915, 6995 };
+ int bw160[] = { 5955, 6115, 6275, 6435, 6595, 6755, 6915 };
struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
u8 channel;
int i, chan_idx, ht40 = -1, res, obss_scan = 1;
@@ -2400,7 +2446,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
struct hostapd_freq_params vht_freq;
int chwidth, seg0, seg1;
u32 vht_caps = 0;
- int is_24ghz;
+ bool is_24ghz, is_6ghz;
freq->freq = ssid->frequency;
@@ -2457,6 +2503,13 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
hw_mode == HOSTAPD_MODE_IEEE80211B;
+ /* HT/VHT and corresponding overrides are not applicable to 6 GHz.
+ * However, HE is mandatory for 6 GHz.
+ */
+ is_6ghz = is_6ghz_freq(freq->freq);
+ if (is_6ghz)
+ goto skip_to_6ghz;
+
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht) {
freq->ht_enabled = 0;
@@ -2584,8 +2637,6 @@ skip_ht40:
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
return;
- vht_freq = *freq;
-
#ifdef CONFIG_VHT_OVERRIDES
if (ssid->disable_vht) {
freq->vht_enabled = 0;
@@ -2593,46 +2644,67 @@ skip_ht40:
}
#endif /* CONFIG_VHT_OVERRIDES */
+skip_to_6ghz:
+ vht_freq = *freq;
+
+ /* 6 GHz does not have VHT enabled, so allow that exception here. */
vht_freq.vht_enabled = vht_supported(mode);
- if (!vht_freq.vht_enabled)
+ if (!vht_freq.vht_enabled && !is_6ghz)
return;
/* Enable HE with VHT for 5 GHz */
freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
/* setup center_freq1, bandwidth */
- for (j = 0; j < ARRAY_SIZE(vht80); j++) {
- if (freq->channel >= vht80[j] &&
- freq->channel < vht80[j] + 16)
+ for (j = 0; j < ARRAY_SIZE(bw80); j++) {
+ if (freq->freq >= bw80[j] &&
+ freq->freq < bw80[j] + 80)
break;
}
- if (j == ARRAY_SIZE(vht80))
+ if (j == ARRAY_SIZE(bw80) ||
+ ieee80211_freq_to_chan(bw80[j], &channel) == NUM_HOSTAPD_MODES)
return;
- for (i = vht80[j]; i < vht80[j] + 16; i += 4) {
- struct hostapd_channel_data *chan;
+ /* Back to HT configuration if channel not usable */
+ if (!ibss_mesh_is_80mhz_avail(channel, mode))
+ return;
- chan = hw_get_channel_chan(mode, i, NULL);
- if (!chan)
- return;
+ chwidth = CHANWIDTH_80MHZ;
+ seg0 = channel + 6;
+ seg1 = 0;
- /* Back to HT configuration if channel not usable */
- if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
+ if ((mode->he_capab[ieee80211_mode].phy_cap[
+ HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) && is_6ghz) {
+ /* In 160 MHz, the initial four 20 MHz channels were validated
+ * above; check the remaining four 20 MHz channels for the total
+ * of 160 MHz bandwidth.
+ */
+ if (!ibss_mesh_is_80mhz_avail(channel + 16, mode))
return;
- }
- chwidth = CHANWIDTH_80MHZ;
- seg0 = vht80[j] + 6;
- seg1 = 0;
+ for (j = 0; j < ARRAY_SIZE(bw160); j++) {
+ if (freq->freq == bw160[j]) {
+ chwidth = CHANWIDTH_160MHZ;
+ seg0 = channel + 14;
+ break;
+ }
+ }
+ }
if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) {
/* setup center_freq2, bandwidth */
- for (k = 0; k < ARRAY_SIZE(vht80); k++) {
+ for (k = 0; k < ARRAY_SIZE(bw80); k++) {
/* Only accept 80 MHz segments separated by a gap */
- if (j == k || abs(vht80[j] - vht80[k]) == 16)
+ if (j == k || abs(bw80[j] - bw80[k]) == 80)
continue;
- for (i = vht80[k]; i < vht80[k] + 16; i += 4) {
+
+ if (ieee80211_freq_to_chan(bw80[k], &channel) ==
+ NUM_HOSTAPD_MODES)
+ return;
+
+ for (i = channel; i < channel + 16; i += 4) {
struct hostapd_channel_data *chan;
chan = hw_get_channel_chan(mode, i, NULL);
@@ -2646,9 +2718,10 @@ skip_ht40:
/* Found a suitable second segment for 80+80 */
chwidth = CHANWIDTH_80P80MHZ;
- vht_caps |=
- VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
- seg1 = vht80[k] + 6;
+ if (!is_6ghz)
+ vht_caps |=
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ seg1 = channel + 6;
}
if (chwidth == CHANWIDTH_80P80MHZ)
@@ -2666,7 +2739,7 @@ skip_ht40:
}
} else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) {
chwidth = CHANWIDTH_USE_HT;
- seg0 = vht80[j] + 2;
+ seg0 = channel + 2;
#ifdef CONFIG_HT_OVERRIDES
if (ssid->disable_ht40)
seg0 = 0;
@@ -2786,6 +2859,54 @@ int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_FILS */
+static int wpas_populate_wfa_capa(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss,
+ u8 *wpa_ie, size_t wpa_ie_len,
+ size_t max_wpa_ie_len)
+{
+ struct wpabuf *wfa_ie = NULL;
+ u8 wfa_capa[1];
+ size_t wfa_ie_len, buf_len;
+
+ os_memset(wfa_capa, 0, sizeof(wfa_capa));
+ if (wpa_s->enable_dscp_policy_capa)
+ wfa_capa[0] |= WFA_CAPA_QM_DSCP_POLICY;
+
+ if (!wfa_capa[0])
+ return wpa_ie_len;
+
+ /* Wi-Fi Alliance element */
+ buf_len = 1 + /* Element ID */
+ 1 + /* Length */
+ 3 + /* OUI */
+ 1 + /* OUI Type */
+ 1 + /* Capabilities Length */
+ sizeof(wfa_capa); /* Capabilities */
+ wfa_ie = wpabuf_alloc(buf_len);
+ if (!wfa_ie)
+ return wpa_ie_len;
+
+ wpabuf_put_u8(wfa_ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(wfa_ie, buf_len - 2);
+ wpabuf_put_be24(wfa_ie, OUI_WFA);
+ wpabuf_put_u8(wfa_ie, WFA_CAPA_OUI_TYPE);
+ wpabuf_put_u8(wfa_ie, sizeof(wfa_capa));
+ wpabuf_put_data(wfa_ie, wfa_capa, sizeof(wfa_capa));
+
+ wfa_ie_len = wpabuf_len(wfa_ie);
+ if (wpa_ie_len + wfa_ie_len <= max_wpa_ie_len) {
+ wpa_hexdump_buf(MSG_MSGDUMP, "WFA Capabilities element",
+ wfa_ie);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(wfa_ie),
+ wfa_ie_len);
+ wpa_ie_len += wfa_ie_len;
+ }
+
+ wpabuf_free(wfa_ie);
+ return wpa_ie_len;
+}
+
+
static u8 * wpas_populate_assoc_ies(
struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
@@ -3228,6 +3349,10 @@ pfs_fail:
wpa_ie_len += wpa_s->rsnxe_len;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_s->disable_mscs_support)
+ goto mscs_end;
+#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS) &&
wpa_s->robust_av.valid_config) {
struct wpabuf *mscs_ie;
@@ -3243,7 +3368,7 @@ pfs_fail:
if (!mscs_ie) {
wpa_printf(MSG_INFO,
"MSCS: Failed to allocate MSCS IE");
- goto mscs_fail;
+ goto mscs_end;
}
wpas_populate_mscs_descriptor_ie(&wpa_s->robust_av, mscs_ie);
@@ -3257,7 +3382,10 @@ pfs_fail:
wpabuf_free(mscs_ie);
}
-mscs_fail:
+mscs_end:
+
+ wpa_ie_len = wpas_populate_wfa_capa(wpa_s, bss, wpa_ie, wpa_ie_len,
+ max_wpa_ie_len);
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -3868,7 +3996,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
"failed");
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) {
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_VALID_ERROR_CODES) {
/*
* The driver is known to mean what is saying, so we
* can stop right here; the association will not
@@ -3961,6 +4089,9 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
+
+ wpas_scs_deinit(wpa_s);
+ wpas_dscp_deinit(wpa_s);
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
}
@@ -4728,8 +4859,13 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
}
if (name == NULL) {
- /* default to first driver in the list */
- return select_driver(wpa_s, 0);
+ /* Default to first successful driver in the list */
+ for (i = 0; wpa_drivers[i]; i++) {
+ if (select_driver(wpa_s, i) == 0)
+ return 0;
+ }
+ /* Drivers have each reported failure, so no wpa_msg() here. */
+ return -1;
}
do {
@@ -5159,6 +5295,7 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent)
#ifdef CONFIG_TESTING_OPTIONS
dl_list_init(&wpa_s->drv_signal_override);
#endif /* CONFIG_TESTING_OPTIONS */
+ dl_list_init(&wpa_s->active_scs_ids);
return wpa_s;
}
@@ -7789,6 +7926,16 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
}
+int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ if (wpa_s->current_ssid == NULL ||
+ wpa_s->wpa_state < WPA_4WAY_HANDSHAKE ||
+ os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0)
+ return 0;
+ return wpa_sm_pmf_enabled(wpa_s->wpa);
+}
+
+
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
{
if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
@@ -8146,6 +8293,9 @@ struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
{
u16 i;
+ if (!modes)
+ return NULL;
+
for (i = 0; i < num_modes; i++) {
if (modes[i].mode != mode ||
!modes[i].num_channels || !modes[i].channels)
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index e3ae77114680..fa257f3dec1b 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -988,7 +988,7 @@ fast_reauth=1
# WPA3-Personal-only mode: ieee80211w=2 and key_mgmt=SAE
#
# ocv: whether operating channel validation is enabled
-# This is a countermeasure against multi-channel man-in-the-middle attacks.
+# This is a countermeasure against multi-channel on-path attacks.
# Enabling this automatically also enables ieee80211w, if not yet enabled.
# 0 = disabled (default)
# 1 = enabled if wpa_supplicant's SME in use. Otherwise enabled only when the
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 60acb53c5c38..cbc955159bbe 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -524,6 +524,19 @@ struct robust_av_data {
bool valid_config;
};
+struct dscp_policy_status {
+ u8 id;
+ u8 status;
+};
+
+struct dscp_resp_data {
+ bool more;
+ bool reset;
+ bool solicited;
+ struct dscp_policy_status *policy;
+ int num_policies;
+};
+
#ifdef CONFIG_PASN
struct pasn_fils {
@@ -576,6 +589,95 @@ struct wpas_pasn {
};
#endif /* CONFIG_PASN */
+
+enum ip_version {
+ IPV4 = 4,
+ IPV6 = 6,
+};
+
+
+struct ipv4_params {
+ struct in_addr src_ip;
+ struct in_addr dst_ip;
+ u16 src_port;
+ u16 dst_port;
+ u8 dscp;
+ u8 protocol;
+ u8 param_mask;
+};
+
+
+struct ipv6_params {
+ struct in6_addr src_ip;
+ struct in6_addr dst_ip;
+ u16 src_port;
+ u16 dst_port;
+ u8 dscp;
+ u8 next_header;
+ u8 flow_label[3];
+ u8 param_mask;
+};
+
+
+struct type4_params {
+ u8 classifier_mask;
+ enum ip_version ip_version;
+ union {
+ struct ipv4_params v4;
+ struct ipv6_params v6;
+ } ip_params;
+};
+
+
+struct type10_params {
+ u8 prot_instance;
+ u8 prot_number;
+ u8 *filter_value;
+ u8 *filter_mask;
+ size_t filter_len;
+};
+
+
+struct tclas_element {
+ u8 user_priority;
+ u8 classifier_type;
+ union {
+ struct type4_params type4_param;
+ struct type10_params type10_param;
+ } frame_classifier;
+};
+
+
+struct scs_desc_elem {
+ u8 scs_id;
+ enum scs_request_type request_type;
+ u8 intra_access_priority;
+ bool scs_up_avail;
+ struct tclas_element *tclas_elems;
+ unsigned int num_tclas_elem;
+ u8 tclas_processing;
+};
+
+
+struct scs_robust_av_data {
+ struct scs_desc_elem *scs_desc_elems;
+ unsigned int num_scs_desc;
+};
+
+
+enum scs_response_status {
+ SCS_DESC_SENT = 0,
+ SCS_DESC_SUCCESS = 1,
+};
+
+
+struct active_scs_elem {
+ struct dl_list list;
+ u8 scs_id;
+ enum scs_response_status status;
+};
+
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -1038,6 +1140,7 @@ struct wpa_supplicant {
unsigned int p2p_disable_ip_addr_req:1;
unsigned int p2ps_method_config_any:1;
unsigned int p2p_cli_probe:1;
+ unsigned int p2p_go_allow_dfs:1;
enum hostapd_hw_mode p2p_go_acs_band;
int p2p_persistent_go_freq;
int p2p_persistent_id;
@@ -1402,6 +1505,19 @@ struct wpa_supplicant {
struct wpas_pasn pasn;
struct wpa_radio_work *pasn_auth_work;
#endif /* CONFIG_PASN */
+ struct scs_robust_av_data scs_robust_av_req;
+ u8 scs_dialog_token;
+#ifdef CONFIG_TESTING_OPTIONS
+ unsigned int disable_scs_support:1;
+ unsigned int disable_mscs_support:1;
+#endif /* CONFIG_TESTING_OPTIONS */
+ struct dl_list active_scs_ids;
+ bool ongoing_scs_req;
+ u8 dscp_req_dialog_token;
+ u8 dscp_query_dialog_token;
+ unsigned int enable_dscp_policy_capa:1;
+ unsigned int connection_dscp:1;
+ unsigned int wait_for_dscp_req:1;
};
@@ -1427,6 +1543,8 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s);
int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
int wpa_supplicant_update_bridge_ifname(struct wpa_supplicant *wpa_s,
const char *bridge_ifname);
+void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, struct wpa_ie_data *ie);
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
u8 *wpa_ie, size_t *wpa_ie_len);
@@ -1580,7 +1698,7 @@ void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s);
/* op_classes.c */
enum chan_allowed {
- NOT_ALLOWED, NO_IR, ALLOWED
+ NOT_ALLOWED, NO_IR, RADAR, ALLOWED
};
enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
@@ -1667,6 +1785,7 @@ static inline int wpas_mode_to_ieee80211_mode(enum wpas_mode mode)
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr);
int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
@@ -1734,6 +1853,23 @@ void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s,
size_t len);
void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *ies, size_t ies_len);
+int wpas_send_scs_req(struct wpa_supplicant *wpa_s);
+void free_up_tclas_elem(struct scs_desc_elem *elem);
+void free_up_scs_desc(struct scs_robust_av_data *data);
+void wpas_handle_robust_av_scs_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *buf,
+ size_t len);
+void wpas_scs_deinit(struct wpa_supplicant *wpa_s);
+void wpas_handle_qos_mgmt_recv_action(struct wpa_supplicant *wpa_s,
+ const u8 *src,
+ const u8 *buf, size_t len);
+void wpas_dscp_deinit(struct wpa_supplicant *wpa_s);
+int wpas_send_dscp_response(struct wpa_supplicant *wpa_s,
+ struct dscp_resp_data *resp_data);
+void wpas_handle_assoc_resp_qos_mgmt(struct wpa_supplicant *wpa_s,
+ const u8 *ies, size_t ies_len);
+int wpas_send_dscp_query(struct wpa_supplicant *wpa_s, const char *domain_name,
+ size_t domain_name_length);
int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
const u8 *bssid, int akmp, int cipher,
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 96818697882f..17fc05bcbdab 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -780,6 +780,7 @@ static int wpa_supplicant_tdls_peer_addset(
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_he_6ghz_band_cap *he_6ghz_he_capab,
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, size_t supp_oper_classes_len)
@@ -805,6 +806,7 @@ static int wpa_supplicant_tdls_peer_addset(
params.vht_capabilities = vht_capab;
params.he_capab = he_capab;
params.he_capab_len = he_capab_len;
+ params.he_6ghz_capab = he_6ghz_he_capab;
params.qosinfo = qosinfo;
params.listen_interval = 0;
params.supp_rates = supp_rates;