[wpa_supplicant] Cumulative patch from commit 27e828d72
Bug: 231272394
Test: connect/disconnect to WPA2, WPA3 networks
Test: SoftAp & p2p connection
Test: Regression test(b/231636895)
BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from Open source
27e828d72 ACS: Send EHT enabled info to driver
82066bd36 nl80211: Don't force VHT channel definition with EHT
43fe1ce35 EHT: Add [EHT] flag into AP mode STA command
696ad5c2d EHT: Indicate wifi_generation=7 in wpa_supplicant STATUS output
4994c41f2 EHT: Indicate ieee80211be configuration in hostapd STATUS output
50d883710 EHT: Fix invalid length checking for EHT Capability element
6c7b2be42 SAE: Send real status code to the driver when AP rejects external auth
2c78f11a9 Fix compilation due to forward declaration of macaddr_acl
c8e822801 OpenSSL: Fix build with old library versions that do not support TLS 1.3
c24e18e5c LibreSSL: Fix compilation issue with TLS 1.3 session ticket limit
eb5e63985 LibreSSL: Fix compilation issue with RSA-OAEP
5d56cf1c7 BoringSSL: Fix compilation error due to TLS 1.3 session tickets
a561d12d2 EAP peer status notification for server not supporting RFC 5746
566ce69a8 EAP peer: Workaround for servers that do not support safe TLS renegotiation
ccb3206b6 Fix tls_connection_set_success_data() in TLS library wrappers
decac7cd1 OpenSSL: Do not send out a TLS 1.3 session ticket if caching disabled
05406f7ae EAP-PEAP server: Fix TLS 1.3 move to Phase 2 without a new session ticket
10746875e OpenSSL: Allow no OCSP response when resuming a session with TLS 1.3
2be1bcaf7 EAP-TLS peer: Fix protected success indication check for resumed session
1c66276d9 EAP-TLS server: Send final TLS message for resumed session with TLS 1.3
81e249888 OpenSSL: Limit the number of TLS 1.3 session tickets to one
d26247c3d wpa_supplicant/README-WPS: Beautifications
a8d058c93 OpenSSL: SSLKEYLOGFILE capability to allow Wireshark TLS decoding
23f389068 wolfSSL: Fix OCSP stapling
a2971f8d8 wolfSSL: Allow TLS version 1.3 to be disabled
a40e48fbe wolfSSL: Fix TLS 1.3 session handling
0c3f68f2a wolfSSL: Check for the too-short-password error in pbkdf2_sha1()
ca2622481 Check the return of pbkdf2_sha1() for errors
013cd694d wolfSSL: Fixes for FIPS builds
9d5f8168f wolfSSL: Register a FIPS callback
8f36e6c0f wolfSSL: Implement crypto_ec_key wrappers
1f7e10177 wolfSSL: Add missing free calls for wolfSSL structs
ec1cd91e7 wolfSSL: Support both DER and PEM blobs
42871a5d2 EAP-SIM/AKA peer: IMSI privacy
21098e39f EAP-SIM/AKA server: IMSI privacy
36b11bbcf OpenSSL: RSA-OAEP-SHA-256 encryption/decryption
c3d389b72 EHT: Channel switch command support
dae7940a4 EHT: Additions to hostapd_set_freq_params()
e646b11fe EHT: Indicate EHT support in Neighbor Report element
f915d52de EHT: Provide EHT capabilities in STA addition path
a6d1b4c46 EHT: Process (Re)Association Request frame capabilities
340c0e212 EHT: Parse elements received in Management frames
d54e3d049 EHT: Add operation element in AP mode Management frames
9b7202d66 EHT: Add capabilities element in AP mode Management frames
a7ea72188 EHT: Add configuration options for beamforming capabilities
8db3881c7 EHT: Add operating channel width configuration
8dcc2139f EHT: AP mode configuration options to enable/disable the support
9f7da264b nl80211: Pass station's EHT capabilities to the driver in sta_add()
0c8a9aa5d nl80211: Parse EHT capabilities from the driver
c08b735fd EHT: Define EHT elements
1a716f86a defconfig: Document IEEE 802.11ax as a published amendment
86310c220 Set hostapd hw_mode automatically based on 6 GHz op_class
664fd83d5 nl80211: Increase the buffer length for debug printing channels
563162a5f QCA vendor attribute to allow eMLSR HW mode
1e34bc49c OpenSSL: Track SSL_SESSION ex data separately
734fa392f MBO: Check association disallowed in Beacon frames, if newer
284e3ad19 Determine whether Beacon frame information is newer in scan results
28c9f29a3 scan: Print SSID in scan results dump
5a0471579 Install wpa_passphrase when not disabled
f1686d776 hostapd: Allow enabling background radar
08d7738bb wolfSSL: Speed up crypto_ec_point_compute_y_sqr()
f50d5c9a8 wolfSSL: Fix crypto_ec_point_compute_y_sqr() error case processing
7302aa761 wolfSSL: Fix the memory leak of crypto_ec_point_compute_y_sqr()
e7dd0fff1 wolfSSL: Use wc_HmacInit() to avoid potential use of uninitialized values
f7be558d6 OpenSSL: Fix build with BoringSSL
6d33ef362 OpenSSL: Remove compatibility options for older versions than 1.0.2
78c2a4cd0 OpenSSL: Drop compatibility options for LibreSSL older than 2.7
b06250767 OpenSSL: Implement crypto_ecdh routines without EC_KEY for OpenSSL 3.0
fc96f6802 OpenSSL: Use new name for the EC_POINT set/get coordinate functions
0aae045af ctrl: Print the source address of the received commands
f94214968 wpa_ctrl: Wait for a total of 10 seconds, not 10 seconds per iteration
0d9be8855 wolfSSL: Fix certificate commonName checking
94e0f39d9 wolfSSL: Use wolfSSL_export_keying_material() when available
c31fc7a64 wolfSSL: Fix crypto_dh_init() and dh5_init()
d7b8c6eef wolfSSL: Fix crypto_ecdh_* with ECC_TIMING_RESISTANT
ae1fb6455 EAP-EKE server: Fix a memory leak on an error path
166acab4e wolfSSL: TLS session caching
12dee16d7 wolfSSL: Add a debug logging callback
a5d190650 wolfSSL: Implement tls_get_tls_unique()
a419fef36 wolfSSL: Implement tls_connection_get_cipher_suite()
364876b7d wolfSSL: Implement tls_connection_get_peer_subject()
d9c716400 wolfSSL: Implement tls_connection_get_own_cert_used()
d677b9dc6 wolfSSL: Conditional build for aes_wrap/aes_unwrap()
b0f016b87 eapol_test: Update with src/ap/ieee802_1x.c changes
747c5f228 Include MS_FUNCS=y for EAP-pwd peer build
c7f71fb86 Include HMAC-SHA384/512 KDF for SAE if SHA384/512 is included
3a759dcc8 ACS: Honor acs_exclude_dfs with hostapd's ACS implementation
3240cedd6 eapol_test: Print out names for additional known EAP types
f5c711c85 OpenSSL: Unload providers only at process exit
33c4dd26c BSS coloring: Handle the collision and CCA events coming from the kernel
27b4cc712 nl80211: Handle driver events for BSS coloring
399d6e64d nl80211: Add the switch_color() handler for BSS color changes
86bd90eb3 BSS coloring: Disable BSS color during CCA
f7d0b740e BSS coloring: BSS Color Change Announcement element generation
654d2395d BSS coloring: Handling of collision events and triggering CCA
52e2516f1 wpa_supplicant: Add the CONFIG_HE_OVERRIDES option to the defconfig
6a2a60f1d OpenSSL: Do not use the deprecated RSAPrivateKey function
ebb3055e1 OpenSSL: Generate DH parameters automatically if not set with dh_file
bcd299b32 OpenSSL: Convert DH/DSA parameter loading to new API
28c1c91d0 Remove unused dh_blob parameter
4a774cf31 Remove useless DH file configuration from TLS library wrappers
65652c67f Remove DH file configuration from TLS client functionality
b94371af8 RADIUS attributes for EAPOL-Key message details
24763e3cd RADIUS: Attributes with Extended Types (RFC 6929)
feed2f9e7 BoringSSL: Use accessor functions for X509 key usage flags
80be88a08 BoringSSL: Replace stack-allocated X509_STORE_CTX with heap one
b95ed17f6 OpenSSL: Fix build with BoringSSL and LibreSSL 3.3.x and older
ae0f6ee97 OpenSSL: CMAC using the OpenSSL library for non-FIPS cases as well
0c61f6234 OpenSSL: Implement CMAC using the EVP_MAC API
4fcd29660 OpenSSL: Extend CMAC to support 192-bit AES
117617843 OpenSSL: Remove now unused compatibility wrapper for RSA_bits()
a2dbb2558 Android: Compile hs20-osu-client to /vendor/bin in test builds
b0769ce61 DPP: Allow a list of supported curves to be used in bootstrapping URI
ef85328a6 QCA vendor command support to reset configuration for eLNA bypass
7008c50fa OpenSSL: Implement DH using the EVP API
e31500ade OpenSSL: Implement HMAC using the EVP_MAC API
097ca6bf0 OpenSSL: Unload providers on deinit
092efd45a OpenSSL: Implement AES keywrap using the EVP API
7e4984d9c OpenSSL: Use a correct EVP_CIPHER_CTX freeing function on an error path
8e0ac5366 RRM: Include passive channels in active beacon report scan
0adc67612 wpa_supplicant: Use unique IDs for networks and credentials
dacb6d278 Update IEEE P802.11ax draft references to published amendment
8128ea76a Add Transmit Power Envelope element in 6 GHz
bc3dc72a3 Extend 6 GHz Operation Info field in HE Operation element
0eb686637 hostapd: Add config option to specify 6 GHz regulatory AP type
ee06165e9 hostapd: Extend Country element to support 6 GHz band
f5ad97245 PASN: Fix build without CONFIG_TESTING_OPTIONS=y
3467a701c wpa_supplicant: Do not associate on 6 GHz with forbidden configurations
43c6eb5e4 SAE-PK: Add the option to the defconfigs
0482251a6 EAP-TLS: Allow TLSv1.3 support to be enabled with build config
7114e5606 EAP-TLS: Testing functionality to skip protected success indication
95fd54b86 Disconnect STA on continuous EAP reauth without 4-way handshake completion
9e11e746f EAP-TLS: Do not allow TLSv1.3 success without protected result indication
6135a8a6a Stop authentication attemps if AP does not disconnect us
88ab59d71 EAP-TLS: Replace the Commitment Message term with RFC 9190 language
63f311b10 EAP-TLS: Update specification references to RFC 5216 and 9190
5ab385321 Revert "Android: Compile hs20-osu-client to /vendor/bin in test builds"
b746cb28b Add support for not transmitting EAPOL-Key group msg 2/2
d27f7bd94 FILS: Fix config check to allow unsolicited broadcast Probe Response
65a3a273c OWE: Reuse own DH private key in AP if STA tries OWE association again
6ff8bda99 hostapd: Add the missing CONFIG_SAE option to the defconfig
1f5b6085c Fix SIGSEGV of eapol_test
576662d27 ieee802_11_auth: Coding style cleanup - NULL comparison
945acf3ef ieee802_11_auth: Coding style cleanup - no string constant splitting
1c3438fec RADIUS ACL/PSK check during 4-way handshake
5b5c954c0 Fix AP config check to recognize all PSK AKMs
c5d9f9064 QCA vendor attribute to indicate NDP interface managemtn using nl80211
a9c90475b FT: Update current_bss to target AP before check for SME-in-driver
0c88d1487 Debug print on CONFIG_NO_TKIP=y prevent RSNE with TKIP as group cipher
d5a9331f9 P2P: Copy only valid opclasses while filtering out 6 GHz channels
99c91beaa Sync with wireless-next.git include/uapi/linux/nl80211.h
d9121335a wpa_cli: Add ACL and BTM control commands
00622fcfe Extend ACL to install allow/deny list to the driver dynamically
077bce96f Set drv_max_acl_mac_addrs in wpa_supplicant AP mode
9828aba16 Support ACL operations in wpa_supplicant AP mode
fd0d738ff Add return value to ACL functions
f5ac42811 Move ACL control interface commands into shared files
930695662 Add BSS-TM-QUERY event to indicate reception of BSS TM Query
febcdf324 Support BTM operations in wpa_supplicant AP mode
0f8c6e995 Move BTM control interface commands into shared file
e059d8ece Update the Extended Capability element to struct sta_info
eb2e6b56b Enable BSS Transition Management in wpa_supplicant AP mode
30ecf0181 DPP: Update Controller parameters when it was already started
b93d1083e DPP: Fix msg_ctx for PKEX over TCP as Controller/Responder
3085e1a67 hs20-osu-client: dNSName values from OSU server certificate for PPS MO
ce86f2446 DFS: Remove unnecessary variable
760a5ae26 DFS: Switch to background radar channel if available
b63d953fe DFS: Enable CSA for background radar detection
25663241c DFS: Introduce hostapd_dfs_request_channel_switch()
316a9dc63 DFS: Configure background radar/CAC detection
bad12effe nl80211: Radar background flag setting
effd6111b DFS: Rely on channel_type in dfs_downgrade_bandwidth()
f9ba3d5c8 OpenSSL 3.0: Set SSL groups using SSL_set1_groups()
09c62aaf1 OpenSSL: Determine RSA key size without low-level routines
b700a56e1 OpenSSL 3.0: Determine the prime length for an EC key group using EVP_PKEY
3c61f4db4 OpenSSL: Replace EC_GROUP_get_curve_GFp() calls with EC_GROUP_get_curve()
e2cb0ca1a OpenSSL 3.0: Implement crypto_ec_key_group() with new API
f6a53f64a OpenSSL: Replace EVP_PKEY_cmp() with EVP_PKEY_eq() when available
5b093570d D-Bus: Add 'wep_disabled' capability
56a14cc72 DFS: Don't let cac_time_left_seconds overflow
ae512c30a DPP: Fix uninitialised variable on error path
3a157fe92 dbus: Set CurrentAuthMode to INACTIVE only if network is not selected
0ce8d55a2 hs20-osu-client: Allow EST server to use different host name
5eaf596e1 HTTP: Make URL available to the cert_cb
abed7978f HS 2.0 server: Event log entry on missing configuration for the realm
1192d5721 Android: Compile hs20-osu-client to /vendor/bin in test builds
1fee1c40c Enhance QCA vendor interface to indicate TWT required capability of AP
a192305a4 Add QCA vendor attributes for AFC support in external ACS
de5939ef5 DPP: Allow Configurator net_access_key_curve to be changed
9638452a6 DPP: Update Configurator to require same netAccessKey curve to be used
2b406eece DPP: Update Auth-I derivation operations
de64dfe98 DPP: Curve change for netAccessKey
fd2eb7a41 DPP: Fix a memory leak on error path
e9551efe0 DPP: Missing/invalid Protocol Version in Reconfig Auth Req
eeb72e7c9 DPP: Extend DPP_PKEX_ADD ver=<1/2> to cover Responder role
6c3c431bb Add QCA vendor attribute to enable Spectral FFT recapture
fcbdaae8a SAE: Add support for RADIUS passphrase as the SAE password
3d86fcee0 cleanup: Remove unreachable code
9683195ee qca-vendor: Fix typos
4c9ef9322 brcm_vendor: Fix typos
d65285ab8 src/drivers: Fix typos
203a027b2 nl80211: Report background radar/CAC detection capability
0a73649b6 DFS: Add capability to select radar-only channels
f39765369 DFS: Introduce dfs_set_valid_channel() utility routine
d001b301b Fix removal of wpa_passphrase on 'make clean'
cb41c214b build: Re-enable options for libwpa_client.so and wpa_passphrase
dec626109 HE: Fix invalid length checking for HE Capability element
53be64f7d HE: Fix calculation of the PPE Threshold field length
738fef2f0 Clear PSK explicitly from memory in couple more cases on deinit
567b9764f Clear PMK explicitly even without FT support in AP build
0bd29c176 Remove duplicated pointer check
007fd6111 Clear temporary results from stack in PBKDF2-SHA1
1364f322b Remove GTK/IGTK/BIGTK from memory explicitly in AP mode
af1f0694e Clear last set keys (for testing purposes) from memory explicitly
6c850a1c0 nl80211: Clear bss->freq when stopping AP mode
a44fa15cb Define a vendor specific NDP attribute for NAN service id
414ca953f DPP: Clear SCANNING state when starting network introduction
0b5f8e3d8 DPP: Clear netrole on starting chirping or reconfiguration
2fcc076d1 Clear wpa_s->last/current_ssid in more cases
7a7f803a9 DPP: Stop offchannel frame TX wait on DPP_STOP_LISTEN in a corner case
7e941e7a1 macsec_linux: Support cipher suite configuration
46c635910 MACsec: Support GCM-AES-256 cipher suite
42944de69 nl80211: Do not store no-wait TX frame cookies to be cancelled
340ec48cd DPP: Clear state on configuration failure in GAS server hander
7e6f59c70 nl80211: Clear the last saved TX frame cookie on wait expiration
9d5fd3328 Update QCA vendor attribute to indicate maximum PCL attributes
19169a53a atheros: Do not include p2p.h
f43d31dda nl80211: Debug print association comeback event data
a91072503 OCV: Don't start SA Query timer on CSA when SA Query is offloaded
f5c8697c0 Sync with mac80211-next.git include/uapi/linux/nl80211.h
632a9995c Clear ignore_old_scan_res on FLUSH command
Change-Id: I35fd1fb999d045ced8c153fe3d8284c9a71069b1
diff --git a/Android.mk b/Android.mk
index bd7a409..bb8326c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,10 +1,15 @@
-LOCAL_PATH:= $(call my-dir)
+S_LOCAL_PATH := $(call my-dir)
ifneq ($(filter VER_0_8_X VER_2_1_DEVEL,$(WPA_SUPPLICANT_VERSION)),)
# The order of the 2 Android.mks does matter!
# TODO: Clean up the Android.mks, reset all the temporary variables at the
# end of each Android.mk, so that one Android.mk doesn't depend on variables
# set up in the other Android.mk.
-include $(LOCAL_PATH)/hostapd/Android.mk \
- $(LOCAL_PATH)/wpa_supplicant/Android.mk
+include $(S_LOCAL_PATH)/hostapd/Android.mk \
+ $(S_LOCAL_PATH)/wpa_supplicant/Android.mk
+ifneq ($(TARGET_BUILD_VARIANT), user)
+ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
+include $(S_LOCAL_PATH)/hs20/client/Android.mk
+endif #End of Check for platform version
+endif #End of Check for target build variant
endif
diff --git a/hostapd/Android.bp b/hostapd/Android.bp
index d7cc39b..2a25208 100644
--- a/hostapd/Android.bp
+++ b/hostapd/Android.bp
@@ -287,7 +287,6 @@
"src/crypto/fips_prf_openssl.c",
"src/crypto/aes-siv.c",
"src/crypto/aes-ctr.c",
- "src/crypto/aes-omac1.c",
"src/crypto/sha1-prf.c",
"src/crypto/sha1-tlsprf.c",
"src/crypto/sha256-prf.c",
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 4c37b77..adb4c08 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -314,6 +314,12 @@
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BE
+CONFIG_IEEE80211AX=y
+L_CFLAGS += -DCONFIG_IEEE80211BE
+OBJS += src/ap/ieee802_11_eht.c
+endif
+
ifdef CONFIG_IEEE80211AX
L_CFLAGS += -DCONFIG_IEEE80211AX
endif
@@ -673,6 +679,7 @@
endif
ifeq ($(CONFIG_TLS), openssl)
+L_CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
ifdef TLS_FUNCS
OBJS += src/crypto/tls_openssl.c
OBJS += src/crypto/tls_openssl_ocsp.c
@@ -845,7 +852,9 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += src/crypto/aes-encblock.c
endif
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += src/crypto/aes-omac1.c
+endif
ifdef NEED_AES_UNWRAP
ifneq ($(CONFIG_TLS), openssl)
NEED_AES_DEC=y
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 98a0102..5f06378 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -343,6 +343,12 @@
CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BE
+CONFIG_IEEE80211AX=y
+CFLAGS += -DCONFIG_IEEE80211BE
+OBJS += ../src/ap/ieee802_11_eht.o
+endif
+
ifdef CONFIG_IEEE80211AX
CFLAGS += -DCONFIG_IEEE80211AX
OBJS += ../src/ap/ieee802_11_he.o
@@ -712,6 +718,7 @@
endif
ifeq ($(CONFIG_TLS), openssl)
+CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
CONFIG_CRYPTO=openssl
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_openssl.o
@@ -936,11 +943,13 @@
ifdef NEED_AES_ENCBLOCK
AESOBJS += ../src/crypto/aes-encblock.o
endif
+ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-omac1.o
endif
endif
+endif
ifdef NEED_AES_UNWRAP
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 7e605ff..2d5a510 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -118,52 +118,6 @@
#endif /* CONFIG_NO_VLAN */
-int hostapd_acl_comp(const void *a, const void *b)
-{
- const struct mac_acl_entry *aa = a;
- const struct mac_acl_entry *bb = b;
- return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
-}
-
-
-int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
- int vlan_id, const u8 *addr)
-{
- struct mac_acl_entry *newacl;
-
- newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
- if (!newacl) {
- wpa_printf(MSG_ERROR, "MAC list reallocation failed");
- return -1;
- }
-
- *acl = newacl;
- os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
- os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
- (*acl)[*num].vlan_id.untagged = vlan_id;
- (*acl)[*num].vlan_id.notempty = !!vlan_id;
- (*num)++;
-
- return 0;
-}
-
-
-void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
- const u8 *addr)
-{
- int i = 0;
-
- while (i < *num) {
- if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) {
- os_remove_in_array(*acl, *num, sizeof(**acl), i);
- (*num)--;
- } else {
- i++;
- }
- }
-}
-
-
static int hostapd_config_read_maclist(const char *fname,
struct mac_acl_entry **acl, int *num)
{
@@ -2635,6 +2589,9 @@
bss->eap_sim_aka_result_ind = atoi(pos);
} else if (os_strcmp(buf, "eap_sim_id") == 0) {
bss->eap_sim_id = atoi(pos);
+ } else if (os_strcmp(buf, "imsi_privacy_key") == 0) {
+ os_free(bss->imsi_privacy_key);
+ bss->imsi_privacy_key = os_strdup(pos);
#endif /* EAP_SERVER_SIM */
#ifdef EAP_SERVER_TNC
} else if (os_strcmp(buf, "tnc") == 0) {
@@ -2975,7 +2932,8 @@
bss->wpa_psk_radius = atoi(pos);
if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
- bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
+ bss->wpa_psk_radius != PSK_RADIUS_REQUIRED &&
+ bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS) {
wpa_printf(MSG_ERROR,
"Line %d: unknown wpa_psk_radius %d",
line, bss->wpa_psk_radius);
@@ -3139,6 +3097,7 @@
line, pos);
return 1;
}
+ conf->hw_mode_set = true;
} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
if (os_strcmp(pos, "ad") == 0)
bss->wps_rf_bands = WPS_RF_60GHZ;
@@ -3193,6 +3152,8 @@
conf->acs_freq_list_present = 1;
} else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) {
conf->acs_exclude_6ghz_non_psc = atoi(pos);
+ } else if (os_strcmp(buf, "enable_background_radar") == 0) {
+ conf->enable_background_radar = atoi(pos);
} else if (os_strcmp(buf, "min_tx_power") == 0) {
int val = atoi(pos);
@@ -3642,6 +3603,8 @@
line, pos);
return 1;
}
+ } else if (os_strcmp(buf, "he_6ghz_reg_pwr_type") == 0) {
+ conf->he_6ghz_reg_pwr_type = atoi(pos);
} else if (os_strcmp(buf, "he_oper_chwidth") == 0) {
conf->he_oper_chwidth = atoi(pos);
} else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) {
@@ -4301,6 +4264,8 @@
conf->skip_send_eapol = atoi(pos);
} else if (os_strcmp(buf, "enable_eapol_large_timeout") == 0) {
conf->enable_eapol_large_timeout = atoi(pos);
+ } else if (os_strcmp(buf, "eap_skip_prot_success") == 0) {
+ bss->eap_skip_prot_success = atoi(pos);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_SAE
} else if (os_strcmp(buf, "sae_password") == 0) {
@@ -4665,6 +4630,16 @@
return 1;
}
bss->mka_priority = mka_priority;
+ } else if (os_strcmp(buf, "macsec_csindex") == 0) {
+ int macsec_csindex = atoi(pos);
+
+ if (macsec_csindex < 0 || macsec_csindex > 1) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid macsec_csindex (%d): '%s'.",
+ line, macsec_csindex, pos);
+ return 1;
+ }
+ bss->macsec_csindex = macsec_csindex;
} else if (os_strcmp(buf, "mka_cak") == 0) {
size_t len = os_strlen(pos);
@@ -4701,6 +4676,8 @@
bss->disable_11ac = !!atoi(pos);
} else if (os_strcmp(buf, "disable_11ax") == 0) {
bss->disable_11ax = !!atoi(pos);
+ } else if (os_strcmp(buf, "disable_11be") == 0) {
+ bss->disable_11be = !!atoi(pos);
#ifdef CONFIG_PASN
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strcmp(buf, "force_kdk_derivation") == 0) {
@@ -4728,6 +4705,20 @@
return 1;
} else if (os_strcmp(buf, "rnr") == 0) {
bss->rnr = atoi(pos);
+#ifdef CONFIG_IEEE80211BE
+ } else if (os_strcmp(buf, "ieee80211be") == 0) {
+ conf->ieee80211be = atoi(pos);
+ } else if (os_strcmp(buf, "eht_oper_chwidth") == 0) {
+ conf->eht_oper_chwidth = atoi(pos);
+ } else if (os_strcmp(buf, "eht_oper_centr_freq_seg0_idx") == 0) {
+ conf->eht_oper_centr_freq_seg0_idx = atoi(pos);
+ } else if (os_strcmp(buf, "eht_su_beamformer") == 0) {
+ conf->eht_phy_capab.su_beamformer = atoi(pos);
+ } else if (os_strcmp(buf, "eht_su_beamformee") == 0) {
+ conf->eht_phy_capab.su_beamformee = atoi(pos);
+ } else if (os_strcmp(buf, "eht_mu_beamformer") == 0) {
+ conf->eht_phy_capab.mu_beamformer = atoi(pos);
+#endif /* CONFIG_IEEE80211BE */
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
diff --git a/hostapd/config_file.h b/hostapd/config_file.h
index 9830f5a..c98bdb6 100644
--- a/hostapd/config_file.h
+++ b/hostapd/config_file.h
@@ -13,10 +13,5 @@
int hostapd_set_iface(struct hostapd_config *conf,
struct hostapd_bss_config *bss, const char *field,
char *value);
-int hostapd_acl_comp(const void *a, const void *b);
-int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
- int vlan_id, const u8 *addr);
-void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
- const u8 *addr);
#endif /* CONFIG_FILE_H */
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index a62f3c7..ad994d4 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -772,235 +772,6 @@
#ifdef CONFIG_WNM_AP
-static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
- const char *cmd)
-{
- u8 addr[ETH_ALEN];
- int disassoc_timer;
- struct sta_info *sta;
-
- if (hwaddr_aton(cmd, addr))
- return -1;
- if (cmd[17] != ' ')
- return -1;
- disassoc_timer = atoi(cmd + 17);
-
- sta = ap_get_sta(hapd, addr);
- if (sta == NULL) {
- wpa_printf(MSG_DEBUG, "Station " MACSTR
- " not found for disassociation imminent message",
- MAC2STR(addr));
- return -1;
- }
-
- return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
-}
-
-
-static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
- const char *cmd)
-{
- u8 addr[ETH_ALEN];
- const char *url, *timerstr;
- int disassoc_timer;
- struct sta_info *sta;
-
- if (hwaddr_aton(cmd, addr))
- return -1;
-
- sta = ap_get_sta(hapd, addr);
- if (sta == NULL) {
- wpa_printf(MSG_DEBUG, "Station " MACSTR
- " not found for ESS disassociation imminent message",
- MAC2STR(addr));
- return -1;
- }
-
- timerstr = cmd + 17;
- if (*timerstr != ' ')
- return -1;
- timerstr++;
- disassoc_timer = atoi(timerstr);
- if (disassoc_timer < 0 || disassoc_timer > 65535)
- return -1;
-
- url = os_strchr(timerstr, ' ');
- if (url == NULL)
- return -1;
- url++;
-
- return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
-}
-
-
-static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
- const char *cmd)
-{
- u8 addr[ETH_ALEN];
- const char *pos, *end;
- int disassoc_timer = 0;
- struct sta_info *sta;
- u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
- u8 bss_term_dur[12];
- char *url = NULL;
- int ret;
- u8 nei_rep[1000];
- int nei_len;
- u8 mbo[10];
- size_t mbo_len = 0;
-
- if (hwaddr_aton(cmd, addr)) {
- wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
- return -1;
- }
-
- sta = ap_get_sta(hapd, addr);
- if (sta == NULL) {
- wpa_printf(MSG_DEBUG, "Station " MACSTR
- " not found for BSS TM Request message",
- MAC2STR(addr));
- return -1;
- }
-
- pos = os_strstr(cmd, " disassoc_timer=");
- if (pos) {
- pos += 16;
- disassoc_timer = atoi(pos);
- if (disassoc_timer < 0 || disassoc_timer > 65535) {
- wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
- return -1;
- }
- }
-
- pos = os_strstr(cmd, " valid_int=");
- if (pos) {
- pos += 11;
- valid_int = atoi(pos);
- }
-
- pos = os_strstr(cmd, " dialog_token=");
- if (pos) {
- pos += 14;
- dialog_token = atoi(pos);
- }
-
- pos = os_strstr(cmd, " bss_term=");
- if (pos) {
- pos += 10;
- req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
- /* TODO: TSF configurable/learnable */
- bss_term_dur[0] = 4; /* Subelement ID */
- bss_term_dur[1] = 10; /* Length */
- os_memset(&bss_term_dur[2], 0, 8);
- end = os_strchr(pos, ',');
- if (end == NULL) {
- wpa_printf(MSG_DEBUG, "Invalid bss_term data");
- return -1;
- }
- end++;
- WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
- }
-
- nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
- sizeof(nei_rep));
- if (nei_len < 0)
- return -1;
-
- pos = os_strstr(cmd, " url=");
- if (pos) {
- size_t len;
- pos += 5;
- end = os_strchr(pos, ' ');
- if (end)
- len = end - pos;
- else
- len = os_strlen(pos);
- url = os_malloc(len + 1);
- if (url == NULL)
- return -1;
- os_memcpy(url, pos, len);
- url[len] = '\0';
- req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
- }
-
- if (os_strstr(cmd, " pref=1"))
- req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
- if (os_strstr(cmd, " abridged=1"))
- req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
- if (os_strstr(cmd, " disassoc_imminent=1"))
- req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
-
-#ifdef CONFIG_MBO
- pos = os_strstr(cmd, "mbo=");
- if (pos) {
- unsigned int mbo_reason, cell_pref, reassoc_delay;
- u8 *mbo_pos = mbo;
-
- ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
- &reassoc_delay, &cell_pref);
- if (ret != 3) {
- wpa_printf(MSG_DEBUG,
- "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
- ret = -1;
- goto fail;
- }
-
- if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
- wpa_printf(MSG_DEBUG,
- "Invalid MBO transition reason code %u",
- mbo_reason);
- ret = -1;
- goto fail;
- }
-
- /* Valid values for Cellular preference are: 0, 1, 255 */
- if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
- wpa_printf(MSG_DEBUG,
- "Invalid MBO cellular capability %u",
- cell_pref);
- ret = -1;
- goto fail;
- }
-
- if (reassoc_delay > 65535 ||
- (reassoc_delay &&
- !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
- wpa_printf(MSG_DEBUG,
- "MBO: Assoc retry delay is only valid in disassoc imminent mode");
- ret = -1;
- goto fail;
- }
-
- *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
- *mbo_pos++ = 1;
- *mbo_pos++ = mbo_reason;
- *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
- *mbo_pos++ = 1;
- *mbo_pos++ = cell_pref;
-
- if (reassoc_delay) {
- *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
- *mbo_pos++ = 2;
- WPA_PUT_LE16(mbo_pos, reassoc_delay);
- mbo_pos += 2;
- }
-
- mbo_len = mbo_pos - mbo;
- }
-#endif /* CONFIG_MBO */
-
- ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
- valid_int, bss_term_dur, dialog_token, url,
- nei_len ? nei_rep : NULL, nei_len,
- mbo_len ? mbo : NULL, mbo_len);
-#ifdef CONFIG_MBO
-fail:
-#endif /* CONFIG_MBO */
- os_free(url);
- return ret;
-}
-
-
static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd,
const char *cmd)
{
@@ -1362,43 +1133,6 @@
}
-static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
-{
- struct sta_info *sta;
- struct vlan_description vlan_id;
-
- if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
- return;
-
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (!hostapd_maclist_found(hapd->conf->accept_mac,
- hapd->conf->num_accept_mac,
- sta->addr, &vlan_id) ||
- (vlan_id.notempty &&
- vlan_compare(&vlan_id, sta->vlan_desc)))
- ap_sta_disconnect(hapd, sta, sta->addr,
- WLAN_REASON_UNSPECIFIED);
- }
-}
-
-
-static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
-{
- struct sta_info *sta;
- struct vlan_description vlan_id;
-
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (hostapd_maclist_found(hapd->conf->deny_mac,
- hapd->conf->num_deny_mac, sta->addr,
- &vlan_id) &&
- (!vlan_id.notempty ||
- !vlan_compare(&vlan_id, sta->vlan_desc)))
- ap_sta_disconnect(hapd, sta, sta->addr,
- WLAN_REASON_UNSPECIFIED);
- }
-}
-
-
static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd,
const char *bands)
{
@@ -1519,6 +1253,9 @@
} else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
os_free(hapd->dpp_configurator_params);
hapd->dpp_configurator_params = os_strdup(value);
+#ifdef CONFIG_DPP2
+ dpp_controller_set_params(hapd->iface->interfaces->dpp, value);
+#endif /* CONFIG_DPP2 */
} else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
hapd->dpp_init_max_tries = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
@@ -2838,7 +2575,7 @@
for (i = 0; i < iface->num_bss; i++) {
- /* Save CHAN_SWITCH VHT and HE config */
+ /* Save CHAN_SWITCH VHT, HE, and EHT config */
hostapd_chan_switch_config(iface->bss[i],
&settings.freq_params);
@@ -3383,80 +3120,6 @@
}
-static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
- const char *txtaddr)
-{
- u8 addr[ETH_ALEN];
- struct vlan_description vlan_id;
-
- if (!(*num))
- return 0;
-
- if (hwaddr_aton(txtaddr, addr))
- return -1;
-
- if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
- hostapd_remove_acl_mac(acl, num, addr);
-
- return 0;
-}
-
-
-static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
- int *num)
-{
- while (*num)
- hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
-}
-
-
-static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
- char *buf, size_t buflen)
-{
- int i = 0, len = 0, ret = 0;
-
- if (!acl)
- return 0;
-
- while (i < num) {
- ret = os_snprintf(buf + len, buflen - len,
- MACSTR " VLAN_ID=%d\n",
- MAC2STR(acl[i].addr),
- acl[i].vlan_id.untagged);
- if (ret < 0 || (size_t) ret >= buflen - len)
- return len;
- i++;
- len += ret;
- }
- return len;
-}
-
-
-static int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
- const char *cmd)
-{
- u8 addr[ETH_ALEN];
- struct vlan_description vlan_id;
- int ret = 0, vlanid = 0;
- const char *pos;
-
- if (hwaddr_aton(cmd, addr))
- return -1;
-
- pos = os_strstr(cmd, "VLAN_ID=");
- if (pos)
- vlanid = atoi(pos + 8);
-
- if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
- ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
- if (ret != -1 && *acl)
- qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
- }
-
- return ret < 0 ? -1 : 0;
-}
-
-
static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd,
const char *field, char *buf,
size_t buflen)
@@ -3832,14 +3495,15 @@
if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
if (hostapd_ctrl_iface_acl_add_mac(
&hapd->conf->accept_mac,
- &hapd->conf->num_accept_mac, buf + 19))
+ &hapd->conf->num_accept_mac, buf + 19) ||
+ hostapd_set_acl(hapd))
reply_len = -1;
} else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
- if (!hostapd_ctrl_iface_acl_del_mac(
+ if (hostapd_ctrl_iface_acl_del_mac(
&hapd->conf->accept_mac,
- &hapd->conf->num_accept_mac, buf + 19))
- hostapd_disassoc_accept_mac(hapd);
- else
+ &hapd->conf->num_accept_mac, buf + 19) ||
+ hostapd_set_acl(hapd) ||
+ hostapd_disassoc_accept_mac(hapd))
reply_len = -1;
} else if (os_strcmp(buf + 11, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
@@ -3849,20 +3513,23 @@
hostapd_ctrl_iface_acl_clear_list(
&hapd->conf->accept_mac,
&hapd->conf->num_accept_mac);
- hostapd_disassoc_accept_mac(hapd);
+ if (hostapd_set_acl(hapd) ||
+ hostapd_disassoc_accept_mac(hapd))
+ reply_len = -1;
}
} else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
- if (!hostapd_ctrl_iface_acl_add_mac(
+ if (hostapd_ctrl_iface_acl_add_mac(
&hapd->conf->deny_mac,
- &hapd->conf->num_deny_mac, buf + 17))
- hostapd_disassoc_deny_mac(hapd);
- else
+ &hapd->conf->num_deny_mac, buf + 17) ||
+ hostapd_set_acl(hapd) ||
+ hostapd_disassoc_deny_mac(hapd))
reply_len = -1;
} else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
if (hostapd_ctrl_iface_acl_del_mac(
&hapd->conf->deny_mac,
- &hapd->conf->num_deny_mac, buf + 17))
+ &hapd->conf->num_deny_mac, buf + 17) ||
+ hostapd_set_acl(hapd))
reply_len = -1;
} else if (os_strcmp(buf + 9, "SHOW") == 0) {
reply_len = hostapd_ctrl_iface_acl_show_mac(
@@ -3872,6 +3539,8 @@
hostapd_ctrl_iface_acl_clear_list(
&hapd->conf->deny_mac,
&hapd->conf->num_deny_mac);
+ if (hostapd_set_acl(hapd))
+ reply_len = -1;
}
#ifdef CONFIG_DPP
} else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) {
@@ -3963,6 +3632,10 @@
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) {
+ if (dpp_configurator_set(hapd->iface->interfaces->dpp,
+ buf + 20) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
if (dpp_configurator_remove(hapd->iface->interfaces->dpp,
buf + 24) < 0)
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 2855acd..6a41dcf 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -156,10 +156,20 @@
#CONFIG_IEEE80211AC=y
# IEEE 802.11ax HE support
+#CONFIG_IEEE80211AX=y
+
+# IEEE 802.11be EHT support
+# CONFIG_IEEE80211AX is mandatory for setting CONFIG_IEEE80211BE.
# Note: This is experimental and work in progress. The definitions are still
# subject to change and this should not be expected to interoperate with the
-# final IEEE 802.11ax version.
-#CONFIG_IEEE80211AX=y
+# final IEEE 802.11be version.
+#CONFIG_IEEE80211BE=y
+
+# Simultaneous Authentication of Equals (SAE), WPA3-Personal
+#CONFIG_SAE=y
+
+# SAE Public Key, WPA3-Personal
+#CONFIG_SAE_PK=y
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 3c2019f..f37d563 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -225,6 +225,16 @@
# Default behavior is to include all PSC and non-PSC channels.
#acs_exclude_6ghz_non_psc=1
+# Enable background radar feature
+# This feature allows CAC to be run on dedicated radio RF chains while the
+# radio(s) are otherwise running normal AP activities on other channels.
+# This requires that the driver and the radio support it before feature will
+# actually be enabled, i.e., this parameter value is ignored with drivers that
+# do not advertise support for the capability.
+# 0: Leave disabled (default)
+# 1: Enable it.
+#enable_background_radar=1
+
# Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection.
# (default 0, i.e., not constraint)
#min_tx_power=20
@@ -965,6 +975,13 @@
# (default)
#he_6ghz_tx_ant_pat=1
+# 6 GHz Access Point type
+# This config is to set the 6 GHz Access Point type. Possible options are:
+# 0 = Indoor AP (default)
+# 1 = Standard Power AP
+# This has no impact for operation on other bands.
+#he_6ghz_reg_pwr_type=0
+
# Unsolicited broadcast Probe Response transmission settings
# This is for the 6 GHz band only. If the interval is set to a non-zero value,
# the AP schedules unsolicited broadcast Probe Response frames to be
@@ -973,6 +990,40 @@
# Valid range: 0..20 TUs; default is 0 (disabled)
#unsol_bcast_probe_resp_interval=0
+##### IEEE 802.11be related configuration #####################################
+
+#ieee80211be: Whether IEEE 802.11be (EHT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+#ieee80211be=1
+
+#disable_11be: Boolean (0/1) to disable EHT for a specific BSS
+#disable_11be=0
+
+#eht_su_beamformer: EHT single user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#eht_su_beamformer=1
+
+#eht_su_beamformee: EHT single user beamformee support
+# 0 = not supported (default)
+# 1 = supported
+#eht_su_beamformee=1
+
+#eht_mu_beamformer: EHT multiple user beamformer support
+# 0 = not supported (default)
+# 1 = supported
+#eht_mu_beamformer=1
+
+# EHT operating channel information; see matching he_* parameters for details.
+# The field eht_oper_centr_freq_seg0_idx field is used to indicate center
+# frequency of 40, 80, and 160 MHz bandwidth operation.
+# In the 6 GHz band, eht_oper_chwidth is ignored and the channel width is
+# derived from the configured operating class (IEEE P802.11be/D1.5,
+# Annex E.1 - Country information and operating classes).
+#eht_oper_chwidth
+#eht_oper_centr_freq_seg0_idx
+
##### IEEE 802.1X-2004 related configuration ##################################
# Require IEEE 802.1X authorization
@@ -1070,6 +1121,10 @@
# mka_priority (Priority of MKA Actor)
# Range: 0..255 (default: 255)
#
+# macsec_csindex: IEEE 802.1X/MACsec cipher suite
+# 0 = GCM-AES-128 (default)
+# 1 = GCM-AES-256 (default)
+#
# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
# In this mode, instances of hostapd can act as MACsec peers. The peer
@@ -1243,12 +1298,11 @@
# dh_file: File path to DH/DSA parameters file (in PEM format)
# This is an optional configuration file for setting parameters for an
-# ephemeral DH key exchange. In most cases, the default RSA authentication does
-# not use this configuration. However, it is possible setup RSA to use
-# ephemeral DH key exchange. In addition, ciphers with DSA keys always use
-# ephemeral DH keys. This can be used to achieve forward secrecy. If the file
-# is in DSA parameters format, it will be automatically converted into DH
-# params. This parameter is required if anonymous EAP-FAST is used.
+# ephemeral DH key exchange. If the file is in DSA parameters format, it will
+# be automatically converted into DH params. If the used TLS library supports
+# automatic DH parameter selection, that functionality will be used if this
+# parameter is not set. DH parameters are required if anonymous EAP-FAST is
+# used.
# You can generate DH parameters file with OpenSSL, e.g.,
# "openssl dhparam -out /etc/hostapd.dh.pem 2048"
#dh_file=/etc/hostapd.dh.pem
@@ -1369,6 +1423,10 @@
# 3 = use pseudonyms and use fast reauthentication (default)
#eap_sim_id=3
+# IMSI privacy key (PEM encoded RSA 2048-bit private key) for decrypting
+# permanent identity when using EAP-SIM/AKA/AKA'.
+#imsi_privacy_key=imsi-privacy-key.pem
+
# Trusted Network Connect (TNC)
# If enabled, TNC validation will be required before the peer is allowed to
# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
@@ -1651,12 +1709,15 @@
#wpa_psk_file=/etc/hostapd.wpa_psk
# Optionally, WPA passphrase can be received from RADIUS authentication server
-# This requires macaddr_acl to be set to 2 (RADIUS)
+# This requires macaddr_acl to be set to 2 (RADIUS) for wpa_psk_radius values
+# 1 and 2.
# 0 = disabled (default)
# 1 = optional; use default passphrase/psk if RADIUS server does not include
# Tunnel-Password
# 2 = required; reject authentication if RADIUS server does not include
# Tunnel-Password
+# 3 = ask RADIUS server during 4-way handshake if there is no locally
+# configured PSK/passphrase for the STA
#wpa_psk_radius=0
# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 2609121..60396f3 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1169,7 +1169,7 @@
"arguments (count and freq)\n"
"usage: <cs_count> <freq> [sec_channel_offset=] "
"[center_freq1=] [center_freq2=] [bandwidth=] "
- "[blocktx] [ht|vht]\n");
+ "[blocktx] [ht|vht|he|eht]\n");
return -1;
}
diff --git a/hostapd/main.c b/hostapd/main.c
index d028fb5..eab57b6 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -15,6 +15,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/uuid.h"
+#include "crypto/crypto.h"
#include "crypto/random.h"
#include "crypto/tls.h"
#include "common/version.h"
@@ -725,7 +726,6 @@
case 'v':
show_version();
exit(1);
- break;
case 'g':
if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
return -1;
@@ -947,6 +947,7 @@
fst_global_deinit();
+ crypto_unload();
os_program_deinit();
return ret;
diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk
index c42d53c..bb77341 100644
--- a/hs20/client/Android.mk
+++ b/hs20/client/Android.mk
@@ -60,6 +60,10 @@
L_CFLAGS += -Wno-unused-parameter
+ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+L_CFLAGS += -DANDROID_LOG_NAME='"hs20-osu-client"'
+endif
########################
include $(CLEAR_VARS)
@@ -71,9 +75,15 @@
LOCAL_SHARED_LIBRARIES := libc libcutils
LOCAL_SHARED_LIBRARIES += libcrypto libssl
+ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0)
+LOCAL_VENDOR_MODULE := true
+LOCAL_SHARED_LIBRARIES += libxml2
+LOCAL_SHARED_LIBRARIES += liblog
+else
#LOCAL_SHARED_LIBRARIES += libxml2
LOCAL_STATIC_LIBRARIES += libxml2
LOCAL_SHARED_LIBRARIES += libicuuc
+endif # End of check for platform version
LOCAL_SHARED_LIBRARIES += libcurl
LOCAL_CFLAGS := $(L_CFLAGS)
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index 11bf0db..7b274da 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -2911,20 +2911,27 @@
int found;
char *host = NULL;
- wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)",
- !ctx->no_osu_cert_validation, ctx->server_url);
+ wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s server_url=%s)",
+ !ctx->no_osu_cert_validation, cert->url ? cert->url : "N/A",
+ ctx->server_url);
- host = get_hostname(ctx->server_url);
+ if (ctx->no_osu_cert_validation && cert->url)
+ host = get_hostname(cert->url);
+ else
+ host = get_hostname(ctx->server_url);
- for (i = 0; i < ctx->server_dnsname_count; i++)
- os_free(ctx->server_dnsname[i]);
- os_free(ctx->server_dnsname);
- ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *));
- ctx->server_dnsname_count = 0;
+ if (!ctx->no_osu_cert_validation) {
+ for (i = 0; i < ctx->server_dnsname_count; i++)
+ os_free(ctx->server_dnsname[i]);
+ os_free(ctx->server_dnsname);
+ ctx->server_dnsname = os_calloc(cert->num_dnsname,
+ sizeof(char *));
+ ctx->server_dnsname_count = 0;
+ }
found = 0;
for (i = 0; i < cert->num_dnsname; i++) {
- if (ctx->server_dnsname) {
+ if (!ctx->no_osu_cert_validation && ctx->server_dnsname) {
ctx->server_dnsname[ctx->server_dnsname_count] =
os_strdup(cert->dnsname[i]);
if (ctx->server_dnsname[ctx->server_dnsname_count])
@@ -3249,7 +3256,6 @@
default:
usage();
exit(0);
- break;
}
}
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
index 39d10e0..194518e 100644
--- a/hs20/client/spp_client.c
+++ b/hs20/client/spp_client.c
@@ -564,7 +564,6 @@
free(id);
return -1;
}
- return 0;
}
if (strcasecmp(name, "uploadMO") == 0) {
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
index a50e907..72694be 100644
--- a/hs20/server/spp_server.c
+++ b/hs20/server/spp_server.c
@@ -1385,8 +1385,11 @@
SUBSCRIPTION_REGISTRATION, mac_addr) < 0)
return NULL;
val = db_get_osu_config_val(ctx, realm, "signup_url");
- if (val == NULL)
+ if (!val) {
+ hs20_eventlog(ctx, NULL, realm, session_id,
+ "signup_url not configured in osu_config", NULL);
return NULL;
+ }
spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK",
NULL);
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 0030edc..faaedbf 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -540,6 +540,10 @@
if (!acs_usable_chan(chan))
continue;
+ if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+ iface->conf->acs_exclude_dfs)
+ continue;
+
if (!is_in_chanlist(iface, chan))
continue;
@@ -670,6 +674,10 @@
if (!chan_pri_allowed(chan))
continue;
+ if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+ iface->conf->acs_exclude_dfs)
+ continue;
+
if (!is_in_chanlist(iface, chan))
continue;
@@ -1044,7 +1052,9 @@
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
+ ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+ iface->conf->acs_exclude_dfs))
continue;
if (!is_in_chanlist(iface, chan))
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 33c68d4..db86a76 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration helper functions
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -463,9 +463,12 @@
wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
(u8 *) ssid->wpa_passphrase,
os_strlen(ssid->wpa_passphrase));
- pbkdf2_sha1(ssid->wpa_passphrase,
- ssid->ssid, ssid->ssid_len,
- 4096, ssid->wpa_psk->psk, PMK_LEN);
+ if (pbkdf2_sha1(ssid->wpa_passphrase,
+ ssid->ssid, ssid->ssid_len,
+ 4096, ssid->wpa_psk->psk, PMK_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()");
+ return -1;
+ }
wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
ssid->wpa_psk->psk, PMK_LEN);
return 0;
@@ -811,6 +814,7 @@
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
os_free(conf->eap_sim_db);
+ os_free(conf->imsi_privacy_key);
os_free(conf->radius_server_clients);
os_free(conf->radius);
os_free(conf->radius_das_shared_secret);
@@ -1245,15 +1249,18 @@
if (full_config && bss->wpa &&
bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+ bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
"RADIUS checking (macaddr_acl=2) enabled.");
return -1;
}
- if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+ if (full_config && bss->wpa &&
+ wpa_key_mgmt_wpa_psk_no_sae(bss->wpa_key_mgmt) &&
bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
bss->ssid.wpa_psk_file == NULL &&
+ bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS &&
(bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
@@ -1426,7 +1433,7 @@
#endif /* CONFIG_SAE_PK */
#ifdef CONFIG_FILS
- if (full_config && bss->fils_discovery_min_int &&
+ if (full_config && bss->fils_discovery_max_int &&
bss->unsol_bcast_probe_resp_interval) {
wpa_printf(MSG_ERROR,
"Cannot enable both FILS discovery and unsolicited broadcast Probe Response at the same time");
@@ -1434,6 +1441,14 @@
}
#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211BE
+ if (full_config && !bss->disable_11be && bss->disable_11ax) {
+ bss->disable_11be = true;
+ wpa_printf(MSG_INFO,
+ "Disabling IEEE 802.11be as IEEE 802.11ax is disabled for this BSS");
+ }
+#endif /* CONFIG_IEEE80211BE */
+
return 0;
}
@@ -1465,6 +1480,13 @@
{
size_t i;
+ if (full_config && is_6ghz_op_class(conf->op_class) &&
+ !conf->hw_mode_set) {
+ /* Use the appropriate hw_mode value automatically when the
+ * op_class parameter has been set, but hw_mode was not. */
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+ }
+
if (full_config && conf->ieee80211d &&
(!conf->country[0] || !conf->country[1])) {
wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
@@ -1502,6 +1524,14 @@
return -1;
}
+#ifdef CONFIG_IEEE80211BE
+ if (full_config && conf->ieee80211be && !conf->ieee80211ax) {
+ wpa_printf(MSG_ERROR,
+ "Cannot set ieee80211be without ieee80211ax");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
for (i = 0; i < conf->num_bss; i++) {
if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
return -1;
@@ -1648,3 +1678,49 @@
return with_pk;
}
#endif /* CONFIG_SAE_PK */
+
+
+int hostapd_acl_comp(const void *a, const void *b)
+{
+ const struct mac_acl_entry *aa = a;
+ const struct mac_acl_entry *bb = b;
+ return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
+}
+
+
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+ int vlan_id, const u8 *addr)
+{
+ struct mac_acl_entry *newacl;
+
+ newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
+ if (!newacl) {
+ wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+ return -1;
+ }
+
+ *acl = newacl;
+ os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+ os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id));
+ (*acl)[*num].vlan_id.untagged = vlan_id;
+ (*acl)[*num].vlan_id.notempty = !!vlan_id;
+ (*num)++;
+
+ return 0;
+}
+
+
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+ const u8 *addr)
+{
+ int i = 0;
+
+ while (i < *num) {
+ if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) {
+ os_remove_in_array(*acl, *num, sizeof(**acl), i);
+ (*num)--;
+ } else {
+ i++;
+ }
+ }
+}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index c1a0f71..b97d49c 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,12 @@
#include "fst/fst.h"
#include "vlan.h"
+enum macaddr_acl {
+ ACCEPT_UNLESS_DENIED = 0,
+ DENY_UNLESS_ACCEPTED = 1,
+ USE_EXTERNAL_RADIUS_AUTH = 2
+};
+
/**
* mesh_conf - local MBSS state and settings
*/
@@ -331,12 +337,11 @@
int eap_reauth_period;
int erp_send_reauth_start;
char *erp_domain;
+#ifdef CONFIG_TESTING_OPTIONS
+ bool eap_skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
- enum macaddr_acl {
- ACCEPT_UNLESS_DENIED = 0,
- DENY_UNLESS_ACCEPTED = 1,
- USE_EXTERNAL_RADIUS_AUTH = 2
- } macaddr_acl;
+ enum macaddr_acl macaddr_acl;
struct mac_acl_entry *accept_mac;
int num_accept_mac;
struct mac_acl_entry *deny_mac;
@@ -364,7 +369,8 @@
enum {
PSK_RADIUS_IGNORED = 0,
PSK_RADIUS_ACCEPTED = 1,
- PSK_RADIUS_REQUIRED = 2
+ PSK_RADIUS_REQUIRED = 2,
+ PSK_RADIUS_DURING_4WAY_HS = 3,
} wpa_psk_radius;
int wpa_pairwise;
int group_cipher; /* wpa_group value override from configuation */
@@ -439,6 +445,7 @@
int eap_teap_id;
int eap_sim_aka_result_ind;
int eap_sim_id;
+ char *imsi_privacy_key;
int tnc;
int fragment_size;
u16 pwd_group;
@@ -537,6 +544,7 @@
bool disable_11n;
bool disable_11ac;
bool disable_11ax;
+ bool disable_11be;
/* IEEE 802.11v */
int time_advertisement;
@@ -849,6 +857,13 @@
int mka_priority;
/**
+ * macsec_csindex - Cipher suite index for MACsec
+ *
+ * Range: 0-1 (default: 0)
+ */
+ int macsec_csindex;
+
+ /**
* mka_ckn - MKA pre-shared CKN
*/
#define MACSEC_CKN_MAX_LEN 32
@@ -937,6 +952,15 @@
};
/**
+ * struct eht_phy_capabilities_info - EHT PHY capabilities
+ */
+struct eht_phy_capabilities_info {
+ bool su_beamformer;
+ bool su_beamformee;
+ bool mu_beamformer;
+};
+
+/**
* struct hostapd_config - Per-radio interface configuration
*/
struct hostapd_config {
@@ -957,7 +981,9 @@
int acs_exclude_dfs;
u8 min_tx_power;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+ bool hw_mode_set;
int acs_exclude_6ghz_non_psc;
+ int enable_background_radar;
enum {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
@@ -1075,6 +1101,7 @@
u8 he_6ghz_max_ampdu_len_exp;
u8 he_6ghz_rx_ant_pat;
u8 he_6ghz_tx_ant_pat;
+ u8 he_6ghz_reg_pwr_type;
#endif /* CONFIG_IEEE80211AX */
/* VHT enable/disable config from CHAN_SWITCH */
@@ -1102,11 +1129,27 @@
unsigned int airtime_update_interval;
#define AIRTIME_MODE_MAX (__AIRTIME_MODE_MAX - 1)
#endif /* CONFIG_AIRTIME_POLICY */
+
+ int ieee80211be;
+#ifdef CONFIG_IEEE80211BE
+ u8 eht_oper_chwidth;
+ u8 eht_oper_centr_freq_seg0_idx;
+ struct eht_phy_capabilities_info eht_phy_capab;
+#endif /* CONFIG_IEEE80211BE */
+
+ /* EHT enable/disable config from CHAN_SWITCH */
+#define CH_SWITCH_EHT_ENABLED BIT(0)
+#define CH_SWITCH_EHT_DISABLED BIT(1)
+ unsigned int ch_switch_eht_config;
};
static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf)
{
+#ifdef CONFIG_IEEE80211BE
+ if (conf->ieee80211be)
+ return conf->eht_oper_chwidth;
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
return conf->he_oper_chwidth;
@@ -1117,6 +1160,10 @@
static inline void
hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth)
{
+#ifdef CONFIG_IEEE80211BE
+ if (conf->ieee80211be)
+ conf->eht_oper_chwidth = oper_chwidth;
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
conf->he_oper_chwidth = oper_chwidth;
@@ -1127,6 +1174,10 @@
static inline u8
hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf)
{
+#ifdef CONFIG_IEEE80211BE
+ if (conf->ieee80211be)
+ return conf->eht_oper_centr_freq_seg0_idx;
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
return conf->he_oper_centr_freq_seg0_idx;
@@ -1138,6 +1189,10 @@
hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf,
u8 oper_centr_freq_seg0_idx)
{
+#ifdef CONFIG_IEEE80211BE
+ if (conf->ieee80211be)
+ conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_IEEE80211AX
if (conf->ieee80211ax)
conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
@@ -1197,5 +1252,10 @@
bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf);
bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf);
int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
+int hostapd_acl_comp(const void *a, const void *b);
+int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num,
+ int vlan_id, const u8 *addr);
+void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num,
+ const u8 *addr);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index e917736..8af7a0e 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -418,6 +418,8 @@
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_eht_capabilities *eht_capab,
+ size_t eht_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set)
@@ -440,6 +442,8 @@
params.vht_capabilities = vht_capab;
params.he_capab = he_capab;
params.he_capab_len = he_capab_len;
+ params.eht_capab = eht_capab;
+ params.eht_capab_len = eht_capab_len;
params.he_6ghz_capab = he_6ghz_capab;
params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED);
params.vht_opmode = vht_opmode;
@@ -547,7 +551,7 @@
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int edmg, u8 edmg_channel,
int ht_enabled, int vht_enabled,
- int he_enabled,
+ int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
{
@@ -556,12 +560,15 @@
if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
edmg_channel, ht_enabled,
- vht_enabled, he_enabled, sec_channel_offset,
- oper_chwidth,
+ vht_enabled, he_enabled, eht_enabled,
+ sec_channel_offset, oper_chwidth,
center_segment0, center_segment1,
cmode ? cmode->vht_capab : 0,
cmode ?
- &cmode->he_capab[IEEE80211_MODE_AP] : NULL))
+ &cmode->he_capab[IEEE80211_MODE_AP] : NULL,
+ cmode ?
+ &cmode->eht_capab[IEEE80211_MODE_AP] :
+ NULL))
return -1;
if (hapd->driver == NULL)
@@ -810,9 +817,10 @@
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
- int he_enabled,
+ int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
- int center_segment0, int center_segment1)
+ int center_segment0, int center_segment1,
+ bool radar_background)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_freq_params data;
@@ -830,18 +838,24 @@
if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
ht_enabled,
- vht_enabled, he_enabled, sec_channel_offset,
+ vht_enabled, he_enabled, eht_enabled,
+ sec_channel_offset,
oper_chwidth, center_segment0,
center_segment1,
cmode->vht_capab,
- &cmode->he_capab[IEEE80211_MODE_AP])) {
+ &cmode->he_capab[IEEE80211_MODE_AP],
+ &cmode->eht_capab[IEEE80211_MODE_AP])) {
wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
}
+ data.radar_background = radar_background;
res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
if (!res) {
- iface->cac_started = 1;
+ if (radar_background)
+ iface->radar_background.cac_started = 1;
+ else
+ iface->cac_started = 1;
os_get_reltime(&iface->dfs_cac_start);
}
@@ -953,13 +967,15 @@
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
+ params.eht_enabled = !!(hapd->iface->conf->ieee80211be);
params.ch_width = 20;
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
params.ch_width = 40;
/* Note: VHT20 is defined by combination of ht_capab & oper_chwidth
*/
- if ((hapd->iface->conf->ieee80211ax ||
+ if ((hapd->iface->conf->ieee80211be ||
+ hapd->iface->conf->ieee80211ax ||
hapd->iface->conf->ieee80211ac) &&
params.ht40_enabled) {
u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf);
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 61c8f64..b4fb766 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -43,6 +43,8 @@
const struct ieee80211_vht_capabilities *vht_capab,
const struct ieee80211_he_capabilities *he_capab,
size_t he_capab_len,
+ const struct ieee80211_eht_capabilities *eht_capab,
+ size_t eht_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
int set);
@@ -64,8 +66,8 @@
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
int freq, int channel, int edmg, u8 edmg_channel,
- int ht_enabled, int vht_enabled,
- int he_enabled, int sec_channel_offset, int oper_chwidth,
+ int ht_enabled, int vht_enabled, int he_enabled,
+ bool eht_enabled, int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
@@ -128,9 +130,10 @@
int hostapd_start_dfs_cac(struct hostapd_iface *iface,
enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
- int he_enabled,
+ int he_enabled, bool eht_enabled,
int sec_channel_offset, int oper_chwidth,
- int center_segment0, int center_segment1);
+ int center_segment0, int center_segment1,
+ bool radar_background);
int hostapd_drv_do_acs(struct hostapd_data *hapd);
int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
u16 reason_code, const u8 *ie, size_t ielen);
@@ -299,6 +302,17 @@
return hapd->driver->switch_channel(hapd->drv_priv, settings);
}
+#ifdef CONFIG_IEEE80211AX
+static inline int hostapd_drv_switch_color(struct hostapd_data *hapd,
+ struct cca_settings *settings)
+{
+ if (!hapd->driver || !hapd->driver->switch_color || !hapd->drv_priv)
+ return -1;
+
+ return hapd->driver->switch_color(hapd->drv_priv, settings);
+}
+#endif /* CONFIG_IEEE80211AX */
+
static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 8e12daf..fd9c96f 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "crypto/crypto.h"
#include "crypto/tls.h"
#include "eap_server/eap.h"
#include "eap_server/eap_sim_db.h"
@@ -168,6 +169,9 @@
wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
data->alert.description);
break;
+ case TLS_UNSAFE_RENEGOTIATION_DISABLED:
+ /* Not applicable to TLS server */
+ break;
}
}
#endif /* EAP_TLS_FUNCS */
@@ -209,6 +213,7 @@
cfg->eap_teap_id = hapd->conf->eap_teap_id;
cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
cfg->eap_sim_id = hapd->conf->eap_sim_id;
+ cfg->imsi_privacy_key = hapd->imsi_privacy_key;
cfg->tnc = hapd->conf->tnc;
cfg->wps = hapd->wps;
cfg->fragment_size = hapd->conf->fragment_size;
@@ -222,6 +227,9 @@
cfg->server_id_len = 7;
}
cfg->erp = hapd->conf->eap_server_erp;
+#ifdef CONFIG_TESTING_OPTIONS
+ cfg->skip_prot_success = hapd->conf->eap_skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
return cfg;
}
@@ -292,6 +300,22 @@
}
#endif /* EAP_TLS_FUNCS */
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(hapd->imsi_privacy_key);
+ hapd->imsi_privacy_key = NULL;
+ if (hapd->conf->imsi_privacy_key) {
+ hapd->imsi_privacy_key = crypto_rsa_key_read(
+ hapd->conf->imsi_privacy_key, true);
+ if (!hapd->imsi_privacy_key) {
+ wpa_printf(MSG_ERROR,
+ "Failed to read/parse IMSI privacy key %s",
+ hapd->conf->imsi_privacy_key);
+ authsrv_deinit(hapd);
+ return -1;
+ }
+ }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
#ifdef EAP_SIM_DB
if (hapd->conf->eap_sim_db) {
hapd->eap_sim_db_priv =
@@ -332,6 +356,11 @@
hapd->radius_srv = NULL;
#endif /* RADIUS_SERVER */
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(hapd->imsi_privacy_key);
+ hapd->imsi_privacy_key = NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
#ifdef EAP_TLS_FUNCS
if (hapd->ssl_ctx) {
tls_deinit(hapd->ssl_ctx);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 8cd1c41..eaa4033 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -186,7 +186,8 @@
}
-static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing,
+static u8 * hostapd_eid_country_add(struct hostapd_data *hapd, u8 *pos,
+ u8 *end, int chan_spacing,
struct hostapd_channel_data *start,
struct hostapd_channel_data *prev)
{
@@ -198,31 +199,23 @@
/* number of channels */
*pos++ = (prev->chan - start->chan) / chan_spacing + 1;
/* maximum transmit power level */
- *pos++ = start->max_tx_power;
+ if (!is_6ghz_op_class(hapd->iconf->op_class))
+ *pos++ = start->max_tx_power;
+ else
+ *pos++ = 0; /* Reserved when operating on the 6 GHz band */
return pos;
}
-static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
- int max_len)
+static u8 * hostapd_fill_subband_triplets(struct hostapd_data *hapd, u8 *pos,
+ u8 *end)
{
- u8 *pos = eid;
- u8 *end = eid + max_len;
int i;
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *start, *prev;
int chan_spacing = 1;
- if (!hapd->iconf->ieee80211d || max_len < 6 ||
- hapd->iface->current_mode == NULL)
- return eid;
-
- *pos++ = WLAN_EID_COUNTRY;
- pos++; /* length will be set later */
- os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
- pos += 3;
-
mode = hapd->iface->current_mode;
if (mode->mode == HOSTAPD_MODE_IEEE80211A)
chan_spacing = 4;
@@ -240,7 +233,8 @@
}
if (start && prev) {
- pos = hostapd_eid_country_add(pos, end, chan_spacing,
+ pos = hostapd_eid_country_add(hapd, pos, end,
+ chan_spacing,
start, prev);
start = NULL;
}
@@ -250,10 +244,50 @@
}
if (start) {
- pos = hostapd_eid_country_add(pos, end, chan_spacing,
+ pos = hostapd_eid_country_add(hapd, pos, end, chan_spacing,
start, prev);
}
+ return pos;
+}
+
+
+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
+ int max_len)
+{
+ u8 *pos = eid;
+ u8 *end = eid + max_len;
+
+ if (!hapd->iconf->ieee80211d || max_len < 6 ||
+ hapd->iface->current_mode == NULL)
+ return eid;
+
+ *pos++ = WLAN_EID_COUNTRY;
+ pos++; /* length will be set later */
+ os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
+ pos += 3;
+
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ /* Force the third octet of the country string to indicate
+ * Global Operating Class (Table E-4) */
+ eid[4] = 0x04;
+
+ /* Operating Triplet field */
+ /* Operating Extension Identifier (>= 201 to indicate this is
+ * not a Subband Triplet field) */
+ *pos++ = 201;
+ /* Operating Class */
+ *pos++ = hapd->iconf->op_class;
+ /* Coverage Class */
+ *pos++ = 0;
+ /* Subband Triplets are required only for the 20 MHz case */
+ if (hapd->iconf->op_class == 131 ||
+ hapd->iconf->op_class == 136)
+ pos = hostapd_fill_subband_triplets(hapd, pos, end);
+ } else {
+ pos = hostapd_fill_subband_triplets(hapd, pos, end);
+ }
+
if ((pos - eid) & 1) {
if (end - pos < 1)
return eid;
@@ -463,12 +497,25 @@
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
- if (is_6ghz_op_class(hapd->iconf->op_class))
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
buflen += sizeof(struct ieee80211_he_6ghz_oper_info) +
3 + sizeof(struct ieee80211_he_6ghz_band_cap);
+ /* An additional Transmit Power Envelope element for
+ * subordinate client */
+ if (hapd->iconf->he_6ghz_reg_pwr_type ==
+ HE_6GHZ_INDOOR_AP)
+ buflen += 4;
+ }
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
+ buflen += 3 + sizeof(struct ieee80211_eht_operation);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP);
buflen += hostapd_mbo_ie_len(hapd);
buflen += hostapd_eid_owe_trans_len(hapd);
@@ -578,14 +625,30 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
+ u8 *cca_pos;
+
pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_he_operation(hapd, pos);
+
+ /* BSS Color Change Announcement element */
+ cca_pos = hostapd_eid_cca(hapd, pos);
+ if (cca_pos != pos)
+ hapd->cca_c_off_proberesp = cca_pos - (u8 *) resp - 2;
+ pos = cca_pos;
+
pos = hostapd_eid_spatial_reuse(hapd, pos);
pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos);
pos = hostapd_eid_he_6ghz_band_cap(hapd, pos);
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP);
+ pos = hostapd_eid_eht_operation(hapd, pos);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
pos = hostapd_eid_vendor_vht(hapd, pos);
@@ -1319,6 +1382,15 @@
buf_len = pos - buf;
total_len += buf_len;
+#ifdef CONFIG_IEEE80211AX
+ /* Transmit Power Envelope element(s) */
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ total_len += 4;
+ if (hapd->iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP)
+ total_len += 4;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
head = os_zalloc(total_len);
if (!head)
return NULL;
@@ -1391,6 +1463,9 @@
pos += buf_len;
}
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ pos = hostapd_eid_txpower_envelope(hapd, pos);
+
*len = pos - (u8 *) head;
wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template",
head, pos - (u8 *) head);
@@ -1465,12 +1540,25 @@
3 + sizeof(struct ieee80211_he_operation) +
3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) +
3 + sizeof(struct ieee80211_spatial_reuse);
- if (is_6ghz_op_class(hapd->iconf->op_class))
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
tail_len += sizeof(struct ieee80211_he_6ghz_oper_info) +
3 + sizeof(struct ieee80211_he_6ghz_band_cap);
+ /* An additional Transmit Power Envelope element for
+ * subordinate client */
+ if (hapd->iconf->he_6ghz_reg_pwr_type ==
+ HE_6GHZ_INDOOR_AP)
+ tail_len += 4;
+ }
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ tail_len += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
+ tail_len += 3 + sizeof(struct ieee80211_eht_operation);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON);
tail_len += hostapd_mbo_ie_len(hapd);
tail_len += hostapd_eid_owe_trans_len(hapd);
@@ -1600,15 +1688,32 @@
#ifdef CONFIG_IEEE80211AX
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
+ u8 *cca_pos;
+
tailpos = hostapd_eid_he_capab(hapd, tailpos,
IEEE80211_MODE_AP);
tailpos = hostapd_eid_he_operation(hapd, tailpos);
+
+ /* BSS Color Change Announcement element */
+ cca_pos = hostapd_eid_cca(hapd, tailpos);
+ if (cca_pos != tailpos)
+ hapd->cca_c_off_beacon = cca_pos - tail - 2;
+ tailpos = cca_pos;
+
tailpos = hostapd_eid_spatial_reuse(hapd, tailpos);
tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos);
tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos);
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ tailpos = hostapd_eid_eht_capab(hapd, tailpos,
+ IEEE80211_MODE_AP);
+ tailpos = hostapd_eid_eht_operation(hapd, tailpos);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht)
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
@@ -1845,12 +1950,14 @@
iconf->channel, iconf->enable_edmg,
iconf->edmg_channel, iconf->ieee80211n,
iconf->ieee80211ac, iconf->ieee80211ax,
+ iconf->ieee80211be,
iconf->secondary_channel,
hostapd_get_oper_chwidth(iconf),
hostapd_get_oper_centr_freq_seg0_idx(iconf),
hostapd_get_oper_centr_freq_seg1_idx(iconf),
cmode->vht_capab,
- &cmode->he_capab[IEEE80211_MODE_AP]) == 0)
+ &cmode->he_capab[IEEE80211_MODE_AP],
+ &cmode->eht_capab[IEEE80211_MODE_AP]) == 0)
params.freq = &freq;
res = hostapd_drv_set_ap(hapd, ¶ms);
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 1d8fb82..29b41f5 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -24,6 +24,7 @@
#include "ap_drv_ops.h"
#include "mbo_ap.h"
#include "taxonomy.h"
+#include "wnm_ap.h"
static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen,
@@ -724,15 +725,15 @@
} else {
/* CAC started and CAC time set - calculate remaining time */
struct os_reltime now;
- unsigned int left_time;
+ long left_time;
os_reltime_age(&iface->dfs_cac_start, &now);
- left_time = iface->dfs_cac_ms / 1000 - now.sec;
+ left_time = (long) iface->dfs_cac_ms / 1000 - now.sec;
ret = os_snprintf(buf + len, buflen - len,
"cac_time_seconds=%u\n"
- "cac_time_left_seconds=%u\n",
+ "cac_time_left_seconds=%lu\n",
iface->dfs_cac_ms / 1000,
- left_time);
+ left_time > 0 ? left_time : 0);
}
if (os_snprintf_error(buflen - len, ret))
return len;
@@ -746,6 +747,7 @@
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
"ieee80211ax=%d\n"
+ "ieee80211be=%d\n"
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
@@ -758,12 +760,27 @@
!hapd->conf->disable_11ac,
iface->conf->ieee80211ax &&
!hapd->conf->disable_11ax,
+ iface->conf->ieee80211be &&
+ !hapd->conf->disable_11be,
iface->conf->beacon_int,
hapd->conf->dtim_period);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+#ifdef CONFIG_IEEE80211BE
+ if (iface->conf->ieee80211be && !hapd->conf->disable_11be) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "eht_oper_chwidth=%d\n"
+ "eht_oper_centr_freq_seg0_idx=%d\n",
+ iface->conf->eht_oper_chwidth,
+ iface->conf->eht_oper_centr_freq_seg0_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_IEEE80211AX
if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) {
ret = os_snprintf(buf + len, buflen - len,
@@ -918,6 +935,7 @@
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
settings->freq_params.he_enabled = !!os_strstr(pos, " he");
+ settings->freq_params.eht_enabled = !!os_strstr(pos, " eht");
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
@@ -1047,3 +1065,351 @@
#endif /* CONFIG_MESH */
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
+
+
+#ifdef CONFIG_WNM_AP
+
+int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ int disassoc_timer;
+ struct sta_info *sta;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+ if (cmd[17] != ' ')
+ return -1;
+ disassoc_timer = atoi(cmd + 17);
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for disassociation imminent message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer);
+}
+
+
+int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ const char *url, *timerstr;
+ int disassoc_timer;
+ struct sta_info *sta;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for ESS disassociation imminent message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ timerstr = cmd + 17;
+ if (*timerstr != ' ')
+ return -1;
+ timerstr++;
+ disassoc_timer = atoi(timerstr);
+ if (disassoc_timer < 0 || disassoc_timer > 65535)
+ return -1;
+
+ url = os_strchr(timerstr, ' ');
+ if (url == NULL)
+ return -1;
+ url++;
+
+ return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
+}
+
+
+int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ const char *pos, *end;
+ int disassoc_timer = 0;
+ struct sta_info *sta;
+ u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01;
+ u8 bss_term_dur[12];
+ char *url = NULL;
+ int ret;
+ u8 nei_rep[1000];
+ int nei_len;
+ u8 mbo[10];
+ size_t mbo_len = 0;
+
+ if (hwaddr_aton(cmd, addr)) {
+ wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
+ return -1;
+ }
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Station " MACSTR
+ " not found for BSS TM Request message",
+ MAC2STR(addr));
+ return -1;
+ }
+
+ pos = os_strstr(cmd, " disassoc_timer=");
+ if (pos) {
+ pos += 16;
+ disassoc_timer = atoi(pos);
+ if (disassoc_timer < 0 || disassoc_timer > 65535) {
+ wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
+ return -1;
+ }
+ }
+
+ pos = os_strstr(cmd, " valid_int=");
+ if (pos) {
+ pos += 11;
+ valid_int = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " dialog_token=");
+ if (pos) {
+ pos += 14;
+ dialog_token = atoi(pos);
+ }
+
+ pos = os_strstr(cmd, " bss_term=");
+ if (pos) {
+ pos += 10;
+ req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
+ /* TODO: TSF configurable/learnable */
+ bss_term_dur[0] = 4; /* Subelement ID */
+ bss_term_dur[1] = 10; /* Length */
+ os_memset(&bss_term_dur[2], 0, 8);
+ end = os_strchr(pos, ',');
+ if (end == NULL) {
+ wpa_printf(MSG_DEBUG, "Invalid bss_term data");
+ return -1;
+ }
+ end++;
+ WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
+ }
+
+ nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep,
+ sizeof(nei_rep));
+ if (nei_len < 0)
+ return -1;
+
+ pos = os_strstr(cmd, " url=");
+ if (pos) {
+ size_t len;
+ pos += 5;
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ url = os_malloc(len + 1);
+ if (url == NULL)
+ return -1;
+ os_memcpy(url, pos, len);
+ url[len] = '\0';
+ req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+ }
+
+ if (os_strstr(cmd, " pref=1"))
+ req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
+ if (os_strstr(cmd, " abridged=1"))
+ req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+ if (os_strstr(cmd, " disassoc_imminent=1"))
+ req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+
+#ifdef CONFIG_MBO
+ pos = os_strstr(cmd, "mbo=");
+ if (pos) {
+ unsigned int mbo_reason, cell_pref, reassoc_delay;
+ u8 *mbo_pos = mbo;
+
+ ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason,
+ &reassoc_delay, &cell_pref);
+ if (ret != 3) {
+ wpa_printf(MSG_DEBUG,
+ "MBO requires three arguments: mbo=<reason>:<reassoc_delay>:<cell_pref>");
+ ret = -1;
+ goto fail;
+ }
+
+ if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO transition reason code %u",
+ mbo_reason);
+ ret = -1;
+ goto fail;
+ }
+
+ /* Valid values for Cellular preference are: 0, 1, 255 */
+ if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid MBO cellular capability %u",
+ cell_pref);
+ ret = -1;
+ goto fail;
+ }
+
+ if (reassoc_delay > 65535 ||
+ (reassoc_delay &&
+ !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) {
+ wpa_printf(MSG_DEBUG,
+ "MBO: Assoc retry delay is only valid in disassoc imminent mode");
+ ret = -1;
+ goto fail;
+ }
+
+ *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = mbo_reason;
+ *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF;
+ *mbo_pos++ = 1;
+ *mbo_pos++ = cell_pref;
+
+ if (reassoc_delay) {
+ *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY;
+ *mbo_pos++ = 2;
+ WPA_PUT_LE16(mbo_pos, reassoc_delay);
+ mbo_pos += 2;
+ }
+
+ mbo_len = mbo_pos - mbo;
+ }
+#endif /* CONFIG_MBO */
+
+ ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
+ valid_int, bss_term_dur, dialog_token, url,
+ nei_len ? nei_rep : NULL, nei_len,
+ mbo_len ? mbo : NULL, mbo_len);
+#ifdef CONFIG_MBO
+fail:
+#endif /* CONFIG_MBO */
+ os_free(url);
+ return ret;
+}
+
+#endif /* CONFIG_WNM_AP */
+
+
+int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct vlan_description vlan_id;
+
+ if (!(*num))
+ return 0;
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ if (hostapd_maclist_found(*acl, *num, addr, &vlan_id))
+ hostapd_remove_acl_mac(acl, num, addr);
+
+ return 0;
+}
+
+
+void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
+ int *num)
+{
+ while (*num)
+ hostapd_remove_acl_mac(acl, num, (*acl)[0].addr);
+}
+
+
+int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
+ char *buf, size_t buflen)
+{
+ int i = 0, len = 0, ret = 0;
+
+ if (!acl)
+ return 0;
+
+ while (i < num) {
+ ret = os_snprintf(buf + len, buflen - len,
+ MACSTR " VLAN_ID=%d\n",
+ MAC2STR(acl[i].addr),
+ acl[i].vlan_id.untagged);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ i++;
+ len += ret;
+ }
+ return len;
+}
+
+
+int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
+ const char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct vlan_description vlan_id;
+ int ret = 0, vlanid = 0;
+ const char *pos;
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = os_strstr(cmd, "VLAN_ID=");
+ if (pos)
+ vlanid = atoi(pos + 8);
+
+ if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) {
+ ret = hostapd_add_acl_maclist(acl, num, vlanid, addr);
+ if (ret != -1 && *acl)
+ qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+ }
+
+ return ret < 0 ? -1 : 0;
+}
+
+
+int hostapd_disassoc_accept_mac(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct vlan_description vlan_id;
+
+ if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED)
+ return 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!hostapd_maclist_found(hapd->conf->accept_mac,
+ hapd->conf->num_accept_mac,
+ sta->addr, &vlan_id) ||
+ (vlan_id.notempty &&
+ vlan_compare(&vlan_id, sta->vlan_desc)))
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ }
+
+ return 0;
+}
+
+
+int hostapd_disassoc_deny_mac(struct hostapd_data *hapd)
+{
+ struct sta_info *sta;
+ struct vlan_description vlan_id;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (hostapd_maclist_found(hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac, sta->addr,
+ &vlan_id) &&
+ (!vlan_id.notempty ||
+ !vlan_compare(&vlan_id, sta->vlan_desc)))
+ ap_sta_disconnect(hapd, sta, sta->addr,
+ WLAN_REASON_UNSPECIFIED);
+ }
+
+ return 0;
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index d1dcebf..614f042 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -37,4 +37,21 @@
const u8 *addr, char *buf, size_t len);
void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd);
+int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
+ const char *cmd);
+int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
+ const char *cmd);
+int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ const char *cmd);
+int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num,
+ const char *cmd);
+int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num,
+ const char *txtaddr);
+void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl,
+ int *num);
+int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num,
+ char *buf, size_t buflen);
+int hostapd_disassoc_accept_mac(struct hostapd_data *hapd);
+int hostapd_disassoc_deny_mac(struct hostapd_data *hapd);
+
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 5c99ecf..e46dd7e 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -19,6 +19,26 @@
#include "dfs.h"
+enum dfs_channel_type {
+ DFS_ANY_CHANNEL,
+ DFS_AVAILABLE, /* non-radar or radar-available */
+ DFS_NO_CAC_YET, /* radar-not-yet-available */
+};
+
+static struct hostapd_channel_data *
+dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
+ u8 *oper_centr_freq_seg0_idx,
+ u8 *oper_centr_freq_seg1_idx,
+ enum dfs_channel_type *channel_type);
+
+
+static bool dfs_use_radar_background(struct hostapd_iface *iface)
+{
+ return (iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) &&
+ iface->conf->enable_background_radar;
+}
+
+
static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
{
int n_chans = 1;
@@ -51,15 +71,27 @@
}
+/* dfs_channel_available: select new channel according to type parameter */
static int dfs_channel_available(struct hostapd_channel_data *chan,
- int skip_radar)
+ enum dfs_channel_type type)
{
+ if (type == DFS_NO_CAC_YET) {
+ /* Select only radar channel where CAC has not been
+ * performed yet
+ */
+ if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
+ (chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
+ HOSTAPD_CHAN_DFS_USABLE)
+ return 1;
+ return 0;
+ }
+
/*
* When radar detection happens, CSA is performed. However, there's no
* time for CAC, so radar channels must be skipped when finding a new
* channel for CSA, unless they are available for immediate use.
*/
- if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
+ if (type == DFS_AVAILABLE && (chan->flag & HOSTAPD_CHAN_RADAR) &&
((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
HOSTAPD_CHAN_DFS_AVAILABLE))
return 0;
@@ -138,7 +170,7 @@
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int first_chan_idx, int num_chans,
- int skip_radar)
+ enum dfs_channel_type type)
{
struct hostapd_channel_data *first_chan, *chan;
int i;
@@ -177,7 +209,7 @@
return 0;
}
- if (!dfs_channel_available(chan, skip_radar)) {
+ if (!dfs_channel_available(chan, type)) {
wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
first_chan->freq + i * 20);
return 0;
@@ -207,7 +239,7 @@
*/
static int dfs_find_channel(struct hostapd_iface *iface,
struct hostapd_channel_data **ret_chan,
- int idx, int skip_radar)
+ int idx, enum dfs_channel_type type)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan;
@@ -232,7 +264,7 @@
}
/* Skip incompatible chandefs */
- if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
+ if (!dfs_chan_range_available(mode, i, n_chans, type)) {
wpa_printf(MSG_DEBUG,
"DFS: range not available for %d (%d)",
chan->freq, chan->chan);
@@ -475,7 +507,7 @@
int *secondary_channel,
u8 *oper_centr_freq_seg0_idx,
u8 *oper_centr_freq_seg1_idx,
- int skip_radar)
+ enum dfs_channel_type type)
{
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL;
@@ -499,7 +531,7 @@
return NULL;
/* Get the count first */
- num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
+ num_available_chandefs = dfs_find_channel(iface, NULL, 0, type);
wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
num_available_chandefs);
if (num_available_chandefs == 0)
@@ -508,7 +540,7 @@
if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
return NULL;
chan_idx = _rand % num_available_chandefs;
- dfs_find_channel(iface, &chan, chan_idx, skip_radar);
+ dfs_find_channel(iface, &chan, chan_idx, type);
if (!chan) {
wpa_printf(MSG_DEBUG, "DFS: no random channel found");
return NULL;
@@ -537,7 +569,7 @@
for (i = 0; i < num_available_chandefs - 1; i++) {
/* start from chan_idx + 1, end when chan_idx - 1 */
chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
- dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
+ dfs_find_channel(iface, &chan2, chan_idx2, type);
if (chan2 && abs(chan2->chan - chan->chan) > 12) {
/* two channels are not adjacent */
sec_chan_idx_80p80 = chan2->chan;
@@ -568,6 +600,30 @@
}
+static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar)
+{
+ struct hostapd_channel_data *channel;
+ u8 cf1 = 0, cf2 = 0;
+ int sec = 0;
+
+ channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
+ skip_radar ? DFS_AVAILABLE :
+ DFS_ANY_CHANNEL);
+ if (!channel) {
+ wpa_printf(MSG_ERROR, "could not get valid channel");
+ return -1;
+ }
+
+ iface->freq = channel->freq;
+ iface->conf->channel = channel->chan;
+ iface->conf->secondary_channel = sec;
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
+
+ return 0;
+}
+
+
static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
{
struct hostapd_hw_modes *mode;
@@ -755,7 +811,6 @@
*/
int hostapd_handle_dfs(struct hostapd_iface *iface)
{
- struct hostapd_channel_data *channel;
int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
int skip_radar = 0;
@@ -810,28 +865,17 @@
wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
res, res ? "yes": "no");
if (res) {
- int sec = 0;
- u8 cf1 = 0, cf2 = 0;
-
- channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
- skip_radar);
- if (!channel) {
- wpa_printf(MSG_ERROR, "could not get valid channel");
+ if (dfs_set_valid_channel(iface, skip_radar) < 0) {
hostapd_set_state(iface, HAPD_IFACE_DFS);
return 0;
}
-
- iface->freq = channel->freq;
- iface->conf->channel = channel->chan;
- iface->conf->secondary_channel = sec;
- hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
- hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
}
} while (res);
/* Finally start CAC */
hostapd_set_state(iface, HAPD_IFACE_DFS);
- wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
+ wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq,
+ dfs_use_radar_background(iface) ? " (background)" : "");
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
iface->freq,
@@ -844,17 +888,41 @@
res = hostapd_start_dfs_cac(
iface, iface->conf->hw_mode, iface->freq, iface->conf->channel,
iface->conf->ieee80211n, iface->conf->ieee80211ac,
- iface->conf->ieee80211ax,
+ iface->conf->ieee80211ax, iface->conf->ieee80211be,
iface->conf->secondary_channel,
hostapd_get_oper_chwidth(iface->conf),
hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
- hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
+ dfs_use_radar_background(iface));
if (res) {
wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
return -1;
}
+ if (dfs_use_radar_background(iface)) {
+ /* Cache background radar parameters. */
+ iface->radar_background.channel = iface->conf->channel;
+ iface->radar_background.secondary_channel =
+ iface->conf->secondary_channel;
+ iface->radar_background.freq = iface->freq;
+ iface->radar_background.centr_freq_seg0_idx =
+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
+ iface->radar_background.centr_freq_seg1_idx =
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
+
+ /*
+ * Let's select a random channel according to the
+ * regulations and perform CAC on dedicated radar chain.
+ */
+ res = dfs_set_valid_channel(iface, 1);
+ if (res < 0)
+ return res;
+
+ iface->radar_background.temp_ch = 1;
+ return 1;
+ }
+
return 0;
}
@@ -876,6 +944,177 @@
}
+static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
+ int channel, int freq,
+ int secondary_channel,
+ u8 current_vht_oper_chwidth,
+ u8 oper_centr_freq_seg0_idx,
+ u8 oper_centr_freq_seg1_idx)
+{
+ struct hostapd_hw_modes *cmode = iface->current_mode;
+ int ieee80211_mode = IEEE80211_MODE_AP, err;
+ struct csa_settings csa_settings;
+ u8 new_vht_oper_chwidth;
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+ "freq=%d chan=%d sec_chan=%d", freq, channel,
+ secondary_channel);
+
+ new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
+
+ /* Setup CSA request */
+ os_memset(&csa_settings, 0, sizeof(csa_settings));
+ csa_settings.cs_count = 5;
+ csa_settings.block_tx = 1;
+#ifdef CONFIG_MESH
+ if (iface->mconf)
+ ieee80211_mode = IEEE80211_MODE_MESH;
+#endif /* CONFIG_MESH */
+ err = hostapd_set_freq_params(&csa_settings.freq_params,
+ iface->conf->hw_mode,
+ freq, channel,
+ iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
+ iface->conf->ieee80211be,
+ secondary_channel,
+ new_vht_oper_chwidth,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx,
+ cmode->vht_capab,
+ &cmode->he_capab[ieee80211_mode],
+ &cmode->eht_capab[ieee80211_mode]);
+
+ if (err) {
+ wpa_printf(MSG_ERROR,
+ "DFS failed to calculate CSA freq params");
+ hostapd_disable_iface(iface);
+ return err;
+ }
+
+ for (i = 0; i < iface->num_bss; i++) {
+ err = hostapd_switch_channel(iface->bss[i], &csa_settings);
+ if (err)
+ break;
+ }
+
+ if (err) {
+ wpa_printf(MSG_WARNING,
+ "DFS failed to schedule CSA (%d) - trying fallback",
+ err);
+ iface->freq = freq;
+ iface->conf->channel = channel;
+ iface->conf->secondary_channel = secondary_channel;
+ hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
+ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+ oper_centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+ oper_centr_freq_seg1_idx);
+
+ hostapd_disable_iface(iface);
+ hostapd_enable_iface(iface);
+
+ return 0;
+ }
+
+ /* Channel configuration will be updated once CSA completes and
+ * ch_switch_notify event is received */
+ wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
+
+ return 0;
+}
+
+
+static void hostpad_dfs_update_background_chain(struct hostapd_iface *iface)
+{
+ int sec = 0;
+ enum dfs_channel_type channel_type = DFS_NO_CAC_YET;
+ struct hostapd_channel_data *channel;
+ u8 oper_centr_freq_seg0_idx = 0;
+ u8 oper_centr_freq_seg1_idx = 0;
+
+ /*
+ * Allow selection of DFS channel in ETSI to comply with
+ * uniform spreading.
+ */
+ if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
+ channel_type = DFS_ANY_CHANNEL;
+
+ channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ channel_type);
+ if (!channel ||
+ channel->chan == iface->conf->channel ||
+ channel->chan == iface->radar_background.channel)
+ channel = dfs_downgrade_bandwidth(iface, &sec,
+ &oper_centr_freq_seg0_idx,
+ &oper_centr_freq_seg1_idx,
+ &channel_type);
+ if (!channel ||
+ hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ channel->freq, channel->chan,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->ieee80211ax,
+ iface->conf->ieee80211be,
+ sec, hostapd_get_oper_chwidth(iface->conf),
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx, true)) {
+ wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel");
+ iface->radar_background.channel = -1;
+ return;
+ }
+
+ iface->radar_background.channel = channel->chan;
+ iface->radar_background.freq = channel->freq;
+ iface->radar_background.secondary_channel = sec;
+ iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx;
+ iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx;
+
+ wpa_printf(MSG_DEBUG,
+ "%s: setting background chain to chan %d (%d MHz)",
+ __func__, channel->chan, channel->freq);
+}
+
+
+static bool
+hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq)
+{
+ return dfs_use_radar_background(iface) &&
+ iface->radar_background.channel != -1 &&
+ iface->radar_background.freq == freq;
+}
+
+
+static int
+hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface)
+{
+ u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+
+ iface->conf->channel = iface->radar_background.channel;
+ iface->freq = iface->radar_background.freq;
+ iface->conf->secondary_channel =
+ iface->radar_background.secondary_channel;
+ hostapd_set_oper_centr_freq_seg0_idx(
+ iface->conf, iface->radar_background.centr_freq_seg0_idx);
+ hostapd_set_oper_centr_freq_seg1_idx(
+ iface->conf, iface->radar_background.centr_freq_seg1_idx);
+
+ hostpad_dfs_update_background_chain(iface);
+
+ return hostapd_dfs_request_channel_switch(
+ iface, iface->conf->channel, iface->freq,
+ iface->conf->secondary_channel, current_vht_oper_chwidth,
+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
+ hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
+}
+
+
int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
@@ -896,6 +1135,22 @@
set_dfs_state(iface, freq, ht_enabled, chan_offset,
chan_width, cf1, cf2,
HOSTAPD_CHAN_DFS_AVAILABLE);
+
+ /*
+ * Radar event from background chain for the selected
+ * channel. Perform CSA, move the main chain to the
+ * selected channel and configure the background chain
+ * to a new DFS channel.
+ */
+ if (hostapd_dfs_is_background_event(iface, freq)) {
+ iface->radar_background.cac_started = 0;
+ if (!iface->radar_background.temp_ch)
+ return 0;
+
+ iface->radar_background.temp_ch = 0;
+ return hostapd_dfs_start_channel_switch_background(iface);
+ }
+
/*
* Just mark the channel available when CAC completion
* event is received in enabled state. CAC result could
@@ -912,6 +1167,9 @@
iface->cac_started = 0;
}
}
+ } else if (hostapd_dfs_is_background_event(iface, freq)) {
+ iface->radar_background.cac_started = 0;
+ hostpad_dfs_update_background_chain(iface);
}
return 0;
@@ -940,7 +1198,8 @@
static struct hostapd_channel_data *
dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
u8 *oper_centr_freq_seg0_idx,
- u8 *oper_centr_freq_seg1_idx, int *skip_radar)
+ u8 *oper_centr_freq_seg1_idx,
+ enum dfs_channel_type *channel_type)
{
struct hostapd_channel_data *channel;
@@ -948,22 +1207,22 @@
channel = dfs_get_valid_channel(iface, secondary_channel,
oper_centr_freq_seg0_idx,
oper_centr_freq_seg1_idx,
- *skip_radar);
+ *channel_type);
if (channel) {
wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d",
channel->chan);
return channel;
}
- if (*skip_radar) {
- *skip_radar = 0;
+ if (*channel_type != DFS_ANY_CHANNEL) {
+ *channel_type = DFS_ANY_CHANNEL;
} else {
int oper_chwidth;
oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
if (oper_chwidth == CHANWIDTH_USE_HT)
break;
- *skip_radar = 1;
+ *channel_type = DFS_AVAILABLE;
hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1);
}
}
@@ -981,7 +1240,7 @@
int secondary_channel;
u8 oper_centr_freq_seg0_idx = 0;
u8 oper_centr_freq_seg1_idx = 0;
- int skip_radar = 0;
+ enum dfs_channel_type channel_type = DFS_ANY_CHANNEL;
int err = 1;
/* Radar detected during active CAC */
@@ -989,13 +1248,13 @@
channel = dfs_get_valid_channel(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
- skip_radar);
+ channel_type);
if (!channel) {
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
- &skip_radar);
+ &channel_type);
if (!channel) {
wpa_printf(MSG_ERROR, "No valid channel available");
return err;
@@ -1022,20 +1281,61 @@
}
+static int
+hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface,
+ int freq)
+{
+ if (!dfs_use_radar_background(iface))
+ return -1; /* Background radar chain not supported. */
+
+ wpa_printf(MSG_DEBUG,
+ "%s called (background CAC active: %s, CSA active: %s)",
+ __func__, iface->radar_background.cac_started ? "yes" : "no",
+ hostapd_csa_in_progress(iface) ? "yes" : "no");
+
+ /* Check if CSA in progress */
+ if (hostapd_csa_in_progress(iface))
+ return 0;
+
+ if (hostapd_dfs_is_background_event(iface, freq)) {
+ /*
+ * Radar pattern is reported on the background chain.
+ * Just select a new random channel according to the
+ * regulations for monitoring.
+ */
+ hostpad_dfs_update_background_chain(iface);
+ return 0;
+ }
+
+ /*
+ * If background radar detection is supported and the radar channel
+ * monitored by the background chain is available switch to it without
+ * waiting for the CAC.
+ */
+ if (iface->radar_background.channel == -1)
+ return -1; /* Background radar chain not available. */
+
+ if (iface->radar_background.cac_started) {
+ /*
+ * Background channel not available yet. Perform CAC on the
+ * main chain.
+ */
+ iface->radar_background.temp_ch = 1;
+ return -1;
+ }
+
+ return hostapd_dfs_start_channel_switch_background(iface);
+}
+
+
static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
{
struct hostapd_channel_data *channel;
int secondary_channel;
u8 oper_centr_freq_seg0_idx;
u8 oper_centr_freq_seg1_idx;
- u8 new_vht_oper_chwidth;
- int skip_radar = 1;
- struct csa_settings csa_settings;
- unsigned int i;
- int err = 1;
- struct hostapd_hw_modes *cmode = iface->current_mode;
+ enum dfs_channel_type channel_type = DFS_AVAILABLE;
u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
- int ieee80211_mode = IEEE80211_MODE_AP;
wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
__func__, iface->cac_started ? "yes" : "no",
@@ -1054,13 +1354,13 @@
* uniform spreading.
*/
if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI)
- skip_radar = 0;
+ channel_type = DFS_ANY_CHANNEL;
/* Perform channel switch/CSA */
channel = dfs_get_valid_channel(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
- skip_radar);
+ channel_type);
if (!channel) {
/*
@@ -1068,11 +1368,11 @@
* there is another channel where we can switch even if it
* requires to perform a CAC first.
*/
- skip_radar = 0;
+ channel_type = DFS_ANY_CHANNEL;
channel = dfs_downgrade_bandwidth(iface, &secondary_channel,
&oper_centr_freq_seg0_idx,
&oper_centr_freq_seg1_idx,
- &skip_radar);
+ &channel_type);
if (!channel) {
/*
* Toggle interface state to enter DFS state
@@ -1083,7 +1383,7 @@
return 0;
}
- if (!skip_radar) {
+ if (channel_type == DFS_ANY_CHANNEL) {
iface->freq = channel->freq;
iface->conf->channel = channel->chan;
iface->conf->secondary_channel = secondary_channel;
@@ -1098,73 +1398,12 @@
}
}
- wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
- channel->chan);
- wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
- "freq=%d chan=%d sec_chan=%d", channel->freq,
- channel->chan, secondary_channel);
-
- new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
- hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
-
- /* Setup CSA request */
- os_memset(&csa_settings, 0, sizeof(csa_settings));
- csa_settings.cs_count = 5;
- csa_settings.block_tx = 1;
-#ifdef CONFIG_MESH
- if (iface->mconf)
- ieee80211_mode = IEEE80211_MODE_MESH;
-#endif /* CONFIG_MESH */
- err = hostapd_set_freq_params(&csa_settings.freq_params,
- iface->conf->hw_mode,
- channel->freq,
- channel->chan,
- iface->conf->enable_edmg,
- iface->conf->edmg_channel,
- iface->conf->ieee80211n,
- iface->conf->ieee80211ac,
- iface->conf->ieee80211ax,
- secondary_channel,
- new_vht_oper_chwidth,
- oper_centr_freq_seg0_idx,
- oper_centr_freq_seg1_idx,
- cmode->vht_capab,
- &cmode->he_capab[ieee80211_mode]);
-
- if (err) {
- wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
- hostapd_disable_iface(iface);
- return err;
- }
-
- for (i = 0; i < iface->num_bss; i++) {
- err = hostapd_switch_channel(iface->bss[i], &csa_settings);
- if (err)
- break;
- }
-
- if (err) {
- wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
- err);
- iface->freq = channel->freq;
- iface->conf->channel = channel->chan;
- iface->conf->secondary_channel = secondary_channel;
- hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
- hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
- oper_centr_freq_seg0_idx);
- hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
- oper_centr_freq_seg1_idx);
-
- hostapd_disable_iface(iface);
- hostapd_enable_iface(iface);
- return 0;
- }
-
- /* Channel configuration will be updated once CSA completes and
- * ch_switch_notify event is received */
-
- wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
- return 0;
+ return hostapd_dfs_request_channel_switch(iface, channel->chan,
+ channel->freq,
+ secondary_channel,
+ current_vht_oper_chwidth,
+ oper_centr_freq_seg0_idx,
+ oper_centr_freq_seg1_idx);
}
@@ -1172,8 +1411,6 @@
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
- int res;
-
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
@@ -1186,20 +1423,23 @@
return 0;
/* mark radar frequency as invalid */
- res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
- cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
- if (!res)
+ if (!set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
+ cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE))
return 0;
- /* Skip if reported radar event not overlapped our channels */
- res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
- if (!res)
- return 0;
+ if (!hostapd_dfs_is_background_event(iface, freq)) {
+ /* Skip if reported radar event not overlapped our channels */
+ if (!dfs_are_channels_overlapped(iface, freq, chan_width,
+ cf1, cf2))
+ return 0;
+ }
- /* radar detected while operating, switch the channel. */
- res = hostapd_dfs_start_channel_switch(iface);
+ if (hostapd_dfs_background_start_channel_switch(iface, freq)) {
+ /* Radar detected while operating, switch the channel. */
+ return hostapd_dfs_start_channel_switch(iface);
+ }
- return res;
+ return 0;
}
@@ -1219,9 +1459,14 @@
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
- /* Handle cases where all channels were initially unavailable */
- if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
+ if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) {
+ /* Handle cases where all channels were initially unavailable */
hostapd_handle_dfs(iface);
+ } else if (dfs_use_radar_background(iface) &&
+ iface->radar_background.channel == -1) {
+ /* Reset radar background chain if disabled */
+ hostpad_dfs_update_background_chain(iface);
+ }
return 0;
}
@@ -1259,17 +1504,24 @@
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
- /* This is called when the driver indicates that an offloaded DFS has
- * started CAC. */
- hostapd_set_state(iface, HAPD_IFACE_DFS);
+ if (hostapd_dfs_is_background_event(iface, freq)) {
+ iface->radar_background.cac_started = 1;
+ } else {
+ /* This is called when the driver indicates that an offloaded
+ * DFS has started CAC. */
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ iface->cac_started = 1;
+ }
/* TODO: How to check CAC time for ETSI weather channels? */
iface->dfs_cac_ms = 60000;
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
"freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
- "seg1=%d cac_time=%ds",
+ "seg1=%d cac_time=%ds%s",
freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
- iface->dfs_cac_ms / 1000);
- iface->cac_started = 1;
+ iface->dfs_cac_ms / 1000,
+ hostapd_dfs_is_background_event(iface, freq) ?
+ " (background)" : "");
+
os_get_reltime(&iface->dfs_cac_start);
return 0;
}
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 96a13fb..d4cbed8 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -31,6 +31,7 @@
static int hostapd_dpp_auth_init_next(struct hostapd_data *hapd);
static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd,
struct dpp_authentication *auth);
+static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd);
#ifdef CONFIG_DPP2
static void hostapd_dpp_reconfig_reply_wait_timeout(void *eloop_ctx,
void *timeout_ctx);
@@ -346,14 +347,8 @@
#endif /* CONFIG_DPP2 */
-enum hostapd_dpp_pkex_ver {
- PKEX_VER_AUTO,
- PKEX_VER_ONLY_1,
- PKEX_VER_ONLY_2,
-};
-
static int hostapd_dpp_pkex_init(struct hostapd_data *hapd,
- enum hostapd_dpp_pkex_ver ver,
+ enum dpp_pkex_ver ver,
const struct hostapd_ip_addr *ipaddr,
int tcp_port)
{
@@ -1160,6 +1155,21 @@
}
+#ifdef CONFIG_DPP3
+static void hostapd_dpp_build_new_key(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth || !auth->waiting_new_key)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key");
+ hostapd_dpp_start_gas_client(hapd);
+}
+#endif /* CONFIG_DPP3 */
+
+
static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_ap_result result,
const struct wpabuf *adv_proto,
@@ -1169,6 +1179,7 @@
const u8 *pos;
struct dpp_authentication *auth = hapd->dpp_auth;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+ int res;
if (!auth || !auth->auth_success) {
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
@@ -1199,7 +1210,16 @@
goto fail;
}
- if (dpp_conf_resp_rx(auth, resp) < 0) {
+ res = dpp_conf_resp_rx(auth, resp);
+#ifdef CONFIG_DPP3
+ if (res == -3) {
+ wpa_printf(MSG_DEBUG, "DPP: New protocol key needed");
+ eloop_register_timeout(0, 0, hostapd_dpp_build_new_key, hapd,
+ NULL);
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+ if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
goto fail;
}
@@ -1986,6 +2006,17 @@
wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
MAC2STR(src));
+ if (hapd->dpp_pkex_ver == PKEX_VER_ONLY_1 && v2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore PKEXv2 Exchange Request when configured to be PKEX v1 only");
+ return;
+ }
+ if (hapd->dpp_pkex_ver == PKEX_VER_ONLY_2 && !v2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore PKEXv1 Exchange Request when configured to be PKEX v2 only");
+ return;
+ }
+
/* TODO: Support multiple PKEX codes by iterating over all the enabled
* values here */
@@ -2349,6 +2380,13 @@
if (!auth)
return;
+#ifdef CONFIG_DPP3
+ if (auth->waiting_new_key && ok) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key");
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
@@ -2409,6 +2447,11 @@
{
struct dpp_bootstrap_info *own_bi;
const char *pos, *end;
+#ifdef CONFIG_DPP3
+ enum dpp_pkex_ver ver = PKEX_VER_AUTO;
+#else /* CONFIG_DPP3 */
+ enum dpp_pkex_ver ver = PKEX_VER_ONLY_1;
+#endif /* CONFIG_DPP3 */
int tcp_port = DPP_TCP_PORT;
struct hostapd_ip_addr *ipaddr = NULL;
#ifdef CONFIG_DPP2
@@ -2474,27 +2517,22 @@
if (!hapd->dpp_pkex_code)
return -1;
+ pos = os_strstr(cmd, " ver=");
+ if (pos) {
+ int v;
+
+ pos += 5;
+ v = atoi(pos);
+ if (v == 1)
+ ver = PKEX_VER_ONLY_1;
+ else if (v == 2)
+ ver = PKEX_VER_ONLY_2;
+ else
+ return -1;
+ }
+ hapd->dpp_pkex_ver = ver;
+
if (os_strstr(cmd, " init=1")) {
-#ifdef CONFIG_DPP3
- enum hostapd_dpp_pkex_ver ver = PKEX_VER_AUTO;
-#else /* CONFIG_DPP3 */
- enum hostapd_dpp_pkex_ver ver = PKEX_VER_ONLY_1;
-#endif /* CONFIG_DPP3 */
-
- pos = os_strstr(cmd, " ver=");
- if (pos) {
- int v;
-
- pos += 5;
- v = atoi(pos);
- if (v == 1)
- ver = PKEX_VER_ONLY_1;
- else if (v == 2)
- ver = PKEX_VER_ONLY_2;
- else
- return -1;
- }
-
if (hostapd_dpp_pkex_init(hapd, ver, ipaddr, tcp_port) < 0)
return -1;
} else {
@@ -2646,6 +2684,9 @@
if (hapd->iface->interfaces)
dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd);
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ eloop_cancel_timeout(hostapd_dpp_build_new_key, hapd, NULL);
+#endif /* CONFIG_DPP3 */
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
hostapd_dpp_pkex_remove(hapd, "*");
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index f353a0e..643a273 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -261,12 +261,7 @@
}
#endif /* NEED_AP_MLME */
-#ifdef CONFIG_INTERWORKING
- if (elems.ext_capab && elems.ext_capab_len > 4) {
- if (elems.ext_capab[4] & 0x01)
- sta->qos_map_enabled = 1;
- }
-#endif /* CONFIG_INTERWORKING */
+ check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len);
#ifdef CONFIG_HS20
wpabuf_free(sta->hs20_ie);
@@ -870,10 +865,11 @@
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+ "driver %s channel switch: freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
finished ? "had" : "starting",
freq, ht, hapd->iconf->ch_switch_vht_config,
- hapd->iconf->ch_switch_he_config, offset,
+ hapd->iconf->ch_switch_he_config,
+ hapd->iconf->ch_switch_eht_config, offset,
width, channel_width_to_string(width), cf1, cf2);
if (!hapd->iface->current_mode) {
@@ -953,9 +949,23 @@
else if (hapd->iconf->ch_switch_he_config &
CH_SWITCH_HE_DISABLED)
hapd->iconf->ieee80211ax = 0;
+#ifdef CONFIG_IEEE80211BE
+ } else if (hapd->iconf->ch_switch_eht_config) {
+ /* CHAN_SWITCH EHT config */
+ if (hapd->iconf->ch_switch_eht_config &
+ CH_SWITCH_EHT_ENABLED) {
+ hapd->iconf->ieee80211be = 1;
+ hapd->iconf->ieee80211ax = 1;
+ if (!is_6ghz_freq(hapd->iface->freq))
+ hapd->iconf->ieee80211ac = 1;
+ } else if (hapd->iconf->ch_switch_eht_config &
+ CH_SWITCH_EHT_DISABLED)
+ hapd->iconf->ieee80211be = 0;
+#endif /* CONFIG_IEEE80211BE */
}
hapd->iconf->ch_switch_vht_config = 0;
hapd->iconf->ch_switch_he_config = 0;
+ hapd->iconf->ch_switch_eht_config = 0;
if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 ||
width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160)
@@ -1011,7 +1021,9 @@
hostapd_neighbor_set_own_report(hapd->iface->bss[i]);
#ifdef CONFIG_OCV
- if (hapd->conf->ocv) {
+ if (hapd->conf->ocv &&
+ !(hapd->iface->drv_flags2 &
+ WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP)) {
struct sta_info *sta;
bool check_sa_query = false;
@@ -2084,6 +2096,32 @@
data->wds_sta_interface.ifname,
data->wds_sta_interface.sta_addr);
break;
+#ifdef CONFIG_IEEE80211AX
+ case EVENT_BSS_COLOR_COLLISION:
+ /* The BSS color is shared amongst all BBSs on a specific phy.
+ * Therefore we always start the color change on the primary
+ * BSS. */
+ wpa_printf(MSG_DEBUG, "BSS color collision on %s",
+ hapd->conf->iface);
+ hostapd_switch_color(hapd->iface->bss[0],
+ data->bss_color_collision.bitmap);
+ break;
+ case EVENT_CCA_STARTED_NOTIFY:
+ wpa_printf(MSG_DEBUG, "CCA started on on %s",
+ hapd->conf->iface);
+ break;
+ case EVENT_CCA_ABORTED_NOTIFY:
+ wpa_printf(MSG_DEBUG, "CCA aborted on on %s",
+ hapd->conf->iface);
+ hostapd_cleanup_cca_params(hapd);
+ break;
+ case EVENT_CCA_NOTIFY:
+ wpa_printf(MSG_DEBUG, "CCA finished on on %s",
+ hapd->conf->iface);
+ hapd->iface->conf->he_op.he_bss_color = hapd->cca_color;
+ hostapd_cleanup_cca_params(hapd);
+ break;
+#endif /* CONFIG_IEEE80211AX */
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 4b88641..ef53c41 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -66,6 +66,10 @@
static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx);
static void hostapd_interface_setup_failure_handler(void *eloop_ctx,
void *timeout_ctx);
+#ifdef CONFIG_IEEE80211AX
+static void hostapd_switch_color_timeout_handler(void *eloop_data,
+ void *user_ctx);
+#endif /* CONFIG_IEEE80211AX */
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
@@ -462,6 +466,10 @@
}
eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL);
#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_IEEE80211AX
+ eloop_cancel_timeout(hostapd_switch_color_timeout_handler, hapd, NULL);
+#endif /* CONFIG_IEEE80211AX */
}
@@ -1458,14 +1466,14 @@
}
-static void hostapd_set_acl(struct hostapd_data *hapd)
+int hostapd_set_acl(struct hostapd_data *hapd)
{
struct hostapd_config *conf = hapd->iconf;
- int err;
+ int err = 0;
u8 accept_acl;
if (hapd->iface->drv_max_acl_mac_addrs == 0)
- return;
+ return 0;
if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
accept_acl = 1;
@@ -1474,7 +1482,7 @@
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set accept acl");
- return;
+ return -1;
}
} else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
accept_acl = 0;
@@ -1483,9 +1491,10 @@
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set deny acl");
- return;
+ return -1;
}
}
+ return err;
}
@@ -2067,6 +2076,7 @@
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
hapd->iconf->ieee80211ax,
+ hapd->iconf->ieee80211be,
hapd->iconf->secondary_channel,
hostapd_get_oper_chwidth(hapd->iconf),
hostapd_get_oper_centr_freq_seg0_idx(
@@ -3452,12 +3462,14 @@
conf->channel, conf->enable_edmg,
conf->edmg_channel, conf->ieee80211n,
conf->ieee80211ac, conf->ieee80211ax,
- conf->secondary_channel,
+ conf->ieee80211be, conf->secondary_channel,
hostapd_get_oper_chwidth(conf),
hostapd_get_oper_centr_freq_seg0_idx(conf),
hostapd_get_oper_centr_freq_seg1_idx(conf),
conf->vht_capab,
mode ? &mode->he_capab[IEEE80211_MODE_AP] :
+ NULL,
+ mode ? &mode->eht_capab[IEEE80211_MODE_AP] :
NULL))
return -1;
@@ -3545,11 +3557,12 @@
&hapd->iface->cs_oper_class,
&chan) == NUM_HOSTAPD_MODES) {
wpa_printf(MSG_DEBUG,
- "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)",
+ "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d)",
settings->freq_params.freq,
settings->freq_params.sec_channel_offset,
settings->freq_params.vht_enabled,
- settings->freq_params.he_enabled);
+ settings->freq_params.he_enabled,
+ settings->freq_params.eht_enabled);
return -1;
}
@@ -3606,6 +3619,11 @@
void hostapd_chan_switch_config(struct hostapd_data *hapd,
struct hostapd_freq_params *freq_params)
{
+ if (freq_params->eht_enabled)
+ hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_ENABLED;
+ else
+ hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_DISABLED;
+
if (freq_params->he_enabled)
hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED;
else
@@ -3618,7 +3636,8 @@
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
- "CHAN_SWITCH HE config 0x%x VHT config 0x%x",
+ "CHAN_SWITCH EHT config 0x%x HE config 0x%x VHT config 0x%x",
+ hapd->iconf->ch_switch_eht_config,
hapd->iconf->ch_switch_he_config,
hapd->iconf->ch_switch_vht_config);
}
@@ -3696,6 +3715,7 @@
iface->conf->ieee80211n = freq_params->ht_enabled;
iface->conf->ieee80211ac = freq_params->vht_enabled;
iface->conf->ieee80211ax = freq_params->he_enabled;
+ iface->conf->ieee80211be = freq_params->eht_enabled;
/*
* cs_params must not be cleared earlier because the freq_params
@@ -3706,6 +3726,139 @@
hostapd_enable_iface(iface);
}
+
+#ifdef CONFIG_IEEE80211AX
+
+void hostapd_cleanup_cca_params(struct hostapd_data *hapd)
+{
+ hapd->cca_count = 0;
+ hapd->cca_color = 0;
+ hapd->cca_c_off_beacon = 0;
+ hapd->cca_c_off_proberesp = 0;
+ hapd->cca_in_progress = false;
+}
+
+
+static int hostapd_fill_cca_settings(struct hostapd_data *hapd,
+ struct cca_settings *settings)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ u8 old_color;
+ int ret;
+
+ if (!iface || iface->conf->he_op.he_bss_color_disabled)
+ return -1;
+
+ old_color = iface->conf->he_op.he_bss_color;
+ iface->conf->he_op.he_bss_color = hapd->cca_color;
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
+ if (ret)
+ return ret;
+
+ iface->conf->he_op.he_bss_color = old_color;
+
+ settings->cca_count = hapd->cca_count;
+ settings->cca_color = hapd->cca_color,
+ hapd->cca_in_progress = true;
+
+ ret = hostapd_build_beacon_data(hapd, &settings->beacon_cca);
+ if (ret) {
+ free_beacon_data(&settings->beacon_after);
+ return ret;
+ }
+
+ settings->counter_offset_beacon = hapd->cca_c_off_beacon;
+ settings->counter_offset_presp = hapd->cca_c_off_proberesp;
+
+ return 0;
+}
+
+
+static void hostapd_switch_color_timeout_handler(void *eloop_data,
+ void *user_ctx)
+{
+ struct hostapd_data *hapd = (struct hostapd_data *) eloop_data;
+ os_time_t delta_t;
+ unsigned int b;
+ int i, r;
+
+ /* CCA can be triggered once the handler constantly receives
+ * color collision events to for at least
+ * DOT11BSS_COLOR_COLLISION_AP_PERIOD (50 s by default). */
+ delta_t = hapd->last_color_collision.sec -
+ hapd->first_color_collision.sec;
+ if (delta_t < DOT11BSS_COLOR_COLLISION_AP_PERIOD)
+ return;
+
+ r = os_random() % HE_OPERATION_BSS_COLOR_MAX;
+ for (i = 0; i < HE_OPERATION_BSS_COLOR_MAX; i++) {
+ if (r && !(hapd->color_collision_bitmap & BIT(r)))
+ break;
+
+ r = (r + 1) % HE_OPERATION_BSS_COLOR_MAX;
+ }
+
+ if (i == HE_OPERATION_BSS_COLOR_MAX) {
+ /* There are no free colors so turn BSS coloring off */
+ wpa_printf(MSG_INFO,
+ "No free colors left, turning off BSS coloring");
+ hapd->iface->conf->he_op.he_bss_color_disabled = 1;
+ hapd->iface->conf->he_op.he_bss_color = os_random() % 63 + 1;
+ for (b = 0; b < hapd->iface->num_bss; b++)
+ ieee802_11_set_beacon(hapd->iface->bss[b]);
+ return;
+ }
+
+ for (b = 0; b < hapd->iface->num_bss; b++) {
+ struct hostapd_data *bss = hapd->iface->bss[b];
+ struct cca_settings settings;
+ int ret;
+
+ hostapd_cleanup_cca_params(bss);
+ bss->cca_color = r;
+ bss->cca_count = 10;
+
+ if (hostapd_fill_cca_settings(bss, &settings)) {
+ hostapd_cleanup_cca_params(bss);
+ continue;
+ }
+
+ ret = hostapd_drv_switch_color(bss, &settings);
+ if (ret)
+ hostapd_cleanup_cca_params(bss);
+
+ free_beacon_data(&settings.beacon_cca);
+ free_beacon_data(&settings.beacon_after);
+ }
+}
+
+
+void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap)
+{
+ struct os_reltime now;
+
+ if (hapd->cca_in_progress)
+ return;
+
+ if (os_get_reltime(&now))
+ return;
+
+ hapd->color_collision_bitmap = bitmap;
+ hapd->last_color_collision = now;
+
+ if (eloop_is_timeout_registered(hostapd_switch_color_timeout_handler,
+ hapd, NULL))
+ return;
+
+ hapd->first_color_collision = now;
+ /* 10 s window as margin for persistent color collision reporting */
+ eloop_register_timeout(DOT11BSS_COLOR_COLLISION_AP_PERIOD + 10, 0,
+ hostapd_switch_color_timeout_handler,
+ hapd, NULL);
+}
+
+#endif /* CONFIG_IEEE80211AX */
+
#endif /* NEED_AP_MLME */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 7f7877b..6b9b65f 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -14,6 +14,7 @@
#endif /* CONFIG_SQLITE */
#include "common/defs.h"
+#include "common/dpp.h"
#include "utils/list.h"
#include "ap_config.h"
#include "drivers/driver.h"
@@ -207,6 +208,7 @@
void *ssl_ctx;
void *eap_sim_db_priv;
+ struct crypto_rsa_key *imsi_privacy_key;
struct radius_server_data *radius_srv;
struct dl_list erp_keys; /* struct eap_server_erp_key */
@@ -294,6 +296,17 @@
unsigned int cs_c_off_ecsa_beacon;
unsigned int cs_c_off_ecsa_proberesp;
+#ifdef CONFIG_IEEE80211AX
+ bool cca_in_progress;
+ u8 cca_count;
+ u8 cca_color;
+ unsigned int cca_c_off_beacon;
+ unsigned int cca_c_off_proberesp;
+ struct os_reltime first_color_collision;
+ struct os_reltime last_color_collision;
+ u64 color_collision_bitmap;
+#endif /* CONFIG_IEEE80211AX */
+
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
@@ -388,6 +401,7 @@
struct dpp_bootstrap_info *dpp_pkex_bi;
char *dpp_pkex_code;
char *dpp_pkex_identifier;
+ enum dpp_pkex_ver dpp_pkex_ver;
char *dpp_pkex_auth_cmd;
char *dpp_configurator_params;
struct os_reltime dpp_last_init;
@@ -521,6 +535,21 @@
int *basic_rates;
int freq;
+ /* Background radar configuration */
+ struct {
+ int channel;
+ int secondary_channel;
+ int freq;
+ int centr_freq_seg0_idx;
+ int centr_freq_seg1_idx;
+ /* Main chain is on temporary channel during
+ * CAC detection on radar offchain.
+ */
+ unsigned int temp_ch:1;
+ /* CAC started on radar offchain */
+ unsigned int cac_started:1;
+ } radar_background;
+
u16 hw_flags;
/* Number of associated Non-ERP stations (i.e., stations using 802.11b
@@ -648,6 +677,9 @@
int hostapd_owe_trans_get_info(struct hostapd_data *hapd);
void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx);
+void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap);
+void hostapd_cleanup_cca_params(struct hostapd_data *hapd);
+
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
@@ -693,4 +725,6 @@
struct fst_wpa_obj *iface_obj);
#endif /* CONFIG_FST */
+int hostapd_set_acl(struct hostapd_data *hapd);
+
#endif /* HOSTAPD_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 6140a49..394e292 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -498,6 +498,7 @@
struct sae_password_entry *pw;
struct sae_pt *pt = NULL;
const struct sae_pk *pk = NULL;
+ struct hostapd_sta_wpa_psk_short *psk = NULL;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
@@ -519,6 +520,15 @@
pt = hapd->conf->ssid.pt;
}
+ if (!password) {
+ for (psk = sta->psk; psk; psk = psk->next) {
+ if (psk->is_passphrase) {
+ password = psk->passphrase;
+ break;
+ }
+ }
+ }
+
if (pw_entry)
*pw_entry = pw;
if (s_pt)
@@ -2315,9 +2325,8 @@
}
-static int
-ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
- int res, struct radius_sta *info)
+int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+ int res, struct radius_sta *info)
{
u32 session_timeout = info->session_timeout;
u32 acct_interim_interval = info->acct_interim_interval;
@@ -3112,6 +3121,7 @@
int ret, inc_y;
bool derive_keys;
u32 i;
+ bool derive_kdk;
if (!groups)
groups = default_groups;
@@ -3151,10 +3161,14 @@
sta->pasn->akmp = rsn_data.key_mgmt;
sta->pasn->cipher = rsn_data.pairwise_cipher;
- if (hapd->conf->force_kdk_derivation ||
- ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
- ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
- WLAN_RSNX_CAPAB_SECURE_LTF)))
+ derive_kdk = (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
+ ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_SECURE_LTF);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!derive_kdk)
+ derive_kdk = hapd->conf->force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (derive_kdk)
sta->pasn->kdk_len = WPA_KDK_MAX_LEN;
else
sta->pasn->kdk_len = 0;
@@ -4123,32 +4137,6 @@
}
-static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *ext_capab_ie, size_t ext_capab_ie_len)
-{
-#ifdef CONFIG_INTERWORKING
- /* check for QoS Map support */
- if (ext_capab_ie_len >= 5) {
- if (ext_capab_ie[4] & 0x01)
- sta->qos_map_enabled = 1;
- }
-#endif /* CONFIG_INTERWORKING */
-
- if (ext_capab_ie_len > 0) {
- sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
- os_free(sta->ext_capability);
- sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
- if (sta->ext_capability) {
- sta->ext_capability[0] = ext_capab_ie_len;
- os_memcpy(sta->ext_capability + 1, ext_capab_ie,
- ext_capab_ie_len);
- }
- }
-
- return WLAN_STATUS_SUCCESS;
-}
-
-
#ifdef CONFIG_OWE
static int owe_group_supported(struct hostapd_data *hapd, u16 group)
@@ -4203,8 +4191,21 @@
else
return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
- crypto_ecdh_deinit(sta->owe_ecdh);
- sta->owe_ecdh = crypto_ecdh_init(group);
+ if (sta->owe_group == group && sta->owe_ecdh) {
+ /* This is a workaround for mac80211 behavior of retransmitting
+ * the Association Request frames multiple times if the link
+ * layer retries (i.e., seq# remains same) fail. The mac80211
+ * initiated retransmission will use a different seq# and as
+ * such, will go through duplicate detection. If we were to
+ * change our DH key for that attempt, there would be two
+ * different DH shared secrets and the STA would likely select
+ * the wrong one. */
+ wpa_printf(MSG_DEBUG,
+ "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again");
+ } else {
+ crypto_ecdh_deinit(sta->owe_ecdh);
+ sta->owe_ecdh = crypto_ecdh_init(group);
+ }
if (!sta->owe_ecdh)
return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
sta->owe_group = group;
@@ -4553,6 +4554,17 @@
}
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP,
+ elems.he_capabilities,
+ elems.he_capabilities_len,
+ elems.eht_capabilities,
+ elems.eht_capabilities_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
+#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_P2P
if (elems.p2p) {
@@ -4924,6 +4936,7 @@
struct ieee80211_ht_capabilities ht_cap;
struct ieee80211_vht_capabilities vht_cap;
struct ieee80211_he_capabilities he_cap;
+ struct ieee80211_eht_capabilities eht_cap;
int set = 1;
/*
@@ -4980,6 +4993,11 @@
sta->he_capab_len);
}
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ if (sta->flags & WLAN_STA_EHT)
+ hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap,
+ sta->eht_capab_len);
+#endif /* CONFIG_IEEE80211BE */
/*
* Add the station with forced WLAN_STA_ASSOC flag. The sta->flags
@@ -4993,6 +5011,8 @@
sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
sta->flags & WLAN_STA_HE ? &he_cap : NULL,
sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0,
+ sta->flags & WLAN_STA_EHT ? &eht_cap : NULL,
+ sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0,
sta->he_6ghz_capab,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
@@ -5043,6 +5063,13 @@
if (sta && sta->dpp_pfs)
buflen += 5 + sta->dpp_pfs->curve->prime_len;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP);
+ buflen += 3 + sizeof(struct ieee80211_eht_operation);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
buf = os_zalloc(buflen);
if (!buf) {
res = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -5151,6 +5178,7 @@
if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) {
p = hostapd_eid_he_capab(hapd, p, IEEE80211_MODE_AP);
p = hostapd_eid_he_operation(hapd, p);
+ p = hostapd_eid_cca(hapd, p);
p = hostapd_eid_spatial_reuse(hapd, p);
p = hostapd_eid_he_mu_edca_parameter_set(hapd, p);
p = hostapd_eid_he_6ghz_band_cap(hapd, p);
@@ -5188,6 +5216,13 @@
rsnxe_done:
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
+ p = hostapd_eid_eht_operation(hapd, p);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
@@ -6903,6 +6938,38 @@
}
+static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count,
+ enum max_tx_pwr_interpretation tx_pwr_intrpn,
+ u8 tx_pwr_cat, u8 tx_pwr)
+{
+ int i;
+
+ *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */
+ *eid++ = 2 + tx_pwr_count; /* Length */
+
+ /*
+ * Transmit Power Information field
+ * bits 0-2 : Maximum Transmit Power Count
+ * bits 3-5 : Maximum Transmit Power Interpretation
+ * bits 6-7 : Maximum Transmit Power Category
+ */
+ *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6);
+
+ /* Maximum Transmit Power field */
+ for (i = 0; i <= tx_pwr_count; i++)
+ *eid++ = tx_pwr;
+
+ return eid;
+}
+
+
+/*
+ * TODO: Extract power limits from channel data after 6G regulatory
+ * support.
+ */
+#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */
+#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */
+
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
{
struct hostapd_iface *iface = hapd->iface;
@@ -6927,6 +6994,43 @@
if (i == mode->num_channels)
return eid;
+#ifdef CONFIG_IEEE80211AX
+ /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United
+ * States): An AP that is an Indoor Access Point per regulatory rules
+ * shall send at least two Transmit Power Envelope elements in Beacon
+ * and Probe Response frames as follows:
+ * - Maximum Transmit Power Category subfield = Default;
+ * Unit interpretation = Regulatory client EIRP PSD
+ * - Maximum Transmit Power Category subfield = Subordinate Device;
+ * Unit interpretation = Regulatory client EIRP PSD
+ */
+ if (is_6ghz_op_class(iconf->op_class)) {
+ enum max_tx_pwr_interpretation tx_pwr_intrpn;
+
+ /* Same Maximum Transmit Power for all 20 MHz bands */
+ tx_pwr_count = 0;
+ tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD;
+
+ /* Default Transmit Power Envelope for Global Operating Class */
+ tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2;
+ eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn,
+ REG_DEFAULT_CLIENT, tx_pwr);
+
+ /* Indoor Access Point must include an additional TPE for
+ * subordinate devices */
+ if (iconf->he_6ghz_reg_pwr_type == HE_6GHZ_INDOOR_AP) {
+ /* TODO: Extract PSD limits from channel data */
+ tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2;
+ eid = hostapd_add_tpe_info(eid, tx_pwr_count,
+ tx_pwr_intrpn,
+ REG_SUBORDINATE_CLIENT,
+ tx_pwr);
+ }
+
+ return eid;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
switch (hostapd_get_oper_chwidth(iconf)) {
case CHANWIDTH_USE_HT:
if (iconf->secondary_channel == 0) {
@@ -6999,19 +7103,9 @@
else
tx_pwr = max_tx_power;
- *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE;
- *eid++ = 2 + tx_pwr_count;
-
- /*
- * Max Transmit Power count and
- * Max Transmit Power units = 0 (EIRP)
- */
- *eid++ = tx_pwr_count;
-
- for (i = 0; i <= tx_pwr_count; i++)
- *eid++ = tx_pwr;
-
- return eid;
+ return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP,
+ 0 /* Reserved for bands other than 6 GHz */,
+ tx_pwr);
}
@@ -7022,7 +7116,8 @@
if (!hapd->cs_freq_params.channel ||
(!hapd->cs_freq_params.vht_enabled &&
- !hapd->cs_freq_params.he_enabled))
+ !hapd->cs_freq_params.he_enabled &&
+ !hapd->cs_freq_params.eht_enabled))
return eid;
/* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index c59ad5e..fa1f47b 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -78,6 +78,10 @@
const struct ieee80211_he_capabilities *he_cap,
struct ieee80211_he_capabilities *neg_he_cap,
size_t he_capab_len);
+void hostapd_get_eht_capab(struct hostapd_data *hapd,
+ const struct ieee80211_eht_capabilities *src,
+ struct ieee80211_eht_capabilities *dest,
+ size_t len);
int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab);
@@ -100,6 +104,7 @@
const u8 *he_6ghz_capab);
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
enum ieee80211_op_mode mode);
+u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
@@ -194,7 +199,20 @@
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
+u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ext_capab_ie, size_t ext_capab_ie_len);
size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type);
u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type);
+int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+ int res, struct radius_sta *info);
+size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd,
+ enum ieee80211_op_mode opmode);
+u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode);
+u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid);
+u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode,
+ const u8 *he_capab, size_t he_capab_len,
+ const u8 *eht_capab, size_t eht_capab_len);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 783ee6d..4277d82 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -20,6 +20,8 @@
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "wpa_auth.h"
#include "ieee802_11.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
@@ -43,6 +45,11 @@
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
size_t auth_msg_len;
struct hostapd_acl_query_data *next;
+ bool radius_psk;
+ int akm;
+ u8 *anonce;
+ u8 *eapol;
+ size_t eapol_len;
};
@@ -95,9 +102,11 @@
static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
{
- if (query == NULL)
+ if (!query)
return;
os_free(query->auth_msg);
+ os_free(query->anonce);
+ os_free(query->eapol);
os_free(query);
}
@@ -111,7 +120,7 @@
query->radius_id = radius_client_get_id(hapd->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
- if (msg == NULL)
+ if (!msg)
return -1;
if (radius_msg_make_authenticator(msg) < 0) {
@@ -153,6 +162,31 @@
goto fail;
}
+ if (query->akm &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
+ wpa_akm_to_suite(query->akm))) {
+ wpa_printf(MSG_DEBUG, "Could not add WLAN-AKM-Suite");
+ goto fail;
+ }
+
+ if (query->anonce &&
+ !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
+ RADIUS_VENDOR_ID_FREERADIUS,
+ RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE,
+ query->anonce, WPA_NONCE_LEN)) {
+ wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-Anonce");
+ goto fail;
+ }
+
+ if (query->eapol &&
+ !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
+ RADIUS_VENDOR_ID_FREERADIUS,
+ RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG,
+ query->eapol, query->eapol_len)) {
+ wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-EAPoL-Key-Msg");
+ goto fail;
+ }
+
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
goto fail;
return 0;
@@ -260,23 +294,23 @@
/* No entry in the cache - query external RADIUS server */
query = os_zalloc(sizeof(*query));
- if (query == NULL) {
+ if (!query) {
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
os_get_reltime(&query->timestamp);
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
- wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
- "for ACL query.");
+ wpa_printf(MSG_DEBUG,
+ "Failed to send Access-Request for ACL query.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
query->auth_msg = os_memdup(msg, len);
- if (query->auth_msg == NULL) {
- wpa_printf(MSG_ERROR, "Failed to allocate memory for "
- "auth frame.");
+ if (!query->auth_msg) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate memory for auth frame.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
@@ -392,7 +426,7 @@
* Passphrase is NULL iff there is no i-th Tunnel-Password
* attribute in msg.
*/
- if (passphrase == NULL)
+ if (!passphrase)
break;
/*
@@ -464,28 +498,30 @@
prev = query;
query = query->next;
}
- if (query == NULL)
+ if (!query)
return RADIUS_RX_UNKNOWN;
- wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
- "message (id=%d)", query->radius_id);
+ wpa_printf(MSG_DEBUG,
+ "Found matching Access-Request for RADIUS message (id=%d)",
+ query->radius_id);
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
- wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
- "correct authenticator - dropped\n");
+ wpa_printf(MSG_INFO,
+ "Incoming RADIUS packet did not have correct authenticator - dropped");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
hdr->code != RADIUS_CODE_ACCESS_REJECT) {
- wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
- "query", hdr->code);
+ wpa_printf(MSG_DEBUG,
+ "Unknown RADIUS message code %d to ACL query",
+ hdr->code);
return RADIUS_RX_UNKNOWN;
}
/* Insert Accept/Reject info into ACL cache */
cache = os_zalloc(sizeof(*cache));
- if (cache == NULL) {
+ if (!cache) {
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
@@ -506,8 +542,9 @@
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
&info->acct_interim_interval) == 0 &&
info->acct_interim_interval < 60) {
- wpa_printf(MSG_DEBUG, "Ignored too small "
- "Acct-Interim-Interval %d for STA " MACSTR,
+ wpa_printf(MSG_DEBUG,
+ "Ignored too small Acct-Interim-Interval %d for STA "
+ MACSTR,
info->acct_interim_interval,
MAC2STR(query->addr));
info->acct_interim_interval = 0;
@@ -557,20 +594,43 @@
cache->next = hapd->acl_cache;
hapd->acl_cache = cache;
+ if (query->radius_psk) {
+ struct sta_info *sta;
+ bool success = cache->accepted == HOSTAPD_ACL_ACCEPT;
+
+ sta = ap_get_sta(hapd, query->addr);
+ if (!sta || !sta->wpa_sm) {
+ wpa_printf(MSG_DEBUG,
+ "No STA/SM entry found for the RADIUS PSK response");
+ goto done;
+ }
+#ifdef NEED_AP_MLME
+ if (success &&
+ (ieee802_11_set_radius_info(hapd, sta, cache->accepted,
+ info) < 0 ||
+ ap_sta_bind_vlan(hapd, sta) < 0))
+ success = false;
+#endif /* NEED_AP_MLME */
+ wpa_auth_sta_radius_psk_resp(sta->wpa_sm, success);
+ } else {
#ifdef CONFIG_DRIVER_RADIUS_ACL
- hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
- info->session_timeout);
+ hostapd_drv_set_radius_acl_auth(hapd, query->addr,
+ cache->accepted,
+ info->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
- /* Re-send original authentication frame for 802.11 processing */
- wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
- "successful RADIUS ACL query");
- ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
+ /* Re-send original authentication frame for 802.11 processing
+ */
+ wpa_printf(MSG_DEBUG,
+ "Re-sending authentication frame after successful RADIUS ACL query");
+ ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
+ NULL);
#endif /* NEED_AP_MLME */
#endif /* CONFIG_DRIVER_RADIUS_ACL */
+ }
done:
- if (prev == NULL)
+ if (!prev)
hapd->acl_queries = query->next;
else
prev->next = query->next;
@@ -646,6 +706,40 @@
while (psk) {
struct hostapd_sta_wpa_psk_short *prev = psk;
psk = psk->next;
- os_free(prev);
+ bin_clear_free(prev, sizeof(*prev));
}
}
+
+
+#ifndef CONFIG_NO_RADIUS
+void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
+ int key_mgmt, const u8 *anonce,
+ const u8 *eapol, size_t eapol_len)
+{
+ struct hostapd_acl_query_data *query;
+
+ query = os_zalloc(sizeof(*query));
+ if (!query)
+ return;
+
+ query->radius_psk = true;
+ query->akm = key_mgmt;
+ os_get_reltime(&query->timestamp);
+ os_memcpy(query->addr, addr, ETH_ALEN);
+ if (anonce)
+ query->anonce = os_memdup(anonce, WPA_NONCE_LEN);
+ if (eapol) {
+ query->eapol = os_memdup(eapol, eapol_len);
+ query->eapol_len = eapol_len;
+ }
+ if (hostapd_radius_acl_query(hapd, addr, query)) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to send Access-Request for RADIUS PSK/ACL query");
+ hostapd_acl_query_free(query);
+ return;
+ }
+
+ query->next = hapd->acl_queries;
+ hapd->acl_queries = query;
+}
+#endif /* CONFIG_NO_RADIUS */
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 9410f55..22ae1a9 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -36,5 +36,8 @@
void hostapd_acl_expire(struct hostapd_data *hapd);
void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
struct hostapd_sta_wpa_psk_short *src);
+void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
+ int key_mgmt, const u8 *anonce,
+ const u8 *eapol, size_t eapol_len);
#endif /* IEEE802_11_AUTH_H */
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
new file mode 100644
index 0000000..dbbf9a6
--- /dev/null
+++ b/src/ap/ieee802_11_eht.c
@@ -0,0 +1,353 @@
+/*
+ * hostapd / IEEE 802.11be EHT
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ieee802_11.h"
+
+
+static u16 ieee80211_eht_ppet_size(u16 ppe_thres_hdr, const u8 *phy_cap_info)
+{
+ u8 ru;
+ u16 sz = 0;
+
+ if ((phy_cap_info[EHT_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] &
+ EHT_PHYCAP_PPE_THRESHOLD_PRESENT) == 0)
+ return 0;
+
+ ru = (ppe_thres_hdr &
+ EHT_PPE_THRES_RU_INDEX_MASK) >> EHT_PPE_THRES_RU_INDEX_SHIFT;
+ while (ru) {
+ if (ru & 0x1)
+ sz++;
+ ru >>= 1;
+ }
+
+ sz = sz * (1 + ((ppe_thres_hdr & EHT_PPE_THRES_NSS_MASK) >>
+ EHT_PPE_THRES_NSS_SHIFT));
+ sz = (sz * 6) + 9;
+ if (sz % 8)
+ sz += 8;
+ sz /= 8;
+
+ return sz;
+}
+
+
+static u8 ieee80211_eht_mcs_set_size(const u8 *he_phy_cap,
+ const u8 *eht_phy_cap)
+{
+ u8 sz = EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+
+ if ((he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0)
+ return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY;
+
+ if (he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
+ (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+ HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))
+ sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+
+ if (eht_phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)
+ sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS;
+
+ return sz;
+}
+
+
+size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd,
+ enum ieee80211_op_mode opmode)
+{
+ struct hostapd_hw_modes *mode;
+ struct eht_capabilities *eht_cap;
+ size_t len = 3 + 2 + EHT_PHY_CAPAB_LEN;
+
+ mode = hapd->iface->current_mode;
+ if (!mode)
+ return 0;
+
+ eht_cap = &mode->eht_capab[opmode];
+ if (!eht_cap->eht_supported)
+ return 0;
+
+ len += ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+ eht_cap->phy_cap);
+ len += ieee80211_eht_ppet_size(WPA_GET_LE16(&eht_cap->ppet[0]),
+ eht_cap->phy_cap);
+
+ return len;
+}
+
+
+u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode)
+{
+ struct hostapd_hw_modes *mode;
+ struct eht_capabilities *eht_cap;
+ struct ieee80211_eht_capabilities *cap;
+ size_t mcs_nss_len, ppe_thresh_len;
+ u8 *pos = eid, *length_pos;
+
+ mode = hapd->iface->current_mode;
+ if (!mode)
+ return eid;
+
+ eht_cap = &mode->eht_capab[opmode];
+ if (!eht_cap->eht_supported)
+ return eid;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ length_pos = pos++;
+ *pos++ = WLAN_EID_EXT_EHT_CAPABILITIES;
+
+ cap = (struct ieee80211_eht_capabilities *) pos;
+ os_memset(cap, 0, sizeof(*cap));
+ cap->mac_cap = host_to_le16(eht_cap->mac_cap);
+ os_memcpy(cap->phy_cap, eht_cap->phy_cap, EHT_PHY_CAPAB_LEN);
+
+ if (!is_6ghz_op_class(hapd->iconf->op_class))
+ cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &=
+ ~EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK;
+ if (!hapd->iface->conf->eht_phy_capab.su_beamformer)
+ cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMER_IDX] &=
+ ~EHT_PHYCAP_SU_BEAMFORMER;
+
+ if (!hapd->iface->conf->eht_phy_capab.su_beamformee)
+ cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMEE_IDX] &=
+ ~EHT_PHYCAP_SU_BEAMFORMEE;
+
+ if (!hapd->iface->conf->eht_phy_capab.mu_beamformer)
+ cap->phy_cap[EHT_PHYCAP_MU_BEAMFORMER_IDX] &=
+ ~EHT_PHYCAP_MU_BEAMFORMER_MASK;
+
+ pos = cap->optional;
+
+ mcs_nss_len = ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+ eht_cap->phy_cap);
+ if (mcs_nss_len) {
+ os_memcpy(pos, eht_cap->mcs, mcs_nss_len);
+ pos += mcs_nss_len;
+ }
+
+ ppe_thresh_len = ieee80211_eht_ppet_size(
+ WPA_GET_LE16(&eht_cap->ppet[0]),
+ eht_cap->phy_cap);
+ if (ppe_thresh_len) {
+ os_memcpy(pos, eht_cap->ppet, ppe_thresh_len);
+ pos += ppe_thresh_len;
+ }
+
+ *length_pos = pos - (eid + 2);
+ return pos;
+}
+
+
+u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+ struct hostapd_config *conf = hapd->iconf;
+ struct ieee80211_eht_operation *oper;
+ u8 *pos = eid, chwidth, seg0 = 0, seg1 = 0;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ *pos++ = WLAN_EID_EXTENSION;
+ *pos++ = 5;
+ *pos++ = WLAN_EID_EXT_EHT_OPERATION;
+
+ oper = (struct ieee80211_eht_operation *) pos;
+ oper->oper_params = EHT_OPER_INFO_PRESENT;
+
+ if (is_6ghz_op_class(conf->op_class))
+ chwidth = op_class_to_ch_width(conf->op_class);
+ else
+ chwidth = conf->eht_oper_chwidth;
+
+ seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf);
+
+ switch (chwidth) {
+#if 0 /* FIX: Need to clean up CHANWIDTH_* use for protocol vs. internal
+ * needs to be able to define this. */
+ case CHANWIDTH_320MHZ:
+ oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_320MHZ;
+ seg1 = seg0;
+ if (hapd->iconf->channel < seg0)
+ seg0 -= 16;
+ else
+ seg0 += 16;
+ break;
+#endif
+ case CHANWIDTH_160MHZ:
+ oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ;
+ seg1 = seg0;
+ if (hapd->iconf->channel < seg0)
+ seg0 -= 8;
+ else
+ seg0 += 8;
+ break;
+ case CHANWIDTH_80MHZ:
+ oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_80MHZ;
+ break;
+ case CHANWIDTH_USE_HT:
+ if (seg0)
+ oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_40MHZ;
+ break;
+ default:
+ return eid;
+ }
+
+ oper->oper_info.ccfs0 = seg0 ? seg0 : hapd->iconf->channel;
+ oper->oper_info.ccfs1 = seg1;
+
+ return pos + 4;
+}
+
+
+static bool check_valid_eht_mcs_nss(struct hostapd_data *hapd, const u8 *ap_mcs,
+ const u8 *sta_mcs, u8 mcs_count, u8 map_len)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < mcs_count; i++) {
+ ap_mcs += i * 3;
+ sta_mcs += i * 3;
+
+ for (j = 0; j < map_len; j++) {
+ if (((ap_mcs[j] >> 4) & 0xFF) == 0)
+ continue;
+
+ if ((sta_mcs[j] & 0xFF) == 0)
+ continue;
+
+ return true;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "No matching EHT MCS found between AP TX and STA RX");
+ return false;
+}
+
+
+static bool check_valid_eht_mcs(struct hostapd_data *hapd,
+ const u8 *sta_eht_capab,
+ enum ieee80211_op_mode opmode)
+{
+ struct hostapd_hw_modes *mode;
+ const struct ieee80211_eht_capabilities *capab;
+ const u8 *ap_mcs, *sta_mcs;
+ u8 mcs_count = 1;
+
+ mode = hapd->iface->current_mode;
+ if (!mode)
+ return true;
+
+ ap_mcs = mode->eht_capab[opmode].mcs;
+ capab = (const struct ieee80211_eht_capabilities *) sta_eht_capab;
+ sta_mcs = capab->optional;
+
+ if (ieee80211_eht_mcs_set_size(mode->he_capab[opmode].phy_cap,
+ mode->eht_capab[opmode].phy_cap) ==
+ EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY)
+ return check_valid_eht_mcs_nss(
+ hapd, ap_mcs, sta_mcs, 1,
+ EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY);
+
+ switch (hapd->iface->conf->eht_oper_chwidth) {
+ /* TODO: CHANWIDTH_320MHZ */
+ case CHANWIDTH_80P80MHZ:
+ case CHANWIDTH_160MHZ:
+ mcs_count = 2;
+ break;
+ }
+
+ return check_valid_eht_mcs_nss(hapd, ap_mcs, sta_mcs, mcs_count,
+ EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS);
+}
+
+
+static bool ieee80211_invalid_eht_cap_size(const u8 *he_cap, const u8 *eht_cap,
+ size_t len)
+{
+ const struct ieee80211_he_capabilities *he_capab;
+ struct ieee80211_eht_capabilities *cap;
+ const u8 *he_phy_cap;
+ size_t cap_len;
+ u16 ppe_thres_hdr;
+
+ he_capab = (const struct ieee80211_he_capabilities *) he_cap;
+ he_phy_cap = he_capab->he_phy_capab_info;
+ cap = (struct ieee80211_eht_capabilities *) eht_cap;
+ cap_len = sizeof(*cap) - sizeof(cap->optional);
+ if (len < cap_len)
+ return true;
+
+ cap_len += ieee80211_eht_mcs_set_size(he_phy_cap, cap->phy_cap);
+ if (len < cap_len)
+ return true;
+
+ ppe_thres_hdr = len > cap_len + 1 ?
+ WPA_GET_LE16(&eht_cap[cap_len]) : 0x01ff;
+ cap_len += ieee80211_eht_ppet_size(ppe_thres_hdr, cap->phy_cap);
+
+ return len < cap_len;
+}
+
+
+u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode,
+ const u8 *he_capab, size_t he_capab_len,
+ const u8 *eht_capab, size_t eht_capab_len)
+{
+ if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be ||
+ !he_capab || he_capab_len < IEEE80211_HE_CAPAB_MIN_LEN ||
+ !eht_capab ||
+ ieee80211_invalid_eht_cap_size(he_capab, eht_capab,
+ eht_capab_len) ||
+ !check_valid_eht_mcs(hapd, eht_capab, opmode)) {
+ sta->flags &= ~WLAN_STA_EHT;
+ os_free(sta->eht_capab);
+ sta->eht_capab = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ os_free(sta->eht_capab);
+ sta->eht_capab = os_memdup(eht_capab, eht_capab_len);
+ if (!sta->eht_capab) {
+ sta->eht_capab_len = 0;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_EHT;
+ sta->eht_capab_len = eht_capab_len;
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+void hostapd_get_eht_capab(struct hostapd_data *hapd,
+ const struct ieee80211_eht_capabilities *src,
+ struct ieee80211_eht_capabilities *dest,
+ size_t len)
+{
+ if (!src || !dest)
+ return;
+
+ if (len > sizeof(*dest))
+ len = sizeof(*dest);
+ /* TODO: mask out unsupported features */
+
+ os_memset(dest, 0, sizeof(*dest));
+ os_memcpy(dest, src, len);
+}
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 6cd6c90..1e74c58 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -29,17 +29,19 @@
ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) &
HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
+ /* Count the number of 1 bits in RU Index Bitmask */
while (ru) {
if (ru & 0x1)
sz++;
ru >>= 1;
}
+ /* fixed header of 3 (NSTS) + 4 (RU Index Bitmask) = 7 bits */
+ /* 6 * (NSTS + 1) bits for bit 1 in RU Index Bitmask */
sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
sz = (sz * 6) + 7;
- if (sz % 8)
- sz += 8;
- sz /= 8;
+ /* PPE Pad to count the number of needed full octets */
+ sz = (sz + 7) / 8;
return sz;
}
@@ -64,6 +66,7 @@
{
struct ieee80211_he_capabilities *cap;
size_t cap_len;
+ u8 ppe_thres_hdr;
cap = (struct ieee80211_he_capabilities *) buf;
cap_len = sizeof(*cap) - sizeof(cap->optional);
@@ -74,9 +77,11 @@
if (len < cap_len)
return 1;
- cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
+ ppe_thres_hdr = len > cap_len ? buf[cap_len] : 0xff;
+ cap_len += ieee80211_he_ppet_size(ppe_thres_hdr,
+ cap->he_phy_capab_info);
- return len != cap_len;
+ return len < cap_len;
}
@@ -195,7 +200,8 @@
if (hapd->iface->conf->he_op.he_er_su_disable)
params |= HE_OPERATION_ER_SU_DISABLE;
- if (hapd->iface->conf->he_op.he_bss_color_disabled)
+ if (hapd->iface->conf->he_op.he_bss_color_disabled ||
+ hapd->cca_in_progress)
params |= HE_OPERATION_BSS_COLOR_DISABLED;
if (hapd->iface->conf->he_op.he_bss_color_partial)
params |= HE_OPERATION_BSS_COLOR_PARTIAL;
@@ -213,6 +219,7 @@
if (is_6ghz_op_class(hapd->iconf->op_class)) {
u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
+ u8 control;
if (!seg0)
seg0 = hapd->iconf->channel;
@@ -220,16 +227,28 @@
params |= HE_OPERATION_6GHZ_OPER_INFO;
/* 6 GHz Operation Information field
- * IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element,
+ * IEEE Std 802.11ax-2021, 9.4.2.249 HE Operation element,
* Figure 9-788k
*/
*pos++ = hapd->iconf->channel; /* Primary Channel */
- /* Control: Channel Width */
+ /* Control:
+ * bits 0-1: Channel Width
+ * bit 2: Duplicate Beacon
+ * bits 3-5: Regulatory Info
+ */
+ /* Channel Width */
if (seg1)
- *pos++ = 3;
+ control = 3;
else
- *pos++ = center_idx_to_bw_6ghz(seg0);
+ control = center_idx_to_bw_6ghz(seg0);
+ if (hapd->iconf->he_6ghz_reg_pwr_type == 1)
+ control |= HE_6GHZ_STANDARD_POWER_AP <<
+ HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT;
+ else
+ control |= HE_6GHZ_INDOOR_AP <<
+ HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT;
+ *pos++ = control;
/* Channel Center Freq Seg0/Seg1 */
if (hapd->iconf->he_oper_chwidth == 2) {
@@ -520,3 +539,19 @@
return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) &&
hapd->iface->conf->he_op.he_twt_responder;
}
+
+
+u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid)
+{
+ if (!hapd->cca_in_progress)
+ return eid;
+
+ /* BSS Color Change Announcement element */
+ *eid++ = WLAN_EID_EXTENSION;
+ *eid++ = 3;
+ *eid++ = WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT;
+ *eid++ = hapd->cca_count; /* Color Switch Countdown */
+ *eid++ = hapd->cca_color; /* New BSS Color Information */
+
+ return eid;
+}
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 4bff9e5..6154895 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -1093,3 +1093,29 @@
return pos;
}
+
+
+u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ext_capab_ie, size_t ext_capab_ie_len)
+{
+#ifdef CONFIG_INTERWORKING
+ /* check for QoS Map support */
+ if (ext_capab_ie_len >= 5) {
+ if (ext_capab_ie[4] & 0x01)
+ sta->qos_map_enabled = 1;
+ }
+#endif /* CONFIG_INTERWORKING */
+
+ if (ext_capab_ie_len > 0) {
+ sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2));
+ os_free(sta->ext_capability);
+ sta->ext_capability = os_malloc(1 + ext_capab_ie_len);
+ if (sta->ext_capability) {
+ sta->ext_capability[0] = ext_capab_ie_len;
+ os_memcpy(sta->ext_capability + 1, ext_capab_ie,
+ ext_capab_ie_len);
+ }
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 753c883..fb5e920 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -2448,6 +2448,9 @@
conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
conf.erp_domain = hapd->conf->erp_domain;
+#ifdef CONFIG_TESTING_OPTIONS
+ conf.eap_skip_prot_success = hapd->conf->eap_skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
os_memset(&cb, 0, sizeof(cb));
cb.eapol_send = ieee802_1x_eapol_send;
diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
index 229edd2..e37324f 100644
--- a/src/ap/neighbor_db.c
+++ b/src/ap/neighbor_db.c
@@ -225,6 +225,7 @@
int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n;
int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac;
int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax;
+ bool eht = he && hapd->iconf->ieee80211be && !hapd->conf->disable_11be;
struct wpa_ssid_value ssid;
u8 channel, op_class;
u8 center_freq1_idx = 0, center_freq2_idx = 0;
@@ -260,10 +261,12 @@
/* VHT bit added in IEEE P802.11-REVmc/D4.3 */
if (vht)
bssid_info |= NEI_REP_BSSID_INFO_VHT;
- if (he)
- bssid_info |= NEI_REP_BSSID_INFO_HE;
}
+ if (he)
+ bssid_info |= NEI_REP_BSSID_INFO_HE;
+ if (eht)
+ bssid_info |= NEI_REP_BSSID_INFO_EHT;
/* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */
if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index ccd1ed9..c541926 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -358,6 +358,7 @@
os_free(sta->vht_operation);
os_free(sta->he_capab);
os_free(sta->he_6ghz_capab);
+ os_free(sta->eht_capab);
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
@@ -410,6 +411,7 @@
#ifdef CONFIG_TESTING_OPTIONS
os_free(sta->sae_postponed_commit);
+ forced_memzero(sta->last_tk, WPA_TK_MAX_LEN);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(sta);
@@ -1251,8 +1253,6 @@
for (psk = ssid->wpa_psk; psk; psk = psk->next)
if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0)
break;
- if (!psk)
- return NULL;
if (!psk || !psk->keyid[0])
return NULL;
@@ -1461,7 +1461,7 @@
buf[0] = '\0';
res = os_snprintf(buf, buflen,
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1481,6 +1481,7 @@
(flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
(flags & WLAN_STA_HE ? "[HE]" : ""),
+ (flags & WLAN_STA_EHT ? "[EHT]" : ""),
(flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
@@ -1553,7 +1554,7 @@
if (hostapd_sta_add(hapd, sta->addr, 0, 0,
sta->supported_rates,
sta->supported_rates_len,
- 0, NULL, NULL, NULL, 0, NULL,
+ 0, NULL, NULL, NULL, 0, NULL, 0, NULL,
sta->flags, 0, 0, 0, 0)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 27e72f9..af8f171 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -42,6 +42,7 @@
#define WLAN_STA_HE BIT(24)
#define WLAN_STA_6GHZ BIT(25)
#define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26)
+#define WLAN_STA_EHT BIT(27)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -213,6 +214,8 @@
struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
+ struct ieee80211_eht_capabilities *eht_capab;
+ size_t eht_capab_len;
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 0042ed6..23a352c 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -409,6 +409,8 @@
u8 dialog_token, reason;
const u8 *pos, *end;
int enabled = hapd->conf->bss_transition;
+ char *hex = NULL;
+ size_t hex_len;
#ifdef CONFIG_MBO
if (hapd->conf->mbo_enabled)
@@ -441,6 +443,17 @@
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
+ hex_len = 2 * (end - pos) + 1;
+ if (hex_len > 1) {
+ hex = os_malloc(hex_len);
+ if (hex)
+ wpa_snprintf_hex(hex, hex_len, pos, end - pos);
+ }
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ BSS_TM_QUERY MACSTR " reason=%u%s%s",
+ MAC2STR(addr), reason, hex ? " neighbor=" : "", hex);
+ os_free(hex);
+
ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
}
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index bb7ee25..ad91883 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -607,7 +607,7 @@
while (group) {
prev = group;
group = group->next;
- os_free(prev);
+ bin_clear_free(prev, sizeof(*prev));
}
os_free(wpa_auth);
@@ -1485,6 +1485,12 @@
struct wpa_authenticator *wpa_auth = eloop_ctx;
struct wpa_state_machine *sm = timeout_ctx;
+ if (sm->waiting_radius_psk) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "Ignore EAPOL-Key timeout while waiting for RADIUS PSK");
+ return;
+ }
+
sm->pending_1_of_4_timeout = 0;
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
sm->TimeoutEvt = true;
@@ -1646,7 +1652,7 @@
if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
(key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
- os_free(buf);
+ bin_clear_free(buf, key_data_len);
return;
}
WPA_PUT_BE16(key_mic + mic_len, key_data_len);
@@ -1667,10 +1673,10 @@
#endif /* CONFIG_NO_RC4 */
} else {
os_free(hdr);
- os_free(buf);
+ bin_clear_free(buf, key_data_len);
return;
}
- os_free(buf);
+ bin_clear_free(buf, key_data_len);
}
if (key_info & WPA_KEY_INFO_MIC) {
@@ -1823,9 +1829,9 @@
case WPA_DEAUTH:
case WPA_DISASSOC:
sm->DeauthenticationRequest = true;
-#ifdef CONFIG_IEEE80211R_AP
os_memset(sm->PMK, 0, sizeof(sm->PMK));
sm->pmk_len = 0;
+#ifdef CONFIG_IEEE80211R_AP
os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
sm->xxkey_len = 0;
os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
@@ -1853,6 +1859,14 @@
break;
}
+ if (sm->ptkstart_without_success > 3) {
+ wpa_printf(MSG_INFO,
+ "WPA: Multiple EAP reauth attempts without 4-way handshake completion, disconnect "
+ MACSTR, MAC2STR(sm->addr));
+ sm->Disconnect = true;
+ break;
+ }
+
if (!sm->use_ext_key_id &&
sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
wpa_printf(MSG_INFO,
@@ -2195,6 +2209,7 @@
sm->PTKRequest = false;
sm->TimeoutEvt = false;
sm->alt_snonce_valid = false;
+ sm->ptkstart_without_success++;
sm->TimeoutCtr++;
if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
@@ -3026,6 +3041,19 @@
break;
}
+ if (!ok && wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
+ wpa_auth->conf.radius_psk && wpa_auth->cb->request_radius_psk &&
+ !sm->waiting_radius_psk) {
+ wpa_printf(MSG_DEBUG, "No PSK available - ask RADIUS server");
+ wpa_auth->cb->request_radius_psk(wpa_auth->cb_ctx, sm->addr,
+ sm->wpa_key_mgmt,
+ sm->ANonce,
+ sm->last_rx_eapol_key,
+ sm->last_rx_eapol_key_len);
+ sm->waiting_radius_psk = 1;
+ return;
+ }
+
if (!ok) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"invalid MIC in msg 2/4 of 4-Way Handshake");
@@ -3279,6 +3307,7 @@
pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
(const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
NULL, 0);
+ forced_memzero(&igtk, sizeof(igtk));
if (!conf->beacon_prot)
return pos;
@@ -3302,6 +3331,7 @@
pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
(const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
NULL, 0);
+ forced_memzero(&bigtk, sizeof(bigtk));
return pos;
}
@@ -3382,7 +3412,7 @@
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, stub_gtk[32];
- size_t gtk_len, kde_len, wpa_ie_len;
+ size_t gtk_len, kde_len = 0, wpa_ie_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
int secure, gtkidx, encr = 0;
@@ -3640,7 +3670,7 @@
WPA_KEY_INFO_KEY_TYPE,
_rsc, sm->ANonce, kde, pos - kde, 0, encr);
done:
- os_free(kde);
+ bin_clear_free(kde, kde_len);
os_free(wpa_ie_buf);
os_free(wpa_ie_buf2);
}
@@ -3709,6 +3739,8 @@
#ifdef CONFIG_IEEE80211R_AP
wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
#endif /* CONFIG_IEEE80211R_AP */
+
+ sm->ptkstart_without_success = 0;
}
@@ -3783,6 +3815,11 @@
} else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
SM_ENTER(WPA_PTK, PTKSTART);
#endif /* CONFIG_SAE */
+ } else if (wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) &&
+ wpa_auth->conf.radius_psk) {
+ wpa_printf(MSG_DEBUG,
+ "INITPSK: No PSK yet available for STA - use RADIUS later");
+ SM_ENTER(WPA_PTK, PTKSTART);
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"no PSK configured for the STA");
@@ -3861,7 +3898,7 @@
struct wpa_group *gsm = sm->group;
const u8 *kde;
u8 *kde_buf = NULL, *pos, hdr[2];
- size_t kde_len;
+ size_t kde_len = 0;
u8 *gtk, stub_gtk[32];
struct wpa_auth_config *conf = &sm->wpa_auth->conf;
@@ -3930,7 +3967,7 @@
(!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
rsc, NULL, kde, kde_len, gsm->GN, 1);
- os_free(kde_buf);
+ bin_clear_free(kde_buf, kde_len);
}
@@ -5572,7 +5609,7 @@
WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
WPA_KEY_INFO_KEY_TYPE,
_rsc, sm->ANonce, kde, pos - kde, 0, encr);
- os_free(kde);
+ bin_clear_free(kde, kde_len);
return 0;
}
@@ -5640,7 +5677,7 @@
(!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
rsc, NULL, kde, kde_len, gsm->GN, 1);
- os_free(kde_buf);
+ bin_clear_free(kde_buf, kde_len);
return 0;
}
@@ -5711,3 +5748,28 @@
#endif /* CONFIG_TESTING_OPTIONS */
+
+
+void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success)
+{
+ if (!sm->waiting_radius_psk) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore RADIUS PSK response for " MACSTR
+ " that did not wait one",
+ MAC2STR(sm->addr));
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RADIUS PSK response for " MACSTR " (%s)",
+ MAC2STR(sm->addr), success ? "success" : "fail");
+ sm->waiting_radius_psk = 0;
+
+ if (success) {
+ /* Try to process the EAPOL-Key msg 2/4 again */
+ sm->EAPOLKeyReceived = true;
+ } else {
+ sm->Disconnect = true;
+ }
+
+ eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 8f0b5a7..348a1de 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -275,6 +275,8 @@
* PTK derivation regardless of advertised capabilities.
*/
bool force_kdk_derivation;
+
+ bool radius_psk;
};
typedef enum {
@@ -322,6 +324,9 @@
void (*store_ptksa)(void *ctx, const u8 *addr, int cipher,
u32 life_time, const struct wpa_ptk *ptk);
void (*clear_ptksa)(void *ctx, const u8 *addr, int cipher);
+ void (*request_radius_psk)(void *ctx, const u8 *addr, int key_mgmt,
+ const u8 *anonce,
+ const u8 *eapol, size_t eapol_len);
#ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
@@ -578,4 +583,6 @@
void wpa_auth_set_enable_eapol_large_timeout(struct wpa_authenticator *wpa_auth,
u8 val);
+void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success);
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index fef1104..7a97613 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2240,6 +2240,7 @@
wpa_printf(MSG_DEBUG,
"FT: GTK subelem encryption failed: kek_len=%d",
(int) kek_len);
+ forced_memzero(keybuf, sizeof(keybuf));
os_free(subelem);
return NULL;
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 9e88ea3..9e8dae1 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1,6 +1,6 @@
/*
* hostapd / WPA authenticator glue code
- * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -29,6 +29,7 @@
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "ieee802_11.h"
+#include "ieee802_11_auth.h"
#include "pmksa_cache_auth.h"
#include "wpa_auth.h"
#include "wpa_auth_glue.h"
@@ -216,6 +217,8 @@
wconf->force_kdk_derivation = conf->force_kdk_derivation;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_PASN */
+
+ wconf->radius_psk = conf->wpa_psk_radius == PSK_RADIUS_DURING_4WAY_HS;
}
@@ -390,10 +393,14 @@
psk = sta->psk->psk;
for (pos = sta->psk; pos; pos = pos->next) {
if (pos->is_passphrase) {
- pbkdf2_sha1(pos->passphrase,
- hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len, 4096,
- pos->psk, PMK_LEN);
+ if (pbkdf2_sha1(pos->passphrase,
+ hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len, 4096,
+ pos->psk, PMK_LEN) != 0) {
+ wpa_printf(MSG_WARNING,
+ "Error in pbkdf2_sha1()");
+ continue;
+ }
pos->is_passphrase = 0;
}
if (pos->psk == prev_psk) {
@@ -1445,6 +1452,23 @@
#endif /* CONFIG_IEEE80211R_AP */
+#ifndef CONFIG_NO_RADIUS
+static void hostapd_request_radius_psk(void *ctx, const u8 *addr, int key_mgmt,
+ const u8 *anonce,
+ const u8 *eapol, size_t eapol_len)
+{
+ struct hostapd_data *hapd = ctx;
+
+ wpa_printf(MSG_DEBUG, "RADIUS PSK request for " MACSTR " key_mgmt=0x%x",
+ MAC2STR(addr), key_mgmt);
+ wpa_hexdump(MSG_DEBUG, "ANonce", anonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAPOL", eapol, eapol_len);
+ hostapd_acl_req_radius_psk(hapd, addr, key_mgmt, anonce, eapol,
+ eapol_len);
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
int hostapd_setup_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config _conf;
@@ -1488,6 +1512,9 @@
.set_session_timeout = hostapd_wpa_auth_set_session_timeout,
.get_session_timeout = hostapd_wpa_auth_get_session_timeout,
#endif /* CONFIG_IEEE80211R_AP */
+#ifndef CONFIG_NO_RADIUS
+ .request_radius_psk = hostapd_request_radius_psk,
+#endif /* CONFIG_NO_RADIUS */
};
const u8 *wpa_ie;
size_t wpa_ie_len;
@@ -1633,4 +1660,10 @@
hapd->l2 = NULL;
hostapd_wpa_unregister_ft_oui(hapd);
#endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ forced_memzero(hapd->last_gtk, WPA_GTK_MAX_LEN);
+ forced_memzero(hapd->last_igtk, WPA_IGTK_MAX_LEN);
+ forced_memzero(hapd->last_bigtk, WPA_BIGTK_MAX_LEN);
+#endif /* CONFIG_TESTING_OPTIONS */
}
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index a6dc1a5..17cb5a2 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -89,6 +89,7 @@
unsigned int rx_eapol_key_secure:1;
unsigned int update_snonce:1;
unsigned int alt_snonce_valid:1;
+ unsigned int waiting_radius_psk:1;
#ifdef CONFIG_IEEE80211R_AP
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
@@ -96,6 +97,8 @@
unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1;
+ unsigned int ptkstart_without_success;
+
#ifdef CONFIG_OCV
int ocv_enabled;
#endif /* CONFIG_OCV */
diff --git a/src/ap/wpa_auth_kay.c b/src/ap/wpa_auth_kay.c
index 46d94b4..e2c4e10 100644
--- a/src/ap/wpa_auth_kay.c
+++ b/src/ap/wpa_auth_kay.c
@@ -138,7 +138,6 @@
switch (co) {
case CONFIDENTIALITY_OFFSET_30:
return 30;
- break;
case CONFIDENTIALITY_OFFSET_50:
return 50;
default:
@@ -329,7 +328,9 @@
hapd->conf->macsec_replay_protect,
hapd->conf->macsec_replay_window,
hapd->conf->macsec_port,
- hapd->conf->mka_priority, hapd->conf->iface,
+ hapd->conf->mka_priority,
+ hapd->conf->macsec_csindex,
+ hapd->conf->iface,
hapd->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
if (!res)
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 4f1c76b..aacfa33 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -1069,10 +1069,11 @@
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
wpabuf_free(wps->dev.vendor_ext[i]);
wps_device_data_free(&wps->dev);
- os_free(wps->network_key);
+ bin_clear_free(wps->network_key, wps->network_key_len);
hostapd_wps_nfc_clear(wps);
wpabuf_free(wps->dh_pubkey);
wpabuf_free(wps->dh_privkey);
+ forced_memzero(wps->psk, sizeof(wps->psk));
os_free(wps);
}
diff --git a/src/common/brcm_vendor.h b/src/common/brcm_vendor.h
index d77b007..c1f5807 100644
--- a/src/common/brcm_vendor.h
+++ b/src/common/brcm_vendor.h
@@ -40,15 +40,15 @@
* @BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS: Set some connect parameters.
* Used for the case that FW handle SAE.
*
- * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP paramters.
+ * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP parameters.
* Used for the case that FW handle SAE.
*
* @BRCM_VENDOR_SCMD_ACS: ACS command/event which is used to
* invoke the ACS function in device and pass selected channels to
* hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes.
*
- * @BRCM_VENDOR_SCMD_MAX: This acts as a the tail of cmds list.
- * Make sure it located at the end of the list.
+ * @BRCM_VENDOR_SCMD_MAX: This acts as a tail of cmds list.
+ * Make sure it is located at the end of the list.
*
*/
enum brcm_nl80211_vendor_subcmds {
@@ -67,7 +67,7 @@
};
/**
- * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers
+ * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchronous event identifiers
*
* @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0
*
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 42a9302..cc26b80 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -345,12 +345,36 @@
}
+static int dpp_parse_uri_supported_curves(struct dpp_bootstrap_info *bi,
+ const char *txt)
+{
+ int val;
+
+ if (!txt)
+ return 0;
+
+ val = hex2num(txt[0]);
+ if (val < 0)
+ return -1;
+ bi->supported_curves = val;
+
+ val = hex2num(txt[1]);
+ if (val > 0)
+ bi->supported_curves |= val << 4;
+
+ wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
+ bi->supported_curves);
+
+ return 0;
+}
+
+
static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri)
{
const char *pos = uri;
const char *end;
const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL;
- const char *version = NULL;
+ const char *version = NULL, *supported_curves = NULL;
struct dpp_bootstrap_info *bi;
wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri));
@@ -383,6 +407,8 @@
pk = pos + 2;
else if (pos[0] == 'V' && pos[1] == ':' && !version)
version = pos + 2;
+ else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves)
+ supported_curves = pos + 2;
else
wpa_hexdump_ascii(MSG_DEBUG,
"DPP: Ignore unrecognized URI parameter",
@@ -404,6 +430,7 @@
dpp_parse_uri_mac(bi, mac) < 0 ||
dpp_parse_uri_info(bi, info) < 0 ||
dpp_parse_uri_version(bi, version) < 0 ||
+ dpp_parse_uri_supported_curves(bi, supported_curves) < 0 ||
dpp_parse_uri_pk(bi, pk) < 0) {
dpp_bootstrap_info_free(bi);
bi = NULL;
@@ -604,6 +631,7 @@
{
char macstr[ETH_ALEN * 2 + 10];
size_t len;
+ char supp_curves[10];
len = 4; /* "DPP:" */
if (bi->chan)
@@ -621,11 +649,26 @@
#endif /* CONFIG_DPP2 */
len += 4 + os_strlen(bi->pk); /* K:...;; */
+ if (bi->supported_curves) {
+ u8 val = bi->supported_curves;
+
+ if (val & 0xf0) {
+ val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
+ len += os_snprintf(supp_curves, sizeof(supp_curves),
+ "B:%02x;", val);
+ } else {
+ len += os_snprintf(supp_curves, sizeof(supp_curves),
+ "B:%x;", val);
+ }
+ } else {
+ supp_curves[0] = '\0';
+ }
+
os_free(bi->uri);
bi->uri = os_malloc(len + 1);
if (!bi->uri)
return -1;
- os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%sK:%s;;",
+ os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;",
bi->chan ? "C:" : "", bi->chan ? bi->chan : "",
bi->chan ? ";" : "",
macstr,
@@ -633,6 +676,7 @@
bi->info ? ";" : "",
DPP_VERSION == 3 ? "V:3;" :
(DPP_VERSION == 2 ? "V:2;" : ""),
+ supp_curves,
bi->pk);
return 0;
}
@@ -658,9 +702,12 @@
{
size_t nonce_len;
size_t json_len, clear_len;
- struct wpabuf *clear = NULL, *msg = NULL;
+ struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL;
u8 *wrapped;
size_t attr_len;
+#ifdef CONFIG_DPP3
+ u8 auth_i[DPP_MAX_HASH_LEN];
+#endif /* CONFIG_DPP3 */
wpa_printf(MSG_DEBUG, "DPP: Build configuration request");
@@ -675,6 +722,18 @@
/* { E-nonce, configAttrib }ke */
clear_len = 4 + nonce_len + 4 + json_len;
+#ifdef CONFIG_DPP3
+ if (auth->waiting_new_key) {
+ pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
+ if (!pe)
+ goto fail;
+ clear_len += 4 + wpabuf_len(pe);
+
+ if (dpp_derive_auth_i(auth, auth_i) < 0)
+ goto fail;
+ clear_len += 4 + auth->curve->hash_len;
+ }
+#endif /* CONFIG_DPP3 */
clear = wpabuf_alloc(clear_len);
attr_len = 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -716,6 +775,21 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
+#ifdef CONFIG_DPP3
+ if (pe) {
+ wpa_printf(MSG_DEBUG, "DPP: Pe");
+ wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(pe));
+ wpabuf_put_buf(clear, pe);
+ }
+ if (auth->waiting_new_key) {
+ wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag");
+ wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG);
+ wpabuf_put_le16(clear, auth->curve->hash_len);
+ wpabuf_put_data(clear, auth_i, auth->curve->hash_len);
+ }
+#endif /* CONFIG_DPP3 */
+
/* configAttrib */
wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ);
wpabuf_put_le16(clear, json_len);
@@ -748,13 +822,15 @@
wpa_hexdump_buf(MSG_DEBUG,
"DPP: Configuration Request frame attributes", msg);
+out:
wpabuf_free(clear);
+ wpabuf_free(pe);
return msg;
fail:
- wpabuf_free(clear);
wpabuf_free(msg);
- return NULL;
+ msg = NULL;
+ goto out;
}
@@ -815,7 +891,7 @@
size_t len, name_len;
const char *tech = "infra";
const char *dpp_name;
- struct wpabuf *buf, *json;
+ struct wpabuf *buf = NULL, *json = NULL;
char *csr = NULL;
#ifdef CONFIG_TESTING_OPTIONS
@@ -840,19 +916,17 @@
csr = base64_encode_no_lf(wpabuf_head(auth->csr),
wpabuf_len(auth->csr), &csr_len);
if (!csr)
- return NULL;
+ goto fail;
len += 30 + csr_len;
}
#endif /* CONFIG_DPP2 */
json = wpabuf_alloc(len);
if (!json)
- return NULL;
+ goto fail;
json_start_object(json, NULL);
- if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) {
- wpabuf_free(json);
- return NULL;
- }
+ if (json_add_string_escape(json, "name", dpp_name, name_len) < 0)
+ goto fail;
json_value_sep(json);
json_add_string(json, "wi-fi_tech", tech);
json_value_sep(json);
@@ -877,6 +951,7 @@
json_end_object(json);
buf = dpp_build_conf_req(auth, wpabuf_head(json));
+fail:
wpabuf_free(json);
os_free(csr);
@@ -1431,7 +1506,8 @@
struct wpabuf *buf = NULL;
char *signed_conn = NULL;
size_t tailroom;
- const struct dpp_curve_params *curve;
+ const struct dpp_curve_params *curve; /* C-sign-key curve */
+ const struct dpp_curve_params *nak_curve; /* netAccessKey curve */
struct wpabuf *dppcon = NULL;
size_t extra_len = 1000;
int incl_legacy;
@@ -1444,6 +1520,10 @@
goto fail;
}
curve = auth->conf->curve;
+ if (auth->new_curve && auth->new_key_received)
+ nak_curve = auth->new_curve;
+ else
+ nak_curve = auth->curve;
akm = conf->akm;
if (dpp_akm_ver2(akm) && auth->peer_version < 2) {
@@ -1461,7 +1541,7 @@
extra_len += os_strlen(conf->group_id);
/* Connector (JSON dppCon object) */
- dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3);
+ dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3);
if (!dppcon)
goto fail;
#ifdef CONFIG_TESTING_OPTIONS
@@ -1491,9 +1571,31 @@
#ifdef CONFIG_TESTING_OPTIONS
skip_groups:
#endif /* CONFIG_TESTING_OPTIONS */
- if (!auth->peer_protocol_key ||
- dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
- auth->curve) < 0) {
+ if (!auth->peer_protocol_key) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No peer protocol key available to build netAccessKey JWK");
+ goto fail;
+ }
+#ifdef CONFIG_DPP3
+ if (auth->conf->net_access_key_curve &&
+ auth->curve != auth->conf->net_access_key_curve &&
+ !auth->new_key_received) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s",
+ auth->curve->name,
+ auth->conf->net_access_key_curve->name,
+ auth->waiting_new_key ?
+ "the required key not received" :
+ "request a new key");
+ if (auth->waiting_new_key)
+ auth->waiting_new_key = false; /* failed */
+ else
+ auth->waiting_new_key = true;
+ goto fail;
+ }
+#endif /* CONFIG_DPP3 */
+ if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL,
+ nak_curve) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK");
goto fail;
}
@@ -1605,6 +1707,20 @@
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object",
wpabuf_head(buf), wpabuf_len(buf));
+#ifdef CONFIG_DPP3
+ if (!auth->conf->net_access_key_curve) {
+ /* All netAccessKey values used in the network will have to be
+ * from the same curve for network introduction to work, so
+ * hardcode the first used netAccessKey curve for consecutive
+ * operations if there was no explicit configuration of which
+ * curve to use. */
+ wpa_printf(MSG_DEBUG,
+ "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning",
+ nak_curve->name);
+ auth->conf->net_access_key_curve = nak_curve;
+ }
+#endif /* CONFIG_DPP3 */
+
out:
os_free(signed_conn);
wpabuf_free(dppcon);
@@ -1732,7 +1848,7 @@
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
u16 e_nonce_len, enum dpp_netrole netrole, bool cert_req)
{
- struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL;
+ struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL;
size_t clear_len, attr_len;
struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped;
@@ -1766,6 +1882,10 @@
else if (!cert_req && netrole == DPP_NETROLE_STA && auth->conf_sta &&
auth->conf_sta->akm == DPP_AKM_DOT1X && !auth->waiting_csr)
status = DPP_STATUS_CSR_NEEDED;
+#ifdef CONFIG_DPP3
+ else if (auth->waiting_new_key)
+ status = DPP_STATUS_NEW_KEY_NEEDED;
+#endif /* CONFIG_DPP3 */
else
status = DPP_STATUS_CONFIGURE_FAILURE;
forced_status:
@@ -1785,6 +1905,31 @@
if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta &&
auth->conf_sta->csrattrs)
clear_len += 4 + os_strlen(auth->conf_sta->csrattrs);
+#ifdef CONFIG_DPP3
+ if (status == DPP_STATUS_NEW_KEY_NEEDED) {
+ struct crypto_ec_key *new_pc;
+
+ clear_len += 6; /* Finite Cyclic Group attribute */
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Generate a new own protocol key for the curve %s",
+ auth->conf->net_access_key_curve->name);
+ new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve);
+ if (!new_pc) {
+ wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc");
+ return NULL;
+ }
+ pc = crypto_ec_key_get_pubkey_point(new_pc, 0);
+ if (!pc) {
+ crypto_ec_key_deinit(new_pc);
+ return NULL;
+ }
+ crypto_ec_key_deinit(auth->own_protocol_key);
+ auth->own_protocol_key = new_pc;
+ auth->new_curve = auth->conf->net_access_key_curve;
+ clear_len += 4 + wpabuf_len(pc);
+ }
+#endif /* CONFIG_DPP3 */
clear = wpabuf_alloc(clear_len);
attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE;
#ifdef CONFIG_TESTING_OPTIONS
@@ -1862,6 +2007,27 @@
wpabuf_put_str(clear, auth->conf_sta->csrattrs);
}
+#ifdef CONFIG_DPP3
+ if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf &&
+ auth->conf->net_access_key_curve) {
+ u16 ike_group = auth->conf->net_access_key_curve->ike_group;
+
+ /* Finite Cyclic Group attribute */
+ wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u",
+ ike_group);
+ wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP);
+ wpabuf_put_le16(clear, 2);
+ wpabuf_put_le16(clear, ike_group);
+
+ if (pc) {
+ wpa_printf(MSG_DEBUG, "DPP: Pc");
+ wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY);
+ wpabuf_put_le16(clear, wpabuf_len(pc));
+ wpabuf_put_buf(clear, pc);
+ }
+ }
+#endif /* CONFIG_DPP3 */
+
#ifdef CONFIG_TESTING_OPTIONS
skip_config_obj:
if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) {
@@ -1912,6 +2078,7 @@
wpabuf_clear_free(conf2);
wpabuf_clear_free(env_data);
wpabuf_clear_free(clear);
+ wpabuf_free(pc);
return msg;
fail:
@@ -1933,6 +2100,10 @@
struct json_token *root = NULL, *token;
enum dpp_netrole netrole;
struct wpabuf *cert_req = NULL;
+#ifdef CONFIG_DPP3
+ const u8 *i_proto;
+ u16 i_proto_len;
+#endif /* CONFIG_DPP3 */
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) {
@@ -1986,6 +2157,59 @@
wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
+#ifdef CONFIG_DPP3
+ i_proto = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len);
+ if (i_proto && !auth->waiting_new_key) {
+ dpp_auth_fail(auth,
+ "Enrollee included a new protocol key even though one was not expected");
+ goto fail;
+ }
+ if (i_proto) {
+ struct crypto_ec_key *pe;
+ u8 auth_i[DPP_MAX_HASH_LEN];
+ const u8 *rx_auth_i;
+ u16 rx_auth_i_len;
+
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)",
+ i_proto, i_proto_len);
+
+ pe = dpp_set_pubkey_point(auth->own_protocol_key,
+ i_proto, i_proto_len);
+ if (!pe) {
+ dpp_auth_fail(auth,
+ "Invalid Initiator Protocol Key (Pe)");
+ goto fail;
+ }
+ dpp_debug_print_key("New Peer Protocol Key (Pe)", pe);
+ crypto_ec_key_deinit(auth->peer_protocol_key);
+ auth->peer_protocol_key = pe;
+ auth->new_key_received = true;
+ auth->waiting_new_key = false;
+
+ if (dpp_derive_auth_i(auth, auth_i) < 0)
+ goto fail;
+
+ rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len);
+ if (!rx_auth_i) {
+ dpp_auth_fail(auth,
+ "Missing Initiator Authentication Tag");
+ goto fail;
+ }
+ if (rx_auth_i_len != auth->curve->hash_len ||
+ os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) {
+ dpp_auth_fail(auth,
+ "Mismatch in Initiator Authenticating Tag");
+ wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I",
+ rx_auth_i, rx_auth_i_len);
+ wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'",
+ auth_i, auth->curve->hash_len);
+ goto fail;
+ }
+ }
+#endif /* CONFIG_DPP3 */
+
config_attr = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONFIG_ATTR_OBJ,
&config_attr_len);
@@ -2989,6 +3213,72 @@
goto fail;
}
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) {
+ const u8 *fcgroup, *r_proto;
+ u16 fcgroup_len, r_proto_len;
+ u16 group;
+ const struct dpp_curve_params *curve;
+ struct crypto_ec_key *new_pe;
+ struct crypto_ec_key *pc;
+
+ fcgroup = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_FINITE_CYCLIC_GROUP,
+ &fcgroup_len);
+ if (!fcgroup || fcgroup_len != 2) {
+ dpp_auth_fail(auth,
+ "Missing or invalid required Finite Cyclic Group attribute");
+ goto fail;
+ }
+ group = WPA_GET_LE16(fcgroup);
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Configurator requested a new protocol key from group %u",
+ group);
+ curve = dpp_get_curve_ike_group(group);
+ if (!curve) {
+ dpp_auth_fail(auth,
+ "Unsupported group for new protocol key");
+ goto fail;
+ }
+
+ new_pe = dpp_gen_keypair(curve);
+ if (!new_pe) {
+ dpp_auth_fail(auth,
+ "Failed to generate a new protocol key");
+ goto fail;
+ }
+
+ crypto_ec_key_deinit(auth->own_protocol_key);
+ auth->own_protocol_key = new_pe;
+ auth->new_curve = curve;
+
+ r_proto = dpp_get_attr(unwrapped, unwrapped_len,
+ DPP_ATTR_R_PROTOCOL_KEY,
+ &r_proto_len);
+ if (!r_proto) {
+ dpp_auth_fail(auth,
+ "Missing required Responder Protocol Key attribute (Pc)");
+ goto fail;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)",
+ r_proto, r_proto_len);
+
+ pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len);
+ if (!pc) {
+ dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)");
+ goto fail;
+ }
+ dpp_debug_print_key("New Peer Protocol Key (Pc)", pc);
+
+ crypto_ec_key_deinit(auth->peer_protocol_key);
+ auth->peer_protocol_key = pc;
+
+ auth->waiting_new_key = true;
+ ret = -3;
+ goto fail;
+ }
+#endif /* CONFIG_DPP3 */
if (status[0] != DPP_STATUS_OK) {
dpp_auth_fail(auth, "Configurator rejected configuration");
goto fail;
@@ -3903,10 +4193,47 @@
}
+static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi,
+ char *txt)
+{
+ char *token, *context = NULL;
+ u8 curves = 0;
+
+ if (!txt)
+ return 0;
+
+ while ((token = str_token(txt, ":", &context))) {
+ if (os_strcmp(token, "P-256") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256);
+ } else if (os_strcmp(token, "P-384") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384);
+ } else if (os_strcmp(token, "P-521") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521);
+ } else if (os_strcmp(token, "BP-256") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256);
+ } else if (os_strcmp(token, "BP-384") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384);
+ } else if (os_strcmp(token, "BP-512") == 0) {
+ curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512);
+ } else {
+ wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'",
+ token);
+ return -1;
+ }
+ }
+ bi->supported_curves = curves;
+
+ wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x",
+ bi->supported_curves);
+
+ return 0;
+}
+
+
int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd)
{
char *mac = NULL, *info = NULL, *curve = NULL;
- char *key = NULL;
+ char *key = NULL, *supported_curves = NULL;
u8 *privkey = NULL;
size_t privkey_len = 0;
int ret = -1;
@@ -3933,6 +4260,7 @@
info = get_param(cmd, " info=");
curve = get_param(cmd, " curve=");
key = get_param(cmd, " key=");
+ supported_curves = get_param(cmd, " supported_curves=");
if (key) {
privkey_len = os_strlen(key) / 2;
@@ -3946,6 +4274,7 @@
dpp_parse_uri_chan_list(bi, bi->chan) < 0 ||
dpp_parse_uri_mac(bi, mac) < 0 ||
dpp_parse_uri_info(bi, info) < 0 ||
+ dpp_parse_supported_curves_list(bi, supported_curves) < 0 ||
dpp_gen_uri(bi) < 0)
goto fail;
@@ -3958,6 +4287,7 @@
os_free(mac);
os_free(info);
str_clear_free(key);
+ os_free(supported_curves);
bin_clear_free(privkey, privkey_len);
dpp_bootstrap_info_free(bi);
return ret;
@@ -4012,12 +4342,43 @@
{
struct dpp_bootstrap_info *bi;
char pkhash[2 * SHA256_MAC_LEN + 1];
+ char supp_curves[100];
bi = dpp_bootstrap_get_id(dpp, id);
if (!bi)
return -1;
wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash,
SHA256_MAC_LEN);
+
+ supp_curves[0] = '\0';
+ if (bi->supported_curves) {
+ int ret;
+ size_t i;
+ char *pos = supp_curves;
+ char *end = &supp_curves[sizeof(supp_curves)];
+ const char *curve[6] = { "P-256", "P-384", "P-521",
+ "BP-256", "BP-384", "BP-512" };
+
+ ret = os_snprintf(pos, end - pos, "supp_curves=");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+
+ for (i = 0; i < ARRAY_SIZE(curve); i++) {
+ if (!(bi->supported_curves & BIT(i)))
+ continue;
+ ret = os_snprintf(pos, end - pos, "%s:", curve[i]);
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
+ if (pos[-1] == ':')
+ pos[-1] = '\n';
+ else
+ supp_curves[0] = '\0';
+ }
+
return os_snprintf(reply, reply_size, "type=%s\n"
"mac_addr=" MACSTR "\n"
"info=%s\n"
@@ -4025,7 +4386,7 @@
"use_freq=%u\n"
"curve=%s\n"
"pkhash=%s\n"
- "version=%d\n",
+ "version=%d\n%s",
dpp_bootstrap_type_txt(bi->type),
MAC2STR(bi->mac_addr),
bi->info ? bi->info : "",
@@ -4033,7 +4394,8 @@
bi->num_freq == 1 ? bi->freq[0] : 0,
bi->curve->name,
pkhash,
- bi->version);
+ bi->version,
+ supp_curves);
}
@@ -4210,12 +4572,25 @@
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd)
{
- char *curve = NULL;
+ char *curve;
char *key = NULL, *ppkey = NULL;
u8 *privkey = NULL, *pp_key = NULL;
size_t privkey_len = 0, pp_key_len = 0;
int ret = -1;
struct dpp_configurator *conf = NULL;
+ const struct dpp_curve_params *net_access_key_curve = NULL;
+
+ curve = get_param(cmd, " net_access_key_curve=");
+ if (curve) {
+ net_access_key_curve = dpp_get_curve_name(curve);
+ if (!net_access_key_curve) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unsupported net_access_key_curve: %s",
+ curve);
+ goto fail;
+ }
+ os_free(curve);
+ }
curve = get_param(cmd, " curve=");
key = get_param(cmd, " key=");
@@ -4242,6 +4617,7 @@
if (!conf)
goto fail;
+ conf->net_access_key_curve = net_access_key_curve;
conf->id = dpp_next_configurator_id(dpp);
dl_list_add(&dpp->configurator, &conf->list);
ret = conf->id;
@@ -4257,6 +4633,32 @@
}
+int dpp_configurator_set(struct dpp_global *dpp, const char *cmd)
+{
+ unsigned int id;
+ struct dpp_configurator *conf;
+ char *curve;
+
+ id = atoi(cmd);
+ conf = dpp_configurator_get_id(dpp, id);
+ if (!conf)
+ return -1;
+
+ curve = get_param(cmd, " net_access_key_curve=");
+ if (curve) {
+ const struct dpp_curve_params *net_access_key_curve;
+
+ net_access_key_curve = dpp_get_curve_name(curve);
+ os_free(curve);
+ if (!net_access_key_curve)
+ return -1;
+ conf->net_access_key_curve = net_access_key_curve;
+ }
+
+ return 0;
+}
+
+
static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id)
{
struct dpp_configurator *conf, *tmp;
diff --git a/src/common/dpp.h b/src/common/dpp.h
index 2f85ebd..fba4119 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -110,6 +110,7 @@
DPP_STATUS_CONFIGURE_PENDING = 11,
DPP_STATUS_CSR_NEEDED = 12,
DPP_STATUS_CSR_BAD = 13,
+ DPP_STATUS_NEW_KEY_NEEDED = 14,
};
/* DPP Reconfig Flags object - connectorKey values */
@@ -145,6 +146,15 @@
DPP_BOOTSTRAP_NFC_URI,
};
+enum dpp_bootstrap_supported_curves {
+ DPP_BOOTSTRAP_CURVE_P_256 = 0,
+ DPP_BOOTSTRAP_CURVE_P_384 = 1,
+ DPP_BOOTSTRAP_CURVE_P_521 = 2,
+ DPP_BOOTSTRAP_CURVE_BP_256 = 3,
+ DPP_BOOTSTRAP_CURVE_BP_384 = 4,
+ DPP_BOOTSTRAP_CURVE_BP_512 = 5,
+};
+
struct dpp_bootstrap_info {
struct dl_list list;
unsigned int id;
@@ -158,6 +168,7 @@
unsigned int num_freq;
bool channels_listed;
u8 version;
+ u8 supported_curves; /* enum dpp_bootstrap_supported_curves bitmap */
int own;
struct crypto_ec_key *pubkey;
u8 pubkey_hash[SHA256_MAC_LEN];
@@ -172,6 +183,12 @@
#define PKEX_COUNTER_T_LIMIT 5
+enum dpp_pkex_ver {
+ PKEX_VER_AUTO,
+ PKEX_VER_ONLY_1,
+ PKEX_VER_ONLY_2,
+};
+
struct dpp_pkex {
void *msg_ctx;
unsigned int initiator:1;
@@ -253,6 +270,7 @@
void *msg_ctx;
u8 peer_version;
const struct dpp_curve_params *curve;
+ const struct dpp_curve_params *new_curve;
struct dpp_bootstrap_info *peer_bi;
struct dpp_bootstrap_info *own_bi;
struct dpp_bootstrap_info *tmp_own_bi;
@@ -353,6 +371,8 @@
char *trusted_eap_server_name;
struct wpabuf *cacert;
struct wpabuf *certbag;
+ bool waiting_new_key;
+ bool new_key_received;
void *config_resp_ctx;
void *gas_server_ctx;
bool use_config_query;
@@ -378,6 +398,7 @@
u8 kid_hash[SHA256_MAC_LEN];
char *kid;
const struct dpp_curve_params *curve;
+ const struct dpp_curve_params *net_access_key_curve;
char *connector; /* own Connector for reconfiguration */
struct crypto_ec_key *connector_key;
struct crypto_ec_key *pp_key;
@@ -512,6 +533,8 @@
DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP = 93,
DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_REQ = 94,
DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_RESP = 95,
+ DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 96,
+ DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 97,
};
extern enum dpp_test_behavior dpp_test;
@@ -681,6 +704,7 @@
struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp,
const u8 *hash);
int dpp_configurator_add(struct dpp_global *dpp, const char *cmd);
+int dpp_configurator_set(struct dpp_global *dpp, const char *cmd);
int dpp_configurator_remove(struct dpp_global *dpp, const char *id);
int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id,
char *buf, size_t buflen);
@@ -698,6 +722,8 @@
size_t data_len);
int dpp_controller_start(struct dpp_global *dpp,
struct dpp_controller_config *config);
+int dpp_controller_set_params(struct dpp_global *dpp,
+ const char *configurator_params);
void dpp_controller_stop(struct dpp_global *dpp);
void dpp_controller_stop_for_ctx(struct dpp_global *dpp, void *cb_ctx);
struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp,
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index 4fac7de..47f56c2 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -2355,6 +2355,97 @@
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i)
+{
+ int ret = -1, res;
+ u8 Sx[DPP_MAX_SHARED_SECRET_LEN];
+ size_t Sx_len;
+ unsigned int hash_len;
+ const char *info = "New DPP Protocol Key";
+ const u8 *addr[3];
+ size_t len[3];
+ u8 tmp[DPP_MAX_HASH_LEN], k[DPP_MAX_HASH_LEN];
+ struct wpabuf *pcx = NULL, *pex = NULL;
+
+ hash_len = auth->curve->hash_len;
+
+ /*
+ * Configurator: S = pc * Pe
+ * Enrollee: S = pe * Pc
+ * k = HKDF(bk, "New DPP Protocol Key", S.x)
+ * = HKDF-Expand(HKDF-Extract(bk, S.X), "New DPP Protocol Key",
+ * len(new-curve-hash-out))
+ * Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)
+ *
+ * auth->own_protocol_key and auth->peer_protocol_key have already been
+ * updated to use the new keys. The new curve determines the size of
+ * the (new) protocol keys and S.x. The other parameters (bk, hash
+ * algorithm, k) are determined based on the initially determined curve
+ * during the (re)authentication exchange.
+ */
+
+ if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key,
+ Sx, &Sx_len) < 0)
+ goto fail;
+
+ wpa_hexdump_key(MSG_DEBUG, "DPP: S.x", Sx, Sx_len);
+
+ /* tmp = HKDF-Extract(bk, S.x) */
+ addr[0] = Sx;
+ len[0] = Sx_len;
+ res = dpp_hmac_vector(hash_len, auth->bk, hash_len, 1, addr, len, tmp);
+ if (res < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "DPP: HKDF-Extract(bk, S.x)",
+ tmp, hash_len);
+ /* k = HKDF-Expand(tmp, "New DPP Protocol Key", len(hash-output))
+ */
+ res = dpp_hkdf_expand(hash_len, tmp, hash_len, info, k, hash_len);
+ if (res < 0)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: k = HKDF-Expand(\"New DPP Protocol Key\")",
+ k, hash_len);
+
+ /* Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x) */
+ addr[0] = auth->e_nonce;
+ len[0] = auth->curve->nonce_len;
+
+ if (auth->configurator) {
+ pcx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
+ pex = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
+ 0);
+ } else {
+ pcx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key,
+ 0);
+ pex = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0);
+ }
+ if (!pcx || !pex)
+ goto fail;
+ addr[1] = wpabuf_head(pcx);
+ len[1] = wpabuf_len(pcx) / 2;
+ addr[2] = wpabuf_head(pex);
+ len[2] = wpabuf_len(pex) / 2;
+
+ if (dpp_hmac_vector(hash_len, k, hash_len, 3, addr, len, auth_i) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG,
+ "DPP: Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)",
+ auth_i, hash_len);
+ ret = 0;
+fail:
+ forced_memzero(Sx, sizeof(Sx));
+ forced_memzero(tmp, sizeof(tmp));
+ forced_memzero(k, sizeof(k));
+ wpabuf_free(pcx);
+ wpabuf_free(pex);
+ return ret;
+}
+#endif /* CONFIG_DPP3 */
+
+
#ifdef CONFIG_TESTING_OPTIONS
int dpp_test_gen_invalid_key(struct wpabuf *msg,
diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h
index 0f31ae5..10db4e8 100644
--- a/src/common/dpp_i.h
+++ b/src/common/dpp_i.h
@@ -136,6 +136,7 @@
struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey,
struct crypto_ec_key *a_nonce,
struct crypto_ec_key *e_prime_id);
+int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i);
char * dpp_sign_connector(struct dpp_configurator *conf,
const struct wpabuf *dppcon);
int dpp_test_gen_invalid_key(struct wpabuf *msg,
diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c
index 7137bc5..452c502 100644
--- a/src/common/dpp_reconfig.c
+++ b/src/common/dpp_reconfig.c
@@ -131,6 +131,7 @@
{
struct wpabuf *msg;
size_t attr_len;
+ u8 ver = DPP_VERSION;
/* Build DPP Reconfig Authentication Request frame attributes */
attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) +
@@ -144,10 +145,25 @@
wpabuf_put_le16(msg, 1);
wpabuf_put_u8(msg, auth->transaction_id);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version");
+ goto skip_proto_ver;
+ }
+ if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) {
+ wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version");
+ ver = 1;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* Protocol Version */
wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
wpabuf_put_le16(msg, 1);
- wpabuf_put_u8(msg, DPP_VERSION);
+ wpabuf_put_u8(msg, ver);
+
+#ifdef CONFIG_TESTING_OPTIONS
+skip_proto_ver:
+#endif /* CONFIG_TESTING_OPTIONS */
/* DPP Connector */
wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR);
diff --git a/src/common/dpp_tcp.c b/src/common/dpp_tcp.c
index e88c6de..c83fb2d 100644
--- a/src/common/dpp_tcp.c
+++ b/src/common/dpp_tcp.c
@@ -89,6 +89,9 @@
static void dpp_controller_auth_success(struct dpp_connection *conn,
int initiator);
static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx);
+#ifdef CONFIG_DPP3
+static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_DPP3 */
static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx);
static void dpp_relay_conn_timeout(void *eloop_ctx, void *timeout_ctx);
@@ -107,6 +110,9 @@
eloop_cancel_timeout(dpp_tcp_build_csr, conn, NULL);
eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL);
eloop_cancel_timeout(dpp_relay_conn_timeout, conn, NULL);
+#ifdef CONFIG_DPP3
+ eloop_cancel_timeout(dpp_tcp_build_new_key, conn, NULL);
+#endif /* CONFIG_DPP3 */
wpabuf_free(conn->msg);
wpabuf_free(conn->msg_out);
dpp_auth_deinit(conn->auth);
@@ -193,6 +199,14 @@
return;
}
+#ifdef CONFIG_DPP3
+ if (auth->waiting_new_key) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key");
+ conn->on_tcp_tx_complete_gas_done = 0;
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+
if (auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
@@ -999,7 +1013,7 @@
return 0;
}
- conn->pkex = dpp_pkex_rx_exchange_req(conn->ctrl->global, ctrl->pkex_bi,
+ conn->pkex = dpp_pkex_rx_exchange_req(conn->msg_ctx, ctrl->pkex_bi,
NULL, NULL,
ctrl->pkex_identifier,
ctrl->pkex_code,
@@ -1440,6 +1454,21 @@
}
+#ifdef CONFIG_DPP3
+static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx)
+{
+ struct dpp_connection *conn = eloop_ctx;
+ struct dpp_authentication *auth = conn->auth;
+
+ if (!auth || !auth->waiting_new_key)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key");
+ dpp_controller_start_gas_client(conn);
+}
+#endif /* CONFIG_DPP3 */
+
+
static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp)
{
struct dpp_authentication *auth = conn->auth;
@@ -1460,6 +1489,14 @@
eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL);
return 0;
}
+#ifdef CONFIG_DPP3
+ if (res == -3) {
+ wpa_printf(MSG_DEBUG, "DPP: New protocol key needed");
+ eloop_register_timeout(0, 0, dpp_tcp_build_new_key, conn,
+ NULL);
+ return 0;
+ }
+#endif /* CONFIG_DPP3 */
if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
return -1;
@@ -2047,6 +2084,29 @@
}
+int dpp_controller_set_params(struct dpp_global *dpp,
+ const char *configurator_params)
+{
+
+ if (!dpp || !dpp->controller)
+ return -1;
+
+ if (configurator_params) {
+ char *val = os_strdup(configurator_params);
+
+ if (!val)
+ return -1;
+ os_free(dpp->controller->configurator_params);
+ dpp->controller->configurator_params = val;
+ } else {
+ os_free(dpp->controller->configurator_params);
+ dpp->controller->configurator_params = NULL;
+ }
+
+ return 0;
+}
+
+
void dpp_controller_stop(struct dpp_global *dpp)
{
if (dpp) {
@@ -2183,6 +2243,9 @@
{
struct dpp_connection *conn;
+ if (!dpp)
+ return false;
+
dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) {
if (conn->auth && conn->auth->conn_status_requested)
return true;
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index f168d4e..732124f 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -383,10 +383,11 @@
int freq, int channel, int enable_edmg,
u8 edmg_channel, int ht_enabled,
int vht_enabled, int he_enabled,
- int sec_channel_offset,
+ bool eht_enabled, int sec_channel_offset,
int oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps,
- struct he_capabilities *he_cap)
+ struct he_capabilities *he_cap,
+ struct eht_capabilities *eht_cap)
{
if (!he_cap || !he_cap->he_supported)
he_enabled = 0;
@@ -397,6 +398,7 @@
data->ht_enabled = ht_enabled;
data->vht_enabled = vht_enabled;
data->he_enabled = he_enabled;
+ data->eht_enabled = eht_enabled;
data->sec_channel_offset = sec_channel_offset;
data->center_freq1 = freq + sec_channel_offset * 10;
data->center_freq2 = 0;
@@ -415,9 +417,9 @@
&data->edmg);
if (is_6ghz_freq(freq)) {
- if (!data->he_enabled) {
+ if (!data->he_enabled && !data->eht_enabled) {
wpa_printf(MSG_ERROR,
- "Can't set 6 GHz mode - HE isn't enabled");
+ "Can't set 6 GHz mode - HE or EHT aren't enabled");
return -1;
}
@@ -480,7 +482,20 @@
return 0;
}
- if (data->he_enabled) switch (oper_chwidth) {
+#if 0 /* FIX: Figure out how to handle CHANWIDTH_320MHZ */
+ if (data->eht_enabled) switch (oper_chwidth) {
+ case CHANWIDTH_320MHZ:
+ if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) {
+ wpa_printf(MSG_ERROR,
+ "320 MHz channel width is not supported in 5 or 6 GHz");
+ return -1;
+ }
+ break;
+ }
+#endif
+
+ if (data->he_enabled || data->eht_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
if (sec_channel_offset == 0)
break;
@@ -543,7 +558,8 @@
break;
}
- if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) {
+ if (data->eht_enabled || data->he_enabled ||
+ data->vht_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
if (center_segment1 ||
(center_segment0 != 0 &&
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 0e92aa0..d87a2ca 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -40,10 +40,11 @@
int freq, int channel, int edmg, u8 edmg_channel,
int ht_enabled,
int vht_enabled, int he_enabled,
- int sec_channel_offset,
+ bool eht_enabled, int sec_channel_offset,
int oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps,
- struct he_capabilities *he_caps);
+ struct he_capabilities *he_caps,
+ struct eht_capabilities *eht_cap);
void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
int disabled);
int ieee80211ac_cap_check(u32 hw, u32 conf);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index adc6f59..44335de 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -311,6 +311,14 @@
elems->pasn_params = pos;
elems->pasn_params_len = elen;
break;
+ case WLAN_EID_EXT_EHT_CAPABILITIES:
+ elems->eht_capabilities = pos;
+ elems->eht_capabilities_len = elen;
+ break;
+ case WLAN_EID_EXT_EHT_OPERATION:
+ elems->eht_operation = pos;
+ elems->eht_operation_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
@@ -1902,7 +1910,7 @@
{ HOSTAPD_MODE_IEEE80211A, 127, 153, 177, 8, BW40MINUS, P2P_SUPP },
/*
- * IEEE P802.11ax/D8.0 Table E-4 actually talks about channel center
+ * IEEE Std 802.11ax-2021, Table E-4 actually talks about channel center
* frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing
* of 80 MHz, but currently use the following definition for simplicity
* (these center frequencies are not actual channels, which makes
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index ec6556f..e21f7be 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -117,6 +117,8 @@
const u8 *sae_pk;
const u8 *s1g_capab;
const u8 *pasn_params;
+ const u8 *eht_capabilities;
+ const u8 *eht_operation;
u8 ssid_len;
u8 supp_rates_len;
@@ -171,6 +173,8 @@
u8 short_ssid_list_len;
u8 sae_pk_len;
u8 pasn_params_len;
+ u8 eht_capabilities_len;
+ u8 eht_operation_len;
struct mb_ies_info mb_ies;
struct frag_ies_info frag_ies;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 4300ae5..c341a1d 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -479,6 +479,7 @@
#define WLAN_EID_EXT_HE_OPERATION 36
#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
#define WLAN_EID_EXT_SPATIAL_REUSE 39
+#define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42
#define WLAN_EID_EXT_OCV_OCI 54
#define WLAN_EID_EXT_SHORT_SSID_LIST 58
#define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59
@@ -489,6 +490,11 @@
#define WLAN_EID_EXT_REJECTED_GROUPS 92
#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93
#define WLAN_EID_EXT_PASN_PARAMS 100
+#define WLAN_EID_EXT_EHT_OPERATION 106
+#define WLAN_EID_EXT_MULTI_LINK 107
+#define WLAN_EID_EXT_EHT_CAPABILITIES 108
+#define WLAN_EID_EXT_TID_TO_LINK_MAPPING 109
+#define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -1953,6 +1959,26 @@
u8 link_margin;
} STRUCT_PACKED;
+/*
+ * IEEE Std 802.11ax-2021, Table 9-275a - Maximum Transmit Power
+ * Interpretation subfield encoding
+ */
+enum max_tx_pwr_interpretation {
+ LOCAL_EIRP = 0,
+ LOCAL_EIRP_PSD = 1,
+ REGULATORY_CLIENT_EIRP = 2,
+ REGULATORY_CLIENT_EIRP_PSD = 3,
+};
+
+/*
+ * IEEE Std 802.11ax-2021, Table E-13 - Maximum Transmit Power
+ * Category subfield encoding in the United States
+ */
+enum reg_6g_client_type {
+ REG_DEFAULT_CLIENT = 0,
+ REG_SUBORDINATE_CLIENT = 1,
+};
+
#define RRM_CAPABILITIES_IE_LEN 5
/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
@@ -2173,6 +2199,7 @@
#define NEI_REP_BSSID_INFO_VHT BIT(12)
#define NEI_REP_BSSID_INFO_FTM BIT(13)
#define NEI_REP_BSSID_INFO_HE BIT(14)
+#define NEI_REP_BSSID_INFO_EHT BIT(21)
/*
* IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information
@@ -2209,7 +2236,7 @@
* Operation Information subfield (5 octets). */
} STRUCT_PACKED;
-/* IEEE P802.11ax/D6.0, Figure 9-787k - 6 GHz Operation Information field */
+/* IEEE Std 802.11ax-2021, Figure 9-788k - 6 GHz Operation Information field */
struct ieee80211_he_6ghz_oper_info {
u8 primary_chan;
u8 control;
@@ -2218,15 +2245,22 @@
u8 min_rate;
} STRUCT_PACKED;
+/* IEEE Std 802.11ax-2021, Figure 9-788l - Control field format */
#define HE_6GHZ_OPER_INFO_CTRL_CHAN_WIDTH_MASK (BIT(0) | BIT(1))
#define HE_6GHZ_OPER_INFO_CTRL_DUP_BEACON BIT(2)
+#define HE_6GHZ_OPER_INFO_CTRL_REG_INFO_MASK (BIT(3) | BIT(4) | BIT(5))
+#define HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT 3
-/* IEEE P802.11ax/D6.0, 9.4.2.261 HE 6 GHz Band Capabilities element */
+/* IEEE Std 802.11ax-2021, 9.4.2.263 HE 6 GHz Band Capabilities element */
struct ieee80211_he_6ghz_band_cap {
/* Minimum MPDU Start Spacing B0..B2
* Maximum A-MPDU Length Exponent B3..B5
- * Maximum MPDU Length B6..B7 */
- le16 capab;
+ * Maximum MPDU Length B6..B7
+ * SM Power Save B9..B10
+ * RD Responder B11
+ * Rx Antenna Pattern Consistency B12
+ * Tx Antenna Consistency B13 */
+ le16 capab; /* Capabilities Information field */
} STRUCT_PACKED;
#define HE_6GHZ_BAND_CAP_MIN_MPDU_START (BIT(0) | BIT(1) | BIT(2))
@@ -2252,7 +2286,7 @@
#define HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS BIT(13)
/*
- * IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element
+ * IEEE Std 802.11ax-2021, 9.4.2.252 Spatial Reuse Parameter Set element
*/
struct ieee80211_spatial_reuse {
u8 sr_ctrl; /* SR Control */
@@ -2323,6 +2357,7 @@
#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30))
#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31))
#define HE_OPERATION_BSS_COLOR_OFFSET 24
+#define HE_OPERATION_BSS_COLOR_MAX 64
/* HE operation fields length*/
#define HE_OPERATION_IE_MIN_LEN 6
@@ -2330,6 +2365,17 @@
#define HE_OPERATION_COHOSTED_BSSID_INDICATOR_LEN 1
#define HE_OPERATION_6GHZ_OPER_INFO_LEN 5
+/**
+ * enum he_6ghz_ap_type - Allowed Access Point types for 6 GHz Band
+ *
+ * IEEE Std 802.11ax-2021, Table E-12 (Regulatory Info subfield encoding in the
+ * United States)
+ */
+enum he_6ghz_ap_type {
+ HE_6GHZ_INDOOR_AP = 0,
+ HE_6GHZ_STANDARD_POWER_AP = 1,
+};
+
/* Spatial Reuse defines */
#define SPATIAL_REUSE_SRP_DISALLOWED BIT(0)
#define SPATIAL_REUSE_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1)
@@ -2394,6 +2440,105 @@
#define RNR_BSS_PARAM_CO_LOCATED BIT(6)
#define RNR_20_MHZ_PSD_MAX_TXPOWER 255 /* dBm */
+/* IEEE P802.11be/D1.5, 9.4.2.311 - EHT Operation element */
+
+/* Figure 9-1002b: EHT Operation Parameters field subfields */
+#define EHT_OPER_INFO_PRESENT BIT(0)
+#define EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT BIT(1)
+
+/* Control subfield: Channel Width subfield; see Table 9-401b */
+#define EHT_OPER_CHANNEL_WIDTH_20MHZ 0
+#define EHT_OPER_CHANNEL_WIDTH_40MHZ 1
+#define EHT_OPER_CHANNEL_WIDTH_80MHZ 2
+#define EHT_OPER_CHANNEL_WIDTH_160MHZ 3
+#define EHT_OPER_CHANNEL_WIDTH_320MHZ 4
+
+/* Figure 9-1002c: EHT Operation Information field format */
+struct ieee80211_eht_oper_info {
+ u8 control; /* B0..B2: Channel Width */
+ u8 ccfs0;
+ u8 ccfs1;
+ le16 disabled_chan_bitmap; /* 0 or 2 octets */
+} STRUCT_PACKED;
+
+/* Figure 9-1002a: EHT Operation element format */
+struct ieee80211_eht_operation {
+ u8 oper_params; /* EHT Operation Parameters: EHT_OPER_* bits */
+ struct ieee80211_eht_oper_info oper_info; /* 0 or 3 or 5 octets */
+} STRUCT_PACKED;
+
+/* IEEE P802.11be/D1.5, 9.4.2.313 - EHT Capabilities element */
+
+/* Figure 9-1002af: EHT MAC Capabilities Information field */
+#define EHT_MACCAP_EPCS_PRIO BIT(0)
+#define EHT_MACCAP_OM_CONTROL BIT(1)
+#define EHT_MACCAP_TRIGGERED_TXOP_MODE1 BIT(2)
+#define EHT_MACCAP_TRIGGERED_TXOP_MODE2 BIT(3)
+#define EHT_MACCAP_RESTRICTED_TWT BIT(4)
+#define EHT_MACCAP_SCS_TRAFFIC_DESC BIT(5)
+#define EHT_MACCAP_MAX_MPDU_LEN_MASK (BIT(6) | BIT(7))
+#define EHT_MACCAP_MAX_MPDU_LEN_3895 0
+#define EHT_MACCAP_MAX_MPDU_LEN_7991 BIT(6)
+#define EHT_MACCAP_MAX_MPDU_LEN_11454 BIT(7)
+#define EHT_MACCAP_MAX_AMPDU_LEN_EXP_EXT BIT(8)
+
+/* Figure 9-1002ag: EHT PHY Capabilities Information field format
+ * _IDX indicates the octet index within the field */
+#define EHT_PHY_CAPAB_LEN 9
+
+#define EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX 0
+#define EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK ((u8) BIT(1))
+
+#define EHT_PHYCAP_SU_BEAMFORMER_IDX 0
+#define EHT_PHYCAP_SU_BEAMFORMER ((u8) BIT(5))
+#define EHT_PHYCAP_SU_BEAMFORMEE_IDX 0
+#define EHT_PHYCAP_SU_BEAMFORMEE ((u8) BIT(6))
+
+#define EHT_PHYCAP_PPE_THRESHOLD_PRESENT_IDX 5
+#define EHT_PHYCAP_PPE_THRESHOLD_PRESENT ((u8) BIT(3))
+
+#define EHT_PHYCAP_MU_BEAMFORMER_IDX 7
+#define EHT_PHYCAP_MU_BEAMFORMER_80MHZ ((u8) BIT(4))
+#define EHT_PHYCAP_MU_BEAMFORMER_160MHZ ((u8) BIT(5))
+#define EHT_PHYCAP_MU_BEAMFORMER_320MHZ ((u8) BIT(6))
+#define EHT_PHYCAP_MU_BEAMFORMER_MASK (EHT_PHYCAP_MU_BEAMFORMER_80MHZ | \
+ EHT_PHYCAP_MU_BEAMFORMER_160MHZ | \
+ EHT_PHYCAP_MU_BEAMFORMER_320MHZ)
+
+/* Figure 9-1002ah: Supported EHT-MCS and NSS Set field format */
+#define EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY 4
+#define EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS 3
+
+#define EHT_MCS_NSS_CAPAB_LEN 9
+/*
+ * Figure 9-1002ak: EHT PPE Thresholds field format
+ * Maximum PPE threshold length: 62 octets
+ * NSS: 4 bits (maximum NSS: 16), RU index: 5 bits, each pair: 6 bits
+ * 4 + 5 + 5 * 16 * 6 = 489 bits, Padding: 7 bits
+ */
+#define EHT_PPE_THRESH_CAPAB_LEN 62
+
+/* 9.4.2.313.5: EHT PPE Thresholds field */
+#define EHT_PPE_THRES_NSS_SHIFT 0
+#define EHT_PPE_THRES_NSS_MASK ((u8) (BIT(0) | BIT(1) | \
+ BIT(2) | BIT(3)))
+#define EHT_PPE_THRES_RU_INDEX_SHIFT 4
+#define EHT_PPE_THRES_RU_INDEX_MASK ((u16) (BIT(4) | BIT(5) | \
+ BIT(6) | BIT(7) | \
+ BIT(8)))
+
+#define EHT_NSS_MAX_STREAMS 8
+
+/* Figure 9-1002ae: EHT Capabilities element format */
+struct ieee80211_eht_capabilities {
+ /* EHT MAC Capabilities Information */
+ le16 mac_cap;
+ /* EHT PHY Capabilities Information */
+ u8 phy_cap[EHT_PHY_CAPAB_LEN];
+ /* Supported EHT-MCS And NSS Set and EHT PPE thresholds (Optional) */
+ u8 optional[EHT_MCS_NSS_CAPAB_LEN + EHT_PPE_THRESH_CAPAB_LEN];
+} STRUCT_PACKED;
+
/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
@@ -2494,10 +2639,16 @@
#define FD_CAP_PHY_INDEX_SHIFT 10
/*
- * IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning
+ * IEEE Std 802.11ax-2021, 26.17.2.3.2, AP behavior for fast passive scanning
*/
#define FD_MAX_INTERVAL_6GHZ 20 /* TUs */
+/* IEEE Std 802.11ax-2021, 26.17.3.5.1: AP needs to wait and see the collision
+ * persists for at least the minimum default timeout
+ * dot11BSSColorCollisionAPPeriod (50 seconds)
+ */
+#define DOT11BSS_COLOR_COLLISION_AP_PERIOD 50
+
/* Protected Vendor-specific QoS Management Action frame identifiers - WFA */
#define QM_ACTION_VENDOR_TYPE 0x506f9a1a
#define QM_ACTION_OUI_TYPE 0x1a
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 0f7d3af..d04c8d1 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1599,6 +1599,18 @@
* synchronous (in vendor command reply) to the request. Each TWT
* operation is specifically mentioned (against its respective
* documentation) to support either of these or both modes.
+ * @QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI: Flag indicates
+ * that the driver requires add/del virtual interface path using the
+ * generic nl80211 commands for NDP interface create/delete and to
+ * register/unregister the netdev instead of creating/deleting the NDP
+ * interface using the vendor commands
+ * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE and
+ * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE. With the latest kernel
+ * (5.12 version onward), interface creation/deletion is not allowed using
+ * vendor commands as it leads to a deadlock while acquiring the RTNL_LOCK
+ * during the register/unregister of netdev. Create and delete NDP
+ * interface using NL80211_CMD_NEW_INTERFACE and NL80211_CMD_DEL_INTERFACE
+ * commands respectively if the driver advertises this capability set.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -1617,6 +1629,7 @@
QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R = 12,
QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS = 13,
QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT = 14,
+ QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI = 15,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -2390,7 +2403,10 @@
QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES = 58,
/* 8-bit unsigned value for ELNA bypass.
- * 1-Enable, 0-Disable
+ * 0 - Disable eLNA bypass.
+ * 1 - Enable eLNA bypass.
+ * 2 - Reset eLNA bypass configuration, the driver should
+ * revert to the default configuration of eLNA bypass.
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59,
@@ -5627,6 +5643,8 @@
* current channel.
*/
QCA_WLAN_VENDOR_ACS_SELECT_REASON_JAMMER_INTERFERENCE,
+ /* Represents the reason that ACS triggered by AFC */
+ QCA_WLAN_VENDOR_ACS_SELECT_REASON_AFC_TRIGGER,
};
/**
@@ -5834,6 +5852,21 @@
*/
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = 13,
+ /*
+ * 16-bit attribute of bits indicating the AP power modes supported by
+ * the channel (u16).
+ * Note: Currently, only 3 bits are used in the attribute and each bit
+ * corresponds to the power mode mentioned in enum
+ * qca_wlan_vendor_external_acs_chan_power_mode and a given bit is
+ * set if the associated mode is supported.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_SUPP_POWER_MODES
+ = 14,
+ /* Array of nested attributes for each power mode. It takes attr as
+ * defined in enum
+ * qca_wlan_vendor_external_acs_event_chan_power_info_attr.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR = 15,
/* keep last */
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST,
QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX =
@@ -5841,6 +5874,56 @@
};
/**
+ * qca_wlan_vendor_external_acs_chan_power_mode - Specifies the valid
+ * values that the vendor external ACS channel power attribute
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE can
+ * take.
+ * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_LOW_POWER: Low power/Indoor mode
+ * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_STANDARD_POWER: Standard power mode
+ * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_VERY_LOW_POWER: Very low power mode
+ */
+enum qca_wlan_vendor_external_acs_chan_power_level {
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_LOW_POWER = 0,
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_STANDARD_POWER = 1,
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_VERY_LOW_POWER = 2,
+};
+
+/**
+ * qca_wlan_vendor_external_acs_event_chan_power_info_attr: Represents nested
+ * attributes for power mode type and power values corresponding to that.
+ * These attributes are sent as part of
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR.
+ */
+enum qca_wlan_vendor_external_acs_event_chan_power_info_attr {
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_INVALID = 0,
+ /*
+ * Power mode (u8) takes the values defined in enum
+ * qca_wlan_vendor_external_acs_chan_power_mode
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE
+ = 1,
+ /*
+ * Indicates if power value is a PSD/EIRP value (flag). If flag is
+ * present, it indicates a PSD value.
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_PSD_FLAG = 2,
+ /*
+ * Power value (u32) PSD/EIRP as indicated by
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_PSD_FLAG,
+ * for power mode corresponding to the
+ * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE.
+ * Units for PSD - dBm/MHz
+ * Units for EIRP - dBm
+ */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_VALUE
+ = 3,
+ /* keep last */
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_LAST,
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_MAX =
+ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_LAST - 1,
+};
+
+/**
* qca_wlan_vendor_attr_pcl: Represents attributes for
* preferred channel list (PCL). These attributes are sent as part of
* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL and
@@ -5864,6 +5947,10 @@
* bit 3 set: channel should be excluded in GO negotiation
*/
QCA_WLAN_VENDOR_ATTR_PCL_FLAG = 4,
+
+ /* Keep last */
+ QCA_WLAN_VENDOR_ATTR_PCL_LAST,
+ QCA_WLAN_VENDOR_ATTR_PCL_MAX = QCA_WLAN_VENDOR_ATTR_PCL_LAST - 1
};
/**
@@ -5926,6 +6013,10 @@
* qca_wlan_vendor_attr_rropavail_info.
*/
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_RROPAVAIL_INFO = 14,
+ /* Flag attribute to indicate if driver supports 6 GHz AFC trigger
+ * for External ACS
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AFC_CAPABILITY = 15,
/* keep last */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST,
@@ -6529,6 +6620,12 @@
* for the current operating bandwidth.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BANDWIDTH = 30,
+ /* Spectral FFT recapture flag attribute, to enable FFT recapture.
+ * Recapture can only be enabled for scan period greater than 52 us.
+ * If this attribute is enabled, re-triggers will be enabled when AGC
+ * gain changes.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_RECAPTURE = 31,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX =
@@ -7032,7 +7129,7 @@
* Use XR level to benefit XR (extended reality) application to achieve
* latency and power by via constraint scan/roaming/adaptive PS.
* @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW:
- * Use low latency level to benifit application like concurrent
+ * Use low latency level to benefit application like concurrent
* downloading or video streaming via constraint scan/adaptive PS.
* @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW:
* Use ultra low latency level to benefit for gaming/voice
@@ -7356,6 +7453,14 @@
* 1:support 0:not support
*/
QCA_WLAN_VENDOR_ATTR_PEER_NDPE_SUPPORT = 30,
+ /* As per Wi-Fi Aware Specification v3.2 Service Id is the first
+ * 48 bits of the SHA-256 hash of the Service Name.
+ * A lower-case representation of the Service Name shall be used to
+ * calculate the Service ID.
+ * Array of u8: length is 6 bytes
+ * This attribute is used and optional for ndp indication.
+ */
+ QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_ID = 31,
/* keep last */
QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST,
@@ -7365,9 +7470,24 @@
enum qca_wlan_ndp_sub_cmd {
QCA_WLAN_VENDOR_ATTR_NDP_INVALID = 0,
- /* Command to create a NAN data path interface */
+ /* Command to create a NAN data path interface.
+ * This command was initially designed to both create and start a NAN
+ * data path interface. However, changes to Linux 5.12 no longer allow
+ * interface creation via vendor commands. When the driver advertises
+ * QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI
+ * userspace must explicitly first create the interface using
+ * NL80211_CMD_NEW_INTERFACE before subsequently invoking this command
+ * to start the interface.
+ */
QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE = 1,
- /* Command to delete a NAN data path interface */
+ /* Command to delete a NAN data path interface.
+ * This command was initially designed to both stop and delete a NAN
+ * data path interface. However, changes to Linux 5.12 no longer allow
+ * interface deletion via vendor commands. When the driver advertises
+ * QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI
+ * userspace must explicitly delete the interface using
+ * NL80211_CMD_DEL_INTERFACE after calling this command.
+ */
QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE = 2,
/* Command to initiate a NAN data path session */
QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST = 3,
@@ -8515,6 +8635,18 @@
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BCAST_TWT_SUPPORT = 57,
+ /* 8-bit unsigned value to configure the driver/firmware to allow eMLSR
+ * mode for IEEE 802.11be MLO capable devices. If the attribute is set
+ * to 1, and if the firmware supports this capability too, the STA
+ * advertises this capability to the AP over Association Request frame.
+ * This attribute will not have any effect on legacy devices with no
+ * IEEE 802.11be support.
+ * 0 - Default behavior
+ * 1 - Enable eMLSR (Enhanced Multi-link Single-Radio) mode
+ * This attribute is used to configure the testbed device.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_11BE_EMLSR_MODE = 58,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -8585,12 +8717,17 @@
* peer. Refers the enum qca_wlan_vendor_attr_twt_capability. It's a synchronous
* operation.
*
- * @QCA_WLAN_TWT_SETUP_READY_NOTIFY: Notify userspace that the firmare is
+ * @QCA_WLAN_TWT_SETUP_READY_NOTIFY: Notify userspace that the firmware is
* ready for a new TWT session setup after it issued a TWT teardown.
*
* @QCA_WLAN_TWT_SET_PARAM: Configure TWT related parameters. Required
* parameters are obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refer
* the enum qca_wlan_vendor_attr_twt_set_param.
+ *
+ * @QCA_WLAN_TWT_NOTIFY: Used to notify userspace about changes in TWT
+ * related information for example TWT required bit in AP capabilities etc.
+ * The reason for the notification is sent using
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS.
*/
enum qca_wlan_twt_operation {
QCA_WLAN_TWT_SET = 0,
@@ -8604,6 +8741,7 @@
QCA_WLAN_TWT_GET_CAPABILITIES = 8,
QCA_WLAN_TWT_SETUP_READY_NOTIFY = 9,
QCA_WLAN_TWT_SET_PARAM = 10,
+ QCA_WLAN_TWT_NOTIFY = 11,
};
/**
@@ -8620,11 +8758,17 @@
* enum qca_wlan_vendor_attr_twt_setup, enum qca_wlan_vendor_attr_twt_resume,
* enum qca_wlan_vendor_attr_twt_set_param, or
* enum qca_wlan_vendor_attr_twt_stats based on the operation.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS: Size is u8, mandatory when
+ * QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION is set to QCA_WLAN_TWT_NOTIFY.
+ * The values used by this attribute are defined in
+ * enum qca_wlan_vendor_twt_status.
*/
enum qca_wlan_vendor_attr_config_twt {
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION = 1,
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS = 2,
+ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST,
@@ -9100,6 +9244,10 @@
* QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE: The driver requested to
* terminate an existing TWT session on power save exit request from userspace.
* Used on the TWT_TERMINATE notification from the driver/firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED: The peer has set the TWT
+ * required bit in its capabilities.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED: The peer has cleared
+ * the TWT required bit(1->0) in its capabilities.
*/
enum qca_wlan_vendor_twt_status {
QCA_WLAN_VENDOR_TWT_STATUS_OK = 0,
@@ -9125,6 +9273,8 @@
QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS = 20,
QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS = 21,
QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE = 22,
+ QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED = 23,
+ QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED = 24,
};
/**
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index b78db05..27336c9 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1599,6 +1599,13 @@
"%s: invalid group cipher 0x%x (%08x)",
__func__, data->group_cipher,
WPA_GET_BE32(pos));
+#ifdef CONFIG_NO_TKIP
+ if (RSN_SELECTOR_GET(pos) == RSN_CIPHER_SUITE_TKIP) {
+ wpa_printf(MSG_DEBUG,
+ "%s: TKIP as group cipher not supported in CONFIG_NO_TKIP=y build",
+ __func__);
+ }
+#endif /* CONFIG_NO_TKIP */
return -1;
}
pos += RSN_SELECTOR_LEN;
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index c1ce68c..779b2cf 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -487,7 +487,7 @@
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
- struct os_reltime started_at;
+ struct os_reltime started_at, ending_at;
int res;
fd_set rfds;
const char *_cmd;
@@ -543,9 +543,19 @@
}
os_free(cmd_buf);
+ os_get_reltime(&ending_at);
+ ending_at.sec += 10;
+
for (;;) {
- tv.tv_sec = 10;
- tv.tv_usec = 0;
+ struct os_reltime diff;
+
+ os_get_reltime(&started_at);
+ if (os_reltime_before(&ending_at, &started_at))
+ return -2;
+ os_reltime_sub(&ending_at, &started_at, &diff);
+ tv.tv_sec = diff.sec;
+ tv.tv_usec = diff.usec;
+
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 3d3a62a..055bf73 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -363,6 +363,9 @@
#define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED "
#define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON "
+/* BSS Transition Management Query frame received */
+#define BSS_TM_QUERY "BSS-TM-QUERY "
+
/* BSS Transition Management Response frame received */
#define BSS_TM_RESP "BSS-TM-RESP "
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index e6150b0..e4f3eb3 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -1275,4 +1275,46 @@
struct crypto_ec_key *key,
enum crypto_hash_alg algo);
+struct crypto_rsa_key;
+
+/**
+ * crypto_rsa_key_read - Read an RSA key
+ * @file: File from which to read (PEM encoded, can be X.509v3 certificate)
+ * @private_key: Whether to read the private key instead of public key
+ * Returns: RSA key or %NULL on failure
+ */
+struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key);
+
+/**
+ * crypto_rsa_oaep_sha256_encrypt - RSA-OAEP-SHA-256 encryption
+ * @key: RSA key from crypto_rsa_key_read()
+ * @in: Plaintext input data
+ * Returns: Encrypted output data or %NULL on failure
+ */
+struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in);
+
+/**
+ * crypto_rsa_oaep_sha256_decrypt - RSA-OAEP-SHA-256 decryption
+ * @key: RSA key from crypto_rsa_key_read()
+ * @in: Encrypted input data
+ * Returns: Decrypted output data or %NULL on failure
+ */
+struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in);
+
+/**
+ * crypto_rsa_key_free - Free an RSA key
+ * @key: RSA key from crypto_rsa_key_read()
+ */
+void crypto_rsa_key_free(struct crypto_rsa_key *key);
+
+/**
+ * crypto_unload - Unload crypto resources
+ *
+ * This function is called just before the process exits to allow dynamic
+ * resource allocations to be freed.
+ */
+void crypto_unload(void);
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_gnutls.c b/src/crypto/crypto_gnutls.c
index 4ef1146..a7a163f 100644
--- a/src/crypto/crypto_gnutls.c
+++ b/src/crypto/crypto_gnutls.c
@@ -504,3 +504,8 @@
gcry_cipher_close(ctx->dec);
os_free(ctx);
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index aad40af..d15c363 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -326,3 +326,8 @@
void crypto_global_deinit(void)
{
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_libtomcrypt.c b/src/crypto/crypto_libtomcrypt.c
index ed30efa..fd79c1a 100644
--- a/src/crypto/crypto_libtomcrypt.c
+++ b/src/crypto/crypto_libtomcrypt.c
@@ -766,3 +766,8 @@
}
#endif /* CONFIG_MODEXP */
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_linux.c b/src/crypto/crypto_linux.c
index 1724456..9278e27 100644
--- a/src/crypto/crypto_linux.c
+++ b/src/crypto/crypto_linux.c
@@ -1007,3 +1007,8 @@
void crypto_global_deinit(void)
{
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_nettle.c b/src/crypto/crypto_nettle.c
index f85d365..d745027 100644
--- a/src/crypto/crypto_nettle.c
+++ b/src/crypto/crypto_nettle.c
@@ -467,3 +467,8 @@
{
bin_clear_free(ctx, sizeof(*ctx));
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_none.c b/src/crypto/crypto_none.c
index 5479194..a0dc0f5 100644
--- a/src/crypto/crypto_none.c
+++ b/src/crypto/crypto_none.c
@@ -22,3 +22,8 @@
{
return 0;
}
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 82c8576..c6e065f 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
* Wrapper functions for OpenSSL libcrypto
- * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -16,16 +16,17 @@
#include <openssl/dh.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
-#ifdef CONFIG_OPENSSL_CMAC
-#include <openssl/cmac.h>
-#endif /* CONFIG_OPENSSL_CMAC */
+#include <openssl/pem.h>
#ifdef CONFIG_ECC
#include <openssl/ec.h>
#include <openssl/x509.h>
-#include <openssl/pem.h>
#endif /* CONFIG_ECC */
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/provider.h>
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#else /* OpenSSL version >= 3.0 */
+#include <openssl/cmac.h>
#endif /* OpenSSL version >= 3.0 */
#include "common.h"
@@ -40,9 +41,7 @@
#include "aes_wrap.h"
#include "crypto.h"
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
/* Compatibility wrappers for older versions. */
static HMAC_CTX * HMAC_CTX_new(void)
@@ -121,30 +120,89 @@
#endif /* OpenSSL version < 1.1.0 */
+#if OPENSSL_VERSION_NUMBER < 0x10101000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x30400000L)
+
+static int EC_POINT_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point, BIGNUM *x,
+ BIGNUM *y, BN_CTX *ctx)
+{
+ return EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx);
+}
+
+
+static int EC_POINT_set_affine_coordinates(const EC_GROUP *group,
+ EC_POINT *point, const BIGNUM *x,
+ const BIGNUM *y, BN_CTX *ctx)
+{
+ return EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx);
+}
+
+#endif /* OpenSSL version < 1.1.1 */
+
+
+#if OPENSSL_VERSION_NUMBER < 0x10101000L || \
+ defined(OPENSSL_IS_BORINGSSL) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER < 0x30400000L)
+
+static int EC_POINT_set_compressed_coordinates(const EC_GROUP *group,
+ EC_POINT *point, const BIGNUM *x,
+ int y_bit, BN_CTX *ctx)
+{
+ return EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit,
+ ctx);
+}
+
+
+static int EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
+ BIGNUM *b, BN_CTX *ctx)
+{
+ return EC_GROUP_get_curve_GFp(group, p, a, b, ctx);
+}
+
+#endif /* OpenSSL version < 1.1.1 */
+
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static OSSL_PROVIDER *openssl_default_provider = NULL;
+static OSSL_PROVIDER *openssl_legacy_provider = NULL;
+#endif /* OpenSSL version >= 3.0 */
+
void openssl_load_legacy_provider(void)
{
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- static bool loaded = false;
- OSSL_PROVIDER *legacy;
-
- if (loaded)
+ if (openssl_legacy_provider)
return;
- legacy = OSSL_PROVIDER_load(NULL, "legacy");
+ openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
+ if (openssl_legacy_provider && !openssl_default_provider)
+ openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
+#endif /* OpenSSL version >= 3.0 */
+}
- if (legacy) {
- OSSL_PROVIDER_load(NULL, "default");
- loaded = true;
+
+static void openssl_unload_legacy_provider(void)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (openssl_legacy_provider) {
+ OSSL_PROVIDER_unload(openssl_legacy_provider);
+ openssl_legacy_provider = NULL;
+ }
+ if (openssl_default_provider) {
+ OSSL_PROVIDER_unload(openssl_default_provider);
+ openssl_default_provider = NULL;
}
#endif /* OpenSSL version >= 3.0 */
}
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+
static BIGNUM * get_group5_prime(void)
{
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
return BN_get_rfc3526_prime_1536(NULL);
#elif !defined(OPENSSL_IS_BORINGSSL)
return get_rfc3526_prime_1536(NULL);
@@ -195,6 +253,8 @@
return BN_bin2bn(RFC3526_ORDER_1536, sizeof(RFC3526_ORDER_1536), NULL);
}
+#endif /* OpenSSL version < 3.0 */
+
#ifdef OPENSSL_NO_SHA256
#define NO_SHA256_WRAPPER
@@ -403,7 +463,7 @@
if (ctx == NULL)
return NULL;
if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
- os_free(ctx);
+ EVP_CIPHER_CTX_free(ctx);
return NULL;
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
@@ -501,8 +561,52 @@
#ifndef CONFIG_FIPS
#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static const EVP_CIPHER * aes_get_evp_wrap_cipher(size_t keylen)
+{
+ switch (keylen) {
+ case 16:
+ return EVP_aes_128_wrap();
+ case 24:
+ return EVP_aes_192_wrap();
+ case 32:
+ return EVP_aes_256_wrap();
+ default:
+ return NULL;
+ }
+}
+#endif /* OpenSSL version >= 3.0 */
+
+
int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *type;
+ int ret = -1, len;
+ u8 buf[16];
+
+ if (TEST_FAIL())
+ return -1;
+
+ type = aes_get_evp_wrap_cipher(kek_len);
+ if (!type)
+ return -1;
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ return -1;
+
+ if (EVP_EncryptInit_ex(ctx, type, NULL, kek, NULL) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_EncryptUpdate(ctx, cipher, &len, plain, n * 8) == 1 &&
+ len == (n + 1) * 8 &&
+ EVP_EncryptFinal_ex(ctx, buf, &len) == 1)
+ ret = 0;
+
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+#else /* OpenSSL version >= 3.0 */
AES_KEY actx;
int res;
@@ -513,12 +617,40 @@
res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
OPENSSL_cleanse(&actx, sizeof(actx));
return res <= 0 ? -1 : 0;
+#endif /* OpenSSL version >= 3.0 */
}
int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
u8 *plain)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *type;
+ int ret = -1, len;
+ u8 buf[16];
+
+ if (TEST_FAIL())
+ return -1;
+
+ type = aes_get_evp_wrap_cipher(kek_len);
+ if (!type)
+ return -1;
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ return -1;
+
+ if (EVP_DecryptInit_ex(ctx, type, NULL, kek, NULL) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_DecryptUpdate(ctx, plain, &len, cipher, (n + 1) * 8) == 1 &&
+ len == n * 8 &&
+ EVP_DecryptFinal_ex(ctx, buf, &len) == 1)
+ ret = 0;
+
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+#else /* OpenSSL version >= 3.0 */
AES_KEY actx;
int res;
@@ -529,6 +661,7 @@
res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
OPENSSL_cleanse(&actx, sizeof(actx));
return res <= 0 ? -1 : 0;
+#endif /* OpenSSL version >= 3.0 */
}
#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
@@ -819,9 +952,7 @@
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
size_t publen, privlen;
@@ -870,6 +1001,57 @@
wpabuf_clear_free(privkey);
DH_free(dh);
return NULL;
+#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *pkey = NULL;
+ OSSL_PARAM params[2];
+ size_t pub_len = OSSL_PARAM_UNMODIFIED;
+ size_t priv_len;
+ struct wpabuf *pubkey = NULL, *privkey = NULL;
+ BIGNUM *priv_bn = NULL;
+ EVP_PKEY_CTX *gctx;
+
+ *priv = NULL;
+ wpabuf_free(*publ);
+ *publ = NULL;
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+ "modp_1536", 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ gctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
+ if (!gctx ||
+ EVP_PKEY_keygen_init(gctx) != 1 ||
+ EVP_PKEY_CTX_set_params(gctx, params) != 1 ||
+ EVP_PKEY_generate(gctx, &pkey) != 1 ||
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
+ &priv_bn) != 1 ||
+ EVP_PKEY_get_octet_string_param(pkey,
+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+ NULL, 0, &pub_len) < 0 ||
+ pub_len == OSSL_PARAM_UNMODIFIED ||
+ (priv_len = BN_num_bytes(priv_bn)) == 0 ||
+ !(pubkey = wpabuf_alloc(pub_len)) ||
+ !(privkey = wpabuf_alloc(priv_len)) ||
+ EVP_PKEY_get_octet_string_param(pkey,
+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+ wpabuf_put(pubkey, pub_len),
+ pub_len, NULL) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ wpabuf_free(pubkey);
+ wpabuf_clear_free(privkey);
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ } else {
+ BN_bn2bin(priv_bn, wpabuf_put(privkey, priv_len));
+
+ *priv = privkey;
+ *publ = pubkey;
+ }
+
+ BN_clear_free(priv_bn);
+ EVP_PKEY_CTX_free(gctx);
+ return pkey;
#else
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
@@ -929,9 +1111,7 @@
void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
DH *dh;
dh = DH_new();
@@ -962,6 +1142,39 @@
err:
DH_free(dh);
return NULL;
+#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *pkey = NULL;
+ OSSL_PARAM_BLD *bld;
+ OSSL_PARAM *params = NULL;
+ BIGNUM *priv_key, *pub_key;
+ EVP_PKEY_CTX *fctx;
+
+ fctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
+ priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+ pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+ bld = OSSL_PARAM_BLD_new();
+ if (!fctx || !priv_key || !pub_key || !bld ||
+ OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME,
+ "modp_1536", 0) != 1 ||
+ OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY,
+ priv_key) != 1 ||
+ OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY,
+ pub_key) != 1 ||
+ !(params = OSSL_PARAM_BLD_to_param(bld)) ||
+ EVP_PKEY_fromdata_init(fctx) != 1 ||
+ EVP_PKEY_fromdata(fctx, &pkey, EVP_PKEY_KEYPAIR, params) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_fromdata failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ }
+
+ BN_clear_free(priv_key);
+ BN_free(pub_key);
+ EVP_PKEY_CTX_free(fctx);
+ OSSL_PARAM_BLD_free(bld);
+ OSSL_PARAM_free(params);
+ return pkey;
#else
DH *dh;
BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL;
@@ -1004,6 +1217,36 @@
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *pkey = ctx;
+ EVP_PKEY *peer_pub;
+ size_t len;
+ struct wpabuf *res = NULL;
+ EVP_PKEY_CTX *dctx = NULL;
+
+ peer_pub = EVP_PKEY_new();
+ if (!pkey || !peer_pub ||
+ EVP_PKEY_copy_parameters(peer_pub, pkey) != 1 ||
+ EVP_PKEY_set1_encoded_public_key(peer_pub, wpabuf_head(peer_public),
+ wpabuf_len(peer_public)) != 1 ||
+ !(dctx = EVP_PKEY_CTX_new(pkey, NULL)) ||
+ EVP_PKEY_derive_init(dctx) != 1 ||
+ EVP_PKEY_derive_set_peer(dctx, peer_pub) != 1 ||
+ EVP_PKEY_derive(dctx, NULL, &len) != 1 ||
+ !(res = wpabuf_alloc(len)) ||
+ EVP_PKEY_derive(dctx, wpabuf_mhead(res), &len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ wpabuf_free(res);
+ res = NULL;
+ } else {
+ wpabuf_put(res, len);
+ }
+
+ EVP_PKEY_free(peer_pub);
+ EVP_PKEY_CTX_free(dctx);
+ return res;
+#else /* OpenSSL version >= 3.0 */
BIGNUM *pub_key;
struct wpabuf *res = NULL;
size_t rlen;
@@ -1035,27 +1278,93 @@
BN_clear_free(pub_key);
wpabuf_clear_free(res);
return NULL;
+#endif /* OpenSSL version >= 3.0 */
}
void dh5_free(void *ctx)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *pkey = ctx;
+
+ EVP_PKEY_free(pkey);
+#else /* OpenSSL version >= 3.0 */
DH *dh;
if (ctx == NULL)
return;
dh = ctx;
DH_free(dh);
+#endif /* OpenSSL version >= 3.0 */
}
struct crypto_hash {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_CTX *ctx;
+#else /* OpenSSL version >= 3.0 */
HMAC_CTX *ctx;
+#endif /* OpenSSL version >= 3.0 */
};
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct crypto_hash *ctx;
+ EVP_MAC *mac;
+ OSSL_PARAM params[2];
+ char *a = NULL;
+
+ switch (alg) {
+#ifndef OPENSSL_NO_MD5
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ a = "MD5";
+ break;
+#endif /* OPENSSL_NO_MD5 */
+#ifndef OPENSSL_NO_SHA
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ a = "SHA1";
+ break;
+#endif /* OPENSSL_NO_SHA */
+#ifndef OPENSSL_NO_SHA256
+#ifdef CONFIG_SHA256
+ case CRYPTO_HASH_ALG_HMAC_SHA256:
+ a = "SHA256";
+ break;
+#endif /* CONFIG_SHA256 */
+#endif /* OPENSSL_NO_SHA256 */
+ default:
+ return NULL;
+ }
+
+ mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ if (!mac)
+ return NULL;
+
+ params[0] = OSSL_PARAM_construct_utf8_string("digest", a, 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (!ctx)
+ return NULL;
+ ctx->ctx = EVP_MAC_CTX_new(mac);
+ if (!ctx->ctx) {
+ EVP_MAC_free(mac);
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (EVP_MAC_init(ctx->ctx, key, key_len, params) != 1) {
+ EVP_MAC_CTX_free(ctx->ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+ EVP_MAC_free(mac);
+ return NULL;
+ }
+
+ EVP_MAC_free(mac);
+ return ctx;
+#else /* OpenSSL version >= 3.0 */
struct crypto_hash *ctx;
const EVP_MD *md;
@@ -1097,6 +1406,7 @@
}
return ctx;
+#endif /* OpenSSL version >= 3.0 */
}
@@ -1104,12 +1414,49 @@
{
if (ctx == NULL)
return;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_update(ctx->ctx, data, len);
+#else /* OpenSSL version >= 3.0 */
HMAC_Update(ctx->ctx, data, len);
+#endif /* OpenSSL version >= 3.0 */
}
int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ size_t mdlen;
+ int res;
+
+ if (!ctx)
+ return -2;
+
+ if (!mac || !len) {
+ EVP_MAC_CTX_free(ctx->ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+ return 0;
+ }
+
+ res = EVP_MAC_final(ctx->ctx, NULL, &mdlen, 0);
+ if (res != 1) {
+ EVP_MAC_CTX_free(ctx->ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+ return -1;
+ }
+ res = EVP_MAC_final(ctx->ctx, mac, &mdlen, mdlen);
+ EVP_MAC_CTX_free(ctx->ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+
+ if (TEST_FAIL())
+ return -1;
+
+ if (res == 1) {
+ *len = mdlen;
+ return 0;
+ }
+
+ return -1;
+#else /* OpenSSL version >= 3.0 */
unsigned int mdlen;
int res;
@@ -1136,9 +1483,148 @@
}
return -1;
+#endif /* OpenSSL version >= 3.0 */
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+static int openssl_hmac_vector(char *digest, const u8 *key,
+ size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac,
+ unsigned int mdlen)
+{
+ EVP_MAC *hmac;
+ OSSL_PARAM params[2];
+ EVP_MAC_CTX *ctx;
+ size_t i, mlen;
+ int res;
+
+ if (TEST_FAIL())
+ return -1;
+
+ hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+ if (!hmac)
+ return -1;
+
+ params[0] = OSSL_PARAM_construct_utf8_string("digest", digest, 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ ctx = EVP_MAC_CTX_new(hmac);
+ EVP_MAC_free(hmac);
+ if (!ctx)
+ return -1;
+
+ if (EVP_MAC_init(ctx, key, key_len, params) != 1)
+ goto fail;
+
+ for (i = 0; i < num_elem; i++) {
+ if (EVP_MAC_update(ctx, addr[i], len[i]) != 1)
+ goto fail;
+ }
+
+ res = EVP_MAC_final(ctx, mac, &mlen, mdlen);
+ EVP_MAC_CTX_free(ctx);
+
+ return res == 1 ? 0 : -1;
+fail:
+ EVP_MAC_CTX_free(ctx);
+ return -1;
+}
+
+
+#ifndef CONFIG_FIPS
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("MD5", key ,key_len, num_elem, addr, len,
+ mac, 16);
+}
+
+
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("SHA1", key, key_len, num_elem, addr,
+ len, mac, 20);
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("SHA256", key, key_len, num_elem, addr,
+ len, mac, 32);
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("SHA384", key, key_len, num_elem, addr,
+ len, mac, 48);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
+#ifdef CONFIG_SHA512
+
+int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector("SHA512", key, key_len, num_elem, addr,
+ len, mac, 64);
+}
+
+
+int hmac_sha512(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA512 */
+
+#else /* OpenSSL version >= 3.0 */
+
static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac,
@@ -1188,16 +1674,6 @@
#endif /* CONFIG_FIPS */
-int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
- int iterations, u8 *buf, size_t buflen)
-{
- if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
- ssid_len, iterations, buflen, buf) != 1)
- return -1;
- return 0;
-}
-
-
int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
@@ -1269,6 +1745,18 @@
#endif /* CONFIG_SHA512 */
+#endif /* OpenSSL version >= 3.0 */
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+ int iterations, u8 *buf, size_t buflen)
+{
+ if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+ ssid_len, iterations, buflen, buf) != 1)
+ return -1;
+ return 0;
+}
+
int crypto_get_random(void *buf, size_t len)
{
@@ -1278,10 +1766,49 @@
}
-#ifdef CONFIG_OPENSSL_CMAC
int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MAC_CTX *ctx = NULL;
+ EVP_MAC *emac;
+ int ret = -1;
+ size_t outlen, i;
+ OSSL_PARAM params[2];
+ char *cipher = NULL;
+
+ if (TEST_FAIL())
+ return -1;
+
+ emac = EVP_MAC_fetch(NULL, "CMAC", NULL);
+
+ if (key_len == 32)
+ cipher = "aes-256-cbc";
+ else if (key_len == 24)
+ cipher = "aes-192-cbc";
+ else if (key_len == 16)
+ cipher = "aes-128-cbc";
+
+ params[0] = OSSL_PARAM_construct_utf8_string("cipher", cipher, 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ if (!emac || !cipher ||
+ !(ctx = EVP_MAC_CTX_new(emac)) ||
+ EVP_MAC_init(ctx, key, key_len, params) != 1)
+ goto fail;
+
+ for (i = 0; i < num_elem; i++) {
+ if (!EVP_MAC_update(ctx, addr[i], len[i]))
+ goto fail;
+ }
+ if (EVP_MAC_final(ctx, mac, &outlen, 16) != 1 || outlen != 16)
+ goto fail;
+
+ ret = 0;
+fail:
+ EVP_MAC_CTX_free(ctx);
+ return ret;
+#else /* OpenSSL version >= 3.0 */
CMAC_CTX *ctx;
int ret = -1;
size_t outlen, i;
@@ -1296,6 +1823,9 @@
if (key_len == 32) {
if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL))
goto fail;
+ } else if (key_len == 24) {
+ if (!CMAC_Init(ctx, key, 24, EVP_aes_192_cbc(), NULL))
+ goto fail;
} else if (key_len == 16) {
if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
goto fail;
@@ -1313,6 +1843,7 @@
fail:
CMAC_CTX_free(ctx);
return ret;
+#endif /* OpenSSL version >= 3.0 */
}
@@ -1333,7 +1864,6 @@
{
return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
}
-#endif /* CONFIG_OPENSSL_CMAC */
struct crypto_bignum * crypto_bignum_init(void)
@@ -1752,7 +2282,7 @@
e->b = BN_new();
if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
e->order == NULL || e->a == NULL || e->b == NULL ||
- !EC_GROUP_get_curve_GFp(e->group, e->prime, e->a, e->b, e->bnctx) ||
+ !EC_GROUP_get_curve(e->group, e->prime, e->a, e->b, e->bnctx) ||
!EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
crypto_ec_deinit(e);
e = NULL;
@@ -1847,10 +2377,10 @@
int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p,
struct crypto_bignum *x)
{
- return EC_POINT_get_affine_coordinates_GFp(e->group,
- (const EC_POINT *) p,
- (BIGNUM *) x, NULL,
- e->bnctx) == 1 ? 0 : -1;
+ return EC_POINT_get_affine_coordinates(e->group,
+ (const EC_POINT *) p,
+ (BIGNUM *) x, NULL,
+ e->bnctx) == 1 ? 0 : -1;
}
@@ -1868,8 +2398,8 @@
y_bn = BN_new();
if (x_bn && y_bn &&
- EC_POINT_get_affine_coordinates_GFp(e->group, (EC_POINT *) point,
- x_bn, y_bn, e->bnctx)) {
+ EC_POINT_get_affine_coordinates(e->group, (EC_POINT *) point,
+ x_bn, y_bn, e->bnctx)) {
if (x) {
crypto_bignum_to_bin((struct crypto_bignum *) x_bn,
x, len, len);
@@ -1907,8 +2437,7 @@
return NULL;
}
- if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y,
- e->bnctx)) {
+ if (!EC_POINT_set_affine_coordinates(e->group, elem, x, y, e->bnctx)) {
EC_POINT_clear_free(elem);
elem = NULL;
}
@@ -2009,8 +2538,8 @@
x = BN_new();
y = BN_new();
if (!x || !y ||
- EC_POINT_get_affine_coordinates_GFp(e->group, (const EC_POINT *) p,
- x, y, e->bnctx) != 1)
+ EC_POINT_get_affine_coordinates(e->group, (const EC_POINT *) p,
+ x, y, e->bnctx) != 1)
goto fail;
x_str = BN_bn2hex(x);
@@ -2035,6 +2564,33 @@
struct crypto_ecdh * crypto_ecdh_init(int group)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct crypto_ecdh *ecdh;
+ const char *name;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ name = OSSL_EC_curve_nid2name(ecdh->ec->nid);
+ if (!name)
+ goto fail;
+
+ ecdh->pkey = EVP_EC_gen(name);
+ if (!ecdh->pkey)
+ goto fail;
+
+done:
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ ecdh = NULL;
+ goto done;
+#else /* OpenSSL version >= 3.0 */
struct crypto_ecdh *ecdh;
EVP_PKEY *params = NULL;
EC_KEY *ec_params = NULL;
@@ -2089,11 +2645,32 @@
crypto_ecdh_deinit(ecdh);
ecdh = NULL;
goto done;
+#endif /* OpenSSL version >= 3.0 */
}
struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct crypto_ecdh *ecdh;
+
+ ecdh = os_zalloc(sizeof(*ecdh));
+ if (!ecdh)
+ goto fail;
+
+ ecdh->ec = crypto_ec_init(group);
+ if (!ecdh->ec)
+ goto fail;
+
+ ecdh->pkey = EVP_PKEY_dup((EVP_PKEY *) own_key);
+ if (!ecdh->pkey)
+ goto fail;
+
+ return ecdh;
+fail:
+ crypto_ecdh_deinit(ecdh);
+ return NULL;
+#else /* OpenSSL version >= 3.0 */
struct crypto_ecdh *ecdh;
ecdh = os_zalloc(sizeof(*ecdh));
@@ -2115,11 +2692,34 @@
fail:
crypto_ecdh_deinit(ecdh);
return NULL;
+#endif /* OpenSSL version >= 3.0 */
}
struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct wpabuf *buf = NULL;
+ unsigned char *pub;
+ size_t len, exp_len;
+
+ len = EVP_PKEY_get1_encoded_public_key(ecdh->pkey, &pub);
+ if (len == 0)
+ return NULL;
+
+ /* Encoded using SECG SEC 1, Sec. 2.3.4 format */
+ exp_len = 1 + 2 * crypto_ec_prime_len(ecdh->ec);
+ if (len != exp_len) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL:%s: Unexpected encoded public key length %zu (expected %zu)",
+ __func__, len, exp_len);
+ goto fail;
+ }
+ buf = wpabuf_alloc_copy(pub + 1, inc_y ? len - 1 : len / 2);
+fail:
+ OPENSSL_free(pub);
+ return buf;
+#else /* OpenSSL version >= 3.0 */
struct wpabuf *buf = NULL;
EC_KEY *eckey;
const EC_POINT *pubkey;
@@ -2145,10 +2745,10 @@
if (!x || !buf)
goto fail;
- if (EC_POINT_get_affine_coordinates_GFp(ecdh->ec->group, pubkey,
- x, y, ecdh->ec->bnctx) != 1) {
+ if (EC_POINT_get_affine_coordinates(ecdh->ec->group, pubkey,
+ x, y, ecdh->ec->bnctx) != 1) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EC_POINT_get_affine_coordinates_GFp failed: %s",
+ "OpenSSL: EC_POINT_get_affine_coordinates failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
@@ -2175,12 +2775,57 @@
wpabuf_free(buf);
buf = NULL;
goto done;
+#endif /* OpenSSL version >= 3.0 */
}
struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
const u8 *key, size_t len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY *peerkey = EVP_PKEY_new();
+ EVP_PKEY_CTX *ctx;
+ size_t res_len;
+ struct wpabuf *res = NULL;
+ u8 *peer;
+
+ /* Encode using SECG SEC 1, Sec. 2.3.4 format */
+ peer = os_malloc(1 + len);
+ if (!peer)
+ return NULL;
+ peer[0] = inc_y ? 0x04 : 0x02;
+ os_memcpy(peer + 1, key, len);
+
+ if (!peerkey ||
+ EVP_PKEY_copy_parameters(peerkey, ecdh->pkey) != 1 ||
+ EVP_PKEY_set1_encoded_public_key(peerkey, peer, 1 + len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_set1_encoded_public_key failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_PKEY_free(peerkey);
+ os_free(peer);
+ return NULL;
+ }
+ os_free(peer);
+
+ ctx = EVP_PKEY_CTX_new(ecdh->pkey, NULL);
+ if (!ctx ||
+ EVP_PKEY_derive_init(ctx) != 1 ||
+ EVP_PKEY_derive_set_peer(ctx, peerkey) != 1 ||
+ EVP_PKEY_derive(ctx, NULL, &res_len) != 1 ||
+ !(res = wpabuf_alloc(res_len)) ||
+ EVP_PKEY_derive(ctx, wpabuf_mhead(res), &res_len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ wpabuf_free(res);
+ res = NULL;
+ } else {
+ wpabuf_put(res, res_len);
+ }
+
+ EVP_PKEY_free(peerkey);
+ EVP_PKEY_CTX_free(ctx);
+ return res;
+#else /* OpenSSL version >= 3.0 */
BIGNUM *x, *y = NULL;
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *peerkey = NULL;
@@ -2198,19 +2843,18 @@
y = BN_bin2bn(key + len / 2, len / 2, NULL);
if (!y)
goto fail;
- if (!EC_POINT_set_affine_coordinates_GFp(ecdh->ec->group, pub,
- x, y,
- ecdh->ec->bnctx)) {
+ if (!EC_POINT_set_affine_coordinates(ecdh->ec->group, pub,
+ x, y, ecdh->ec->bnctx)) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+ "OpenSSL: EC_POINT_set_affine_coordinates failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
- } else if (!EC_POINT_set_compressed_coordinates_GFp(ecdh->ec->group,
- pub, x, 0,
- ecdh->ec->bnctx)) {
+ } else if (!EC_POINT_set_compressed_coordinates(ecdh->ec->group,
+ pub, x, 0,
+ ecdh->ec->bnctx)) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EC_POINT_set_compressed_coordinates_GFp failed: %s",
+ "OpenSSL: EC_POINT_set_compressed_coordinates failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
@@ -2270,6 +2914,7 @@
wpabuf_free(secret);
secret = NULL;
goto done;
+#endif /* OpenSSL version >= 3.0 */
}
@@ -2370,9 +3015,9 @@
if (!x || !y || !point)
goto fail;
- if (!EC_POINT_set_affine_coordinates_GFp(ec_group, point, x, y, ctx)) {
+ if (!EC_POINT_set_affine_coordinates(ec_group, point, x, y, ctx)) {
wpa_printf(MSG_ERROR,
- "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s",
+ "OpenSSL: EC_POINT_set_affine_coordinates failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto fail;
}
@@ -2777,12 +3422,53 @@
}
-struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
- const u8 *data, size_t len)
+static int openssl_evp_pkey_ec_prime_len(struct crypto_ec_key *key)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ char gname[50];
+ int nid;
+ EC_GROUP *group;
+ BIGNUM *prime = NULL;
+ int prime_len = -1;
+
+ if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname),
+ NULL) != 1)
+ return -1;
+ nid = OBJ_txt2nid(gname);
+ group = EC_GROUP_new_by_curve_name(nid);
+ prime = BN_new();
+ if (!group || !prime)
+ return -1;
+ if (EC_GROUP_get_curve(group, prime, NULL, NULL, NULL) == 1)
+ prime_len = BN_num_bytes(prime);
+ EC_GROUP_free(group);
+ BN_free(prime);
+ return prime_len;
+#else
const EC_GROUP *group;
const EC_KEY *eckey;
BIGNUM *prime = NULL;
+ int prime_len = -1;
+
+ eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ if (!eckey)
+ goto fail;
+ group = EC_KEY_get0_group(eckey);
+ prime = BN_new();
+ if (!prime || !group ||
+ !EC_GROUP_get_curve(group, prime, NULL, NULL, NULL))
+ goto fail;
+ prime_len = BN_num_bytes(prime);
+fail:
+ BN_free(prime);
+ return prime_len;
+#endif
+}
+
+
+struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key,
+ const u8 *data, size_t len)
+{
ECDSA_SIG *sig = NULL;
const BIGNUM *r, *s;
u8 *r_buf, *s_buf;
@@ -2790,20 +3476,15 @@
const unsigned char *p;
int prime_len;
+ prime_len = openssl_evp_pkey_ec_prime_len(key);
+ if (prime_len < 0)
+ return NULL;
+
buf = crypto_ec_key_sign(key, data, len);
if (!buf)
return NULL;
/* Extract (r,s) from Ecdsa-Sig-Value */
- eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
- if (!eckey)
- goto fail;
- group = EC_KEY_get0_group(eckey);
- prime = BN_new();
- if (!prime || !group ||
- !EC_GROUP_get_curve_GFp(group, prime, NULL, NULL, NULL))
- goto fail;
- prime_len = BN_num_bytes(prime);
p = wpabuf_head(buf);
sig = d2i_ECDSA_SIG(NULL, &p, wpabuf_len(buf));
@@ -2822,7 +3503,6 @@
goto fail;
out:
- BN_free(prime);
ECDSA_SIG_free(sig);
return buf;
fail:
@@ -2893,6 +3573,15 @@
int crypto_ec_key_group(struct crypto_ec_key *key)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ char gname[50];
+ int nid;
+
+ if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname),
+ NULL) != 1)
+ return -1;
+ nid = OBJ_txt2nid(gname);
+#else
const EC_KEY *eckey;
const EC_GROUP *group;
int nid;
@@ -2904,6 +3593,7 @@
if (!group)
return -1;
nid = EC_GROUP_get_curve_name(group);
+#endif
switch (nid) {
case NID_X9_62_prime256v1:
return 19;
@@ -2932,8 +3622,13 @@
int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (EVP_PKEY_eq((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1)
+ return -1;
+#else
if (EVP_PKEY_cmp((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1)
return -1;
+#endif
return 0;
}
@@ -3242,3 +3937,138 @@
}
#endif /* CONFIG_ECC */
+
+
+static EVP_PKEY * crypto_rsa_key_read_public(FILE *f)
+{
+ EVP_PKEY *pkey;
+ X509 *x509;
+
+ pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
+ if (pkey)
+ return pkey;
+
+ rewind(f);
+ x509 = PEM_read_X509(f, NULL, NULL, NULL);
+ if (!x509)
+ return NULL;
+
+ pkey = X509_get_pubkey(x509);
+ X509_free(x509);
+
+ if (!pkey)
+ return NULL;
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
+ EVP_PKEY_free(pkey);
+ return NULL;
+ }
+
+ return pkey;
+}
+
+
+struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key)
+{
+ FILE *f;
+ EVP_PKEY *pkey;
+
+ f = fopen(file, "r");
+ if (!f)
+ return NULL;
+ if (private_key)
+ pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL);
+ else
+ pkey = crypto_rsa_key_read_public(f);
+ fclose(f);
+ return (struct crypto_rsa_key *) pkey;
+}
+
+
+#ifndef OPENSSL_NO_SHA256
+
+struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in)
+{
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+ EVP_PKEY_CTX *pkctx;
+ struct wpabuf *res = NULL;
+ size_t outlen;
+
+ pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (!pkctx)
+ goto fail;
+
+ if (EVP_PKEY_encrypt_init(pkctx) != 1 ||
+ EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 ||
+ EVP_PKEY_encrypt(pkctx, NULL, &outlen, wpabuf_head(in),
+ wpabuf_len(in)) != 1 ||
+ !(res = wpabuf_alloc(outlen)) ||
+ EVP_PKEY_encrypt(pkctx, wpabuf_put(res, 0), &outlen,
+ wpabuf_head(in), wpabuf_len(in)) != 1) {
+ wpabuf_free(res);
+ res = NULL;
+ goto fail;
+ }
+ wpabuf_put(res, outlen);
+
+fail:
+ EVP_PKEY_CTX_free(pkctx);
+ return res;
+#else
+ wpa_printf(MSG_ERROR, "%s() not supported", __func__);
+ return NULL;
+#endif
+}
+
+
+struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in)
+{
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+ EVP_PKEY_CTX *pkctx;
+ struct wpabuf *res = NULL;
+ size_t outlen;
+
+ pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (!pkctx)
+ goto fail;
+
+ if (EVP_PKEY_decrypt_init(pkctx) != 1 ||
+ EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 ||
+ EVP_PKEY_decrypt(pkctx, NULL, &outlen, wpabuf_head(in),
+ wpabuf_len(in)) != 1 ||
+ !(res = wpabuf_alloc(outlen)) ||
+ EVP_PKEY_decrypt(pkctx, wpabuf_put(res, 0), &outlen,
+ wpabuf_head(in), wpabuf_len(in)) != 1) {
+ wpabuf_free(res);
+ res = NULL;
+ goto fail;
+ }
+ wpabuf_put(res, outlen);
+
+fail:
+ EVP_PKEY_CTX_free(pkctx);
+ return res;
+#else
+ wpa_printf(MSG_ERROR, "%s() not supported", __func__);
+ return NULL;
+#endif
+}
+
+#endif /* OPENSSL_NO_SHA256 */
+
+
+void crypto_rsa_key_free(struct crypto_rsa_key *key)
+{
+ EVP_PKEY_free((EVP_PKEY *) key);
+}
+
+
+void crypto_unload(void)
+{
+ openssl_unload_legacy_provider();
+}
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 00ecf61..f47beeb 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -26,6 +26,8 @@
#include <wolfssl/wolfcrypt/dh.h>
#include <wolfssl/wolfcrypt/cmac.h>
#include <wolfssl/wolfcrypt/ecc.h>
+#include <wolfssl/wolfcrypt/asn_public.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/openssl/bn.h>
@@ -85,6 +87,7 @@
wc_ShaUpdate(&sha, addr[i], len[i]);
wc_ShaFinal(&sha, mac);
+ wc_ShaFree(&sha);
return 0;
}
@@ -106,6 +109,7 @@
wc_Sha256Update(&sha256, addr[i], len[i]);
wc_Sha256Final(&sha256, mac);
+ wc_Sha256Free(&sha256);
return 0;
}
@@ -128,6 +132,7 @@
wc_Sha384Update(&sha384, addr[i], len[i]);
wc_Sha384Final(&sha384, mac);
+ wc_Sha384Free(&sha384);
return 0;
}
@@ -150,6 +155,7 @@
wc_Sha512Update(&sha512, addr[i], len[i]);
wc_Sha512Final(&sha512, mac);
+ wc_Sha512Free(&sha512);
return 0;
}
@@ -169,13 +175,16 @@
if (TEST_FAIL())
return -1;
- if (wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
+ if (wc_HmacInit(&hmac, NULL, INVALID_DEVID) != 0 ||
+ wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0)
return -1;
for (i = 0; i < num_elem; i++)
if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0)
return -1;
if (wc_HmacFinal(&hmac, mac) != 0)
return -1;
+ wc_HmacFree(&hmac);
+
return 0;
}
@@ -274,9 +283,18 @@
int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen)
{
- if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid,
- ssid_len, iterations, buflen, WC_SHA) != 0)
+ int ret;
+
+ ret = wc_PBKDF2(buf, (const byte *) passphrase, os_strlen(passphrase),
+ ssid, ssid_len, iterations, buflen, WC_SHA);
+ if (ret != 0) {
+ if (ret == HMAC_MIN_KEYLEN_E) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Password is too short. Make sure your password is at least %d characters long. This is a requirement for FIPS builds.",
+ HMAC_FIPS_MIN_KEY);
+ }
return -1;
+ }
return 0;
}
@@ -409,8 +427,11 @@
}
+#ifndef CONFIG_FIPS
+#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
{
+#ifdef HAVE_AES_KEYWRAP
int ret;
if (TEST_FAIL())
@@ -419,12 +440,16 @@
ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8,
NULL);
return ret != (n + 1) * 8 ? -1 : 0;
+#else /* HAVE_AES_KEYWRAP */
+ return -1;
+#endif /* HAVE_AES_KEYWRAP */
}
int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
u8 *plain)
{
+#ifdef HAVE_AES_KEYWRAP
int ret;
if (TEST_FAIL())
@@ -433,7 +458,12 @@
ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8,
NULL);
return ret != n * 8 ? -1 : 0;
+#else /* HAVE_AES_KEYWRAP */
+ return -1;
+#endif /* HAVE_AES_KEYWRAP */
}
+#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
+#endif /* CONFIG_FIPS */
#ifndef CONFIG_NO_RC4
@@ -670,6 +700,7 @@
!= 0)
goto done;
+ priv_sz = pub_sz = RFC3526_LEN;
if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &priv_sz,
wpabuf_mhead(pubkey), &pub_sz) != 0)
goto done;
@@ -803,6 +834,7 @@
if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0)
goto done;
+ priv_sz = pub_sz = prime_len;
if (wc_DhGenerateKeyPair(dh, &rng, privkey, &priv_sz, pubkey, &pub_sz)
!= 0)
goto done;
@@ -919,7 +951,8 @@
goto done;
}
- if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
+ if (wc_HmacInit(&hash->hmac, NULL, INVALID_DEVID) != 0 ||
+ wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0)
goto done;
ret = hash;
@@ -1634,35 +1667,21 @@
crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
const struct crypto_bignum *x)
{
- mp_int *y2 = NULL;
- mp_int t;
- int calced = 0;
+ mp_int *y2;
if (TEST_FAIL())
return NULL;
- if (mp_init(&t) != MP_OKAY)
- return NULL;
-
+ /* y^2 = x^3 + ax + b = (x^2 + a)x + b */
y2 = (mp_int *) crypto_bignum_init();
- if (!y2)
- goto done;
-
- if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+ if (!y2 ||
+ mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 ||
+ mp_addmod(y2, &e->a, &e->prime, y2) != 0 ||
mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 ||
- mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 ||
- mp_addmod(y2, &t, &e->prime, y2) != 0 ||
- mp_addmod(y2, &e->b, &e->prime, y2) != 0)
- goto done;
-
- calced = 1;
-done:
- if (!calced) {
- if (y2) {
- mp_clear(y2);
- os_free(y2);
- }
- mp_clear(&t);
+ mp_addmod(y2, &e->b, &e->prime, y2) != 0) {
+ mp_clear(y2);
+ os_free(y2);
+ y2 = NULL;
}
return (struct crypto_bignum *) y2;
@@ -1694,33 +1713,37 @@
struct crypto_ecdh {
struct crypto_ec *ec;
+ WC_RNG rng;
};
struct crypto_ecdh * crypto_ecdh_init(int group)
{
struct crypto_ecdh *ecdh = NULL;
- WC_RNG rng;
int ret;
- if (wc_InitRng(&rng) != 0)
- goto fail;
-
ecdh = os_zalloc(sizeof(*ecdh));
if (!ecdh)
goto fail;
+ if (wc_InitRng(&ecdh->rng) != 0)
+ goto fail;
+
ecdh->ec = crypto_ec_init(group);
if (!ecdh->ec)
goto fail;
- ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key,
- ecdh->ec->key.dp->id);
+ ret = wc_ecc_make_key_ex(&ecdh->rng, ecdh->ec->key.dp->size,
+ &ecdh->ec->key, ecdh->ec->key.dp->id);
if (ret < 0)
goto fail;
-done:
- wc_FreeRng(&rng);
+#if defined(ECC_TIMING_RESISTANT) && !defined(CONFIG_FIPS)
+ ret = wc_ecc_set_rng(&ecdh->ec->key, &ecdh->rng);
+ if (ret < 0)
+ goto fail;
+#endif /* ECC_TIMING_RESISTANT && !CONFIG_FIPS */
+done:
return ecdh;
fail:
crypto_ecdh_deinit(ecdh);
@@ -1733,6 +1756,7 @@
{
if (ecdh) {
crypto_ec_deinit(ecdh->ec);
+ wc_FreeRng(&ecdh->rng);
os_free(ecdh);
}
}
@@ -1822,4 +1846,266 @@
return crypto_ec_prime_len(ecdh->ec);
}
+
+struct crypto_ec_key {
+ ecc_key *eckey;
+ WC_RNG *rng; /* Needs to be initialized before use.
+ * *NOT* initialized in crypto_ec_key_init */
+};
+
+
+static struct crypto_ec_key * crypto_ec_key_init(void)
+{
+ struct crypto_ec_key *key;
+
+ key = os_zalloc(sizeof(struct crypto_ec_key));
+ if (key) {
+#ifdef CONFIG_FIPS
+ key->eckey = os_zalloc(sizeof(ecc_key));
+#else /* CONFIG_FIPS */
+ key->eckey = wc_ecc_key_new(NULL);
+#endif /* CONFIG_FIPS */
+ /* Omit key->rng initialization because it seeds itself and thus
+ * consumes entropy that may never be used. Lazy initialize when
+ * necessary. */
+ if (!key->eckey) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: crypto_ec_key_init() failed");
+ crypto_ec_key_deinit(key);
+ key = NULL;
+ }
+#ifdef CONFIG_FIPS
+ else if (wc_ecc_init_ex(key->eckey, NULL, INVALID_DEVID) != 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_init_ex failed");
+ crypto_ec_key_deinit(key);
+ key = NULL;
+ }
+#endif /* CONFIG_FIPS */
+ }
+ return key;
+}
+
+
+void crypto_ec_key_deinit(struct crypto_ec_key *key)
+{
+ if (key) {
+#ifdef CONFIG_FIPS
+ os_free(key->rng);
+ os_free(key->eckey);
+#else /* CONFIG_FIPS */
+ wc_rng_free(key->rng);
+ wc_ecc_key_free(key->eckey);
+#endif /* CONFIG_FIPS */
+ os_free(key);
+ }
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
+{
+ struct crypto_ec_key *ret;
+ word32 idx = 0;
+
+ ret = crypto_ec_key_init();
+ if (!ret) {
+ wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+ goto fail;
+ }
+
+ if (wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len) !=
+ 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPrivateKeyDecode failed");
+ goto fail;
+ }
+
+ return ret;
+fail:
+ if (ret)
+ crypto_ec_key_deinit(ret);
+ return NULL;
+}
+
+
+int crypto_ec_key_group(struct crypto_ec_key *key)
+{
+
+ if (!key || !key->eckey || !key->eckey->dp) {
+ wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+ __func__);
+ return -1;
+ }
+
+ switch (key->eckey->dp->id) {
+ case ECC_SECP256R1:
+ return 19;
+ case ECC_SECP384R1:
+ return 20;
+ case ECC_SECP521R1:
+ return 21;
+ case ECC_BRAINPOOLP256R1:
+ return 28;
+ case ECC_BRAINPOOLP384R1:
+ return 29;
+ case ECC_BRAINPOOLP512R1:
+ return 30;
+ }
+
+ wpa_printf(MSG_ERROR, "wolfSSL: Unsupported curve (id=%d) in EC key",
+ key->eckey->dp->id);
+ return -1;
+}
+
+
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
+{
+ byte *der = NULL;
+ int der_len;
+ struct wpabuf *ret = NULL;
+
+ if (!key || !key->eckey) {
+ wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+ __func__);
+ goto fail;
+ }
+
+ der_len = wc_EccPublicKeyDerSize(key->eckey, 1);
+ if (der_len <= 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDerSize failed");
+ goto fail;
+ }
+
+ der = os_malloc(der_len);
+ if (!der)
+ goto fail;
+
+ der_len = wc_EccPublicKeyToDer(key->eckey, der, der_len, 1);
+ if (der_len <= 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyToDer failed");
+ goto fail;
+ }
+
+ ret = wpabuf_alloc_copy(der, der_len);
+ os_free(der);
+ return ret;
+
+fail:
+ os_free(der);
+ return NULL;
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
+{
+ word32 idx = 0;
+ struct crypto_ec_key *ret = NULL;
+
+ ret = crypto_ec_key_init();
+ if (!ret) {
+ wpa_printf(MSG_ERROR, "wolfSSL: crypto_ec_key_init failed");
+ goto fail;
+ }
+
+ if (wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len) != 0)
+ {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_EccPublicKeyDecode failed");
+ goto fail;
+ }
+
+ return ret;
+fail:
+ crypto_ec_key_deinit(ret);
+ return NULL;
+}
+
+
+struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
+ size_t len)
+{
+ byte *der = NULL;
+ int der_len;
+ word32 w32_der_len;
+ struct wpabuf *ret = NULL;
+
+ if (!key || !key->eckey || !data || len == 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+ __func__);
+ goto fail;
+ }
+
+ if (!key->rng) {
+ /* Lazy init key->rng */
+#ifdef CONFIG_FIPS
+ key->rng = os_zalloc(sizeof(WC_RNG));
+#else /* CONFIG_FIPS */
+ key->rng = wc_rng_new(NULL, 0, NULL);
+#endif /* CONFIG_FIPS */
+ if (!key->rng) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_rng_new failed");
+ goto fail;
+ }
+#ifdef CONFIG_FIPS
+ if (wc_InitRng(key->rng) != 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_InitRng failed");
+ goto fail;
+ }
+#endif /* CONFIG_FIPS */
+ }
+
+ der_len = wc_ecc_sig_size(key->eckey);
+ if (der_len <= 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sig_size failed");
+ goto fail;
+ }
+
+ der = os_malloc(der_len);
+ if (!der)
+ goto fail;
+
+ w32_der_len = (word32) der_len;
+ if (wc_ecc_sign_hash(data, len, der, &w32_der_len, key->rng, key->eckey)
+ != 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_sign_hash failed");
+ goto fail;
+ }
+
+ ret = wpabuf_alloc_copy(der, der_len);
+ os_free(der);
+ if (!ret)
+ wpa_printf(MSG_ERROR, "wolfSSL: wpabuf_alloc_copy failed");
+ return ret;
+fail:
+ os_free(der);
+ return NULL;
+}
+
+
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+ size_t len, const u8 *sig, size_t sig_len)
+{
+ int res = 0;
+
+ if (!key || !key->eckey || !data || len == 0 || !sig || sig_len == 0) {
+ wpa_printf(MSG_ERROR, "wolfSSL: %s: invalid input parameters",
+ __func__);
+ return -1;
+ }
+
+ if (wc_ecc_verify_hash(sig, sig_len, data, len, &res, key->eckey) != 0)
+ {
+ wpa_printf(MSG_ERROR, "wolfSSL: wc_ecc_verify_hash failed");
+ return -1;
+ }
+
+ if (res != 1)
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: crypto_ec_key_verify_signature failed");
+
+ return res;
+}
+
#endif /* CONFIG_ECC */
+
+
+void crypto_unload(void)
+{
+}
diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c
index 8effe2f..d2bdc95 100644
--- a/src/crypto/sha1-pbkdf2.c
+++ b/src/crypto/sha1-pbkdf2.c
@@ -50,6 +50,8 @@
for (j = 0; j < SHA1_MAC_LEN; j++)
digest[j] ^= tmp2[j];
}
+ forced_memzero(tmp, SHA1_MAC_LEN);
+ forced_memzero(tmp2, SHA1_MAC_LEN);
return 0;
}
@@ -87,6 +89,7 @@
pos += plen;
left -= plen;
}
+ forced_memzero(digest, SHA1_MAC_LEN);
return 0;
}
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 09fb73b..7a2ee32 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -22,7 +22,8 @@
TLS_CERT_CHAIN_SUCCESS,
TLS_CERT_CHAIN_FAILURE,
TLS_PEER_CERTIFICATE,
- TLS_ALERT
+ TLS_ALERT,
+ TLS_UNSAFE_RENEGOTIATION_DISABLED,
};
/*
@@ -112,6 +113,7 @@
#define TLS_CONN_ENABLE_TLSv1_1 BIT(15)
#define TLS_CONN_ENABLE_TLSv1_2 BIT(16)
#define TLS_CONN_TEAP_ANON_DH BIT(17)
+#define TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION BIT(18)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -148,8 +150,6 @@
* @private_key_passwd: Passphrase for decrypted private key, %NULL if no
* passphrase is used.
* @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
- * @dh_blob: dh_file as inlined data or %NULL if not used
- * @dh_blob_len: dh_blob length
* @engine: 1 = use engine (e.g., a smartcard) for private key operations
* (this is OpenSSL specific for now)
* @engine_id: engine id string (this is OpenSSL specific for now)
@@ -198,8 +198,6 @@
const char *private_key_passwd;
const char *private_key_passwd2;
const char *dh_file;
- const u8 *dh_blob;
- size_t dh_blob_len;
/* OpenSSL specific variables */
int engine;
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index daa01d9..e3f5b5a 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -1766,6 +1766,7 @@
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
+ wpabuf_free(data);
}
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 8095b43..f3e05ce 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -281,13 +281,6 @@
return -1;
}
- if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
- params->dh_blob_len)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
- tlsv1_cred_free(cred);
- return -1;
- }
-
if (tlsv1_client_set_cred(conn->client, cred) < 0) {
tlsv1_cred_free(cred);
return -1;
@@ -342,8 +335,7 @@
return -1;
}
- if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
- params->dh_blob_len)) {
+ if (tlsv1_set_dhparams(cred, params->dh_file, NULL, 0)) {
wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
return -1;
}
@@ -791,6 +783,7 @@
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
+ wpabuf_free(data);
}
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 6d6fb0c..87f45f8 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -212,6 +212,7 @@
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
+ wpabuf_free(data);
}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index ba3ef80..a1b5166 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -7,6 +7,9 @@
*/
#include "includes.h"
+#ifdef CONFIG_TESTING_OPTIONS
+#include <fcntl.h>
+#endif /* CONFIG_TESTING_OPTIONS */
#ifndef CONFIG_SMARTCARD
#ifndef OPENSSL_NO_ENGINE
@@ -24,14 +27,21 @@
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif /* OPENSSL_NO_ENGINE */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/core_names.h>
+#include <openssl/decoder.h>
+#include <openssl/param_build.h>
+#else /* OpenSSL version >= 3.0 */
#ifndef OPENSSL_NO_DSA
#include <openssl/dsa.h>
#endif
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
+#endif /* OpenSSL version >= 3.0 */
#include "common.h"
+#include "utils/list.h"
#include "crypto.h"
#include "sha1.h"
#include "sha256.h"
@@ -65,9 +75,7 @@
#endif /* OPENSSL_NO_TLSEXT */
#endif /* SSL_set_tlsext_status_type */
-#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \
+#if OPENSSL_VERSION_NUMBER < 0x10100000L && \
!defined(BORINGSSL_API_VERSION)
/*
* SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
@@ -111,17 +119,7 @@
#endif
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-#ifdef CONFIG_SUITEB
-static int RSA_bits(const RSA *r)
-{
- return BN_num_bits(r->n);
-}
-#endif /* CONFIG_SUITEB */
-
-
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
{
return ASN1_STRING_data((ASN1_STRING *) x);
@@ -234,12 +232,18 @@
static int tls_openssl_ref_count = 0;
static int tls_ex_idx_session = -1;
+struct tls_session_data {
+ struct dl_list list;
+ struct wpabuf *buf;
+};
+
struct tls_context {
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
void *cb_ctx;
int cert_in_cb;
char *ocsp_stapling_response;
+ struct dl_list sessions; /* struct tls_session_data */
};
static struct tls_context *tls_global = NULL;
@@ -307,6 +311,7 @@
struct tls_context *context = os_zalloc(sizeof(*context));
if (context == NULL)
return NULL;
+ dl_list_init(&context->sessions);
if (conf) {
context->event_cb = conf->event_cb;
context->cb_ctx = conf->cb_ctx;
@@ -958,21 +963,53 @@
#endif /* OPENSSL_NO_ENGINE */
+static struct tls_session_data * get_session_data(struct tls_context *context,
+ const struct wpabuf *buf)
+{
+ struct tls_session_data *data;
+
+ dl_list_for_each(data, &context->sessions, struct tls_session_data,
+ list) {
+ if (data->buf == buf)
+ return data;
+ }
+
+ return NULL;
+}
+
+
static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
{
struct wpabuf *buf;
+ struct tls_context *context;
+ struct tls_session_data *found;
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Remove session %p (tls_ex_idx_session=%d)", sess,
+ tls_ex_idx_session);
if (tls_ex_idx_session < 0)
return;
buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
if (!buf)
return;
+
+ context = SSL_CTX_get_app_data(ctx);
+ SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+ found = get_session_data(context, buf);
+ if (!found) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Do not free application session data %p (sess %p)",
+ buf, sess);
+ return;
+ }
+
+ dl_list_del(&found->list);
+ os_free(found);
wpa_printf(MSG_DEBUG,
"OpenSSL: Free application session data %p (sess %p)",
buf, sess);
wpabuf_free(buf);
-
- SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
}
@@ -1019,9 +1056,7 @@
}
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_load_error_strings();
SSL_library_init();
#ifndef OPENSSL_NO_SHA256
@@ -1098,8 +1133,19 @@
SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ /* One session ticket is sufficient for EAP-TLS */
+ SSL_CTX_set_num_tickets(ssl, 1);
+#endif
} else {
SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL)
+ SSL_CTX_set_num_tickets(ssl, 0);
+#endif
}
if (tls_ex_idx_session < 0) {
@@ -1148,18 +1194,30 @@
struct tls_data *data = ssl_ctx;
SSL_CTX *ssl = data->ssl;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
+ struct tls_session_data *sess_data;
+
+ if (data->tls_session_lifetime > 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions");
+ SSL_CTX_flush_sessions(ssl, 0);
+ wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions - done");
+ }
+ while ((sess_data = dl_list_first(&context->sessions,
+ struct tls_session_data, list))) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Freeing not-flushed session data %p",
+ sess_data->buf);
+ wpabuf_free(sess_data->buf);
+ dl_list_del(&sess_data->list);
+ os_free(sess_data);
+ }
if (context != tls_global)
os_free(context);
- if (data->tls_session_lifetime > 0)
- SSL_CTX_flush_sessions(ssl, 0);
os_free(data->ca_cert);
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
if (tls_openssl_ref_count == 0) {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
@@ -1561,6 +1619,63 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+/*
+ * By setting the environment variable SSLKEYLOGFILE to a filename keying
+ * material will be exported that you may use with Wireshark to decode any
+ * TLS flows. Please see the following for more details:
+ *
+ * https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption
+ *
+ * Example logging sessions are (you should delete the file on each run):
+ *
+ * rm -f /tmp/sslkey.log
+ * env SSLKEYLOGFILE=/tmp/sslkey.log hostapd ...
+ *
+ * rm -f /tmp/sslkey.log
+ * env SSLKEYLOGFILE=/tmp/sslkey.log wpa_supplicant ...
+ *
+ * rm -f /tmp/sslkey.log
+ * env SSLKEYLOGFILE=/tmp/sslkey.log eapol_test ...
+ */
+static void tls_keylog_cb(const SSL *ssl, const char *line)
+{
+ int fd;
+ const char *filename;
+ struct iovec iov[2];
+
+ filename = getenv("SSLKEYLOGFILE");
+ if (!filename)
+ return;
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ wpa_printf(MSG_ERROR,
+ "OpenSSL: Failed to open keylog file %s: %s",
+ filename, strerror(errno));
+ return;
+ }
+
+ /* Assume less than _POSIX_PIPE_BUF (512) where writes are guaranteed
+ * to be atomic for O_APPEND. */
+ iov[0].iov_base = (void *) line;
+ iov[0].iov_len = os_strlen(line);
+ iov[1].iov_base = "\n";
+ iov[1].iov_len = 1;
+
+ if (writev(fd, iov, ARRAY_SIZE(iov)) < 01) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Failed to write to keylog file %s: %s",
+ filename, strerror(errno));
+ }
+
+ close(fd);
+}
+#endif
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
struct tls_data *data = ssl_ctx;
@@ -1618,6 +1733,14 @@
SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
#endif
+#ifdef CONFIG_TESTING_OPTIONS
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+ /* Set the keylog file if the admin requested it. */
+ if (getenv("SSLKEYLOGFILE"))
+ SSL_CTX_set_keylog_callback(conn->ssl_ctx, tls_keylog_cb);
+#endif
+#endif /* CONFIG_TESTING_OPTIONS */
+
conn->ssl_in = BIO_new(BIO_s_mem());
if (!conn->ssl_in) {
tls_show_errors(MSG_INFO, __func__,
@@ -2560,16 +2683,11 @@
#ifdef CONFIG_SUITEB
if (conn->flags & TLS_CONN_SUITEB) {
EVP_PKEY *pk;
- RSA *rsa;
int len = -1;
pk = X509_get_pubkey(err_cert);
if (pk) {
- rsa = EVP_PKEY_get1_RSA(pk);
- if (rsa) {
- len = RSA_bits(rsa);
- RSA_free(rsa);
- }
+ len = EVP_PKEY_bits(pk);
EVP_PKEY_free(pk);
}
@@ -2960,7 +3078,6 @@
#ifdef CONFIG_SUITEB
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
static int suiteb_cert_cb(SSL *ssl, void *arg)
{
struct tls_connection *conn = arg;
@@ -2987,7 +3104,6 @@
conn->server_dh_prime_len);
return 0;
}
-#endif /* OPENSSL_VERSION_NUMBER */
#endif /* CONFIG_SUITEB */
@@ -3003,6 +3119,11 @@
SSL_clear_options(ssl, SSL_OP_NO_TICKET);
#endif /* SSL_OP_NO_TICKET */
+#ifdef SSL_OP_LEGACY_SERVER_CONNECT
+ if (flags & TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION)
+ SSL_set_options(ssl, SSL_OP_LEGACY_SERVER_CONNECT);
+#endif /* SSL_OP_LEGACY_SERVER_CONNECT */
+
#ifdef SSL_OP_NO_TLSv1
if (flags & TLS_CONN_DISABLE_TLSv1_0)
SSL_set_options(ssl, SSL_OP_NO_TLSv1);
@@ -3082,7 +3203,6 @@
/* Start with defaults from BoringSSL */
SSL_set_verify_algorithm_prefs(conn->ssl, NULL, 0);
#endif /* OPENSSL_IS_BORINGSSL */
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L
if (flags & TLS_CONN_SUITEB_NO_ECDH) {
const char *ciphers = "DHE-RSA-AES256-GCM-SHA384";
@@ -3098,7 +3218,9 @@
return -1;
}
} else if (flags & TLS_CONN_SUITEB) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
EC_KEY *ecdh;
+#endif
const char *ciphers =
"ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384";
int nid[1] = { NID_secp384r1 };
@@ -3115,6 +3237,14 @@
return -1;
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (SSL_set1_groups(ssl, nid, 1) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set Suite B groups");
+ return -1;
+ }
+
+#else
if (SSL_set1_curves(ssl, nid, 1) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set Suite B curves");
@@ -3129,6 +3259,7 @@
return -1;
}
EC_KEY_free(ecdh);
+#endif
}
if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
#ifdef OPENSSL_IS_BORINGSSL
@@ -3153,13 +3284,6 @@
SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
SSL_set_cert_cb(ssl, suiteb_cert_cb, conn);
}
-#else /* OPENSSL_VERSION_NUMBER < 0x10002000L */
- if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) {
- wpa_printf(MSG_ERROR,
- "OpenSSL: Suite B RSA case not supported with this OpenSSL version");
- return -1;
- }
-#endif /* OPENSSL_VERSION_NUMBER */
#ifdef OPENSSL_IS_BORINGSSL
if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
@@ -3293,14 +3417,14 @@
return 0;
#ifdef PKCS12_FUNCS
-#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
+#ifdef LIBRESSL_VERSION_NUMBER
/*
* Clear previously set extra chain certificates, if any, from PKCS#12
- * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
+ * processing in tls_parse_pkcs12() to allow LibreSSL to build a new
* chain properly.
*/
SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
-#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
+#endif /* LIBRESSL_VERSION_NUMBER */
#endif /* PKCS12_FUNCS */
if (client_cert_blob &&
@@ -3493,7 +3617,7 @@
}
if (certs) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
+#ifndef LIBRESSL_VERSION_NUMBER
if (ssl)
SSL_clear_chain_certs(ssl);
else
@@ -3542,7 +3666,7 @@
* the extra certificates not to be required.
*/
res = 0;
-#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
+#else /* LIBRESSL_VERSION_NUMBER */
SSL_CTX_clear_extra_chain_certs(data->ssl);
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
@@ -3561,7 +3685,7 @@
}
}
sk_X509_pop_free(certs, X509_free);
-#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
+#endif /* LIBRSESSL_VERSION_NUMBER */
}
PKCS12_free(p12);
@@ -3862,6 +3986,7 @@
}
#endif /* OPENSSL_NO_EC */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
(u8 *) private_key_blob,
private_key_blob_len) == 1) {
@@ -3870,6 +3995,7 @@
ok = 1;
break;
}
+#endif
bio = BIO_new_mem_buf((u8 *) private_key_blob,
private_key_blob_len);
@@ -3977,79 +4103,44 @@
}
-static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
-{
-#ifdef OPENSSL_NO_DH
- if (dh_file == NULL)
- return 0;
- wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
- "dh_file specified");
- return -1;
-#else /* OPENSSL_NO_DH */
- DH *dh;
- BIO *bio;
-
- /* TODO: add support for dh_blob */
- if (dh_file == NULL)
- return 0;
- if (conn == NULL)
- return -1;
-
- bio = BIO_new_file(dh_file, "r");
- if (bio == NULL) {
- wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
- dh_file, ERR_error_string(ERR_get_error(), NULL));
- return -1;
- }
- dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
- BIO_free(bio);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#ifndef OPENSSL_NO_DH
#ifndef OPENSSL_NO_DSA
- while (dh == NULL) {
- DSA *dsa;
- wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
- " trying to parse as DSA params", dh_file,
- ERR_error_string(ERR_get_error(), NULL));
- bio = BIO_new_file(dh_file, "r");
- if (bio == NULL)
- break;
- dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
- BIO_free(bio);
- if (!dsa) {
- wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
- "'%s': %s", dh_file,
- ERR_error_string(ERR_get_error(), NULL));
- break;
- }
+/* This is needed to replace the deprecated DSA_dup_DH() function */
+static EVP_PKEY * openssl_dsa_to_dh(EVP_PKEY *dsa)
+{
+ OSSL_PARAM_BLD *bld = NULL;
+ OSSL_PARAM *params = NULL;
+ BIGNUM *p = NULL, *q = NULL, *g = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *pkey = NULL;
- wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
- dh = DSA_dup_DH(dsa);
- DSA_free(dsa);
- if (dh == NULL) {
- wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
- "params into DH params");
- break;
- }
- break;
- }
-#endif /* !OPENSSL_NO_DSA */
- if (dh == NULL) {
- wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
- "'%s'", dh_file);
- return -1;
- }
+ if (!EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_P, &p) ||
+ !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_Q, &q) ||
+ !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_G, &g) ||
+ !(bld = OSSL_PARAM_BLD_new()) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) ||
+ !(params = OSSL_PARAM_BLD_to_param(bld)) ||
+ !(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL)) ||
+ EVP_PKEY_fromdata_init(ctx) != 1 ||
+ EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEY_PARAMETERS,
+ params) != 1)
+ wpa_printf(MSG_INFO,
+ "TLS: Failed to convert DSA parameters to DH parameters");
- if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
- wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
- "%s", dh_file,
- ERR_error_string(ERR_get_error(), NULL));
- DH_free(dh);
- return -1;
- }
- DH_free(dh);
- return 0;
-#endif /* OPENSSL_NO_DH */
+ EVP_PKEY_CTX_free(ctx);
+ OSSL_PARAM_free(params);
+ OSSL_PARAM_BLD_free(bld);
+ BN_free(p);
+ BN_free(q);
+ BN_free(g);
+ return pkey;
}
-
+#endif /* !OPENSSL_NO_DSA */
+#endif /* OPENSSL_NO_DH */
+#endif /* OpenSSL version >= 3.0 */
static int tls_global_dh(struct tls_data *data, const char *dh_file)
{
@@ -4060,15 +4151,88 @@
"dh_file specified");
return -1;
#else /* OPENSSL_NO_DH */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ SSL_CTX *ssl_ctx = data->ssl;
+ BIO *bio;
+ OSSL_DECODER_CTX *ctx = NULL;
+ EVP_PKEY *pkey = NULL, *tmpkey = NULL;
+ bool dsa = false;
+
+ if (!ssl_ctx)
+ return -1;
+ if (!dh_file) {
+ SSL_CTX_set_dh_auto(ssl_ctx, 1);
+ return 0;
+ }
+
+ bio = BIO_new_file(dh_file, "r");
+ if (!bio) {
+ wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
+ dh_file, ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ ctx = OSSL_DECODER_CTX_new_for_pkey(
+ &tmpkey, "PEM", NULL, NULL,
+ OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, NULL, NULL);
+ if (!ctx ||
+ OSSL_DECODER_from_bio(ctx, bio) != 1) {
+ wpa_printf(MSG_INFO,
+ "TLS: Failed to decode domain parameters from '%s': %s",
+ dh_file, ERR_error_string(ERR_get_error(), NULL));
+ BIO_free(bio);
+ return -1;
+ }
+ BIO_free(bio);
+
+ if (!tmpkey) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load domain parameters");
+ return -1;
+ }
+
+#ifndef OPENSSL_NO_DSA
+ if (EVP_PKEY_is_a(tmpkey, "DSA")) {
+ pkey = openssl_dsa_to_dh(tmpkey);
+ EVP_PKEY_free(tmpkey);
+ if (!pkey)
+ return -1;
+ dsa = true;
+ }
+#endif /* !OPENSSL_NO_DSA */
+ if (!dsa) {
+ if (EVP_PKEY_is_a(tmpkey, "DH") ||
+ EVP_PKEY_is_a(tmpkey, "DHX")) {
+ } else {
+ wpa_printf(MSG_INFO,
+ "TLS: No DH parameters found in %s",
+ dh_file);
+ EVP_PKEY_free(tmpkey);
+ return -1;
+ }
+ pkey = tmpkey;
+ tmpkey = NULL;
+ }
+
+ if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, pkey) != 1) {
+ wpa_printf(MSG_INFO,
+ "TLS: Failed to set DH params from '%s': %s",
+ dh_file, ERR_error_string(ERR_get_error(), NULL));
+ EVP_PKEY_free(pkey);
+ return -1;
+ }
+ return 0;
+#else /* OpenSSL version >= 3.0 */
SSL_CTX *ssl_ctx = data->ssl;
DH *dh;
BIO *bio;
- /* TODO: add support for dh_blob */
- if (dh_file == NULL)
- return 0;
- if (ssl_ctx == NULL)
+ if (!ssl_ctx)
return -1;
+ if (!dh_file) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
+ SSL_CTX_set_dh_auto(ssl_ctx, 1);
+#endif
+ return 0;
+ }
bio = BIO_new_file(dh_file, "r");
if (bio == NULL) {
@@ -4122,6 +4286,7 @@
}
DH_free(dh);
return 0;
+#endif /* OpenSSL version >= 3.0 */
#endif /* OPENSSL_NO_DH */
}
@@ -4152,9 +4317,7 @@
#ifdef OPENSSL_NEED_EAP_FAST_PRF
static int openssl_get_keyblock_size(SSL *ssl)
{
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
const EVP_CIPHER *c;
const EVP_MD *h;
int md_size;
@@ -4322,6 +4485,7 @@
static struct wpabuf *
openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
{
+ struct tls_context *context = conn->context;
int res;
struct wpabuf *out_data;
@@ -4351,7 +4515,19 @@
wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
"write");
else {
+ unsigned long error = ERR_peek_last_error();
+
tls_show_errors(MSG_INFO, __func__, "SSL_connect");
+
+ if (context->event_cb &&
+ ERR_GET_LIB(error) == ERR_LIB_SSL &&
+ ERR_GET_REASON(error) ==
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED) {
+ context->event_cb(
+ context->cb_ctx,
+ TLS_UNSAFE_RENEGOTIATION_DISABLED,
+ NULL);
+ }
conn->failed++;
if (!conn->server && !conn->client_hello_generated) {
/* The server would not understand TLS Alert
@@ -4374,8 +4550,6 @@
if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
conn->server_dh_prime_len < 3072) {
- struct tls_context *context = conn->context;
-
/*
* This should not be reached since earlier cert_cb should have
* terminated the handshake. Keep this check here for extra
@@ -4867,6 +5041,21 @@
len = SSL_get_tlsext_status_ocsp_resp(s, &p);
if (!p) {
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
+#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L
+ if (SSL_version(s) == TLS1_3_VERSION && SSL_session_reused(s)) {
+ /* TLS 1.3 sends the OCSP response with the server
+ * Certificate message. Since that Certificate message
+ * is not sent when resuming a session, there can be no
+ * new OCSP response. Allow this since the OCSP response
+ * was validated when checking the initial certificate
+ * exchange. */
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Allow no OCSP response when using TLS 1.3 and a resumed session");
+ return 1;
+ }
+#endif
+#endif
wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
}
@@ -5268,12 +5457,6 @@
return -1;
}
- if (tls_connection_dh(conn, params->dh_file)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
- params->dh_file);
- return -1;
- }
-
ciphers = params->openssl_ciphers;
#ifdef CONFIG_SUITEB
#ifdef OPENSSL_IS_BORINGSSL
@@ -5295,22 +5478,21 @@
if (!params->openssl_ecdh_curves) {
#ifndef OPENSSL_IS_BORINGSSL
#ifndef OPENSSL_NO_EC
-#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
- (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set ECDH curves to auto");
return -1;
}
-#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* < 1.1.0 */
#endif /* OPENSSL_NO_EC */
#endif /* OPENSSL_IS_BORINGSSL */
} else if (params->openssl_ecdh_curves[0]) {
-#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+#ifdef OPENSSL_IS_BORINGSSL
wpa_printf(MSG_INFO,
- "OpenSSL: ECDH configuration nnot supported");
+ "OpenSSL: ECDH configuration not supported");
return -1;
-#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#else /* !OPENSSL_IS_BORINGSSL */
#ifndef OPENSSL_NO_EC
if (SSL_set1_curves_list(conn->ssl,
params->openssl_ecdh_curves) != 1) {
@@ -5520,22 +5702,21 @@
if (!params->openssl_ecdh_curves) {
#ifndef OPENSSL_IS_BORINGSSL
#ifndef OPENSSL_NO_EC
-#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \
- (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) {
wpa_printf(MSG_INFO,
"OpenSSL: Failed to set ECDH curves to auto");
return -1;
}
-#endif /* >= 1.0.2 && < 1.1.0 */
+#endif /* < 1.1.0 */
#endif /* OPENSSL_NO_EC */
#endif /* OPENSSL_IS_BORINGSSL */
} else if (params->openssl_ecdh_curves[0]) {
-#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L)
+#ifdef OPENSSL_IS_BORINGSSL
wpa_printf(MSG_INFO,
- "OpenSSL: ECDH configuration nnot supported");
+ "OpenSSL: ECDH configuration not supported");
return -1;
-#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */
+#else /* !OPENSSL_IS_BORINGSSL */
#ifndef OPENSSL_NO_EC
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
@@ -5597,9 +5778,7 @@
struct tls_connection *conn = arg;
int ret;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
@@ -5710,6 +5889,7 @@
{
SSL_SESSION *sess;
struct wpabuf *old;
+ struct tls_session_data *sess_data = NULL;
if (tls_ex_idx_session < 0)
goto fail;
@@ -5718,20 +5898,35 @@
goto fail;
old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
if (old) {
- wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
- old);
- wpabuf_free(old);
+ struct tls_session_data *found;
+
+ found = get_session_data(conn->context, old);
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Replacing old success data %p (sess %p)%s",
+ old, sess, found ? "" : " (not freeing)");
+ if (found) {
+ dl_list_del(&found->list);
+ os_free(found);
+ wpabuf_free(old);
+ }
}
- if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+
+ sess_data = os_zalloc(sizeof(*sess_data));
+ if (!sess_data ||
+ SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
goto fail;
- wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
+ sess_data->buf = data;
+ dl_list_add(&conn->context->sessions, &sess_data->list);
+ wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p (sess %p)",
+ data, sess);
conn->success_data = 1;
return;
fail:
wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
wpabuf_free(data);
+ os_free(sess_data);
}
diff --git a/src/crypto/tls_openssl_ocsp.c b/src/crypto/tls_openssl_ocsp.c
index 97bf605..b570bea 100644
--- a/src/crypto/tls_openssl_ocsp.c
+++ b/src/crypto/tls_openssl_ocsp.c
@@ -644,13 +644,12 @@
buf);
ctx = X509_STORE_CTX_new();
- if (!ctx ||
- !X509_STORE_CTX_init(ctx, store, signer, untrusted) ||
- !X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER)) {
+ if (!ctx || !X509_STORE_CTX_init(ctx, store, signer, untrusted))
goto fail;
- }
+ X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER);
ret = X509_verify_cert(ctx);
chain = X509_STORE_CTX_get1_chain(ctx);
+ X509_STORE_CTX_cleanup(ctx);
if (ret <= 0) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Could not validate OCSP signer certificate");
@@ -663,6 +662,7 @@
}
if (!signer_trusted) {
+ X509_check_purpose(signer, -1, 0);
if ((X509_get_extension_flags(signer) & EXFLAG_XKUSAGE) &&
(X509_get_extended_key_usage(signer) & XKU_OCSP_SIGN)) {
wpa_printf(MSG_DEBUG,
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index cf482bf..b4f1bbe 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -26,6 +26,10 @@
#include <wolfssl/wolfcrypt/aes.h>
#endif
+#ifdef CONFIG_FIPS
+#include <wolfssl/wolfcrypt/fips_test.h>
+#endif /* CONFIG_FIPS */
+
#if !defined(CONFIG_FIPS) && \
(defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \
defined(EAP_SERVER_FAST))
@@ -58,6 +62,7 @@
void *cb_ctx;
int cert_in_cb;
char *ocsp_stapling_response;
+ unsigned int tls_session_lifetime;
};
static struct tls_context *tls_global = NULL;
@@ -94,6 +99,7 @@
WOLFSSL_X509 *peer_cert;
WOLFSSL_X509 *peer_issuer;
WOLFSSL_X509 *peer_issuer_issuer;
+ char *peer_subject; /* peer subject info for authenticated peer */
};
@@ -190,6 +196,33 @@
}
+#if defined(CONFIG_FIPS) && defined(HAVE_FIPS)
+static void wcFipsCb(int ok, int err, const char *hash)
+{
+ wpa_printf(MSG_INFO,
+ "wolfFIPS: wolfCrypt Fips error callback, ok = %d, err = %d",
+ ok, err);
+ wpa_printf(MSG_INFO, "wolfFIPS: message = %s", wc_GetErrorString(err));
+ wpa_printf(MSG_INFO, "wolfFIPS: hash = %s", hash);
+ if (err == IN_CORE_FIPS_E) {
+ wpa_printf(MSG_ERROR,
+ "wolfFIPS: In core integrity hash check failure, copy above hash");
+ wpa_printf(MSG_ERROR, "wolfFIPS: into verifyCore[] in fips_test.c and rebuild");
+ }
+}
+#endif /* CONFIG_FIPS && HAVE_FIPS */
+
+
+#ifdef DEBUG_WOLFSSL
+static void wolfSSL_logging_cb(const int log_level,
+ const char * const log_message)
+{
+ (void) log_level;
+ wpa_printf(MSG_DEBUG, "wolfSSL log:%s", log_message);
+}
+#endif /* DEBUG_WOLFSSL */
+
+
void * tls_init(const struct tls_config *conf)
{
WOLFSSL_CTX *ssl_ctx;
@@ -197,6 +230,7 @@
const char *ciphers;
#ifdef DEBUG_WOLFSSL
+ wolfSSL_SetLoggingCb(wolfSSL_logging_cb);
wolfSSL_Debugging_ON();
#endif /* DEBUG_WOLFSSL */
@@ -209,7 +243,9 @@
if (wolfSSL_Init() < 0)
return NULL;
- /* wolfSSL_Debugging_ON(); */
+#if defined(CONFIG_FIPS) && defined(HAVE_FIPS)
+ wolfCrypt_SetCb_fips(wcFipsCb);
+#endif /* CONFIG_FIPS && HAVE_FIPS */
}
tls_ref_count++;
@@ -227,17 +263,21 @@
}
wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb);
wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb);
+ context->tls_session_lifetime = conf->tls_session_lifetime;
wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context);
if (conf->tls_session_lifetime > 0) {
+ wolfSSL_CTX_set_session_id_context(ssl_ctx,
+ (const unsigned char *)
+ "hostapd", 7);
wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1);
wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
- SSL_SESS_CACHE_SERVER);
+ WOLFSSL_SESS_CACHE_SERVER);
wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime);
wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb);
} else {
wolfSSL_CTX_set_session_cache_mode(ssl_ctx,
- SSL_SESS_CACHE_CLIENT);
+ WOLFSSL_SESS_CACHE_OFF);
}
if (conf && conf->openssl_ciphers)
@@ -336,6 +376,7 @@
os_free(conn->alt_subject_match);
os_free(conn->suffix_match);
os_free(conn->domain_match);
+ os_free(conn->peer_subject);
/* self */
os_free(conn);
@@ -369,10 +410,13 @@
wolfSSL_set_quiet_shutdown(conn->ssl, 1);
wolfSSL_shutdown(conn->ssl);
- session = wolfSSL_get_session(conn->ssl);
- if (wolfSSL_clear(conn->ssl) != 1)
+ session = wolfSSL_get1_session(conn->ssl);
+ if (wolfSSL_clear(conn->ssl) != 1) {
+ wolfSSL_SESSION_free(session);
return -1;
+ }
wolfSSL_set_session(conn->ssl, session);
+ wolfSSL_SESSION_free(session);
return 0;
}
@@ -420,44 +464,6 @@
}
-static int tls_connection_dh(struct tls_connection *conn, const char *dh_file,
- const u8 *dh_blob, size_t blob_len)
-{
- if (!dh_file && !dh_blob)
- return 0;
-
- wolfSSL_set_accept_state(conn->ssl);
-
- if (dh_blob) {
- if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
- wpa_printf(MSG_INFO, "SSL: use DH DER blob failed");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "SSL: use DH blob OK");
- return 0;
- }
-
- if (dh_file) {
- wpa_printf(MSG_INFO, "SSL: use DH PEM file: %s", dh_file);
- if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
- SSL_FILETYPE_PEM) < 0) {
- wpa_printf(MSG_INFO, "SSL: use DH PEM file failed");
- if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file,
- SSL_FILETYPE_ASN1) < 0) {
- wpa_printf(MSG_INFO,
- "SSL: use DH DER file failed");
- return -1;
- }
- }
- wpa_printf(MSG_DEBUG, "SSL: use DH file OK");
- return 0;
- }
-
- return 0;
-}
-
-
static int tls_connection_client_cert(struct tls_connection *conn,
const char *client_cert,
const u8 *client_cert_blob,
@@ -472,7 +478,13 @@
SSL_FILETYPE_ASN1) != SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use client cert DER blob failed");
- return -1;
+ if (wolfSSL_use_certificate_chain_buffer_format(
+ conn->ssl, client_cert_blob, blob_len,
+ SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: use client cert PEM blob failed");
+ return -1;
+ }
}
wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK");
return 0;
@@ -534,23 +546,35 @@
if (private_key_blob) {
if (wolfSSL_use_PrivateKey_buffer(conn->ssl,
private_key_blob, blob_len,
- SSL_FILETYPE_ASN1) <= 0) {
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use private DER blob failed");
+ if (wolfSSL_use_PrivateKey_buffer(
+ conn->ssl,
+ private_key_blob, blob_len,
+ SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: use private PEM blob failed");
+ } else {
+ ok = 1;
+ }
} else {
- wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
ok = 1;
}
+ if (ok)
+ wpa_printf(MSG_DEBUG, "SSL: use private key blob OK");
}
if (!ok && private_key) {
if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) <= 0) {
+ SSL_FILETYPE_PEM) !=
+ SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use private key PEM file failed");
if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_ASN1) <= 0)
- {
+ SSL_FILETYPE_ASN1) !=
+ SSL_SUCCESS) {
wpa_printf(MSG_INFO,
"SSL: use private key DER file failed");
} else {
@@ -721,8 +745,7 @@
WOLFSSL_X509_NAME_ENTRY *e;
WOLFSSL_ASN1_STRING *cn;
- i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME,
- i);
+ i = wolfSSL_X509_NAME_get_index_by_NID(name, NID_commonName, i);
if (i == -1)
break;
e = wolfSSL_X509_NAME_get_entry(name, i);
@@ -1134,6 +1157,11 @@
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
+ if (depth == 0 && preverify_ok) {
+ os_free(conn->peer_subject);
+ conn->peer_subject = os_strdup(buf);
+ }
+
return preverify_ok;
}
@@ -1194,8 +1222,14 @@
if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len,
SSL_FILETYPE_ASN1) !=
SSL_SUCCESS) {
- wpa_printf(MSG_INFO, "SSL: failed to load CA blob");
- return -1;
+ wpa_printf(MSG_INFO, "SSL: failed to load DER CA blob");
+ if (wolfSSL_CTX_load_verify_buffer(
+ ctx, ca_cert_blob, blob_len,
+ SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ wpa_printf(MSG_INFO,
+ "SSL: failed to load PEM CA blob");
+ return -1;
+ }
}
wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK");
return 0;
@@ -1238,10 +1272,8 @@
static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
{
#ifdef HAVE_SESSION_TICKET
-#if 0
if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
wolfSSL_UseSessionTicket(ssl);
-#endif
#endif /* HAVE_SESSION_TICKET */
if (flags & TLS_CONN_DISABLE_TLSv1_0)
@@ -1250,6 +1282,8 @@
wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
if (flags & TLS_CONN_DISABLE_TLSv1_2)
wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+ if (flags & TLS_CONN_DISABLE_TLSv1_3)
+ wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
}
@@ -1289,12 +1323,6 @@
return -1;
}
- if (tls_connection_dh(conn, params->dh_file, params->dh_blob,
- params->dh_blob_len) < 0) {
- wpa_printf(MSG_INFO, "Error setting DH");
- return -1;
- }
-
if (params->openssl_ciphers &&
wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
wpa_printf(MSG_INFO,
@@ -1311,7 +1339,8 @@
WOLFSSL_CSR_OCSP_USE_NONCE) !=
SSL_SUCCESS)
return -1;
- wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS)
+ return -1;
}
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
@@ -1320,7 +1349,8 @@
WOLFSSL_CSR2_OCSP_MULTI, 0) !=
SSL_SUCCESS)
return -1;
- wolfSSL_CTX_EnableOCSP(tls_ctx, 0);
+ if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS)
+ return -1;
}
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
#if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \
@@ -1427,25 +1457,10 @@
}
-static int tls_global_dh(void *ssl_ctx, const char *dh_file,
- const u8 *dh_blob, size_t blob_len)
+static int tls_global_dh(void *ssl_ctx, const char *dh_file)
{
WOLFSSL_CTX *ctx = ssl_ctx;
- if (!dh_file && !dh_blob)
- return 0;
-
- if (dh_blob) {
- if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len,
- SSL_FILETYPE_ASN1) < 0) {
- wpa_printf(MSG_INFO,
- "SSL: global use DH DER blob failed");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "SSL: global use DH blob OK");
- return 0;
- }
-
if (dh_file) {
if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) <
0) {
@@ -1532,8 +1547,7 @@
return -1;
}
- if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob,
- params->dh_blob_len) < 0) {
+ if (tls_global_dh(tls_ctx, params->dh_file) < 0) {
wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'",
params->dh_file);
return -1;
@@ -1590,6 +1604,9 @@
int verify_peer, unsigned int flags,
const u8 *session_ctx, size_t session_ctx_len)
{
+ static int counter = 0;
+ struct tls_context *context;
+
if (!conn)
return -1;
@@ -1607,6 +1624,22 @@
wolfSSL_set_accept_state(conn->ssl);
+ context = wolfSSL_CTX_get_ex_data((WOLFSSL_CTX *) ssl_ctx, 0);
+ if (context && context->tls_session_lifetime == 0) {
+ /*
+ * Set session id context to a unique value to make sure
+ * session resumption cannot be used either through session
+ * caching or TLS ticket extension.
+ */
+ counter++;
+ wolfSSL_set_session_id_context(conn->ssl,
+ (const unsigned char *) &counter,
+ sizeof(counter));
+ } else {
+ wolfSSL_set_session_id_context(conn->ssl, session_ctx,
+ session_ctx_len);
+ }
+
/* TODO: do we need to fake a session like OpenSSL does here? */
return 0;
@@ -1997,11 +2030,21 @@
const char *label, const u8 *context,
size_t context_len, u8 *out, size_t out_len)
{
- if (context)
+ if (!conn)
return -1;
- if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+#if LIBWOLFSSL_VERSION_HEX >= 0x04007000
+ if (wolfSSL_export_keying_material(conn->ssl, out, out_len,
+ label, os_strlen(label),
+ context, context_len,
+ context != NULL) != WOLFSSL_SUCCESS)
return -1;
return 0;
+#else
+ if (context ||
+ wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0)
+ return -1;
+#endif
+ return 0;
}
@@ -2046,9 +2089,15 @@
_out, skip + out_len);
ret = 0;
} else {
+#ifdef CONFIG_FIPS
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Can't use sha1_md5 in FIPS build");
+ ret = -1;
+#else /* CONFIG_FIPS */
ret = tls_prf_sha1_md5(master_key, master_key_len,
"key expansion", seed, sizeof(seed),
_out, skip + out_len);
+#endif /* CONFIG_FIPS */
}
forced_memzero(master_key, master_key_len);
@@ -2160,6 +2209,39 @@
}
+int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len)
+{
+ size_t len;
+ int reused;
+
+ reused = wolfSSL_session_reused(conn->ssl);
+ if ((wolfSSL_is_server(conn->ssl) && !reused) ||
+ (!wolfSSL_is_server(conn->ssl) && reused))
+ len = wolfSSL_get_peer_finished(conn->ssl, buf, max_len);
+ else
+ len = wolfSSL_get_finished(conn->ssl, buf, max_len);
+
+ if (len == 0 || len > max_len)
+ return -1;
+
+ return len;
+}
+
+
+u16 tls_connection_get_cipher_suite(struct tls_connection *conn)
+{
+ return (u16) wolfSSL_get_current_cipher_suite(conn->ssl);
+}
+
+
+const char * tls_connection_get_peer_subject(struct tls_connection *conn)
+{
+ if (conn)
+ return conn->peer_subject;
+ return NULL;
+}
+
+
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
@@ -2206,3 +2288,11 @@
return NULL;
return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
}
+
+
+bool tls_connection_get_own_cert_used(struct tls_connection *conn)
+{
+ if (conn)
+ return wolfSSL_get_certificate(conn->ssl) != NULL;
+ return false;
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 8b92e12..46cee44 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -200,6 +200,15 @@
u16 he_6ghz_capa;
};
+/* struct eht_capabilities - IEEE 802.11be EHT capabilities */
+struct eht_capabilities {
+ bool eht_supported;
+ u16 mac_cap;
+ u8 phy_cap[EHT_PHY_CAPAB_LEN];
+ u8 mcs[EHT_MCS_NSS_CAPAB_LEN];
+ u8 ppet[EHT_PPE_THRESH_CAPAB_LEN];
+};
+
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
@@ -298,6 +307,11 @@
* for IEEE 802.11ay EDMG configuration.
*/
struct ieee80211_edmg_config edmg;
+
+ /**
+ * eht_capab - EHT (IEEE 802.11be) capabilities
+ */
+ struct eht_capabilities eht_capab[IEEE80211_MODE_NUM];
};
@@ -338,6 +352,7 @@
* @parent_tsf: Time when the Beacon/Probe Response frame was received in terms
* of TSF of the BSS specified by %tsf_bssid.
* @tsf_bssid: The BSS that %parent_tsf TSF time refers to.
+ * @beacon_newer: Whether the Beacon frame data is known to be newer
* @ie_len: length of the following IE field in octets
* @beacon_ie_len: length of the following Beacon IE field in octets
*
@@ -370,6 +385,7 @@
int snr;
u64 parent_tsf;
u8 tsf_bssid[ETH_ALEN];
+ bool beacon_newer;
size_t ie_len;
size_t beacon_ie_len;
/* Followed by ie_len + beacon_ie_len octets of IE data */
@@ -782,6 +798,16 @@
* for IEEE 802.11ay EDMG configuration.
*/
struct ieee80211_edmg_config edmg;
+
+ /**
+ * radar_background - Whether radar/CAC background is requested
+ */
+ bool radar_background;
+
+ /**
+ * eht_enabled - Whether EHT is enabled
+ */
+ bool eht_enabled;
};
/**
@@ -1036,7 +1062,7 @@
*
* If the driver needs to do special configuration for WPS association,
* this variable provides more information on what type of association
- * is being requested. Most drivers should not need ot use this.
+ * is being requested. Most drivers should not need to use this.
*/
enum wps_mode wps;
@@ -1781,7 +1807,7 @@
WPA_IF_P2P_GROUP,
/**
- * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
+ * WPA_IF_P2P_DEVICE - P2P Device interface is used to identify the
* abstracted P2P Device function in the driver
*/
WPA_IF_P2P_DEVICE,
@@ -2033,6 +2059,10 @@
#define WPA_DRIVER_FLAGS2_OCV 0x0000000000000080ULL
/** Driver expects user space implementation of SME in AP mode */
#define WPA_DRIVER_FLAGS2_AP_SME 0x0000000000000100ULL
+/** Driver handles SA Query procedures in AP mode */
+#define WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP 0x0000000000000200ULL
+/** Driver supports background radar/CAC detection */
+#define WPA_DRIVER_RADAR_BACKGROUND 0x0000000000000400ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2200,6 +2230,8 @@
const struct ieee80211_he_capabilities *he_capab;
size_t he_capab_len;
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab;
+ const struct ieee80211_eht_capabilities *eht_capab;
+ size_t eht_capab_len;
u32 flags; /* bitmask of WPA_STA_* flags */
u32 flags_mask; /* unset bits in flags */
#ifdef CONFIG_MESH
@@ -2403,6 +2435,27 @@
u16 counter_offset_presp[2];
};
+/**
+ * struct cca_settings - Settings for color switch command
+ * @cca_count: Count in Beacon frames (TBTT) to perform the switch
+ * @cca_color: The new color that we are switching to
+ * @beacon_cca: Beacon/Probe Response/(Re)Association Response frame info for
+ * color switch period
+ * @beacon_after: Next Beacon/Probe Response/(Re)Association Response frame info
+ * @counter_offset_beacon: Offset to the count field in Beacon frame tail
+ * @counter_offset_presp: Offset to the count field in Probe Response frame
+ */
+struct cca_settings {
+ u8 cca_count;
+ u8 cca_color;
+
+ struct beacon_data beacon_cca;
+ struct beacon_data beacon_after;
+
+ u16 counter_offset_beacon;
+ u16 counter_offset_presp;
+};
+
/* TDLS peer capabilities for send_tdls_mgmt() */
enum tdls_peer_capability {
TDLS_PEER_HT = BIT(0),
@@ -2467,6 +2520,9 @@
/* Indicates whether EDMG is enabled */
int edmg_enabled;
+
+ /* Indicates whether EHT is enabled */
+ bool eht_enabled;
};
struct wpa_bss_trans_info {
@@ -2608,7 +2664,7 @@
* some drivers may expect them in different order than wpa_supplicant
* is using. If the TX/RX keys are swapped, all TKIP encrypted packets
* will trigger Michael MIC errors. This can be fixed by changing the
- * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
+ * order of MIC keys by swapping the bytes 16..23 and 24..31 of the key
* in driver_*.c set_key() implementation, see driver_ndis.c for an
* example on how this can be done.
*/
@@ -3989,6 +4045,17 @@
int (*switch_channel)(void *priv, struct csa_settings *settings);
/**
+ * switch_color - Announce color switch and migrate the BSS to the
+ * given color
+ * @priv: Private driver interface data
+ * @settings: Settings for CCA period and new color
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to move the BSS to its new color.
+ */
+ int (*switch_color)(void *priv, struct cca_settings *settings);
+
+ /**
* add_tx_ts - Add traffic stream
* @priv: Private driver interface data
* @tsid: Traffic stream ID
@@ -4617,7 +4684,7 @@
* This event must be delivered when a Michael MIC error is detected by
* the local driver. Additional data for event processing is
* provided with union wpa_event_data::michael_mic_failure. This
- * information is used to request new encyption key and to initiate
+ * information is used to request new encryption key and to initiate
* TKIP countermeasures if needed.
*/
EVENT_MICHAEL_MIC_FAILURE,
@@ -5147,6 +5214,26 @@
* non-zero wait time and that has not been explicitly cancelled.
*/
EVENT_TX_WAIT_EXPIRE,
+
+ /**
+ * EVENT_BSS_COLOR_COLLISION - Notification of a BSS color collision
+ */
+ EVENT_BSS_COLOR_COLLISION,
+
+ /**
+ * EVENT_CCA_STARTED_NOTIFY - Notification that CCA has started
+ */
+ EVENT_CCA_STARTED_NOTIFY,
+
+ /**
+ * EVENT_CCA_ABORTED_NOTIFY - Notification that CCA has aborted
+ */
+ EVENT_CCA_ABORTED_NOTIFY,
+
+ /**
+ * EVENT_CCA_NOTIFY - Notification that CCA has completed
+ */
+ EVENT_CCA_NOTIFY,
};
@@ -6039,6 +6126,13 @@
struct unprot_beacon {
const u8 *sa;
} unprot_beacon;
+
+ /**
+ * struct bss_color_collision - Data for EVENT_BSS_COLOR_COLLISION
+ */
+ struct bss_color_collision {
+ u64 bitmap;
+ } bss_color_collision;
};
/**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 9b4166d..cb66dfa 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -17,7 +17,6 @@
#include "eloop.h"
#include "common/ieee802_11_defs.h"
#include "l2_packet/l2_packet.h"
-#include "p2p/p2p.h"
#include "common.h"
#ifndef _BYTE_ORDER
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 741521c..8db7861 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -91,6 +91,10 @@
E2S(UPDATE_DH);
E2S(UNPROT_BEACON);
E2S(TX_WAIT_EXPIRE);
+ E2S(BSS_COLOR_COLLISION);
+ E2S(CCA_STARTED_NOTIFY);
+ E2S(CCA_ABORTED_NOTIFY);
+ E2S(CCA_NOTIFY);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index 3dba13c..b609bbf 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -77,6 +77,9 @@
u8 encoding_sa;
bool encoding_sa_set;
+
+ u64 cipher_suite;
+ bool cipher_suite_set;
};
@@ -460,8 +463,14 @@
*/
static int macsec_drv_set_current_cipher_suite(void *priv, u64 cs)
{
+ struct macsec_drv_data *drv = priv;
+
wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs);
- return 0;
+
+ drv->cipher_suite_set = true;
+ drv->cipher_suite = cs;
+
+ return try_commit(drv);
}
@@ -1063,7 +1072,8 @@
}
-static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci)
+static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci,
+ u64 cs)
{
struct rtnl_link *needle;
void *match;
@@ -1074,6 +1084,8 @@
rtnl_link_set_link(needle, parent);
rtnl_link_macsec_set_sci(needle, sci);
+ if (cs)
+ rtnl_link_macsec_set_cipher_suite(needle, cs);
match = nl_cache_find(cache, (struct nl_object *) needle);
rtnl_link_put(needle);
@@ -1098,6 +1110,7 @@
char *ifname;
u64 sci;
int err;
+ u64 cs = 0;
wpa_printf(MSG_DEBUG, DRV_PREFIX
"%s: create_transmit_sc -> " SCISTR " (conf_offset=%d)",
@@ -1122,6 +1135,12 @@
drv->created_link = true;
+ if (drv->cipher_suite_set) {
+ cs = drv->cipher_suite;
+ drv->cipher_suite_set = false;
+ rtnl_link_macsec_set_cipher_suite(link, cs);
+ }
+
err = rtnl_link_add(drv->sk, link, NLM_F_CREATE);
if (err == -NLE_BUSY) {
wpa_printf(MSG_INFO,
@@ -1137,7 +1156,7 @@
rtnl_link_put(link);
nl_cache_refill(drv->sk, drv->link_cache);
- link = lookup_sc(drv->link_cache, drv->parent_ifi, sci);
+ link = lookup_sc(drv->link_cache, drv->parent_ifi, sci, cs);
if (!link) {
wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link");
return -1;
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index 54964f3..eccaf63 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -861,7 +861,7 @@
}
}
- wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__);
+ wpa_printf(MSG_DEBUG, "%s: no available channel", __func__);
return -1;
}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5d79db6..5892fc1 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2943,6 +2943,8 @@
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
drv->ifindex);
+ bss->beacon_set = 0;
+ bss->freq = 0;
nl80211_put_wiphy_data_ap(bss);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
@@ -4770,10 +4772,24 @@
nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)))
goto fail;
- if (drv->device_ap_sme &&
- (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) &&
- nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
- goto fail;
+ if (drv->device_ap_sme) {
+ u32 flags = 0;
+
+ if (params->key_mgmt_suites & WPA_KEY_MGMT_SAE) {
+ /* Add the previously used flag attribute to support
+ * older kernel versions and the newer flag bit for
+ * newer kernels. */
+ if (nla_put_flag(msg,
+ NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
+ goto fail;
+ flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
+ }
+
+ flags |= NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT;
+
+ if (nla_put_u32(msg, NL80211_ATTR_AP_SETTINGS_FLAGS, flags))
+ goto fail;
+ }
wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
params->pairwise_ciphers);
@@ -5007,15 +5023,19 @@
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
return -ENOBUFS;
+ wpa_printf(MSG_DEBUG, " * eht_enabled=%d", freq->eht_enabled);
wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
+ wpa_printf(MSG_DEBUG, " * radar_background=%d",
+ freq->radar_background);
hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
hw_mode == HOSTAPD_MODE_IEEE80211B;
- if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) {
+ if (freq->vht_enabled ||
+ ((freq->he_enabled || freq->eht_enabled) && !is_24ghz)) {
enum nl80211_chan_width cw;
wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth);
@@ -5087,6 +5107,9 @@
NL80211_CHAN_NO_HT))
return -ENOBUFS;
}
+ if (freq->radar_background)
+ nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND);
+
return 0;
}
@@ -5099,9 +5122,10 @@
int ret;
wpa_printf(MSG_DEBUG,
- "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
- freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled,
- freq->bandwidth, freq->center_freq1, freq->center_freq2);
+ "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
+ freq->freq, freq->ht_enabled, freq->vht_enabled,
+ freq->he_enabled, freq->eht_enabled, freq->bandwidth,
+ freq->center_freq1, freq->center_freq2);
msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
NL80211_CMD_SET_WIPHY);
@@ -5250,6 +5274,14 @@
goto fail;
}
+ if (params->eht_capab) {
+ wpa_hexdump(MSG_DEBUG, " * eht_capab",
+ params->eht_capab, params->eht_capab_len);
+ if (nla_put(msg, NL80211_ATTR_EHT_CAPABILITY,
+ params->eht_capab_len, params->eht_capab))
+ goto fail;
+ }
+
if (params->ext_capab) {
wpa_hexdump(MSG_DEBUG, " * ext_capab",
params->ext_capab, params->ext_capab_len);
@@ -8300,6 +8332,11 @@
if (save_cookie)
drv->send_frame_cookie = no_ack ? (u64) -1 : cookie;
+ if (!wait) {
+ /* There is no need to store this cookie since there
+ * is no wait that could be canceled later. */
+ goto fail;
+ }
if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) {
wpa_printf(MSG_DEBUG,
"nl80211: Drop oldest pending send frame cookie 0x%llx",
@@ -8430,7 +8467,8 @@
u64 cookie;
/* Cancel the last pending TX cookie */
- nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
+ if (drv->send_frame_cookie != (u64) -1)
+ nl80211_frame_wait_cancel(bss, drv->send_frame_cookie);
/*
* Cancel the other pending TX cookies, if any. This is needed since
@@ -8622,7 +8660,6 @@
if (!is_ap_interface(drv->nlmode))
return -1;
wpa_driver_nl80211_del_beacon(bss);
- bss->beacon_set = 0;
/*
* If the P2P GO interface was dynamically added, then it is
@@ -8642,7 +8679,6 @@
if (!is_ap_interface(drv->nlmode))
return -1;
wpa_driver_nl80211_del_beacon(bss);
- bss->beacon_set = 0;
return 0;
}
@@ -10080,6 +10116,87 @@
}
+#ifdef CONFIG_IEEE80211AX
+static int nl80211_switch_color(void *priv, struct cca_settings *settings)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nlattr *beacon_cca;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Color change request (cca_count=%u color=%d)",
+ settings->cca_count, settings->cca_color);
+
+ if (drv->nlmode != NL80211_IFTYPE_AP)
+ return -EOPNOTSUPP;
+
+ if (!settings->beacon_cca.tail)
+ return -EINVAL;
+
+ if (settings->beacon_cca.tail_len <= settings->counter_offset_beacon ||
+ settings->beacon_cca.tail[settings->counter_offset_beacon] !=
+ settings->cca_count)
+ return -EINVAL;
+
+ if (settings->beacon_cca.probe_resp &&
+ (settings->beacon_cca.probe_resp_len <=
+ settings->counter_offset_presp ||
+ settings->beacon_cca.probe_resp[settings->counter_offset_presp] !=
+ settings->cca_count))
+ return -EINVAL;
+
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_COLOR_CHANGE_REQUEST);
+ if (!msg ||
+ nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COUNT,
+ settings->cca_count) ||
+ nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COLOR,
+ settings->cca_color))
+ goto error;
+
+ /* beacon_after params */
+ ret = set_beacon_data(msg, &settings->beacon_after);
+ if (ret)
+ goto error;
+
+ /* beacon_csa params */
+ beacon_cca = nla_nest_start(msg, NL80211_ATTR_COLOR_CHANGE_ELEMS);
+ if (!beacon_cca) {
+ ret = -ENOBUFS;
+ goto error;
+ }
+
+ ret = set_beacon_data(msg, &settings->beacon_cca);
+ if (ret)
+ goto error;
+
+ if (nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_BEACON,
+ settings->counter_offset_beacon) ||
+ (settings->beacon_cca.probe_resp &&
+ nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_PRESP,
+ settings->counter_offset_presp))) {
+ ret = -ENOBUFS;
+ goto error;
+ }
+
+ nla_nest_end(msg, beacon_cca);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: switch_color failed err=%d (%s)",
+ ret, strerror(-ret));
+ }
+ return ret;
+
+error:
+ nlmsg_free(msg);
+ wpa_printf(MSG_DEBUG, "nl80211: Could not build color switch request");
+ return ret;
+}
+#endif /* CONFIG_IEEE80211AX */
+
+
static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
u8 user_priority, u16 admitted_time)
{
@@ -11235,6 +11352,8 @@
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
(params->vht_enabled &&
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
+ (params->eht_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED)) ||
nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
params->ch_width) ||
add_acs_ch_list(msg, params->freq_list) ||
@@ -11247,9 +11366,10 @@
nla_nest_end(msg, data);
wpa_printf(MSG_DEBUG,
- "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d",
+ "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d EHT: %d BW: %d EDMG: %d",
params->hw_mode, params->ht_enabled, params->ht40_enabled,
- params->vht_enabled, params->ch_width, params->edmg_enabled);
+ params->vht_enabled, params->eht_enabled, params->ch_width,
+ params->edmg_enabled);
ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
if (ret) {
@@ -12399,6 +12519,9 @@
.get_survey = wpa_driver_nl80211_get_survey,
.status = wpa_driver_nl80211_status,
.switch_channel = nl80211_switch_channel,
+#ifdef CONFIG_IEEE80211AX
+ .switch_color = nl80211_switch_color,
+#endif /* CONFIG_IEEE80211AX */
#ifdef ANDROID_P2P
.set_noa = wpa_driver_set_p2p_noa,
.get_noa = wpa_driver_get_p2p_noa,
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 400eb4b..75df36c 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -664,6 +664,10 @@
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION))
capa->flags2 |= WPA_DRIVER_FLAGS2_OCV;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_RADAR_BACKGROUND))
+ capa->flags2 |= WPA_DRIVER_RADAR_BACKGROUND;
}
@@ -919,8 +923,15 @@
wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
- if (tb[NL80211_ATTR_DEVICE_AP_SME])
+ if (tb[NL80211_ATTR_DEVICE_AP_SME]) {
+ u32 ap_sme_features_flags =
+ nla_get_u32(tb[NL80211_ATTR_DEVICE_AP_SME]);
+
+ if (ap_sme_features_flags & NL80211_AP_SME_SA_QUERY_OFFLOAD)
+ capa->flags2 |= WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP;
+
info->device_ap_sme = 1;
+ }
wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]);
@@ -1335,7 +1346,7 @@
drv->has_capability = 1;
drv->has_driver_key_mgmt = info.has_key_mgmt | info.has_key_mgmt_iftype;
- /* Fallback to hardcoded defaults if the driver does nott advertize any
+ /* Fallback to hardcoded defaults if the driver does not advertise any
* AKM capabilities. */
if (!drv->has_driver_key_mgmt) {
drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
@@ -1772,12 +1783,14 @@
}
-static void phy_info_iftype_copy(struct he_capabilities *he_capab,
+static void phy_info_iftype_copy(struct hostapd_hw_modes *mode,
enum ieee80211_op_mode opmode,
struct nlattr **tb, struct nlattr **tb_flags)
{
enum nl80211_iftype iftype;
size_t len;
+ struct he_capabilities *he_capab = &mode->he_capab[opmode];
+ struct eht_capabilities *eht_capab = &mode->eht_capab[opmode];
switch (opmode) {
case IEEE80211_MODE_INFRA:
@@ -1847,6 +1860,47 @@
capa = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]);
he_capab->he_6ghz_capa = le_to_host16(capa);
}
+
+ if (!tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC] ||
+ !tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY])
+ return;
+
+ eht_capab->eht_supported = true;
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC] &&
+ nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]) >= 2) {
+ const u8 *pos;
+
+ pos = nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]);
+ eht_capab->mac_cap = WPA_GET_LE16(pos);
+ }
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]);
+ if (len > sizeof(eht_capab->phy_cap))
+ len = sizeof(eht_capab->phy_cap);
+ os_memcpy(eht_capab->phy_cap,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]),
+ len);
+ }
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]);
+ if (len > sizeof(eht_capab->mcs))
+ len = sizeof(eht_capab->mcs);
+ os_memcpy(eht_capab->mcs,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]),
+ len);
+ }
+
+ if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]) {
+ len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]);
+ if (len > sizeof(eht_capab->ppet))
+ len = sizeof(eht_capab->ppet);
+ os_memcpy(&eht_capab->ppet,
+ nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]),
+ len);
+ }
}
@@ -1868,7 +1922,7 @@
return NL_STOP;
for (i = 0; i < IEEE80211_MODE_NUM; i++)
- phy_info_iftype_copy(&mode->he_capab[i], i, tb, tb_flags);
+ phy_info_iftype_copy(mode, i, tb, tb_flags);
return NL_OK;
}
@@ -2430,7 +2484,7 @@
for (i = 0; i < num_modes; i++) {
struct hostapd_hw_modes *mode = &modes[i];
- char str[200];
+ char str[1000];
char *pos = str;
char *end = pos + sizeof(str);
int j, res;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 2926a45..5c103a4 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -171,6 +171,13 @@
C2S(NL80211_CMD_UNPROT_BEACON)
C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS)
C2S(NL80211_CMD_SET_SAR_SPECS)
+ C2S(NL80211_CMD_OBSS_COLOR_COLLISION)
+ C2S(NL80211_CMD_COLOR_CHANGE_REQUEST)
+ C2S(NL80211_CMD_COLOR_CHANGE_STARTED)
+ C2S(NL80211_CMD_COLOR_CHANGE_ABORTED)
+ C2S(NL80211_CMD_COLOR_CHANGE_COMPLETED)
+ C2S(NL80211_CMD_SET_FILS_AAD)
+ C2S(NL80211_CMD_ASSOC_COMEBACK)
C2S(__NL80211_CMD_AFTER_LAST)
}
#undef C2S
@@ -2822,7 +2829,8 @@
nla_len(tb[NL80211_ATTR_FRAME]));
break;
default:
- wpa_printf(MSG_INFO, "nl80211: Unxpected ethertype 0x%04x from "
+ wpa_printf(MSG_INFO,
+ "nl80211: Unexpected ethertype 0x%04x from "
MACSTR " over control port",
ethertype, MAC2STR(src_addr));
break;
@@ -2871,9 +2879,12 @@
}
}
wpa_printf(MSG_DEBUG,
- "nl80211: TX frame wait expired for cookie 0x%llx%s",
+ "nl80211: TX frame wait expired for cookie 0x%llx%s%s",
(long long unsigned int) cookie,
- match ? " (match)" : "");
+ match ? " (match)" : "",
+ drv->send_frame_cookie == cookie ? " (match-saved)" : "");
+ if (drv->send_frame_cookie == cookie)
+ drv->send_frame_cookie = (u64) -1;
if (!match)
return;
@@ -2887,6 +2898,69 @@
}
+static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *mac, struct nlattr *timeout)
+{
+ if (!mac || !timeout)
+ return;
+ wpa_printf(MSG_DEBUG, "nl80211: Association comeback requested by "
+ MACSTR " (timeout: %u ms)",
+ MAC2STR((u8 *) nla_data(mac)), nla_get_u32(timeout));
+}
+
+
+#ifdef CONFIG_IEEE80211AX
+
+static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+
+ if (!tb[NL80211_ATTR_OBSS_COLOR_BITMAP])
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ data.bss_color_collision.bitmap =
+ nla_get_u64(tb[NL80211_ATTR_OBSS_COLOR_BITMAP]);
+
+ wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08lx",
+ data.bss_color_collision.bitmap);
+ wpa_supplicant_event(drv->ctx, EVENT_BSS_COLOR_COLLISION, &data);
+}
+
+
+static void
+nl80211_color_change_announcement_started(struct wpa_driver_nl80211_data *drv)
+{
+ union wpa_event_data data = {};
+
+ wpa_printf(MSG_DEBUG, "nl80211: CCA started");
+ wpa_supplicant_event(drv->ctx, EVENT_CCA_STARTED_NOTIFY, &data);
+}
+
+
+static void
+nl80211_color_change_announcement_aborted(struct wpa_driver_nl80211_data *drv)
+{
+ union wpa_event_data data = {};
+
+ wpa_printf(MSG_DEBUG, "nl80211: CCA aborted");
+ wpa_supplicant_event(drv->ctx, EVENT_CCA_ABORTED_NOTIFY, &data);
+}
+
+
+static void
+nl80211_color_change_announcement_completed(struct wpa_driver_nl80211_data *drv)
+{
+ union wpa_event_data data = {};
+
+ wpa_printf(MSG_DEBUG, "nl80211: CCA completed");
+ wpa_supplicant_event(drv->ctx, EVENT_CCA_NOTIFY, &data);
+}
+
+#endif /* CONFIG_IEEE80211AX */
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
@@ -3136,6 +3210,24 @@
case NL80211_CMD_FRAME_WAIT_CANCEL:
nl80211_frame_wait_cancel(drv, tb[NL80211_ATTR_COOKIE]);
break;
+ case NL80211_CMD_ASSOC_COMEBACK:
+ nl80211_assoc_comeback(drv, tb[NL80211_ATTR_MAC],
+ tb[NL80211_ATTR_TIMEOUT]);
+ break;
+#ifdef CONFIG_IEEE80211AX
+ case NL80211_CMD_OBSS_COLOR_COLLISION:
+ nl80211_obss_color_collision(drv, tb);
+ break;
+ case NL80211_CMD_COLOR_CHANGE_STARTED:
+ nl80211_color_change_announcement_started(drv);
+ break;
+ case NL80211_CMD_COLOR_CHANGE_ABORTED:
+ nl80211_color_change_announcement_aborted(drv);
+ break;
+ case NL80211_CMD_COLOR_CHANGE_COMPLETED:
+ nl80211_color_change_announcement_completed(drv);
+ break;
+#endif /* CONFIG_IEEE80211AX */
default:
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
"(cmd=%d)", cmd);
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 1316084..b82e5af 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -713,6 +713,7 @@
[NL80211_BSS_STATUS] = { .type = NLA_U32 },
[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_BEACON_TSF] = { .type = NLA_U64 },
[NL80211_BSS_PARENT_TSF] = { .type = NLA_U64 },
[NL80211_BSS_PARENT_BSSID] = { .type = NLA_UNSPEC },
[NL80211_BSS_LAST_SEEN_BOOTTIME] = { .type = NLA_U64 },
@@ -774,8 +775,10 @@
r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
if (bss[NL80211_BSS_BEACON_TSF]) {
u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]);
- if (tsf > r->tsf)
+ if (tsf > r->tsf) {
r->tsf = tsf;
+ r->beacon_newer = true;
+ }
}
if (bss[NL80211_BSS_SEEN_MS_AGO])
r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
diff --git a/src/drivers/ndis_events.c b/src/drivers/ndis_events.c
index 93673a3..4d4ec81 100644
--- a/src/drivers/ndis_events.c
+++ b/src/drivers/ndis_events.c
@@ -372,8 +372,9 @@
L"MSNdis_NotifyAdapterRemoval") == 0) {
ndis_events_adapter_removal(events);
} else {
- wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
- "'%S'", vtClass.bstrVal);
+ wpa_printf(MSG_DEBUG,
+ "Unexpected event - __CLASS: '%S'",
+ vtClass.bstrVal);
}
VariantClear(&vtClass);
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index f962c06..0568a79 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -11,7 +11,7 @@
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -301,6 +301,29 @@
*/
/**
+ * DOC: FILS shared key crypto offload
+ *
+ * This feature is applicable to drivers running in AP mode.
+ *
+ * FILS shared key crypto offload can be advertised by drivers by setting
+ * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD flag. The drivers that support
+ * FILS shared key crypto offload should be able to encrypt and decrypt
+ * association frames for FILS shared key authentication as per IEEE 802.11ai.
+ * With this capability, for FILS key derivation, drivers depend on userspace.
+ *
+ * After FILS key derivation, userspace shares the FILS AAD details with the
+ * driver and the driver stores the same to use in decryption of association
+ * request and in encryption of association response. The below parameters
+ * should be given to the driver in %NL80211_CMD_SET_FILS_AAD.
+ * %NL80211_ATTR_MAC - STA MAC address, used for storing FILS AAD per STA
+ * %NL80211_ATTR_FILS_KEK - Used for encryption or decryption
+ * %NL80211_ATTR_FILS_NONCES - Used for encryption or decryption
+ * (STA Nonce 16 bytes followed by AP Nonce 16 bytes)
+ *
+ * Once the association is done, the driver cleans the FILS AAD data.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -337,7 +360,10 @@
* @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
* %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
* userspace to request deletion of a virtual interface, then requires
- * attribute %NL80211_ATTR_IFINDEX.
+ * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are
+ * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS,
+ * and if this command is used for the transmitting interface, then all
+ * the non-transmitting interfaces are deleted as well.
*
* @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
* by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
@@ -1185,6 +1211,32 @@
* passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
* specify the wiphy index to be applied to.
*
+ * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever
+ * mac80211/drv detects a bss color collision.
+ *
+ * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that
+ * userspace wants to change the BSS color.
+ *
+ * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has
+ * started
+ *
+ * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has
+ * been aborted
+ *
+ * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change
+ * has completed
+ *
+ * @NL80211_CMD_SET_FILS_AAD: Set FILS AAD data to the driver using -
+ * &NL80211_ATTR_MAC - for STA MAC address
+ * &NL80211_ATTR_FILS_KEK - for KEK
+ * &NL80211_ATTR_FILS_NONCES - for FILS Nonces
+ * (STA Nonce 16 bytes followed by AP Nonce 16 bytes)
+ *
+ * @NL80211_CMD_ASSOC_COMEBACK: notification about an association
+ * temporal rejection with comeback. The event includes %NL80211_ATTR_MAC
+ * to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to
+ * specify the timeout value.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1417,6 +1469,18 @@
NL80211_CMD_SET_SAR_SPECS,
+ NL80211_CMD_OBSS_COLOR_COLLISION,
+
+ NL80211_CMD_COLOR_CHANGE_REQUEST,
+
+ NL80211_CMD_COLOR_CHANGE_STARTED,
+ NL80211_CMD_COLOR_CHANGE_ABORTED,
+ NL80211_CMD_COLOR_CHANGE_COMPLETED,
+
+ NL80211_CMD_SET_FILS_AAD,
+
+ NL80211_CMD_ASSOC_COMEBACK,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2413,7 +2477,9 @@
* space supports external authentication. This attribute shall be used
* with %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP request. The driver
* may offload authentication processing to user space if this capability
- * is indicated in the respective requests from the user space.
+ * is indicated in the respective requests from the user space. (This flag
+ * attribute deprecated for %NL80211_CMD_START_AP, use
+ * %NL80211_ATTR_AP_SETTINGS_FLAGS)
*
* @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this
* u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
@@ -2560,6 +2626,43 @@
* disassoc events to indicate that an immediate reconnect to the AP
* is desired.
*
+ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the
+ * %NL80211_CMD_OBSS_COLOR_COLLISION event.
+ *
+ * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's
+ * until the color switch event.
+ * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are
+ * switching to
+ * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE
+ * information for the time while performing a color switch.
+ *
+ * @NL80211_ATTR_MBSSID_CONFIG: Nested attribute for multiple BSSID
+ * advertisements (MBSSID) parameters in AP mode.
+ * Kernel uses this attribute to indicate the driver's support for MBSSID
+ * and enhanced multi-BSSID advertisements (EMA AP) to the userspace.
+ * Userspace should use this attribute to configure per interface MBSSID
+ * parameters.
+ * See &enum nl80211_mbssid_config_attributes for details.
+ *
+ * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements.
+ * Mandatory parameter for the transmitting interface to enable MBSSID.
+ * Optional for the non-transmitting interfaces.
+ *
+ * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain
+ * available for radar/CAC detection on some hw. This chain can't be used
+ * to transmit or receive frames and it is bounded to a running wdev.
+ * Background radar/CAC detection allows to avoid the CAC downtime
+ * switching on a different channel during CAC detection on the selected
+ * radar channel.
+ *
+ * @NL80211_ATTR_AP_SETTINGS_FLAGS: u32 attribute contains ap settings flags,
+ * enumerated in &enum nl80211_ap_settings_flags. This attribute shall be
+ * used with %NL80211_CMD_START_AP request.
+ *
+ * @NL80211_ATTR_EHT_CAPABILITY: EHT Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION). Can be set
+ * only if %NL80211_STA_FLAG_WME is set.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3057,6 +3160,21 @@
NL80211_ATTR_DISABLE_HE,
+ NL80211_ATTR_OBSS_COLOR_BITMAP,
+
+ NL80211_ATTR_COLOR_CHANGE_COUNT,
+ NL80211_ATTR_COLOR_CHANGE_COLOR,
+ NL80211_ATTR_COLOR_CHANGE_ELEMS,
+
+ NL80211_ATTR_MBSSID_CONFIG,
+ NL80211_ATTR_MBSSID_ELEMS,
+
+ NL80211_ATTR_RADAR_BACKGROUND,
+
+ NL80211_ATTR_AP_SETTINGS_FLAGS,
+
+ NL80211_ATTR_EHT_CAPABILITY,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3112,6 +3230,8 @@
#define NL80211_HE_MAX_CAPABILITY_LEN 54
#define NL80211_MAX_NR_CIPHER_SUITES 5
#define NL80211_MAX_NR_AKM_SUITES 2
+#define NL80211_EHT_MIN_CAPABILITY_LEN 13
+#define NL80211_EHT_MAX_CAPABILITY_LEN 51
#define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10
@@ -3139,7 +3259,7 @@
* and therefore can't be created in the normal ways, use the
* %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
* commands to create and destroy one
- * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
+ * @NL80211_IFTYPE_OCB: Outside Context of a BSS
* This mode corresponds to the MIB variable dot11OCBActivated=true
* @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev)
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
@@ -3281,6 +3401,56 @@
};
/**
+ * enum nl80211_eht_gi - EHT guard interval
+ * @NL80211_RATE_INFO_EHT_GI_0_8: 0.8 usec
+ * @NL80211_RATE_INFO_EHT_GI_1_6: 1.6 usec
+ * @NL80211_RATE_INFO_EHT_GI_3_2: 3.2 usec
+ */
+enum nl80211_eht_gi {
+ NL80211_RATE_INFO_EHT_GI_0_8,
+ NL80211_RATE_INFO_EHT_GI_1_6,
+ NL80211_RATE_INFO_EHT_GI_3_2,
+};
+
+/**
+ * enum nl80211_eht_ru_alloc - EHT RU allocation values
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_26: 26-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_52: 52-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_52P26: 52+26-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_106: 106-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_106P26: 106+26 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_242: 242-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_484: 484-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_484P242: 484+242 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_996: 996-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484: 996+484 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242: 996+484+242 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996: 2x996-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484: 2x996+484 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996: 3x996-tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484: 3x996+484 tone RU allocation
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC_4x996: 4x996-tone RU allocation
+ */
+enum nl80211_eht_ru_alloc {
+ NL80211_RATE_INFO_EHT_RU_ALLOC_26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_4x996,
+};
+
+/**
* enum nl80211_rate_info - bitrate information
*
* These attribute types are used with %NL80211_STA_INFO_TXRATE
@@ -3319,6 +3489,13 @@
* @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1)
* @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then
* non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc)
+ * @NL80211_RATE_INFO_320_MHZ_WIDTH: 320 MHz bitrate
+ * @NL80211_RATE_INFO_EHT_MCS: EHT MCS index (u8, 0-15)
+ * @NL80211_RATE_INFO_EHT_NSS: EHT NSS value (u8, 1-8)
+ * @NL80211_RATE_INFO_EHT_GI: EHT guard interval identifier
+ * (u8, see &enum nl80211_eht_gi)
+ * @NL80211_RATE_INFO_EHT_RU_ALLOC: EHT RU allocation, if not present then
+ * non-OFDMA was used (u8, see &enum nl80211_eht_ru_alloc)
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -3340,6 +3517,11 @@
NL80211_RATE_INFO_HE_GI,
NL80211_RATE_INFO_HE_DCM,
NL80211_RATE_INFO_HE_RU_ALLOC,
+ NL80211_RATE_INFO_320_MHZ_WIDTH,
+ NL80211_RATE_INFO_EHT_MCS,
+ NL80211_RATE_INFO_EHT_NSS,
+ NL80211_RATE_INFO_EHT_GI,
+ NL80211_RATE_INFO_EHT_RU_ALLOC,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
@@ -3650,11 +3832,20 @@
* capabilities IE
* @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as
* defined in HE capabilities IE
- * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently
- * defined
* @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16),
* given for all 6 GHz band channels
+ * @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are
+ * advertised on this band/for this iftype (binary)
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC: EHT MAC capabilities as in EHT
+ * capabilities element
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY: EHT PHY capabilities as in EHT
+ * capabilities element
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET: EHT supported NSS/MCS as in EHT
+ * capabilities element
+ * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE: EHT PPE thresholds information as
+ * defined in EHT capabilities element
* @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
+ * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band attribute currently defined
*/
enum nl80211_band_iftype_attr {
__NL80211_BAND_IFTYPE_ATTR_INVALID,
@@ -3665,6 +3856,11 @@
NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
+ NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET,
+ NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE,
/* keep last */
__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
@@ -3809,6 +4005,10 @@
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed
* on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_320MHZ: any 320 MHz channel using this channel
+ * as the primary or any of the secondary channels isn't possible
+ * @NL80211_FREQUENCY_ATTR_NO_EHT: EHT operation is not allowed on this channel
+ * in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -3845,6 +4045,8 @@
NL80211_FREQUENCY_ATTR_4MHZ,
NL80211_FREQUENCY_ATTR_8MHZ,
NL80211_FREQUENCY_ATTR_16MHZ,
+ NL80211_FREQUENCY_ATTR_NO_320MHZ,
+ NL80211_FREQUENCY_ATTR_NO_EHT,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -4043,6 +4245,7 @@
* @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
* @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
* @NL80211_RRF_NO_HE: HE operation not allowed
+ * @NL80211_RRF_NO_320MHZ: 320MHz operation not allowed
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -4061,6 +4264,7 @@
NL80211_RRF_NO_80MHZ = 1<<15,
NL80211_RRF_NO_160MHZ = 1<<16,
NL80211_RRF_NO_HE = 1<<17,
+ NL80211_RRF_NO_320MHZ = 1<<18,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
@@ -4558,6 +4762,8 @@
* @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel
* @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel
* @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel
+ * @NL80211_CHAN_WIDTH_320: 320 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ * attribute must be provided as well
*/
enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT,
@@ -4573,6 +4779,7 @@
NL80211_CHAN_WIDTH_4,
NL80211_CHAN_WIDTH_8,
NL80211_CHAN_WIDTH_16,
+ NL80211_CHAN_WIDTH_320,
};
/**
@@ -4887,6 +5094,7 @@
* @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz)
* @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz)
* @NL80211_BAND_S1GHZ: around 900MHz, supported by S1G PHYs
+ * @NL80211_BAND_LC: light communication band (placeholder)
* @NUM_NL80211_BANDS: number of bands, avoid using this in userspace
* since newer kernel versions may support more bands
*/
@@ -4896,6 +5104,7 @@
NL80211_BAND_60GHZ,
NL80211_BAND_6GHZ,
NL80211_BAND_S1GHZ,
+ NL80211_BAND_LC,
NUM_NL80211_BANDS,
};
@@ -5462,7 +5671,7 @@
* => allows 8 of AP/GO that can have BI gcd >= min gcd
*
* numbers = [ #{STA} <= 2 ], channels = 2, max = 2
- * => allows two STAs on different channels
+ * => allows two STAs on the same or on different channels
*
* numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
* => allows a STA plus three P2P interfaces
@@ -5507,7 +5716,7 @@
* @NL80211_PLINK_ESTAB: mesh peer link is established
* @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled
* @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh
- * plink are discarded
+ * plink are discarded, except for authentication frames
* @NUM_NL80211_PLINK_STATES: number of peer link states
* @MAX_NL80211_PLINK_STATES: highest numerical value of plink states
*/
@@ -5644,13 +5853,15 @@
NL80211_TDLS_DISABLE_LINK,
};
-/*
+/**
* enum nl80211_ap_sme_features - device-integrated AP features
- * Reserved for future use, no bits are defined in
- * NL80211_ATTR_DEVICE_AP_SME yet.
-enum nl80211_ap_sme_features {
-};
+ * @NL80211_AP_SME_SA_QUERY_OFFLOAD: SA Query procedures offloaded to driver
+ * when user space indicates support for SA Query procedures offload during
+ * "start ap" with %NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT.
*/
+enum nl80211_ap_sme_features {
+ NL80211_AP_SME_SA_QUERY_OFFLOAD = 1 << 0,
+};
/**
* enum nl80211_feature_flags - device/driver features
@@ -5950,6 +6161,17 @@
* frame protection for all management frames exchanged during the
* negotiation and range measurement procedure.
*
+ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
+ * detection and change announcemnts.
+ *
+ * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD: Driver running in AP mode supports
+ * FILS encryption and decryption for (Re)Association Request and Response
+ * frames. Userspace has to share FILS AAD details to the driver by using
+ * @NL80211_CMD_SET_FILS_AAD.
+ *
+ * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC
+ * detection.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -6014,6 +6236,9 @@
NL80211_EXT_FEATURE_SECURE_LTF,
NL80211_EXT_FEATURE_SECURE_RTT,
NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
+ NL80211_EXT_FEATURE_BSS_COLOR,
+ NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD,
+ NL80211_EXT_FEATURE_RADAR_BACKGROUND,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6912,6 +7137,9 @@
* @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only
* valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or
* %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set.
+ * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the
+ * responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED
+ * or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set.
*
* @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
* @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
@@ -6931,6 +7159,7 @@
NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED,
NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED,
NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK,
+ NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR,
/* keep last */
NUM_NL80211_PMSR_FTM_REQ_ATTR,
@@ -7299,4 +7528,76 @@
NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1,
};
+/**
+ * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced
+ * multi-BSSID advertisements (EMA) in AP mode.
+ * Kernel uses some of these attributes to advertise driver's support for
+ * MBSSID and EMA.
+ * Remaining attributes should be used by the userspace to configure the
+ * features.
+ *
+ * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise
+ * the maximum number of MBSSID interfaces supported by the driver.
+ * Driver should indicate MBSSID support by setting
+ * wiphy->mbssid_max_interfaces to a value more than or equal to 2.
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel
+ * to advertise the maximum profile periodicity supported by the driver
+ * if EMA is enabled. Driver should indicate EMA support to the userspace
+ * by setting wiphy->ema_max_profile_periodicity to
+ * a non-zero value.
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of
+ * this BSS (u8) in the multiple BSSID set.
+ * Value must be set to 0 for the transmitting interface and non-zero for
+ * all non-transmitting interfaces. The userspace will be responsible
+ * for using unique indices for the interfaces.
+ * Range: 0 to wiphy->mbssid_max_interfaces-1.
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for
+ * a non-transmitted profile which provides the interface index (u32) of
+ * the transmitted profile. The value must match one of the interface
+ * indices advertised by the kernel. Optional if the interface being set up
+ * is the transmitting one, however, if provided then the value must match
+ * the interface index of the same.
+ *
+ * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature.
+ * Setting this flag is permitted only if the driver advertises EMA support
+ * by setting wiphy->ema_max_profile_periodicity to non-zero.
+ *
+ * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal
+ * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute
+ */
+enum nl80211_mbssid_config_attributes {
+ __NL80211_MBSSID_CONFIG_ATTR_INVALID,
+
+ NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES,
+ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY,
+ NL80211_MBSSID_CONFIG_ATTR_INDEX,
+ NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX,
+ NL80211_MBSSID_CONFIG_ATTR_EMA,
+
+ /* keep last */
+ __NL80211_MBSSID_CONFIG_ATTR_LAST,
+ NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_ap_settings_flags - AP settings flags
+ *
+ * @NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external
+ * authentication.
+ * @NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT: Userspace supports SA Query
+ * procedures offload to driver. If driver advertises
+ * %NL80211_AP_SME_SA_QUERY_OFFLOAD in AP SME features, userspace shall
+ * ignore SA Query procedures and validations when this flag is set by
+ * userspace.
+ */
+enum nl80211_ap_settings_flags {
+ NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = 1 << 0,
+ NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 70999c4..3346ec5 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -72,7 +72,7 @@
EAP_TYPE_MD5 = 4, /* RFC 3748 */
EAP_TYPE_OTP = 5 /* RFC 3748 */,
EAP_TYPE_GTC = 6, /* RFC 3748 */
- EAP_TYPE_TLS = 13 /* RFC 2716 */,
+ EAP_TYPE_TLS = 13 /* RFC 5216 */,
EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
EAP_TYPE_SIM = 18 /* RFC 4186 */,
EAP_TYPE_TTLS = 21 /* RFC 5281 */,
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 5fd370f..276dca3 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1684,6 +1684,7 @@
struct wpabuf *resp;
const u8 *identity;
size_t identity_len;
+ struct wpabuf *privacy_identity = NULL;
if (config == NULL) {
wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
@@ -1706,6 +1707,30 @@
identity_len = config->machine_identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
identity, identity_len);
+ } else if (config->imsi_privacy_key && config->identity &&
+ config->identity_len > 0) {
+ const u8 *pos = config->identity;
+ const u8 *end = config->identity + config->identity_len;
+
+ privacy_identity = wpabuf_alloc(9 + config->identity_len);
+ if (!privacy_identity)
+ return NULL;
+
+ /* Include method prefix */
+ if (*pos == '0' || *pos == '1' || *pos == '6')
+ wpabuf_put_u8(privacy_identity, *pos);
+ wpabuf_put_str(privacy_identity, "anonymous");
+
+ /* Include realm */
+ while (pos < end && *pos != '@')
+ pos++;
+ wpabuf_put_data(privacy_identity, pos, end - pos);
+
+ identity = wpabuf_head(privacy_identity);
+ identity_len = wpabuf_len(privacy_identity);
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP: using IMSI privacy anonymous identity",
+ identity, identity_len);
} else {
identity = config->identity;
identity_len = config->identity_len;
@@ -1742,6 +1767,7 @@
return NULL;
wpabuf_put_data(resp, identity, identity_len);
+ wpabuf_free(privacy_identity);
return resp;
}
@@ -2157,6 +2183,11 @@
eap_notify_status(sm, "remote TLS alert",
data->alert.description);
break;
+ case TLS_UNSAFE_RENEGOTIATION_DISABLED:
+ wpa_printf(MSG_INFO,
+ "TLS handshake failed due to the server not supporting safe renegotiation (RFC 5746); phase1 parameter allow_unsafe_renegotiation=1 can be used to work around this");
+ eap_notify_status(sm, "unsafe server renegotiation", "failure");
+ break;
}
os_free(hash_hex);
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 8c475f1..8caae1d 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "pcsc_funcs.h"
#include "crypto/crypto.h"
#include "crypto/sha1.h"
@@ -58,6 +59,7 @@
u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
size_t last_kdf_count;
int error_code;
+ struct crypto_rsa_key *imsi_privacy_key;
};
@@ -101,6 +103,25 @@
data->eap_method = EAP_TYPE_AKA;
+ if (config && config->imsi_privacy_key) {
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ data->imsi_privacy_key = crypto_rsa_key_read(
+ config->imsi_privacy_key, false);
+ if (!data->imsi_privacy_key) {
+ wpa_printf(MSG_ERROR,
+ "EAP-AKA: Failed to read/parse IMSI privacy key %s",
+ config->imsi_privacy_key);
+ os_free(data);
+ return NULL;
+ }
+#else /* CRYPTO_RSA_OAEP_SHA256 */
+ wpa_printf(MSG_ERROR,
+ "EAP-AKA: No support for imsi_privacy_key in the build");
+ os_free(data);
+ return NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+ }
+
/* Zero is a valid error code, so we need to initialize */
data->error_code = NO_EAP_METHOD_ERROR;
@@ -160,6 +181,9 @@
wpabuf_free(data->id_msgs);
os_free(data->network_name);
eap_aka_clear_keys(data, 0);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(data->imsi_privacy_key);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
os_free(data);
}
}
@@ -617,6 +641,47 @@
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+static struct wpabuf *
+eap_aka_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
+ const u8 *identity, size_t identity_len)
+{
+ struct wpabuf *imsi_buf, *enc;
+ char *b64;
+ size_t b64_len;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypt permanent identity",
+ identity, identity_len);
+
+ imsi_buf = wpabuf_alloc_copy(identity, identity_len);
+ if (!imsi_buf)
+ return NULL;
+ enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf);
+ wpabuf_free(imsi_buf);
+ if (!enc)
+ return NULL;
+
+ b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len);
+ wpabuf_free(enc);
+ if (!b64)
+ return NULL;
+
+ enc = wpabuf_alloc(1 + b64_len);
+ if (!enc) {
+ os_free(b64);
+ return NULL;
+ }
+ wpabuf_put_u8(enc, '\0');
+ wpabuf_put_data(enc, b64, b64_len);
+ os_free(b64);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypted permanent identity",
+ wpabuf_head(enc), wpabuf_len(enc));
+
+ return enc;
+}
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
+
static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm,
struct eap_aka_data *data,
u8 id,
@@ -625,6 +690,7 @@
const u8 *identity = NULL;
size_t identity_len = 0;
struct eap_sim_msg *msg;
+ struct wpabuf *enc_identity = NULL;
data->reauth = 0;
if (id_req == ANY_ID && data->reauth_id) {
@@ -649,6 +715,22 @@
ids &= ~CLEAR_PSEUDONYM;
eap_aka_clear_identities(sm, data, ids);
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ if (identity && data->imsi_privacy_key) {
+ enc_identity = eap_aka_encrypt_identity(
+ data->imsi_privacy_key,
+ identity, identity_len);
+ if (!enc_identity) {
+ wpa_printf(MSG_INFO,
+ "EAP-AKA: Failed to encrypt permanent identity");
+ return eap_aka_client_error(
+ data, id,
+ EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+ }
+ identity = wpabuf_head(enc_identity);
+ identity_len = wpabuf_len(enc_identity);
+ }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
}
if (id_req != NO_ID_REQ)
eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
@@ -663,6 +745,7 @@
eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
identity, identity_len);
}
+ wpabuf_free(enc_identity);
return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0);
}
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 3238f74..eaf514b 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -104,24 +104,6 @@
char *private_key_passwd;
/**
- * dh_file - File path to DH/DSA parameters file (in PEM format)
- *
- * This is an optional configuration file for setting parameters for an
- * ephemeral DH key exchange. In most cases, the default RSA
- * authentication does not use this configuration. However, it is
- * possible setup RSA to use ephemeral DH key exchange. In addition,
- * ciphers with DSA keys always use ephemeral DH keys. This can be used
- * to achieve forward secrecy. If the file is in DSA parameters format,
- * it will be automatically converted into DH params. Full path to the
- * file should be used since working directory may change when
- * wpa_supplicant is run in the background.
- *
- * Alternatively, a named configuration blob can be used by setting
- * this to blob://blob_name.
- */
- char *dh_file;
-
- /**
* subject_match - Constraint for server certificate subject
*
* This substring is matched against the subject of the authentication
@@ -336,6 +318,16 @@
size_t imsi_identity_len;
/**
+ * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate)
+ *
+ * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
+ * identity (IMSI) to improve privacy. The X.509v3 certificate needs to
+ * include a 2048-bit RSA public key and this is from the operator who
+ * authenticates the SIM/USIM.
+ */
+ char *imsi_privacy_key;
+
+ /**
* machine_identity - EAP Identity for machine credential
*
* This field is used to set the machine identity or NAI for cases where
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 0986627..3b4c836 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -9,7 +9,9 @@
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "pcsc_funcs.h"
+#include "crypto/crypto.h"
#include "crypto/milenage.h"
#include "crypto/random.h"
#include "eap_peer/eap_i.h"
@@ -49,6 +51,7 @@
int result_ind, use_result_ind;
int use_pseudonym;
int error_code;
+ struct crypto_rsa_key *imsi_privacy_key;
};
@@ -98,6 +101,25 @@
return NULL;
}
+ if (config && config->imsi_privacy_key) {
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ data->imsi_privacy_key = crypto_rsa_key_read(
+ config->imsi_privacy_key, false);
+ if (!data->imsi_privacy_key) {
+ wpa_printf(MSG_ERROR,
+ "EAP-SIM: Failed to read/parse IMSI privacy key %s",
+ config->imsi_privacy_key);
+ os_free(data);
+ return NULL;
+ }
+#else /* CRYPTO_RSA_OAEP_SHA256 */
+ wpa_printf(MSG_ERROR,
+ "EAP-SIM: No support for imsi_privacy_key in the build");
+ os_free(data);
+ return NULL;
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+ }
+
/* Zero is a valid error code, so we need to initialize */
data->error_code = NO_EAP_METHOD_ERROR;
@@ -162,6 +184,9 @@
os_free(data->reauth_id);
os_free(data->last_eap_identity);
eap_sim_clear_keys(data, 0);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ crypto_rsa_key_free(data->imsi_privacy_key);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
os_free(data);
}
}
@@ -481,6 +506,47 @@
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+static struct wpabuf *
+eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key,
+ const u8 *identity, size_t identity_len)
+{
+ struct wpabuf *imsi_buf, *enc;
+ char *b64;
+ size_t b64_len;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypt permanent identity",
+ identity, identity_len);
+
+ imsi_buf = wpabuf_alloc_copy(identity, identity_len);
+ if (!imsi_buf)
+ return NULL;
+ enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf);
+ wpabuf_free(imsi_buf);
+ if (!enc)
+ return NULL;
+
+ b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len);
+ wpabuf_free(enc);
+ if (!b64)
+ return NULL;
+
+ enc = wpabuf_alloc(1 + b64_len);
+ if (!enc) {
+ os_free(b64);
+ return NULL;
+ }
+ wpabuf_put_u8(enc, '\0');
+ wpabuf_put_data(enc, b64, b64_len);
+ os_free(b64);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypted permanent identity",
+ wpabuf_head(enc), wpabuf_len(enc));
+
+ return enc;
+}
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
+
+
static struct wpabuf * eap_sim_response_start(struct eap_sm *sm,
struct eap_sim_data *data, u8 id,
enum eap_sim_id_req id_req)
@@ -489,6 +555,7 @@
size_t identity_len = 0;
struct eap_sim_msg *msg;
struct wpabuf *resp;
+ struct wpabuf *enc_identity = NULL;
data->reauth = 0;
if (id_req == ANY_ID && data->reauth_id) {
@@ -513,6 +580,22 @@
ids &= ~CLEAR_PSEUDONYM;
eap_sim_clear_identities(sm, data, ids);
}
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ if (identity && data->imsi_privacy_key) {
+ enc_identity = eap_sim_encrypt_identity(
+ data->imsi_privacy_key,
+ identity, identity_len);
+ if (!enc_identity) {
+ wpa_printf(MSG_INFO,
+ "EAP-SIM: Failed to encrypt permanent identity");
+ return eap_sim_client_error(
+ data, id,
+ EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+ }
+ identity = wpabuf_head(enc_identity);
+ identity_len = wpabuf_len(enc_identity);
+ }
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
}
if (id_req != NO_ID_REQ)
eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
@@ -526,6 +609,7 @@
eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len,
identity, identity_len);
}
+ wpabuf_free(enc_identity);
if (!data->reauth) {
wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT",
data->nonce_mt, EAP_SIM_NONCE_MT_LEN);
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index 0d479f1..4167e99 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -1,5 +1,5 @@
/*
- * EAP peer method: EAP-TLS (RFC 2716)
+ * EAP peer method: EAP-TLS (RFC 5216, RFC 9190)
* Copyright (c) 2004-2008, 2012-2019, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
@@ -26,6 +26,7 @@
void *ssl_ctx;
u8 eap_type;
struct wpabuf *pending_resp;
+ bool prot_success_received;
};
@@ -302,15 +303,20 @@
return NULL;
}
- /* draft-ietf-emu-eap-tls13-13 Section 2.5 */
+ /* RFC 9190 Section 2.5 */
if (res == 2 && data->ssl.tls_v13 && wpabuf_len(resp) == 1 &&
*wpabuf_head_u8(resp) == 0) {
- wpa_printf(MSG_DEBUG, "EAP-TLS: ACKing Commitment Message");
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: ACKing protected success indication (appl data 0x00)");
eap_peer_tls_reset_output(&data->ssl);
res = 1;
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ data->prot_success_received = true;
}
- if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
+ if (tls_connection_established(data->ssl_ctx, data->ssl.conn) &&
+ (!data->ssl.tls_v13 || data->prot_success_received))
eap_tls_success(sm, data, ret);
if (res == 1) {
@@ -335,6 +341,7 @@
wpabuf_free(data->pending_resp);
data->pending_resp = NULL;
+ data->prot_success_received = false;
}
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 1aaca36..3050456 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -102,6 +102,10 @@
params->flags |= TLS_CONN_SUITEB_NO_ECDH;
if (os_strstr(txt, "tls_suiteb_no_ecdh=0"))
params->flags &= ~TLS_CONN_SUITEB_NO_ECDH;
+ if (os_strstr(txt, "allow_unsafe_renegotiation=1"))
+ params->flags |= TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION;
+ if (os_strstr(txt, "allow_unsafe_renegotiation=0"))
+ params->flags &= ~TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION;
}
@@ -113,7 +117,6 @@
params->client_cert = config->client_cert;
params->private_key = config->private_key;
params->private_key_passwd = config->private_key_passwd;
- params->dh_file = config->dh_file;
params->subject_match = config->subject_match;
params->altsubject_match = config->altsubject_match;
params->check_cert_subject = config->check_cert_subject;
@@ -192,18 +195,20 @@
* TLS v1.3 changes, so disable this by default for now. */
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
}
+#ifndef EAP_TLSV1_3
if (data->eap_type == EAP_TYPE_TLS ||
data->eap_type == EAP_UNAUTH_TLS_TYPE ||
data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) {
/* While the current EAP-TLS implementation is more or less
- * complete for TLS v1.3, there has been no interoperability
- * testing with other implementations, so disable for by default
- * for now until there has been chance to confirm that no
- * significant interoperability issues show up with TLS version
- * update.
+ * complete for TLS v1.3, there has been only minimal
+ * interoperability testing with other implementations, so
+ * disable it by default for now until there has been chance to
+ * confirm that no significant interoperability issues show up
+ * with TLS version update.
*/
params->flags |= TLS_CONN_DISABLE_TLSv1_3;
}
+#endif /* EAP_TLSV1_3 */
if (phase2 && sm->use_machine_cred) {
wpa_printf(MSG_DEBUG, "TLS: using machine config options");
eap_tls_params_from_conf2m(params, config);
@@ -228,9 +233,7 @@
¶ms->client_cert_blob_len) ||
eap_tls_check_blob(sm, ¶ms->private_key,
¶ms->private_key_blob,
- ¶ms->private_key_blob_len) ||
- eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob,
- ¶ms->dh_blob_len)) {
+ ¶ms->private_key_blob_len)) {
wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
return -1;
}
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index c401915..c8e2de0 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -1473,11 +1473,11 @@
goto start;
}
- /* draft-ietf-emu-eap-tls13-13 Section 2.5 */
+ /* RFC 9190 Section 2.5 */
if (data->ssl.tls_v13 && wpabuf_len(in_decrypted) == 1 &&
*wpabuf_head_u8(in_decrypted) == 0) {
wpa_printf(MSG_DEBUG,
- "EAP-TTLS: ACKing EAP-TLS Commitment Message");
+ "EAP-TLS: ACKing protected success indication (appl data 0x00)");
eap_peer_tls_reset_output(&data->ssl);
wpabuf_free(in_decrypted);
return 1;
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 61032cc..2894cfb 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -124,6 +124,9 @@
* callback context.
*/
void *eap_sim_db_priv;
+
+ struct crypto_rsa_key *imsi_privacy_key;
+
bool backend_auth;
int eap_server;
@@ -258,6 +261,10 @@
unsigned int max_auth_rounds;
unsigned int max_auth_rounds_short;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ bool skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
};
struct eap_session_data {
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index e9bf030..5fb19e9 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
#include "crypto/sha256.h"
#include "crypto/crypto.h"
#include "crypto/random.h"
@@ -737,11 +738,8 @@
sm->identity, sm->identity_len);
username = sim_get_username(sm->identity, sm->identity_len);
- if (username == NULL) {
- data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
- eap_aka_state(data, NOTIFICATION);
- return;
- }
+ if (!username)
+ goto fail;
if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
os_free(username);
@@ -785,16 +783,87 @@
username);
os_strlcpy(data->permanent, username, sizeof(data->permanent));
os_free(username);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ } else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
+ char *enc_id, *pos, *end;
+ size_t enc_id_len;
+ u8 *decoded_id;
+ size_t decoded_id_len;
+ struct wpabuf *enc, *dec;
+ u8 *new_id;
+
+ os_free(username);
+ if (!sm->cfg->imsi_privacy_key) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
+ goto fail;
+ }
+
+ enc_id = (char *) &sm->identity[1];
+ end = (char *) &sm->identity[sm->identity_len];
+ for (pos = enc_id; pos < end; pos++) {
+ if (*pos == ',')
+ break;
+ }
+ enc_id_len = pos - enc_id;
+
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-AKA: Encrypted permanent identity",
+ enc_id, enc_id_len);
+ decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
+ if (!decoded_id) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Could not base64 decode encrypted identity");
+ goto fail;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-AKA: Decoded encrypted permanent identity",
+ decoded_id, decoded_id_len);
+ enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
+ os_free(decoded_id);
+ if (!enc)
+ goto fail;
+ dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
+ enc);
+ wpabuf_free(enc);
+ if (!dec) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-AKA: Failed to decrypt encrypted identity");
+ goto fail;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Decrypted permanent identity",
+ wpabuf_head(dec), wpabuf_len(dec));
+ username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
+ if (!username) {
+ wpabuf_free(dec);
+ goto fail;
+ }
+ new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
+ if (!new_id) {
+ wpabuf_free(dec);
+ goto fail;
+ }
+ os_free(sm->identity);
+ sm->identity = new_id;
+ sm->identity_len = wpabuf_len(dec);
+ wpabuf_free(dec);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
} else {
wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
username);
os_free(username);
- data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
- eap_aka_state(data, NOTIFICATION);
+ goto fail;
return;
}
eap_aka_fullauth(sm, data);
+ return;
+
+fail:
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
}
diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c
index eac3245..5440670 100644
--- a/src/eap_server/eap_server_eke.c
+++ b/src/eap_server/eap_server_eke.c
@@ -276,6 +276,7 @@
if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
+ wpabuf_free(msg);
eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
return eap_eke_build_failure(data, id);
}
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index f526e8b..998d0e8 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -56,6 +56,10 @@
};
+static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
+ int vendor, enum eap_type eap_type);
+
+
static const char * eap_peap_state_txt(int state)
{
switch (state) {
@@ -558,10 +562,24 @@
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
"starting Phase2");
eap_peap_state(data, PHASE2_START);
+ if (data->ssl.tls_v13 && data->ssl.tls_out &&
+ wpabuf_len(data->ssl.tls_out) == 0) {
+ /* This can happen with TLS 1.3 when a new
+ * session ticket is not generated and the
+ * Finished message from the peer terminates
+ * Phase 1. */
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: No pending data to send - move directly to Phase 2 ID query");
+ eap_peap_state(data, PHASE2_ID);
+ eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF,
+ EAP_TYPE_IDENTITY);
+ goto phase2_id;
+ }
}
break;
case PHASE2_ID:
case PHASE2_METHOD:
+ phase2_id:
wpabuf_free(data->ssl.tls_out);
data->ssl.tls_out_pos = 0;
data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 8a68289..1bcf26c 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -9,6 +9,8 @@
#include "includes.h"
#include "common.h"
+#include "utils/base64.h"
+#include "crypto/crypto.h"
#include "crypto/random.h"
#include "eap_server/eap_i.h"
#include "eap_common/eap_sim_common.h"
@@ -512,6 +514,73 @@
username);
os_strlcpy(data->permanent, username, sizeof(data->permanent));
os_free(username);
+#ifdef CRYPTO_RSA_OAEP_SHA256
+ } else if (sm->identity_len > 1 && sm->identity[0] == '\0') {
+ char *enc_id, *pos, *end;
+ size_t enc_id_len;
+ u8 *decoded_id;
+ size_t decoded_id_len;
+ struct wpabuf *enc, *dec;
+ u8 *new_id;
+
+ os_free(username);
+ if (!sm->cfg->imsi_privacy_key) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Received encrypted identity, but no IMSI privacy key configured to decrypt it");
+ goto failed;
+ }
+
+ enc_id = (char *) &sm->identity[1];
+ end = (char *) &sm->identity[sm->identity_len];
+ for (pos = enc_id; pos < end; pos++) {
+ if (*pos == ',')
+ break;
+ }
+ enc_id_len = pos - enc_id;
+
+ wpa_hexdump_ascii(MSG_DEBUG,
+ "EAP-SIM: Encrypted permanent identity",
+ enc_id, enc_id_len);
+ decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len);
+ if (!decoded_id) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Could not base64 decode encrypted identity");
+ goto failed;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "EAP-SIM: Decoded encrypted permanent identity",
+ decoded_id, decoded_id_len);
+ enc = wpabuf_alloc_copy(decoded_id, decoded_id_len);
+ os_free(decoded_id);
+ if (!enc)
+ goto failed;
+ dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key,
+ enc);
+ wpabuf_free(enc);
+ if (!dec) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-SIM: Failed to decrypt encrypted identity");
+ goto failed;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Decrypted permanent identity",
+ wpabuf_head(dec), wpabuf_len(dec));
+ username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec));
+ if (!username) {
+ wpabuf_free(dec);
+ goto failed;
+ }
+ new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec));
+ if (!new_id) {
+ wpabuf_free(dec);
+ goto failed;
+ }
+ os_free(sm->identity);
+ sm->identity = new_id;
+ sm->identity_len = wpabuf_len(dec);
+ wpabuf_free(dec);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+#endif /* CRYPTO_RSA_OAEP_SHA256 */
} else {
wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
username);
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 00a496f..443c293 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -1,5 +1,5 @@
/*
- * hostapd / EAP-TLS (RFC 2716)
+ * hostapd / EAP-TLS (RFC 5216, RFC 9190)
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
@@ -306,6 +306,14 @@
wpa_printf(MSG_DEBUG,
"EAP-TLS: Resuming previous session");
+
+ if (data->ssl.tls_v13 && data->ssl.tls_out) {
+ wpa_hexdump_buf(MSG_DEBUG,
+ "EAP-TLS: Additional data to be sent for TLS 1.3",
+ data->ssl.tls_out);
+ return;
+ }
+
eap_tls_state(data, SUCCESS);
tls_connection_set_success_data_resumed(data->ssl.conn);
/* TODO: Cache serial number with session and update EAP user
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index a9b53b1..717af2e 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -94,6 +94,11 @@
if (data->tls_out_limit > 100)
data->tls_out_limit -= 100;
}
+
+#ifdef CONFIG_TESTING_OPTIONS
+ data->skip_prot_success = sm->cfg->skip_prot_success;
+#endif /* CONFIG_TESTING_OPTIONS */
+
return 0;
}
@@ -367,14 +372,14 @@
sm->cfg->ssl_ctx, data->conn);
/*
- * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5
+ * RFC 9190 Section 2.5
*
* We need to signal the other end that TLS negotiation is done. We
* can't send a zero-length application data message, so we send
* application data which is one byte of zero.
*
* Note this is only done for when there is no application data to be
- * sent. So this is done always for EAP-TLS but notibly not for PEAP
+ * sent. So this is done always for EAP-TLS but notably not for PEAP
* even on resumption.
*/
if (data->tls_v13 &&
@@ -390,8 +395,15 @@
break;
/* fallthrough */
case EAP_TYPE_TLS:
+#ifdef CONFIG_TESTING_OPTIONS
+ if (data->skip_prot_success) {
+ wpa_printf(MSG_INFO,
+ "TESTING: Do not send protected success indication");
+ break;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
wpa_printf(MSG_DEBUG,
- "EAP-TLS: Send Commitment Message");
+ "EAP-TLS: Send protected success indication (appl data 0x00)");
plain = wpabuf_alloc(1);
if (!plain)
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index b0723a1..ad28c79 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -55,6 +55,8 @@
* tls_v13 - Whether TLS v1.3 or newer is used
*/
int tls_v13;
+
+ bool skip_prot_success; /* testing behavior only for TLS v1.3 */
};
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 5fe89c6..61b7039 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -23,6 +23,7 @@
size_t eap_req_id_text_len;
int erp_send_reauth_start;
char *erp_domain; /* a copy of this will be allocated */
+ bool eap_skip_prot_success;
/* Opaque context pointer to owner data for callback functions */
void *ctx;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 7d21f68..a203606 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -508,7 +508,7 @@
return;
}
- for (i = 0, j = 0; i < P2P_MAX_REG_CLASSES; i++) {
+ for (i = 0, j = 0; i < src->reg_classes; i++) {
if (is_6ghz_op_class(src->reg_class[i].reg_class))
continue;
os_memcpy(&dst->reg_class[j], &src->reg_class[i],
diff --git a/src/pae/ieee802_1x_cp.c b/src/pae/ieee802_1x_cp.c
index cf41d8d..2bf3e8e 100644
--- a/src/pae/ieee802_1x_cp.c
+++ b/src/pae/ieee802_1x_cp.c
@@ -20,7 +20,7 @@
#define STATE_MACHINE_DATA struct ieee802_1x_cp_sm
#define STATE_MACHINE_DEBUG_PREFIX "CP"
-static u64 default_cs_id = CS_ID_GCM_AES_128;
+static u64 cs_id[] = { CS_ID_GCM_AES_128, CS_ID_GCM_AES_256 };
/* The variable defined in clause 12 in IEEE Std 802.1X-2010 */
enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE };
@@ -210,7 +210,6 @@
sm->replay_protect = sm->kay->macsec_replay_protect;
sm->validate_frames = sm->kay->macsec_validate;
- /* NOTE: now no other than default cipher suite (AES-GCM-128) */
sm->current_cipher_suite = sm->cipher_suite;
secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
@@ -473,8 +472,8 @@
sm->orx = false;
sm->otx = false;
- sm->current_cipher_suite = default_cs_id;
- sm->cipher_suite = default_cs_id;
+ sm->current_cipher_suite = cs_id[kay->macsec_csindex];
+ sm->cipher_suite = cs_id[kay->macsec_csindex];
sm->cipher_offset = CONFIDENTIALITY_OFFSET_0;
sm->confidentiality_offset = sm->cipher_offset;
sm->transmit_delay = MKA_LIFE_TIME;
@@ -491,6 +490,7 @@
secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
secy_cp_control_confidentiality_offset(sm->kay,
sm->confidentiality_offset);
+ secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
SM_STEP_RUN(CP);
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 657de93..a1f8ae9 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -221,8 +221,16 @@
wpa_printf(MSG_DEBUG, "\tKey Number............: %d",
be_to_host32(body->kn));
- /* TODO: Other than GCM-AES-128 case: MACsec Cipher Suite */
- wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", body->sak, 24);
+ if (body_len == 28) {
+ wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:",
+ body->sak, 24);
+ } else if (body_len > CS_ID_LEN - sizeof(body->kn)) {
+ wpa_hexdump(MSG_DEBUG, "\tMACsec Cipher Suite...:",
+ body->sak, CS_ID_LEN);
+ wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:",
+ body->sak + CS_ID_LEN,
+ body_len - CS_ID_LEN - sizeof(body->kn));
+ }
}
@@ -3456,7 +3464,8 @@
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
- u16 port, u8 priority, const char *ifname, const u8 *addr)
+ u16 port, u8 priority, u32 macsec_csindex,
+ const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
@@ -3493,7 +3502,7 @@
kay->dist_time = 0;
kay->pn_exhaustion = PENDING_PN_EXHAUSTION;
- kay->macsec_csindex = DEFAULT_CS_INDEX;
+ kay->macsec_csindex = macsec_csindex;
kay->mka_algindex = DEFAULT_MKA_ALG_INDEX;
kay->mka_version = MKA_VERSION_ID;
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 1d3c2ac..11cf7b7 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -240,7 +240,8 @@
struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
- u16 port, u8 priority, const char *ifname, const u8 *addr);
+ u16 port, u8 priority, u32 macsec_csindex,
+ const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
struct ieee802_1x_mka_participant *
diff --git a/src/radius/radius.c b/src/radius/radius.c
index be16e27..a642280 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -159,7 +159,8 @@
struct radius_attr_type {
- u8 type;
+ u16 type; /* 0..255 for basic types;
+ * (241 << 8) | <ext-type> for extended types */
char *name;
enum {
RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
@@ -260,11 +261,31 @@
RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher",
RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_EXT_TYPE_1, "Extended-Type-1", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_TYPE_2, "Extended-Type-2", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_TYPE_3, "Extended-Type-3", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_TYPE_4, "Extended-Type-4", RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_LONG_EXT_TYPE_1, "Long-Extended-Type-1",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_LONG_EXT_TYPE_2, "Long-Extended-Type-2",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1, "Extended-Vendor-Specific-1",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2, "Extended-Vendor-Specific-2",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3, "Extended-Vendor-Specific-3",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4, "Extended-Vendor-Specific-4",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, "Extended-Vendor-Specific-5",
+ RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6, "Extended-Vendor-Specific-6",
+ RADIUS_ATTR_UNDIST },
};
#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
-static const struct radius_attr_type *radius_get_attr_type(u8 type)
+static const struct radius_attr_type * radius_get_attr_type(u16 type)
{
size_t i;
@@ -277,23 +298,60 @@
}
+static bool radius_is_long_ext_type(u8 type)
+{
+ return type == RADIUS_ATTR_LONG_EXT_TYPE_1 ||
+ type == RADIUS_ATTR_LONG_EXT_TYPE_2;
+}
+
+
+static bool radius_is_ext_type(u8 type)
+{
+ return type >= RADIUS_ATTR_EXT_TYPE_1 &&
+ type <= RADIUS_ATTR_LONG_EXT_TYPE_2;
+}
+
+
static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
{
+ struct radius_attr_hdr_ext *ext = NULL;
const struct radius_attr_type *attr;
int len;
unsigned char *pos;
char buf[1000];
- attr = radius_get_attr_type(hdr->type);
-
- wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
- hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
-
- if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
+ if (hdr->length < sizeof(struct radius_attr_hdr))
return;
- len = hdr->length - sizeof(struct radius_attr_hdr);
- pos = (unsigned char *) (hdr + 1);
+ if (radius_is_ext_type(hdr->type)) {
+ if (hdr->length < 4) {
+ wpa_printf(MSG_INFO,
+ " Invalid attribute %d (too short for extended type)",
+ hdr->type);
+ return;
+ }
+
+ ext = (struct radius_attr_hdr_ext *) hdr;
+ }
+
+ if (ext) {
+ attr = radius_get_attr_type((ext->type << 8) | ext->ext_type);
+ wpa_printf(MSG_INFO, " Attribute %d.%d (%s) length=%d",
+ ext->type, ext->ext_type,
+ attr ? attr->name : "?Unknown?", ext->length);
+ pos = (unsigned char *) (ext + 1);
+ len = ext->length - sizeof(struct radius_attr_hdr_ext);
+ } else {
+ attr = radius_get_attr_type(hdr->type);
+ wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
+ hdr->type, attr ? attr->name : "?Unknown?",
+ hdr->length);
+ pos = (unsigned char *) (hdr + 1);
+ len = hdr->length - sizeof(struct radius_attr_hdr);
+ }
+
+ if (!attr)
+ return;
switch (attr->data_type) {
case RADIUS_ATTR_TEXT:
@@ -627,22 +685,54 @@
}
-struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
- const u8 *data, size_t data_len)
+struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type,
+ const u8 *data, size_t data_len)
{
- size_t buf_needed;
- struct radius_attr_hdr *attr;
+ size_t buf_needed, max_len;
+ struct radius_attr_hdr *attr = NULL;
+ struct radius_attr_hdr_ext *ext;
+ u8 ext_type = 0;
if (TEST_FAIL())
return NULL;
- if (data_len > RADIUS_MAX_ATTR_LEN) {
- wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
- (unsigned long) data_len);
- return NULL;
+ if (type > 255) {
+ if (!radius_is_ext_type(type >> 8)) {
+ wpa_printf(MSG_ERROR,
+ "%s: Undefined extended type %d.%d",
+ __func__, type >> 8, type & 0xff);
+ return NULL;
+ }
+ ext_type = type & 0xff;
+ type >>= 8;
+ } else if (radius_is_ext_type(type)) {
+ wpa_printf(MSG_ERROR, "%s: Unexpected extended type use for %d",
+ __func__, type);
}
- buf_needed = sizeof(*attr) + data_len;
+ if (radius_is_long_ext_type(type)) {
+ size_t hdr_len = sizeof(struct radius_attr_hdr_ext) + 1;
+ size_t plen = 255 - hdr_len;
+ size_t num;
+
+ max_len = 4096;
+ num = (data_len + plen - 1) / plen;
+ if (num == 0)
+ num = 1;
+ buf_needed = num * hdr_len + data_len;
+ } else if (radius_is_ext_type(type)) {
+ max_len = RADIUS_MAX_EXT_ATTR_LEN;
+ buf_needed = sizeof(struct radius_attr_hdr_ext) + data_len;
+ } else {
+ max_len = RADIUS_MAX_ATTR_LEN;
+ buf_needed = sizeof(*attr) + data_len;
+ }
+ if (data_len > max_len) {
+ wpa_printf(MSG_ERROR,
+ "%s: too long attribute (%zu > %zu bytes)",
+ __func__, data_len, max_len);
+ return NULL;
+ }
if (wpabuf_tailroom(msg->buf) < buf_needed) {
/* allocate more space for message buffer */
@@ -651,13 +741,44 @@
msg->hdr = wpabuf_mhead(msg->buf);
}
- attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
- attr->type = type;
- attr->length = sizeof(*attr) + data_len;
- wpabuf_put_data(msg->buf, data, data_len);
+ if (radius_is_long_ext_type(type)) {
+ size_t plen = 255 - sizeof(struct radius_attr_hdr_ext) - 1;
+ size_t alen;
- if (radius_msg_add_attr_to_array(msg, attr))
- return NULL;
+ do {
+ alen = data_len > plen ? plen : data_len;
+ ext = wpabuf_put(msg->buf,
+ sizeof(struct radius_attr_hdr_ext));
+ if (!attr)
+ attr = (struct radius_attr_hdr *) ext;
+ ext->type = type;
+ ext->length = sizeof(*ext) + 1 + alen;
+ ext->ext_type = ext_type;
+ wpabuf_put_u8(msg->buf, data_len > alen ? 0x80 : 0);
+ wpabuf_put_data(msg->buf, data, data_len);
+ data += alen;
+ data_len -= alen;
+ if (radius_msg_add_attr_to_array(
+ msg, (struct radius_attr_hdr *) ext))
+ return NULL;
+ } while (data_len > 0);
+ } else if (radius_is_ext_type(type)) {
+ ext = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr_ext));
+ attr = (struct radius_attr_hdr *) ext;
+ ext->type = type;
+ ext->length = sizeof(*ext) + data_len;
+ ext->ext_type = ext_type;
+ wpabuf_put_data(msg->buf, data, data_len);
+ if (radius_msg_add_attr_to_array(msg, attr))
+ return NULL;
+ } else {
+ attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
+ attr->type = type;
+ attr->length = sizeof(*attr) + data_len;
+ wpabuf_put_data(msg->buf, data, data_len);
+ if (radius_msg_add_attr_to_array(msg, attr))
+ return NULL;
+ }
return attr;
}
@@ -1285,6 +1406,28 @@
}
+int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id,
+ u8 vendor_type, const u8 *data, size_t len)
+{
+ struct radius_attr_hdr *attr;
+ u8 *buf, *pos;
+ size_t alen;
+
+ alen = 4 + 1 + len;
+ buf = os_malloc(alen);
+ if (!buf)
+ return 0;
+ pos = buf;
+ WPA_PUT_BE32(pos, vendor_id);
+ pos += 4;
+ *pos++ = vendor_type;
+ os_memcpy(pos, data, len);
+ attr = radius_msg_add_attr(msg, type, buf, alen);
+ os_free(buf);
+ return attr != NULL;
+}
+
+
int radius_user_password_hide(struct radius_msg *msg,
const u8 *data, size_t data_len,
const u8 *secret, size_t secret_len,
diff --git a/src/radius/radius.h b/src/radius/radius.h
index fb81481..177c64a 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, 2014-2022, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -46,7 +46,15 @@
/* followed by length-2 octets of attribute value */
} STRUCT_PACKED;
+struct radius_attr_hdr_ext {
+ u8 type;
+ u8 length; /* including this header */
+ u8 ext_type;
+ /* followed by length-3 octets of attribute value */
+} STRUCT_PACKED;
+
#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr))
+#define RADIUS_MAX_EXT_ATTR_LEN (255 - sizeof(struct radius_attr_hdr_ext))
enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_USER_PASSWORD = 2,
@@ -113,6 +121,18 @@
RADIUS_ATTR_WLAN_GROUP_CIPHER = 187,
RADIUS_ATTR_WLAN_AKM_SUITE = 188,
RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER = 189,
+ RADIUS_ATTR_EXT_TYPE_1 = 241,
+ RADIUS_ATTR_EXT_TYPE_2 = 242,
+ RADIUS_ATTR_EXT_TYPE_3 = 243,
+ RADIUS_ATTR_EXT_TYPE_4 = 244,
+ RADIUS_ATTR_LONG_EXT_TYPE_1 = 245,
+ RADIUS_ATTR_LONG_EXT_TYPE_2 = 246,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1 = (241 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2 = (242 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3 = (243 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4 = (244 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5 = (245 << 8) | 26,
+ RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6 = (246 << 8) | 26,
};
@@ -188,6 +208,13 @@
RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
};
+/* FreeRADIUS vendor-specific attributes */
+#define RADIUS_VENDOR_ID_FREERADIUS 11344
+/* Extended-Vendor-Specific-5 (245.26; long extended header) */
+enum {
+ RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE = 1,
+ RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG = 2,
+};
/* Hotspot 2.0 - WFA Vendor-specific RADIUS Attributes */
#define RADIUS_VENDOR_ID_WFA 40808
@@ -257,7 +284,7 @@
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len,
int require_message_authenticator);
-struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
+struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type,
const u8 *data, size_t data_len);
struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
int radius_msg_add_eap(struct radius_msg *msg, const u8 *data,
@@ -284,6 +311,8 @@
const u8 *recv_key, size_t recv_key_len);
int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
size_t len);
+int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id,
+ u8 vendor_type, const u8 *data, size_t len);
int radius_user_password_hide(struct radius_msg *msg,
const u8 *data, size_t data_len,
const u8 *secret, size_t secret_len,
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 66a7806..00b7e84 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -2024,6 +2024,13 @@
u8 *rbuf, *key_mic;
size_t kde_len = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->disable_eapol_g2_tx) {
+ wpa_printf(MSG_INFO, "TEST: Disable sending EAPOL-Key 2/2");
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm))
kde_len = OCV_OCI_KDE_LEN;
@@ -3381,6 +3388,9 @@
case WPA_PARAM_OCI_FREQ_FILS_ASSOC:
sm->oci_freq_override_fils_assoc = value;
break;
+ case WPA_PARAM_DISABLE_EAPOL_G2_TX:
+ sm->disable_eapol_g2_tx = value;
+ break;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_DPP2
case WPA_PARAM_DPP_PFS:
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 2e84a22..00fa0bc 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -118,6 +118,7 @@
WPA_PARAM_OCI_FREQ_EAPOL_G2,
WPA_PARAM_OCI_FREQ_FT_ASSOC,
WPA_PARAM_OCI_FREQ_FILS_ASSOC,
+ WPA_PARAM_DISABLE_EAPOL_G2_TX,
};
struct rsn_supp_config {
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 6cdce32..579616f 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -185,6 +185,7 @@
unsigned int oci_freq_override_eapol_g2;
unsigned int oci_freq_override_ft_assoc;
unsigned int oci_freq_override_fils_assoc;
+ unsigned int disable_eapol_g2_tx;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FILS
diff --git a/src/utils/common.c b/src/utils/common.c
index 2c12751..6acfcbd 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -13,7 +13,7 @@
#include "common.h"
-static int hex2num(char c)
+int hex2num(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
diff --git a/src/utils/common.h b/src/utils/common.h
index 45f72bb..435a9a8 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -477,6 +477,7 @@
int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
int hwaddr_compact_aton(const char *txt, u8 *addr);
int hwaddr_aton2(const char *txt, u8 *addr);
+int hex2num(char c);
int hex2byte(const char *hex);
int hexstr2bin(const char *hex, u8 *buf, size_t len);
void inc_byte_array(u8 *counter, size_t len);
diff --git a/src/utils/http-utils.h b/src/utils/http-utils.h
index d9fc925..23e9ecd 100644
--- a/src/utils/http-utils.h
+++ b/src/utils/http-utils.h
@@ -33,6 +33,7 @@
size_t num_othername;
struct http_logo *logo;
size_t num_logo;
+ const char *url;
};
int soap_init_client(struct http_ctx *ctx, const char *address,
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index e62fbf9..30b07f2 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -64,6 +64,7 @@
X509 *peer_issuer_issuer;
const char *last_err;
+ const char *url;
};
@@ -871,6 +872,7 @@
X509 *cert, GENERAL_NAMES **names)
{
os_memset(hcert, 0, sizeof(*hcert));
+ hcert->url = ctx->url ? ctx->url : ctx->svc_address;
*names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
if (*names)
@@ -1617,23 +1619,23 @@
const char *fname, const char *ca_fname)
{
CURL *curl;
- FILE *f;
+ FILE *f = NULL;
CURLcode res;
long http = 0;
+ int ret = -1;
ctx->last_err = NULL;
+ ctx->url = url;
wpa_printf(MSG_DEBUG, "curl: Download file from %s to %s (ca=%s)",
url, fname, ca_fname);
curl = curl_easy_init();
if (curl == NULL)
- return -1;
+ goto fail;
f = fopen(fname, "wb");
- if (f == NULL) {
- curl_easy_cleanup(curl);
- return -1;
- }
+ if (!f)
+ goto fail;
curl_easy_setopt(curl, CURLOPT_URL, url);
if (ca_fname) {
@@ -1655,9 +1657,7 @@
ctx->last_err = curl_easy_strerror(res);
wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s",
ctx->last_err);
- curl_easy_cleanup(curl);
- fclose(f);
- return -1;
+ goto fail;
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http);
@@ -1665,15 +1665,19 @@
if (http != 200) {
ctx->last_err = "HTTP download failed";
wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http);
- curl_easy_cleanup(curl);
- fclose(f);
- return -1;
+ goto fail;
}
- curl_easy_cleanup(curl);
- fclose(f);
+ ret = 0;
- return 0;
+fail:
+ ctx->url = NULL;
+ if (curl)
+ curl_easy_cleanup(curl);
+ if (f)
+ fclose(f);
+
+ return ret;
}
@@ -1686,16 +1690,17 @@
{
long http = 0;
CURLcode res;
- char *ret;
+ char *ret = NULL;
CURL *curl;
struct curl_slist *curl_hdr = NULL;
ctx->last_err = NULL;
+ ctx->url = url;
wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url);
curl = setup_curl_post(ctx, url, ca_fname, username, password,
client_cert, client_key);
if (curl == NULL)
- return NULL;
+ goto fail;
if (content_type) {
char ct[200];
@@ -1715,8 +1720,7 @@
ctx->last_err = curl_easy_strerror(res);
wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s",
ctx->last_err);
- free_curl_buf(ctx);
- return NULL;
+ goto fail;
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http);
@@ -1724,12 +1728,11 @@
if (http != 200) {
ctx->last_err = "HTTP POST failed";
wpa_printf(MSG_INFO, "HTTP POST failed - code %ld", http);
- free_curl_buf(ctx);
- return NULL;
+ goto fail;
}
if (ctx->curl_buf == NULL)
- return NULL;
+ goto fail;
ret = ctx->curl_buf;
if (resp_len)
@@ -1739,6 +1742,9 @@
wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ret);
+fail:
+ free_curl_buf(ctx);
+ ctx->url = NULL;
return ret;
}
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index 0d088bb..db11387 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -301,7 +301,6 @@
"src/common/sae_pk.c",
"src/common/wpa_common.c",
"src/crypto/aes-ctr.c",
- "src/crypto/aes-omac1.c",
"src/crypto/aes-siv.c",
"src/crypto/crypto_openssl.c",
"src/crypto/dh_groups.c",
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index cdf8943..d1436e2 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -119,7 +119,6 @@
ifdef CONFIG_FIPS
CONFIG_NO_RANDOM_POOL=
-CONFIG_OPENSSL_CMAC=y
endif
OBJS = config.c
@@ -515,6 +514,9 @@
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_TLSV1_3
+L_CFLAGS += -DEAP_TLSV1_3
+endif
endif
ifdef CONFIG_EAP_UNAUTH_TLS
@@ -775,6 +777,7 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_ECC=y
NEED_DRAGONFLY=y
+MS_FUNCS=y
endif
ifdef CONFIG_EAP_EKE
@@ -945,6 +948,9 @@
ifdef CONFIG_IEEE80211AX
OBJS += src/ap/ieee802_11_he.c
endif
+ifdef CONFIG_IEEE80211BE
+OBJS += src/ap/ieee802_11_eht.c
+endif
ifdef CONFIG_WNM_AP
L_CFLAGS += -DCONFIG_WNM_AP
OBJS += src/ap/wnm_ap.c
@@ -967,6 +973,10 @@
ifdef CONFIG_IEEE80211AC
L_CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BE
+CONFIG_IEEE80211AX=y
+L_CFLAGS += -DCONFIG_IEEE80211BE
+endif
ifdef CONFIG_IEEE80211AX
L_CFLAGS += -DCONFIG_IEEE80211AX
endif
@@ -1099,6 +1109,7 @@
endif
ifeq ($(CONFIG_TLS), openssl)
+L_CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
ifdef TLS_FUNCS
L_CFLAGS += -DEAP_TLS_OPENSSL
OBJS += src/crypto/tls_openssl.c
@@ -1303,9 +1314,7 @@
AESOBJS += src/crypto/aes-encblock.c
endif
NEED_AES_ENC=y
-ifdef CONFIG_OPENSSL_CMAC
-L_CFLAGS += -DCONFIG_OPENSSL_CMAC
-else
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += src/crypto/aes-omac1.c
endif
ifdef NEED_AES_WRAP
@@ -1399,6 +1408,17 @@
endif
endif
+ifdef CONFIG_SAE
+ifdef NEED_SHA384
+# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled.
+NEED_HMAC_SHA384_KDF=y
+endif
+ifdef NEED_SHA512
+# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled.
+NEED_HMAC_SHA512_KDF=y
+endif
+endif
+
SHA256OBJS = # none by default
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 18ffbcb..1c6911b 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1,24 +1,29 @@
BINALL=wpa_supplicant wpa_cli
-ifndef CONFIG_NO_WPA_PASSPHRASE
-BINALL += wpa_passphrase
-endif
-
ALL = $(BINALL)
ALL += systemd/wpa_supplicant.service
ALL += systemd/wpa_supplicant@.service
ALL += systemd/wpa_supplicant-nl80211@.service
ALL += systemd/wpa_supplicant-wired@.service
ALL += dbus/fi.w1.wpa_supplicant1.service
-ifdef CONFIG_BUILD_WPA_CLIENT_SO
-ALL += libwpa_client.so
-endif
EXTRA_TARGETS=dynamic_eap_methods
CONFIG_FILE=.config
include ../src/build.rules
+ifdef CONFIG_BUILD_WPA_CLIENT_SO
+# add the dependency this way to allow CONFIG_BUILD_WPA_CLIENT_SO
+# being set in the config which is read by build.rules
+_all: libwpa_client.so
+endif
+
+ifndef CONFIG_NO_WPA_PASSPHRASE
+# add the dependency this way to allow CONFIG_NO_WPA_PASSPHRASE
+# being set in the config which is read by build.rules
+_all: wpa_passphrase
+endif
+
ifdef LIBS
# If LIBS is set with some global build system defaults, clone those for
# LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well.
@@ -68,6 +73,9 @@
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL))
$(MAKE) -C ../src install
+ifndef CONFIG_NO_WPA_PASSPHRASE
+ install -D wpa_passphrase $(DESTDIR)/$(BINDIR)/wpa_passphrase
+endif
ifdef CONFIG_BUILD_WPA_CLIENT_SO
install -m 0644 -D libwpa_client.so $(DESTDIR)/$(LIBDIR)/libwpa_client.so
install -m 0644 -D ../src/common/wpa_ctrl.h $(DESTDIR)/$(INCDIR)/wpa_ctrl.h
@@ -79,7 +87,6 @@
ifdef CONFIG_FIPS
CONFIG_NO_RANDOM_POOL=
-CONFIG_OPENSSL_CMAC=y
endif
OBJS = config.o
@@ -484,6 +491,9 @@
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_TLSV1_3
+CFLAGS += -DEAP_TLSV1_3
+endif
endif
ifdef CONFIG_EAP_UNAUTH_TLS
@@ -750,6 +760,7 @@
CONFIG_IEEE8021X_EAPOL=y
NEED_ECC=y
NEED_DRAGONFLY=y
+MS_FUNCS=y
endif
ifdef CONFIG_EAP_EKE
@@ -939,6 +950,9 @@
ifdef CONFIG_IEEE80211AX
OBJS += ../src/ap/ieee802_11_he.o
endif
+ifdef CONFIG_IEEE80211BE
+OBJS += ../src/ap/ieee802_11_eht.o
+endif
ifdef CONFIG_WNM_AP
CFLAGS += -DCONFIG_WNM_AP
OBJS += ../src/ap/wnm_ap.o
@@ -961,6 +975,10 @@
ifdef CONFIG_IEEE80211AC
CFLAGS += -DCONFIG_IEEE80211AC
endif
+ifdef CONFIG_IEEE80211BE
+CONFIG_IEEE80211AX=y
+CFLAGS += -DCONFIG_IEEE80211BE
+endif
ifdef CONFIG_IEEE80211AX
CFLAGS += -DCONFIG_IEEE80211AX
endif
@@ -1107,6 +1125,7 @@
endif
ifeq ($(CONFIG_TLS), openssl)
+CFLAGS += -DCRYPTO_RSA_OAEP_SHA256
ifdef TLS_FUNCS
CFLAGS += -DEAP_TLS_OPENSSL
OBJS += ../src/crypto/tls_openssl.o
@@ -1358,9 +1377,7 @@
AESOBJS += ../src/crypto/aes-encblock.o
endif
NEED_AES_ENC=y
-ifdef CONFIG_OPENSSL_CMAC
-CFLAGS += -DCONFIG_OPENSSL_CMAC
-else
+ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
ifneq ($(CONFIG_TLS), wolfssl)
AESOBJS += ../src/crypto/aes-omac1.o
@@ -1474,6 +1491,17 @@
endif
endif
+ifdef CONFIG_SAE
+ifdef NEED_SHA384
+# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled.
+NEED_HMAC_SHA384_KDF=y
+endif
+ifdef NEED_SHA512
+# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled.
+NEED_HMAC_SHA512_KDF=y
+endif
+endif
+
SHA256OBJS = # none by default
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
@@ -2076,3 +2104,4 @@
rm -f libwpa_client.a
rm -f libwpa_client.so
rm -f libwpa_test1 libwpa_test2
+ rm -f wpa_passphrase
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
index b076621..a099a85 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -168,6 +168,12 @@
# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
# format
#
+# imsi_privacy_key: IMSI privacy key (PEM encoded X.509v3 certificate)
+# This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
+# identity (IMSI) to improve privacy. The X.509v3 certificate needs to
+# include a 2048-bit RSA public key and this is from the operator who
+# authenticates the SIM/USIM.
+#
# domain_suffix_match: Constraint for server domain name
# If set, this FQDN is used as a suffix match requirement for the AAA
# server certificate in SubjectAltName dNSName element(s). If a
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index b884f67..e902cc8 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -24,8 +24,8 @@
environments that require secure network access without chance for
allowing outsiders to gain access during the setup phase.
-WPS uses following terms to describe the entities participating in the
-network setup:
+WPS uses the following terms to describe the entities participating
+in the network setup:
- access point: the WLAN access point
- Registrar: a device that control a network and can authorize
addition of new devices); this may be either in the AP ("internal
@@ -55,22 +55,22 @@
WPS is an optional component that needs to be enabled in
wpa_supplicant build configuration (.config). Here is an example
-configuration that includes WPS support and Linux nl80211 -based
+configuration that includes WPS support and Linux nl80211-based
driver interface:
CONFIG_DRIVER_NL80211=y
CONFIG_WPS=y
If you want to enable WPS external registrar (ER) functionality, you
-will also need to add following line:
+will also need to add the following line:
CONFIG_WPS_ER=y
-Following parameter can be used to enable support for NFC config method:
+The following parameter can be used to enable support for NFC config
+method:
CONFIG_WPS_NFC=y
-
WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
the device. This is configured in the runtime configuration for
wpa_supplicant (if not set, UUID will be generated based on local MAC
@@ -91,7 +91,6 @@
update_config=1
-
External operations
-------------------
@@ -118,7 +117,6 @@
the client will be enrolled with credentials needed to connect to the
AP to access the network.
-
If the client device does not have a display that could show the
random PIN, a hardcoded PIN that is printed on a label can be
used. wpa_supplicant is notified this with a control interface
@@ -135,7 +133,6 @@
wpa_cli wps_pin any 12345670 300
-
If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
can be used to generate a new PIN without starting WPS negotiation.
This random PIN can then be passed as an argument to another wps_pin
@@ -154,7 +151,6 @@
negotiation which will generate a new WPA PSK in the same way as the
PIN method described above.
-
If the client wants to operate in the Registrar role to learn the
current AP configuration and optionally, to configure an AP,
wpa_supplicant is notified over the control interface, e.g., with
@@ -218,7 +214,8 @@
processing the credential attributes and updating wpa_supplicant
configuration based on them.
-Following control interface messages are sent out for external programs:
+The following control interface messages are sent out for external
+programs:
WPS-CRED-RECEIVED <hexdump of Credential attribute(s)>
For example:
@@ -236,7 +233,7 @@
Separate wpa_supplicant process can be started for WPS ER
operations. A special "none" driver can be used in such a case to
indicate that no local network interface is actually controlled. For
-example, following command could be used to start the ER:
+example, the following command could be used to start the ER:
wpa_supplicant -Dnone -c er.conf -ieth0
@@ -245,7 +242,6 @@
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin
device_name=WPS External Registrar
-
wpa_cli commands for ER functionality:
wps_er_start [IP address]
@@ -275,7 +271,6 @@
<auth> must be one of the following: OPEN WPAPSK WPA2PSK
<encr> must be one of the following: NONE WEP TKIP CCMP
-
wps_er_pbc <Enrollee UUID|MAC address>
- accept an Enrollee PBC using External Registrar
@@ -285,7 +280,6 @@
- if the MAC address of the enrollee is known, it should be configured
to allow the AP to advertise list of authorized enrollees
-
WPS ER events:
WPS_EVENT_ER_AP_ADD
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 0559822..7b31d8e 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -1028,6 +1028,7 @@
hapd_iface->extended_capa = wpa_s->extended_capa;
hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
hapd_iface->extended_capa_len = wpa_s->extended_capa_len;
+ hapd_iface->drv_max_acl_mac_addrs = wpa_s->drv_max_acl_mac_addrs;
wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
if (conf == NULL) {
@@ -1105,6 +1106,11 @@
hapd_iface->bss[i]->ext_eapol_frame_io =
wpa_s->ext_eapol_frame_io;
#endif /* CONFIG_TESTING_OPTIONS */
+
+#ifdef CONFIG_WNM_AP
+ if (ssid->mode == WPAS_MODE_AP)
+ hapd_iface->bss[i]->conf->bss_transition = 1;
+#endif /* CONFIG_WNM_AP */
}
os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
@@ -1564,6 +1570,183 @@
return pos - buf;
}
+
+#ifdef CONFIG_WNM_AP
+
+int ap_ctrl_iface_disassoc_imminent(struct wpa_supplicant *wpa_s,
+ const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+ return hostapd_ctrl_iface_disassoc_imminent(hapd, buf);
+}
+
+
+int ap_ctrl_iface_ess_disassoc(struct wpa_supplicant *wpa_s, const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+ return hostapd_ctrl_iface_ess_disassoc(hapd, buf);
+}
+
+
+int ap_ctrl_iface_bss_tm_req(struct wpa_supplicant *wpa_s, const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+ return hostapd_ctrl_iface_bss_tm_req(hapd, buf);
+}
+
+#endif /* CONFIG_WNM_AP */
+
+
+int ap_ctrl_iface_acl_add_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type,
+ const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ hapd->conf->macaddr_acl = acl_type;
+
+ if (acl_type == ACCEPT_UNLESS_DENIED)
+ return hostapd_ctrl_iface_acl_add_mac(&hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac,
+ buf);
+ if (acl_type == DENY_UNLESS_ACCEPTED)
+ return hostapd_ctrl_iface_acl_add_mac(
+ &hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac, buf);
+
+ return -1;
+}
+
+
+int ap_ctrl_iface_acl_del_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type,
+ const char *buf)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ hapd->conf->macaddr_acl = acl_type;
+
+ if (acl_type == ACCEPT_UNLESS_DENIED)
+ return hostapd_ctrl_iface_acl_del_mac(&hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac,
+ buf);
+ if (acl_type == DENY_UNLESS_ACCEPTED)
+ return hostapd_ctrl_iface_acl_del_mac(
+ &hapd->conf->accept_mac, &hapd->conf->num_accept_mac,
+ buf);
+
+ return -1;
+}
+
+
+int ap_ctrl_iface_acl_show_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type, char *buf,
+ size_t buflen)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ if (acl_type == ACCEPT_UNLESS_DENIED)
+ return hostapd_ctrl_iface_acl_show_mac(hapd->conf->deny_mac,
+ hapd->conf->num_deny_mac,
+ buf, buflen);
+ if (acl_type == DENY_UNLESS_ACCEPTED)
+ return hostapd_ctrl_iface_acl_show_mac(
+ hapd->conf->accept_mac, hapd->conf->num_accept_mac,
+ buf, buflen);
+
+ return -1;
+}
+
+
+void ap_ctrl_iface_acl_clear_list(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return;
+
+ hapd->conf->macaddr_acl = acl_type;
+
+ if (acl_type == ACCEPT_UNLESS_DENIED)
+ hostapd_ctrl_iface_acl_clear_list(&hapd->conf->deny_mac,
+ &hapd->conf->num_deny_mac);
+ else if (acl_type == DENY_UNLESS_ACCEPTED)
+ hostapd_ctrl_iface_acl_clear_list(&hapd->conf->accept_mac,
+ &hapd->conf->num_accept_mac);
+}
+
+
+int ap_ctrl_iface_disassoc_deny_mac(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ return hostapd_disassoc_deny_mac(hapd);
+}
+
+
+int ap_ctrl_iface_disassoc_accept_mac(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ return hostapd_disassoc_accept_mac(hapd);
+}
+
+
+int ap_ctrl_iface_set_acl(struct wpa_supplicant *wpa_s)
+{
+ struct hostapd_data *hapd;
+
+ if (wpa_s->ap_iface)
+ hapd = wpa_s->ap_iface->bss[0];
+ else
+ return -1;
+
+ return hostapd_set_acl(hapd);
+}
+
#endif /* CONFIG_CTRL_IFACE */
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 7bc1b78..ccd3e7b 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -10,6 +10,8 @@
#ifndef AP_H
#define AP_H
+enum macaddr_acl;
+
int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
@@ -38,6 +40,22 @@
const char *txtaddr);
int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen, int verbose);
+int ap_ctrl_iface_disassoc_imminent(struct wpa_supplicant *wpa_s,
+ const char *buf);
+int ap_ctrl_iface_ess_disassoc(struct wpa_supplicant *wpa_s, const char *buf);
+int ap_ctrl_iface_bss_tm_req(struct wpa_supplicant *wpa_s, const char *buf);
+int ap_ctrl_iface_acl_add_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type, const char *buf);
+int ap_ctrl_iface_acl_del_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type, const char *buf);
+int ap_ctrl_iface_acl_show_mac(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type, char *buf,
+ size_t buflen);
+void ap_ctrl_iface_acl_clear_list(struct wpa_supplicant *wpa_s,
+ enum macaddr_acl acl_type);
+int ap_ctrl_iface_disassoc_deny_mac(struct wpa_supplicant *wpa_s);
+int ap_ctrl_iface_disassoc_accept_mac(struct wpa_supplicant *wpa_s);
+int ap_ctrl_iface_set_acl(struct wpa_supplicant *wpa_s);
void ap_tx_status(void *ctx, const u8 *addr,
const u8 *buf, size_t len, int ack);
void ap_eapol_tx_status(void *ctx, const u8 *dst,
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index e13783c..429c6e7 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -291,6 +291,7 @@
dst->noise = src->noise;
dst->level = src->level;
dst->tsf = src->tsf;
+ dst->beacon_newer = src->beacon_newer;
dst->est_throughput = src->est_throughput;
dst->snr = src->snr;
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 4078b9b..146aaee 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -108,6 +108,8 @@
int level;
/** Timestamp of last Beacon/Probe Response frame */
u64 tsf;
+ /** Whether the Beacon frame data is known to be newer */
+ bool beacon_newer;
/** Time of the last update (i.e., Beacon or Probe Response RX) */
struct os_reltime last_update;
/** Estimated throughput in kbps */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index f344e1d..c8844bb 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2451,7 +2451,6 @@
{ STRe(client_cert, cert.client_cert) },
{ STRe(private_key, cert.private_key) },
{ STR_KEYe(private_key_passwd, cert.private_key_passwd) },
- { STRe(dh_file, cert.dh_file) },
{ STRe(subject_match, cert.subject_match) },
{ STRe(check_cert_subject, cert.check_cert_subject) },
{ STRe(altsubject_match, cert.altsubject_match) },
@@ -2462,7 +2461,6 @@
{ STRe(client_cert2, phase2_cert.client_cert) },
{ STRe(private_key2, phase2_cert.private_key) },
{ STR_KEYe(private_key2_passwd, phase2_cert.private_key_passwd) },
- { STRe(dh_file2, phase2_cert.dh_file) },
{ STRe(subject_match2, phase2_cert.subject_match) },
{ STRe(check_cert_subject2, phase2_cert.check_cert_subject) },
{ STRe(altsubject_match2, phase2_cert.altsubject_match) },
@@ -2490,7 +2488,6 @@
{ STRe(machine_private_key, machine_cert.private_key) },
{ STR_KEYe(machine_private_key_passwd,
machine_cert.private_key_passwd) },
- { STRe(machine_dh_file, machine_cert.dh_file) },
{ STRe(machine_subject_match, machine_cert.subject_match) },
{ STRe(machine_check_cert_subject, machine_cert.check_cert_subject) },
{ STRe(machine_altsubject_match, machine_cert.altsubject_match) },
@@ -2506,6 +2503,7 @@
{ INTe(machine_ocsp, machine_cert.ocsp) },
{ INT(eapol_flags) },
{ INTe(sim_num, sim_num) },
+ { STRe(imsi_privacy_key, imsi_privacy_key) },
{ STRe(openssl_ciphers, openssl_ciphers) },
{ INTe(erp, erp) },
#endif /* IEEE8021X_EAPOL */
@@ -2612,6 +2610,7 @@
{ INT(macsec_replay_window) },
{ INT_RANGE(macsec_port, 1, 65534) },
{ INT_RANGE(mka_priority, 0, 255) },
+ { INT_RANGE(macsec_csindex, 0, 1) },
{ FUNC_KEY(mka_cak) },
{ FUNC_KEY(mka_ckn) },
#endif /* CONFIG_MACSEC */
@@ -2753,7 +2752,6 @@
os_free(cert->client_cert);
os_free(cert->private_key);
str_clear_free(cert->private_key_passwd);
- os_free(cert->dh_file);
os_free(cert->subject_match);
os_free(cert->check_cert_subject);
os_free(cert->altsubject_match);
@@ -2773,6 +2771,7 @@
bin_clear_free(eap->identity, eap->identity_len);
os_free(eap->anonymous_identity);
os_free(eap->imsi_identity);
+ os_free(eap->imsi_privacy_key);
os_free(eap->machine_identity);
bin_clear_free(eap->password, eap->password_len);
bin_clear_free(eap->machine_password, eap->machine_password_len);
@@ -2876,6 +2875,7 @@
os_free(cred->req_conn_capab_port[i]);
os_free(cred->req_conn_capab_port);
os_free(cred->req_conn_capab_proto);
+ os_free(cred->imsi_privacy_key);
os_free(cred);
}
@@ -3155,6 +3155,26 @@
}
+static const char *removed_fields[] = {
+ "dh_file",
+ "dh_file2",
+ "machine_dh_file",
+ NULL
+};
+
+static bool removed_field(const char *field)
+{
+ int i;
+
+ for (i = 0; removed_fields[i]; i++) {
+ if (os_strcmp(field, removed_fields[i]) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+
/**
* wpa_config_set - Set a variable in network configuration
* @ssid: Pointer to network configuration data
@@ -3203,6 +3223,12 @@
break;
}
if (i == NUM_SSID_FIELDS) {
+ if (removed_field(var)) {
+ wpa_printf(MSG_INFO,
+ "Line %d: Ignore removed configuration field '%s'",
+ line, var);
+ return ret;
+ }
if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown network field "
"'%s'.", line, var);
@@ -3400,8 +3426,11 @@
void wpa_config_update_psk(struct wpa_ssid *ssid)
{
#ifndef CONFIG_NO_PBKDF2
- pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
- ssid->psk, PMK_LEN);
+ if (pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
+ ssid->psk, PMK_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()");
+ return;
+ }
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
ssid->psk, PMK_LEN);
ssid->psk_set = 1;
@@ -3882,6 +3911,12 @@
return 0;
}
+ if (os_strcmp(var, "imsi_privacy_key") == 0) {
+ os_free(cred->imsi_privacy_key);
+ cred->imsi_privacy_key = val;
+ return 0;
+ }
+
if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
line, var);
@@ -4032,6 +4067,9 @@
if (os_strcmp(var, "imsi") == 0)
return alloc_strdup(cred->imsi);
+ if (os_strcmp(var, "imsi_privacy_key") == 0)
+ return alloc_strdup(cred->imsi_privacy_key);
+
if (os_strcmp(var, "milenage") == 0) {
if (!(cred->milenage))
return NULL;
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 696fb38..77d6ab5 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -182,6 +182,16 @@
char *milenage;
/**
+ * imsi_privacy_key - IMSI privacy key (PEM encoded X.509v3 certificate)
+ *
+ * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent
+ * identity (IMSI) to improve privacy. The X.509v3 certificate needs to
+ * include a 2048-bit RSA public key and this is from the operator who
+ * authenticates the SIM/USIM.
+ */
+ char *imsi_privacy_key;
+
+ /**
* engine - Use an engine for private key operations
*/
int engine;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 778da45..978cc6a 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -297,8 +297,8 @@
struct wpa_ssid *ssid, *tail, *head;
struct wpa_cred *cred, *cred_tail, *cred_head;
struct wpa_config *config;
- int id = 0;
- int cred_id = 0;
+ static int id = 0;
+ static int cred_id = 0;
if (name == NULL)
return NULL;
@@ -699,7 +699,6 @@
STR(client_cert);
STR(private_key);
STR(private_key_passwd);
- STR(dh_file);
STR(subject_match);
STR(check_cert_subject);
STR(altsubject_match);
@@ -710,7 +709,6 @@
STR(client_cert2);
STR(private_key2);
STR(private_key2_passwd);
- STR(dh_file2);
STR(subject_match2);
STR(check_cert_subject2);
STR(altsubject_match2);
@@ -721,7 +719,6 @@
STR(machine_client_cert);
STR(machine_private_key);
STR(machine_private_key_passwd);
- STR(machine_dh_file);
STR(machine_subject_match);
STR(machine_check_cert_subject);
STR(machine_altsubject_match);
@@ -810,6 +807,7 @@
INT(macsec_replay_window);
INT(macsec_port);
INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER);
+ INT(macsec_csindex);
#endif /* CONFIG_MACSEC */
#ifdef CONFIG_HS20
INT(update_identifier);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index dd8b1d9..4d3d114 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -911,6 +911,13 @@
int mka_priority;
/**
+ * macsec_csindex - Cipher suite index for MACsec
+ *
+ * Range: 0-1 (default: 0)
+ */
+ int macsec_csindex;
+
+ /**
* mka_ckn - MKA pre-shared CKN
*/
#define MACSEC_CKN_MAX_LEN 32
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 1b7f96e..b27c6cf 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -905,7 +905,6 @@
STR(client_cert);
STR(private_key);
STR(private_key_passwd);
- STR(dh_file);
STR(subject_match);
STR(check_cert_subject);
STR(altsubject_match);
@@ -914,7 +913,6 @@
STR(client_cert2);
STR(private_key2);
STR(private_key2_passwd);
- STR(dh_file2);
STR(subject_match2);
STR(check_cert_subject2);
STR(altsubject_match2);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index dc6c772..e8a8118 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -674,6 +674,9 @@
} else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) {
os_free(wpa_s->dpp_configurator_params);
wpa_s->dpp_configurator_params = os_strdup(value);
+#ifdef CONFIG_DPP2
+ dpp_controller_set_params(wpa_s->dpp, value);
+#endif /* CONFIG_DPP2 */
} else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) {
wpa_s->dpp_init_max_tries = atoi(value);
} else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) {
@@ -836,6 +839,11 @@
wpa_s->disable_scs_support = !!atoi(value);
} else if (os_strcasecmp(cmd, "disable_mscs_support") == 0) {
wpa_s->disable_mscs_support = !!atoi(value);
+ } else if (os_strcasecmp(cmd, "disable_eapol_g2_tx") == 0) {
+ wpa_s->disable_eapol_g2_tx = !!atoi(value);
+ /* Populate value to wpa_sm if already associated. */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX,
+ wpa_s->disable_eapol_g2_tx);
#ifdef CONFIG_DPP
} else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) {
os_free(wpa_s->dpp_config_obj_override);
@@ -2306,11 +2314,12 @@
if (wpa_s->connection_set &&
(wpa_s->connection_ht || wpa_s->connection_vht ||
- wpa_s->connection_he)) {
+ wpa_s->connection_he || wpa_s->connection_eht)) {
ret = os_snprintf(pos, end - pos,
"wifi_generation=%u\n",
- wpa_s->connection_he ? 6 :
- (wpa_s->connection_vht ? 5 : 4));
+ wpa_s->connection_eht ? 7 :
+ (wpa_s->connection_he ? 6 :
+ (wpa_s->connection_vht ? 5 : 4)));
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -8539,6 +8548,7 @@
wpa_s->oci_freq_override_ft_assoc = 0;
wpa_s->oci_freq_override_fils_assoc = 0;
wpa_s->oci_freq_override_wnm_sleep = 0;
+ wpa_s->disable_eapol_g2_tx = 0;
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
wpa_s->dpp_config_obj_override = NULL;
@@ -8592,6 +8602,8 @@
if (wpa_s->mac_addr_changed && wpa_s->conf->mac_addr == 0)
wpas_restore_permanent_mac_addr(wpa_s);
+
+ wpa_s->conf->ignore_old_scan_res = 0;
}
@@ -9984,8 +9996,9 @@
int flow_id = 0;
bool protection = false;
u8 twt_channel = 0;
- u8 control = BIT(4); /* Control field (IEEE P802.11ax/D8.0 Figure
- * 9-687): B4 = TWT Information Frame Disabled */
+ u8 control = BIT(4); /* Control field (IEEE Std 802.11ax-2021,
+ * Figure 9-687 - Control field format):
+ * B4 = TWT Information Frame Disabled */
const char *tok_s;
tok_s = os_strstr(cmd, " dialog=");
@@ -10687,7 +10700,7 @@
#endif /* CONFIG_FILS */
-static int wpas_ctrl_cmd_debug_level(const char *cmd)
+int wpas_ctrl_cmd_debug_level(const char *cmd)
{
if (os_strcmp(cmd, "PING") == 0 ||
os_strncmp(cmd, "BSS ", 4) == 0 ||
@@ -12019,6 +12032,58 @@
} else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
if (wpas_ap_update_beacon(wpa_s))
reply_len = -1;
+ } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) {
+ if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) {
+ if (ap_ctrl_iface_acl_add_mac(wpa_s,
+ DENY_UNLESS_ACCEPTED,
+ buf + 19) ||
+ ap_ctrl_iface_set_acl(wpa_s))
+ reply_len = -1;
+ } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) {
+ if (ap_ctrl_iface_acl_del_mac(wpa_s,
+ DENY_UNLESS_ACCEPTED,
+ buf + 19) ||
+ ap_ctrl_iface_set_acl(wpa_s) ||
+ ap_ctrl_iface_disassoc_accept_mac(wpa_s))
+ reply_len = -1;
+ } else if (os_strcmp(buf + 11, "SHOW") == 0) {
+ reply_len = ap_ctrl_iface_acl_show_mac(
+ wpa_s, DENY_UNLESS_ACCEPTED,
+ reply, reply_size);
+ } else if (os_strcmp(buf + 11, "CLEAR") == 0) {
+ ap_ctrl_iface_acl_clear_list(wpa_s,
+ DENY_UNLESS_ACCEPTED);
+ if (ap_ctrl_iface_set_acl(wpa_s) ||
+ ap_ctrl_iface_disassoc_accept_mac(wpa_s))
+ reply_len = -1;
+ } else {
+ reply_len = -1;
+ }
+ } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) {
+ if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) {
+ if (ap_ctrl_iface_acl_add_mac(wpa_s,
+ ACCEPT_UNLESS_DENIED,
+ buf + 17) ||
+ ap_ctrl_iface_set_acl(wpa_s) ||
+ ap_ctrl_iface_disassoc_deny_mac(wpa_s))
+ reply_len = -1;
+ } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) {
+ if (ap_ctrl_iface_acl_del_mac(wpa_s,
+ ACCEPT_UNLESS_DENIED,
+ buf + 17) ||
+ ap_ctrl_iface_set_acl(wpa_s))
+ reply_len = -1;
+ } else if (os_strcmp(buf + 9, "SHOW") == 0) {
+ reply_len = ap_ctrl_iface_acl_show_mac(
+ wpa_s, ACCEPT_UNLESS_DENIED, reply, reply_size);
+ } else if (os_strcmp(buf + 9, "CLEAR") == 0) {
+ ap_ctrl_iface_acl_clear_list(wpa_s,
+ ACCEPT_UNLESS_DENIED);
+ if (ap_ctrl_iface_set_acl(wpa_s))
+ reply_len = -1;
+ } else {
+ reply_len = -1;
+ }
#endif /* CONFIG_AP */
} else if (os_strcmp(buf, "SUSPEND") == 0) {
wpas_notify_suspend(wpa_s->global);
@@ -12114,6 +12179,17 @@
if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18))
reply_len = -1;
#endif /* CONFIG_WNM */
+#ifdef CONFIG_WNM_AP
+ } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
+ if (ap_ctrl_iface_disassoc_imminent(wpa_s, buf + 18))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
+ if (ap_ctrl_iface_ess_disassoc(wpa_s, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
+ if (ap_ctrl_iface_bss_tm_req(wpa_s, buf + 11))
+ reply_len = -1;
+#endif /* CONFIG_WNM_AP */
} else if (os_strcmp(buf, "FLUSH") == 0) {
wpa_supplicant_ctrl_iface_flush(wpa_s);
} else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) {
@@ -12312,6 +12388,9 @@
if (os_snprintf_error(reply_size, reply_len))
reply_len = -1;
}
+ } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) {
+ if (dpp_configurator_set(wpa_s->dpp, buf + 20) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) {
if (dpp_configurator_remove(wpa_s->dpp, buf + 24) < 0)
reply_len = -1;
diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h
index dfbd25a..9842ea1 100644
--- a/wpa_supplicant/ctrl_iface.h
+++ b/wpa_supplicant/ctrl_iface.h
@@ -122,6 +122,8 @@
void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s);
+int wpas_ctrl_cmd_debug_level(const char *cmd);
+
#else /* CONFIG_CTRL_IFACE */
static inline struct ctrl_iface_priv *
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 1cbf7fa..1178f40 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -337,6 +337,9 @@
else
reply_len = 2;
} else {
+ sockaddr_print(wpas_ctrl_cmd_debug_level(buf),
+ "Control interface recv command from:",
+ &from, fromlen);
reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
&reply_len);
}
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 639573d..2052873 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -178,6 +178,9 @@
else
reply_len = 2;
} else {
+ sockaddr_print(wpas_ctrl_cmd_debug_level(buf),
+ "Control interface recv command from:",
+ &from, fromlen);
reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
&reply_len);
reply = reply_buf;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 959a68b..0b1002b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -1121,7 +1121,7 @@
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[13];
+ const char *capabilities[14];
size_t num_items = 0;
struct wpa_global *global = user_data;
struct wpa_supplicant *wpa_s;
@@ -1177,6 +1177,9 @@
#endif /* CONFIG_SUITEB192 */
if (ext_key_id_supported)
capabilities[num_items++] = "extended_key_id";
+#ifndef CONFIG_WEP
+ capabilities[num_items++] = "wep_disabled";
+#endif /* !CONFIG_WEP */
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -3951,7 +3954,7 @@
const char *auth_mode;
char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
- if (wpa_s->wpa_state != WPA_COMPLETED) {
+ if (wpa_s->wpa_state <= WPA_SCANNING) {
auth_mode = "INACTIVE";
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 6208e9e..95dc4e3 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -101,6 +101,9 @@
# EAP-TLS
CONFIG_EAP_TLS=y
+# Enable EAP-TLSv1.3 support by default (currently disabled unless explicitly
+# enabled in network configuration)
+#CONFIG_EAP_TLSV1_3=y
# EAL-PEAP
CONFIG_EAP_PEAP=y
@@ -203,6 +206,9 @@
# Support VHT overrides (disable VHT, mask MCS rates, etc.)
#CONFIG_VHT_OVERRIDES=y
+# Support HE overrides
+#CONFIG_HE_OVERRIDES=y
+
# Development testing
#CONFIG_EAPOL_TEST=y
@@ -248,6 +254,9 @@
# Simultaneous Authentication of Equals (SAE), WPA3-Personal
CONFIG_SAE=y
+# SAE Public Key, WPA3-Personal
+#CONFIG_SAE_PK=y
+
# Disable scan result processing (ap_scan=1) to save code size by about 1 kB.
# This can be used if ap_scan=1 mode is never enabled.
#CONFIG_NO_SCAN_PROCESSING=y
@@ -474,6 +483,16 @@
# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
CONFIG_IEEE80211AC=y
+# IEEE 802.11ax HE support (mainly for AP mode)
+CONFIG_IEEE80211AX=y
+
+# IEEE 802.11be EHT support (mainly for AP mode)
+# CONFIG_IEEE80211AX is mandatory for setting CONFIG_IEEE80211BE.
+# Note: This is experimental and work in progress. The definitions are still
+# subject to change and this should not be expected to interoperate with the
+# final IEEE 802.11be version.
+#CONFIG_IEEE80211BE=y
+
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
#CONFIG_WNM=y
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index d570cfe..b6dbc98 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -1148,6 +1148,7 @@
return;
}
+ wpa_s->dpp_pkex_wait_auth_req = false;
wpa_s->dpp_gas_client = 0;
wpa_s->dpp_gas_server = 0;
wpa_s->dpp_auth_ok_on_ack = 0;
@@ -1661,6 +1662,21 @@
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+static void wpas_dpp_build_new_key(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct dpp_authentication *auth = wpa_s->dpp_auth;
+
+ if (!auth || !auth->waiting_new_key)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key");
+ wpas_dpp_start_gas_client(wpa_s);
+}
+#endif /* CONFIG_DPP3 */
+
+
static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
enum gas_query_result result,
const struct wpabuf *adv_proto,
@@ -1714,6 +1730,14 @@
return;
}
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ if (res == -3) {
+ wpa_printf(MSG_DEBUG, "DPP: New protocol key needed");
+ eloop_register_timeout(0, 0, wpas_dpp_build_new_key, wpa_s,
+ NULL);
+ return;
+ }
+#endif /* CONFIG_DPP3 */
if (res < 0) {
wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed");
goto fail;
@@ -2748,14 +2772,8 @@
#endif /* CONFIG_DPP2 */
-enum wpas_dpp_pkex_ver {
- PKEX_VER_AUTO,
- PKEX_VER_ONLY_1,
- PKEX_VER_ONLY_2,
-};
-
static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s,
- enum wpas_dpp_pkex_ver ver,
+ enum dpp_pkex_ver ver,
const struct hostapd_ip_addr *ipaddr,
int tcp_port)
{
@@ -2908,6 +2926,17 @@
wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR,
MAC2STR(src));
+ if (wpa_s->dpp_pkex_ver == PKEX_VER_ONLY_1 && v2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore PKEXv2 Exchange Request when configured to be PKEX v1 only");
+ return;
+ }
+ if (wpa_s->dpp_pkex_ver == PKEX_VER_ONLY_2 && !v2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Ignore PKEXv1 Exchange Request when configured to be PKEX v2 only");
+ return;
+ }
+
/* TODO: Support multiple PKEX codes by iterating over all the enabled
* values here */
@@ -2935,6 +2964,7 @@
return;
}
+ wpa_s->dpp_pkex_wait_auth_req = false;
msg = wpa_s->dpp_pkex->exchange_resp;
wait_time = wpa_s->max_remain_on_chan;
if (wait_time > 2000)
@@ -3051,6 +3081,7 @@
wpabuf_free(msg);
wpas_dpp_pkex_finish(wpa_s, src, freq);
+ wpa_s->dpp_pkex_wait_auth_req = true;
}
@@ -3332,11 +3363,13 @@
return NULL;
}
+ auth->conf_resp = resp;
if (!resp) {
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
wpas_notify_dpp_configuration_failure(wpa_s);
+ dpp_auth_deinit(wpa_s->dpp_auth);
+ wpa_s->dpp_auth = NULL;
}
- auth->conf_resp = resp;
return resp;
}
@@ -3367,6 +3400,14 @@
}
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ if (auth->waiting_new_key && ok) {
+ wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key");
+ wpabuf_free(resp);
+ return;
+ }
+#endif /* CONFIG_DPP3 */
+
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
@@ -3493,6 +3534,8 @@
wpa_printf(MSG_DEBUG,
"DPP: Starting network introduction protocol to derive PMKSA for "
MACSTR, MAC2STR(bss->bssid));
+ if (wpa_s->wpa_state == WPA_SCANNING)
+ wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state);
len = 5 + 4 + os_strlen(ssid->dpp_connector);
#ifdef CONFIG_DPP2
@@ -3614,6 +3657,11 @@
{
struct dpp_bootstrap_info *own_bi;
const char *pos, *end;
+#ifdef CONFIG_DPP3
+ enum dpp_pkex_ver ver = PKEX_VER_AUTO;
+#else /* CONFIG_DPP3 */
+ enum dpp_pkex_ver ver = PKEX_VER_ONLY_1;
+#endif /* CONFIG_DPP3 */
int tcp_port = DPP_TCP_PORT;
struct hostapd_ip_addr *ipaddr = NULL;
#ifdef CONFIG_DPP2
@@ -3679,27 +3727,22 @@
if (!wpa_s->dpp_pkex_code)
return -1;
+ pos = os_strstr(cmd, " ver=");
+ if (pos) {
+ int v;
+
+ pos += 5;
+ v = atoi(pos);
+ if (v == 1)
+ ver = PKEX_VER_ONLY_1;
+ else if (v == 2)
+ ver = PKEX_VER_ONLY_2;
+ else
+ return -1;
+ }
+ wpa_s->dpp_pkex_ver = ver;
+
if (os_strstr(cmd, " init=1")) {
-#ifdef CONFIG_DPP3
- enum wpas_dpp_pkex_ver ver = PKEX_VER_AUTO;
-#else /* CONFIG_DPP3 */
- enum wpas_dpp_pkex_ver ver = PKEX_VER_ONLY_1;
-#endif /* CONFIG_DPP3 */
-
- pos = os_strstr(cmd, " ver=");
- if (pos) {
- int v;
-
- pos += 5;
- v = atoi(pos);
- if (v == 1)
- ver = PKEX_VER_ONLY_1;
- else if (v == 2)
- ver = PKEX_VER_ONLY_2;
- else
- return -1;
- }
-
if (wpas_dpp_pkex_init(wpa_s, ver, ipaddr, tcp_port) < 0)
return -1;
} else {
@@ -3751,12 +3794,13 @@
void wpas_dpp_stop(struct wpa_supplicant *wpa_s)
{
- if (wpa_s->dpp_auth || wpa_s->dpp_pkex)
+ if (wpa_s->dpp_auth || wpa_s->dpp_pkex || wpa_s->dpp_pkex_wait_auth_req)
offchannel_send_action_done(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
dpp_pkex_free(wpa_s->dpp_pkex);
wpa_s->dpp_pkex = NULL;
+ wpa_s->dpp_pkex_wait_auth_req = false;
if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0)
gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token);
}
@@ -3822,6 +3866,9 @@
dpp_free_reconfig_id(wpa_s->dpp_reconfig_id);
wpa_s->dpp_reconfig_id = NULL;
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ eloop_cancel_timeout(wpas_dpp_build_new_key, wpa_s, NULL);
+#endif /* CONFIG_DPP3 */
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
wpas_dpp_stop(wpa_s);
@@ -4236,6 +4283,7 @@
wpas_dpp_chirp_stop(wpa_s);
wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
wpa_s->dpp_qr_mutual = 0;
wpa_s->dpp_chirp_bi = bi;
wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi);
@@ -4320,6 +4368,7 @@
}
wpas_dpp_chirp_stop(wpa_s);
wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE;
+ wpa_s->dpp_netrole = DPP_NETROLE_STA;
wpa_s->dpp_qr_mutual = 0;
wpa_s->dpp_reconfig_ssid = ssid;
wpa_s->dpp_reconfig_ssid_id = ssid->id;
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index e256ac5..f806895 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -15,6 +15,7 @@
#include "common.h"
#include "utils/ext_password.h"
#include "common/version.h"
+#include "crypto/crypto.h"
#include "crypto/tls.h"
#include "config.h"
#include "eapol_supp/eapol_supp_sm.h"
@@ -732,16 +733,27 @@
case EAP_TYPE_IDENTITY: return "Identity";
case EAP_TYPE_NOTIFICATION: return "Notification";
case EAP_TYPE_NAK: return "Nak";
- case EAP_TYPE_TLS: return "TLS";
- case EAP_TYPE_TTLS: return "TTLS";
- case EAP_TYPE_PEAP: return "PEAP";
- case EAP_TYPE_SIM: return "SIM";
- case EAP_TYPE_GTC: return "GTC";
+
case EAP_TYPE_MD5: return "MD5";
case EAP_TYPE_OTP: return "OTP";
+ case EAP_TYPE_GTC: return "GTC";
+ case EAP_TYPE_TLS: return "TLS";
+ case EAP_TYPE_LEAP: return "LEAP";
+ case EAP_TYPE_SIM: return "SIM";
+ case EAP_TYPE_TTLS: return "TTLS";
+ case EAP_TYPE_AKA: return "AKA";
+ case EAP_TYPE_PEAP: return "PEAP";
+ case EAP_TYPE_MSCHAPV2: return "MSCHAPv2";
case EAP_TYPE_FAST: return "FAST";
- case EAP_TYPE_SAKE: return "SAKE";
+ case EAP_TYPE_PAX: return "PAX";
case EAP_TYPE_PSK: return "PSK";
+ case EAP_TYPE_SAKE: return "SAKE";
+ case EAP_TYPE_IKEV2: return "IKEv2";
+ case EAP_TYPE_AKA_PRIME: return "AKA-PRIME";
+ case EAP_TYPE_GPSK: return "GPSK";
+ case EAP_TYPE_PWD: return "PWD";
+ case EAP_TYPE_EKE: return "EKE";
+ case EAP_TYPE_TEAP: return "TEAP";
default: return "Unknown";
}
}
@@ -761,20 +773,20 @@
msg = e->last_recv_radius;
eap = radius_msg_get_eap(msg);
- if (eap == NULL) {
- /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3:
+ if (!eap) {
+ /* RFC 3579, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
* attribute */
- wpa_printf(MSG_DEBUG, "could not extract "
- "EAP-Message from RADIUS message");
+ wpa_printf(MSG_DEBUG,
+ "could not extract EAP-Message from RADIUS message");
wpabuf_free(e->last_eap_radius);
e->last_eap_radius = NULL;
return;
}
if (wpabuf_len(eap) < sizeof(*hdr)) {
- wpa_printf(MSG_DEBUG, "too short EAP packet "
- "received from authentication server");
+ wpa_printf(MSG_DEBUG,
+ "too short EAP packet received from authentication server");
wpabuf_free(eap);
return;
}
@@ -810,11 +822,11 @@
wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap);
break;
}
- wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d "
- "id=%d len=%d) from RADIUS server: %s",
- hdr->code, hdr->identifier, ntohs(hdr->length), buf);
-
- /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
+ buf[sizeof(buf) - 1] = '\0';
+ wpa_printf(MSG_DEBUG,
+ "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s",
+ hdr->code, hdr->identifier, be_to_host16(hdr->length),
+ buf);
wpabuf_free(e->last_eap_radius);
e->last_eap_radius = eap;
@@ -847,7 +859,7 @@
keys = radius_msg_get_ms_keys(msg, req, shared_secret,
shared_secret_len);
- if (keys && keys->send == NULL && keys->recv == NULL) {
+ if (keys && !keys->send && !keys->recv) {
os_free(keys);
keys = radius_msg_get_cisco_keys(msg, req, shared_secret,
shared_secret_len);
@@ -908,20 +920,19 @@
radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
0) < 0 &&
radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
- wpa_printf(MSG_DEBUG, "Allowing RADIUS "
- "Access-Reject without Message-Authenticator "
- "since it does not include EAP-Message\n");
+ wpa_printf(MSG_DEBUG,
+ "Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
req, 1)) {
- printf("Incoming RADIUS packet did not have correct "
- "Message-Authenticator - dropped\n");
- return RADIUS_RX_UNKNOWN;
+ wpa_printf(MSG_INFO,
+ "Incoming RADIUS packet did not have correct Message-Authenticator - dropped");
+ return RADIUS_RX_INVALID_AUTHENTICATOR;
}
if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
hdr->code != RADIUS_CODE_ACCESS_REJECT &&
hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
- printf("Unknown RADIUS message code\n");
+ wpa_printf(MSG_INFO, "Unknown RADIUS message code");
return RADIUS_RX_UNKNOWN;
}
@@ -1549,6 +1560,7 @@
else
printf("SUCCESS\n");
+ crypto_unload();
os_program_deinit();
return ret;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 35467ce..170cec7 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -149,19 +149,22 @@
}
-static void wpa_supplicant_update_current_bss(struct wpa_supplicant *wpa_s)
+static struct wpa_bss *
+wpa_supplicant_update_current_bss(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
- struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid);
+ struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
if (!bss) {
wpa_supplicant_update_scan_results(wpa_s);
/* Get the BSS from the new scan results */
- bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid);
+ bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
}
if (bss)
wpa_s->current_bss = bss;
+
+ return bss;
}
@@ -173,7 +176,7 @@
int res;
if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid) {
- wpa_supplicant_update_current_bss(wpa_s);
+ wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid);
if (wpa_s->current_ssid->ssid_len == 0)
return 0; /* current profile still in use */
@@ -250,7 +253,7 @@
old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
- wpa_supplicant_update_current_bss(wpa_s);
+ wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid);
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
@@ -567,6 +570,7 @@
#ifdef CONFIG_WEP
int wep_ok;
#endif /* CONFIG_WEP */
+ bool is_6ghz_bss = is_6ghz_freq(bss->freq);
ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
if (ret >= 0)
@@ -581,6 +585,13 @@
#endif /* CONFIG_WEP */
rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ if (is_6ghz_bss && !rsn_ie) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - 6 GHz BSS without RSNE");
+ return 0;
+ }
+
while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) {
proto_match++;
@@ -595,6 +606,16 @@
if (!ie.has_group)
ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
+ if (is_6ghz_bss) {
+ /* WEP and TKIP are not allowed on 6 GHz */
+ ie.pairwise_cipher &= ~(WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104 |
+ WPA_CIPHER_TKIP);
+ ie.group_cipher &= ~(WPA_CIPHER_WEP40 |
+ WPA_CIPHER_WEP104 |
+ WPA_CIPHER_TKIP);
+ }
+
#ifdef CONFIG_WEP
if (wep_ok &&
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
@@ -636,6 +657,21 @@
break;
}
+ if (is_6ghz_bss) {
+ /* MFPC must be supported on 6 GHz */
+ if (!(ie.capabilities & WPA_CAPABILITY_MFPC)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip RSNE - 6 GHz without MFPC");
+ break;
+ }
+
+ /* WPA PSK is not allowed on the 6 GHz band */
+ ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK |
+ WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256);
+ }
+
if (!(ie.key_mgmt & ssid->key_mgmt)) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -666,6 +702,13 @@
return 1;
}
+ if (is_6ghz_bss) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - 6 GHz BSS without matching RSNE");
+ return 0;
+ }
+
if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED &&
(!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) {
if (debug_print)
@@ -1317,7 +1360,10 @@
}
#ifdef CONFIG_SAE
- if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) &&
+ /* When using SAE Password Identifier and when operationg on the 6 GHz
+ * band, only H2E is allowed. */
+ if ((wpa_s->conf->sae_pwe == 1 || is_6ghz_freq(bss->freq) ||
+ ssid->sae_password_id) &&
wpa_s->conf->sae_pwe != 3 && wpa_key_mgmt_sae(ssid->key_mgmt) &&
#ifdef CONFIG_DRIVER_NL80211_BRCM
!(wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) &&
@@ -1412,7 +1458,7 @@
if (wpa_s->ignore_assoc_disallow)
goto skip_assoc_disallow;
#endif /* CONFIG_TESTING_OPTIONS */
- assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW);
+ assoc_disallow = wpas_mbo_check_assoc_disallow(bss);
if (assoc_disallow && assoc_disallow[1] >= 1) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -2961,6 +3007,8 @@
BAND_2_4_GHZ);
wpa_s->connection_he = req_elems.he_capabilities &&
resp_elems.he_capabilities;
+ wpa_s->connection_eht = req_elems.eht_capabilities &&
+ resp_elems.eht_capabilities;
int max_nss_rx_req = get_max_nss_capability(&req_elems, 1);
int max_nss_rx_resp = get_max_nss_capability(&resp_elems, 1);
@@ -3394,6 +3442,26 @@
#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
ft_completed = wpa_ft_is_completed(wpa_s->wpa);
+
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+ wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ return;
+ }
+
+ if (ft_completed &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION)) {
+ wpa_msg(wpa_s, MSG_INFO, "Attempt to roam to " MACSTR,
+ MAC2STR(bssid));
+ if (!wpa_supplicant_update_current_bss(wpa_s, bssid)) {
+ wpa_printf(MSG_ERROR,
+ "Can't find target AP's information!");
+ return;
+ }
+ wpa_supplicant_assoc_update_ie(wpa_s);
+ }
+
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
return;
/*
@@ -3404,13 +3472,6 @@
if (!ft_completed)
ft_completed = wpa_fils_is_completed(wpa_s->wpa);
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
- wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
- wpa_supplicant_deauthenticate(
- wpa_s, WLAN_REASON_DEAUTH_LEAVING);
- return;
- }
-
#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
/* For driver based roaming, insert PSK during the initial association */
if (is_zero_ether_addr(wpa_s->bssid) &&
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index ca380b9..9a459c2 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1065,6 +1065,12 @@
goto fail;
}
+ if (cred->imsi_privacy_key && cred->imsi_privacy_key[0]) {
+ if (wpa_config_set_quoted(ssid, "imsi_privacy_key",
+ cred->imsi_privacy_key) < 0)
+ goto fail;
+ }
+
wpa_s->next_ssid = ssid;
wpa_config_update_prio_list(wpa_s->conf);
if (!only_add)
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 51a8a02..9229eb5 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -12,6 +12,7 @@
#endif /* __linux__ */
#include "common.h"
+#include "crypto/crypto.h"
#include "fst/fst.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -403,6 +404,7 @@
#endif /* CONFIG_MATCH_IFACE */
os_free(params.pid_file);
+ crypto_unload();
os_program_deinit();
return exitcode;
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 8ac73ef..31d0fce 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -65,14 +65,18 @@
}
-const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
+static const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss,
+ enum mbo_attr_id attr, bool beacon)
{
const u8 *mbo, *end;
if (!bss)
return NULL;
- mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
+ if (beacon)
+ mbo = wpa_bss_get_vendor_ie_beacon(bss, MBO_IE_VENDOR_TYPE);
+ else
+ mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
if (!mbo)
return NULL;
@@ -83,6 +87,19 @@
}
+const u8 * wpas_mbo_check_assoc_disallow(struct wpa_bss *bss)
+{
+ const u8 *assoc_disallow;
+
+ assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW,
+ bss->beacon_newer);
+ if (assoc_disallow && assoc_disallow[1] >= 1)
+ return assoc_disallow;
+
+ return NULL;
+}
+
+
void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
struct wpa_ssid *ssid)
{
@@ -92,8 +109,8 @@
wpa_s->disable_mbo_oce = 0;
if (!bss)
return;
- mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND);
- oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND);
+ mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND, false);
+ oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND, false);
if (!mbo && !oce)
return;
if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON))
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index d6b8a1a..b67396d 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -225,12 +225,13 @@
ifmsh->conf->ieee80211n,
ifmsh->conf->ieee80211ac,
ifmsh->conf->ieee80211ax,
+ false,
ifmsh->conf->secondary_channel,
hostapd_get_oper_chwidth(ifmsh->conf),
hostapd_get_oper_centr_freq_seg0_idx(ifmsh->conf),
hostapd_get_oper_centr_freq_seg1_idx(ifmsh->conf),
ifmsh->conf->vht_capab,
- he_capab)) {
+ he_capab, NULL)) {
wpa_printf(MSG_ERROR, "Error updating mesh frequency params");
wpa_supplicant_mesh_deinit(wpa_s, true);
return -1;
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 4c30518..1442353 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -420,6 +420,10 @@
{
if (wpa_s->next_ssid == ssid)
wpa_s->next_ssid = NULL;
+ if (wpa_s->last_ssid == ssid)
+ wpa_s->last_ssid = NULL;
+ if (wpa_s->current_ssid == ssid)
+ wpa_s->current_ssid = NULL;
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 &&
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index f1d033b..c8f2e5c 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -8899,7 +8899,7 @@
hapd->conf->ssid.wpa_psk = psk->next;
rem = psk;
psk = psk->next;
- os_free(rem);
+ bin_clear_free(rem, sizeof(*rem));
} else {
prev = psk;
psk = psk->next;
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index baf4c26..dc21b6a 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -1000,6 +1000,7 @@
struct wpa_ssid *ssid = NULL;
struct wpabuf *frame;
int ret;
+ bool derive_kdk;
/* TODO: Currently support only ECC groups */
if (!dragonfly_suitable_group(group, 1)) {
@@ -1079,9 +1080,14 @@
pasn->group = group;
pasn->freq = freq;
- if (wpa_s->conf->force_kdk_derivation ||
- (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF &&
- ieee802_11_rsnx_capab(beacon_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)))
+ derive_kdk = (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) &&
+ ieee802_11_rsnx_capab(beacon_rsnxe,
+ WLAN_RSNX_CAPAB_SECURE_LTF);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (!derive_kdk)
+ derive_kdk = wpa_s->conf->force_kdk_derivation;
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (derive_kdk)
pasn->kdk_len = WPA_KDK_MAX_LEN;
else
pasn->kdk_len = 0;
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 31b5532..3ae99da 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -13,6 +13,7 @@
#include <assert.h>
#include "common.h"
+#include "crypto/crypto.h"
#include "config.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eloop.h"
@@ -365,6 +366,7 @@
eloop_destroy();
+ crypto_unload();
os_program_deinit();
return ret;
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index cf107eb..4457b6c 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -501,7 +501,7 @@
static int * wpas_add_channels(const struct oper_class_map *op,
- struct hostapd_hw_modes *mode, int active,
+ struct hostapd_hw_modes *mode,
const u8 *channels, const u8 size)
{
int *freqs, *next_freq;
@@ -532,7 +532,7 @@
enum chan_allowed res = verify_channel(mode, op->op_class, chan,
op->bw);
- if (res == NOT_ALLOWED || (res == NO_IR && active))
+ if (res == NOT_ALLOWED)
continue;
if (wpas_add_channel(op->op_class, chan, num_primary_channels,
@@ -554,7 +554,7 @@
static int * wpas_op_class_freqs(const struct oper_class_map *op,
- struct hostapd_hw_modes *mode, int active)
+ struct hostapd_hw_modes *mode)
{
u8 channels_80mhz_5ghz[] = { 42, 58, 106, 122, 138, 155, 171 };
u8 channels_160mhz_5ghz[] = { 50, 114, 163 };
@@ -581,11 +581,11 @@
ARRAY_SIZE(channels_160mhz_5ghz);
}
- return wpas_add_channels(op, mode, active, channels, num_chan);
+ return wpas_add_channels(op, mode, channels, num_chan);
}
-static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active,
+static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s,
const char *country, const u8 *subelems,
size_t len)
{
@@ -633,7 +633,7 @@
* by a corresponding AP Channel Report element as specified in
* IEEE Std 802.11-2016, 11.11.9.1.
*/
- new_freqs = wpas_add_channels(op, mode, active, pos, left);
+ new_freqs = wpas_add_channels(op, mode, pos, left);
if (new_freqs)
int_array_concat(&freqs, new_freqs);
@@ -648,7 +648,7 @@
static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s,
- u8 op_class, u8 chan, int active,
+ u8 op_class, u8 chan,
const u8 *subelems, size_t len)
{
int *freqs = NULL, *ext_freqs = NULL;
@@ -678,7 +678,7 @@
switch (chan) {
case 0:
- freqs = wpas_op_class_freqs(op, mode, active);
+ freqs = wpas_op_class_freqs(op, mode);
if (!freqs)
return NULL;
break;
@@ -686,14 +686,13 @@
/* freqs will be added from AP channel subelements */
break;
default:
- freqs = wpas_add_channels(op, mode, active, &chan, 1);
+ freqs = wpas_add_channels(op, mode, &chan, 1);
if (!freqs)
return NULL;
break;
}
- ext_freqs = wpas_channel_report_freqs(wpa_s, active, country, subelems,
- len);
+ ext_freqs = wpas_channel_report_freqs(wpa_s, country, subelems, len);
if (ext_freqs) {
int_array_concat(&freqs, ext_freqs);
os_free(ext_freqs);
@@ -1220,10 +1219,9 @@
goto out;
}
- params->freqs = wpas_beacon_request_freqs(
- wpa_s, req->oper_class, req->channel,
- req->mode == BEACON_REPORT_MODE_ACTIVE,
- req->variable, len - sizeof(*req));
+ params->freqs = wpas_beacon_request_freqs(wpa_s, req->oper_class,
+ req->channel, req->variable,
+ len - sizeof(*req));
if (!params->freqs) {
wpa_printf(MSG_DEBUG, "Beacon request: No valid channels");
reject_mode = MEASUREMENT_REPORT_MODE_REJECT_REFUSED;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index dde2f44..042b24e 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -2194,20 +2194,33 @@
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *r = scan_res->res[i];
u8 *pos;
+ const u8 *ssid_ie, *ssid = NULL;
+ size_t ssid_len = 0;
+
+ ssid_ie = wpa_scan_get_ie(r, WLAN_EID_SSID);
+ if (ssid_ie) {
+ ssid = ssid_ie + 2;
+ ssid_len = ssid_ie[1];
+ }
+
if (r->flags & WPA_SCAN_LEVEL_DBM) {
int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID);
- wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u",
- MAC2STR(r->bssid), r->freq, r->qual,
+ wpa_printf(MSG_EXCESSIVE, MACSTR
+ " ssid=%s freq=%d qual=%d noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u",
+ MAC2STR(r->bssid),
+ wpa_ssid_txt(ssid, ssid_len),
+ r->freq, r->qual,
r->noise, noise_valid ? "" : "~", r->level,
r->snr, r->snr >= GREAT_SNR ? "*" : "",
r->flags,
r->age, r->est_throughput);
} else {
- wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d flags=0x%x age=%u est=%u",
- MAC2STR(r->bssid), r->freq, r->qual,
+ wpa_printf(MSG_EXCESSIVE, MACSTR
+ " ssid=%s freq=%d qual=%d noise=%d level=%d flags=0x%x age=%u est=%u",
+ MAC2STR(r->bssid),
+ wpa_ssid_txt(ssid, ssid_len),
+ r->freq, r->qual,
r->noise, r->level, r->flags, r->age,
r->est_throughput);
}
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 0b02f75..cc55fa6 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1366,7 +1366,7 @@
" auth_type=%u auth_transaction=%u status_code=%u",
MAC2STR(bssid), WLAN_AUTH_SAE,
auth_transaction, status_code);
- return -1;
+ return -2;
}
if (auth_transaction == 1) {
@@ -1517,7 +1517,10 @@
if (res < 0) {
/* Notify failure to the driver */
sme_send_external_auth_status(
- wpa_s, WLAN_STATUS_UNSPECIFIED_FAILURE);
+ wpa_s,
+ res == -2 ?
+ le_to_host16(header->u.auth.status_code) :
+ WLAN_STATUS_UNSPECIFIED_FAILURE);
return;
}
if (res != 1)
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 033589f..0e2315d 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1418,11 +1418,11 @@
#ifdef IEEE8021X_EAPOL
"eap", "identity", "anonymous_identity", "password", "ca_cert",
"ca_path", "client_cert", "private_key", "private_key_passwd",
- "dh_file", "subject_match", "altsubject_match",
+ "subject_match", "altsubject_match",
"check_cert_subject",
"domain_suffix_match", "domain_match", "ca_cert2", "ca_path2",
"client_cert2", "private_key2", "private_key2_passwd",
- "dh_file2", "subject_match2", "altsubject_match2",
+ "subject_match2", "altsubject_match2",
"check_cert_subject2",
"domain_suffix_match2", "domain_match2", "phase1", "phase2",
"pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id",
@@ -2046,6 +2046,20 @@
return wpa_ctrl_command(ctrl, "UPDATE_BEACON");
}
+
+static int wpa_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv);
+}
+
#endif /* CONFIG_AP */
@@ -2894,6 +2908,31 @@
#endif /* CONFIG_WNM */
+#ifdef CONFIG_WNM_AP
+
+static int wpa_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "DISASSOC_IMMINENT", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "ESS_DISASSOC", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "BSS_TM_REQ", 1, argc, argv);
+}
+
+#endif /* CONFIG_WNM_AP */
+
+
static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
if (argc == 0)
@@ -3599,6 +3638,10 @@
{ "update_beacon", wpa_cli_cmd_update_beacon, NULL,
cli_cmd_flag_none,
"= update Beacon frame contents"},
+ { "accept_acl", wpa_cli_cmd_accept_macacl, NULL, cli_cmd_flag_none,
+ "=Add/Delete/Show/Clear allow MAC ACL" },
+ { "deny_acl", wpa_cli_cmd_deny_macacl, NULL, cli_cmd_flag_none,
+ "=Add/Delete/Show/Clear deny MAC ACL" },
#endif /* CONFIG_AP */
{ "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
"= notification of suspend/hibernate" },
@@ -3845,6 +3888,14 @@
" [neighbor=<BSSID>,<BSSID information>,<operating class>,<channel number>,<PHY type>[,<hexdump of optional subelements>]"
" = Send BSS Transition Management Query" },
#endif /* CONFIG_WNM */
+#ifdef CONFIG_WNM_AP
+ { "disassoc_imminent", wpa_cli_cmd_disassoc_imminent, NULL, cli_cmd_flag_none,
+ "= send Disassociation Imminent notification" },
+ { "ess_disassoc", wpa_cli_cmd_ess_disassoc, NULL, cli_cmd_flag_none,
+ "= send ESS Dissassociation Imminent notification" },
+ { "bss_tm_req", wpa_cli_cmd_bss_tm_req, NULL, cli_cmd_flag_none,
+ "= send BSS Transition Management Request" },
+#endif /* CONFIG_WNM_AP */
{ "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
"<params..> = Sent unprocessed command" },
{ "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none,
diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index 538997e..d9c07e6 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -58,7 +58,11 @@
return 1;
}
- pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32);
+ if (pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32)
+ != 0) {
+ fprintf(stderr, "Error in pbkdf2_sha1()\n");
+ return 1;
+ }
printf("network={\n");
printf("\tssid=\"%s\"\n", ssid);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 99af85e..24c8818 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1715,6 +1715,8 @@
wpa_s->oci_freq_override_ft_assoc);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCI_FREQ_FILS_ASSOC,
wpa_s->oci_freq_override_fils_assoc);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX,
+ wpa_s->disable_eapol_g2_tx);
#endif /* CONFIG_TESTING_OPTIONS */
/* Extended Key ID is only supported in infrastructure BSS so far */
@@ -1786,9 +1788,15 @@
if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
ssid->passphrase && !sae_only) {
u8 psk[PMK_LEN];
- pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
- 4096, psk, PMK_LEN);
- wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+
+ if (pbkdf2_sha1(ssid->passphrase, bss->ssid,
+ bss->ssid_len,
+ 4096, psk, PMK_LEN) != 0) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "Error in pbkdf2_sha1()");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
psk, PMK_LEN);
wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL);
psk_set = 1;
@@ -1822,8 +1830,14 @@
#ifndef CONFIG_NO_PBKDF2
if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
{
- pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
- 4096, psk, PMK_LEN);
+ if (pbkdf2_sha1(pw_str, bss->ssid,
+ bss->ssid_len,
+ 4096, psk, PMK_LEN) != 0) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "Error in pbkdf2_sha1()");
+ ext_password_free(pw);
+ return -1;
+ }
os_memset(pw_str, 0, sizeof(pw_str));
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
"external passphrase)",
@@ -2247,6 +2261,7 @@
else
rand_style = ssid->mac_addr;
+ wpa_s->eapol_failed = 0;
wpa_s->multi_ap_ie = 0;
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
@@ -2779,9 +2794,11 @@
freq->channel, ssid->enable_edmg,
ssid->edmg_channel, freq->ht_enabled,
vht_freq.vht_enabled, freq->he_enabled,
+ false,
freq->sec_channel_offset,
chwidth, seg0, seg1, vht_caps,
- &mode->he_capab[ieee80211_mode]) != 0)
+ &mode->he_capab[ieee80211_mode],
+ NULL) != 0)
return;
*freq = vht_freq;
@@ -4280,7 +4297,7 @@
*/
int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
{
- struct wpa_ssid *ssid;
+ struct wpa_ssid *ssid, *prev = wpa_s->current_ssid;
int was_disabled;
ssid = wpa_config_get_network(wpa_s->conf, id);
@@ -4288,10 +4305,7 @@
return -1;
wpas_notify_network_removed(wpa_s, ssid);
- if (wpa_s->last_ssid == ssid)
- wpa_s->last_ssid = NULL;
-
- if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
+ if (ssid == prev || !prev) {
#ifdef CONFIG_SME
wpa_s->sme.prev_bssid_set = 0;
#endif /* CONFIG_SME */
@@ -4302,7 +4316,7 @@
eapol_sm_invalidate_cached_session(wpa_s->eapol);
}
- if (ssid == wpa_s->current_ssid) {
+ if (ssid == prev) {
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
@@ -4365,8 +4379,6 @@
id = ssid->id;
ssid = ssid->next;
- if (wpa_s->last_ssid == remove_ssid)
- wpa_s->last_ssid = NULL;
wpas_notify_network_removed(wpa_s, remove_ssid);
wpa_config_remove_network(wpa_s->conf, id);
}
@@ -6747,6 +6759,7 @@
wpa_s->drv_flags2 = capa.flags2;
wpa_s->drv_enc = capa.enc;
wpa_s->drv_rrm_flags = capa.rrm_flags;
+ wpa_s->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 9376b03..fd54fef 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1234,14 +1234,6 @@
# to blob://<blob name>.
# private_key_passwd: Password for private key file (if left out, this will be
# asked through control interface)
-# dh_file: File path to DH/DSA parameters file (in PEM format)
-# This is an optional configuration file for setting parameters for an
-# ephemeral DH key exchange. In most cases, the default RSA
-# authentication does not use this configuration. However, it is possible
-# setup RSA to use ephemeral DH key exchange. In addition, ciphers with
-# DSA keys always use ephemeral DH keys. This can be used to achieve
-# forward secrecy. If the file is in DSA parameters format, it will be
-# automatically converted into DH params.
# subject_match: Substring to be matched against the subject of the
# authentication server certificate. If this string is set, the server
# certificate is only accepted if it contains this string in the subject.
@@ -1378,6 +1370,11 @@
# tls_suiteb=0 - do not apply Suite B 192-bit constraints on TLS (default)
# tls_suiteb=1 - apply Suite B 192-bit constraints on TLS; this is used in
# particular when using Suite B with RSA keys of >= 3K (3072) bits
+# allow_unsafe_renegotiation=1 - allow connection with a TLS server that does
+# not support safe renegotiation (RFC 5746); please note that this
+# workaround should be only when having to authenticate with an old
+# authentication server that cannot be updated to use secure TLS
+# implementation.
#
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 1d2c3e2..3adb819 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -14,6 +14,7 @@
#include "common/defs.h"
#include "common/sae.h"
#include "common/wpa_ctrl.h"
+#include "common/dpp.h"
#include "crypto/sha384.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "wps/wps_defs.h"
@@ -929,6 +930,7 @@
u64 drv_flags2;
unsigned int drv_enc;
unsigned int drv_rrm_flags;
+ unsigned int drv_max_acl_mac_addrs;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -965,6 +967,7 @@
struct os_reltime pending_eapol_rx_time;
u8 pending_eapol_rx_src[ETH_ALEN];
unsigned int last_eapol_matches_bssid:1;
+ unsigned int eapol_failed:1;
unsigned int eap_expected_failure:1;
unsigned int reattach:1; /* reassociation to the same BSS requested */
unsigned int mac_addr_changed:1;
@@ -976,6 +979,7 @@
unsigned int connection_ht:1;
unsigned int connection_vht:1;
unsigned int connection_he:1;
+ unsigned int connection_eht:1;
unsigned int connection_max_nss_rx:4;
unsigned int connection_max_nss_tx:4;
unsigned int connection_channel_bandwidth:5;
@@ -1368,6 +1372,7 @@
unsigned int oci_freq_override_fils_assoc;
unsigned int oci_freq_override_wnm_sleep;
int force_hunting_and_pecking_pwe;
+ unsigned int disable_eapol_g2_tx;
#endif /* CONFIG_TESTING_OPTIONS */
struct wmm_ac_assoc_data *wmm_ac_assoc_info;
@@ -1483,6 +1488,7 @@
struct dpp_bootstrap_info *dpp_pkex_bi;
char *dpp_pkex_code;
char *dpp_pkex_identifier;
+ enum dpp_pkex_ver dpp_pkex_ver;
char *dpp_pkex_auth_cmd;
char *dpp_configurator_params;
struct os_reltime dpp_last_init;
@@ -1495,6 +1501,7 @@
u8 dpp_last_ssid[SSID_MAX_LEN];
size_t dpp_last_ssid_len;
bool dpp_conf_backup_received;
+ bool dpp_pkex_wait_auth_req;
#ifdef CONFIG_DPP2
struct dpp_pfs *dpp_pfs;
int dpp_pfs_fallback;
@@ -1707,7 +1714,7 @@
int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
int add_oce_capa);
const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
-const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
+const u8 * wpas_mbo_check_assoc_disallow(struct wpa_bss *bss);
void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
struct wpa_ssid *ssid);
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 85028f0..c2bd45f 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -298,13 +298,21 @@
EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
if (result != EAPOL_SUPP_RESULT_SUCCESS) {
+ int timeout = 2;
/*
* Make sure we do not get stuck here waiting for long EAPOL
* timeout if the AP does not disconnect in case of
* authentication failure.
*/
- wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
+ if (wpa_s->eapol_failed) {
+ wpa_printf(MSG_DEBUG,
+ "EAPOL authentication failed again and AP did not disconnect us");
+ timeout = 0;
+ }
+ wpa_s->eapol_failed = 1;
+ wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
} else {
+ wpa_s->eapol_failed = 0;
ieee802_1x_notify_create_actor(wpa_s, wpa_s->last_eapol_src);
}
diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c
index defd0f2..c3ef93b 100644
--- a/wpa_supplicant/wpas_kay.c
+++ b/wpa_supplicant/wpas_kay.c
@@ -103,7 +103,6 @@
switch (co) {
case CONFIDENTIALITY_OFFSET_30:
return 30;
- break;
case CONFIDENTIALITY_OFFSET_50:
return 50;
default:
@@ -241,8 +240,8 @@
res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_replay_protect,
ssid->macsec_replay_window, ssid->macsec_port,
- ssid->mka_priority, wpa_s->ifname,
- wpa_s->own_addr);
+ ssid->mka_priority, ssid->macsec_csindex,
+ wpa_s->ifname, wpa_s->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
if (res == NULL)
return -1;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 1ba360e..7428f02 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -356,8 +356,6 @@
/* Remove the duplicated older network entry. */
wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
wpas_notify_network_removed(wpa_s, ssid);
- if (wpa_s->current_ssid == ssid)
- wpa_s->current_ssid = NULL;
wpa_config_remove_network(wpa_s->conf, ssid->id);
}
}