[wpa_supplicant] Cumulative patch from commit 257b119c2
Bug: 265294868
Test: Verify Passpoint ANQP functionality and Passpoint association
Test: Connect to Passpoint, Open, WPA2, WPA3 networks and run traffic
Test: Regression test b/218404053 (Bug: TBD)
BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from Open sourcie
257b119c2 QCA vendor attribute of update roaming cached statistics info
18436f393 Enhance QCA vendor interface for Concurrent AP Policy for XR
58fba11e1 Enhance QCA vendor interface with new hang reason codes
0f3f9cdca dpp-nfc: Try to request with alternative URL in additional cases
8b36248cd Add QCA vendor command to get the monitor mode status
0dd8bcef8 QCA vendor attributes for MLO and EHT capabilities
e5602989c QCA vendor attributes to configure EHT capabilities
d9d5e55c5 DPP: Respond to GAS on the same channel it was received on
651c9e957 Add new status code strings
3a2d27552 Make MFPR value from an associated STA available as hostapdMFPR
546debd5e Force MFPR=1 to be used on the 6 GHz band
f9c6ab834 P2P: Support preferred GO band based optimization for scanning
093bedc05 P2P: Allow persistent group join retry limit to be configured via D-Bus
8717110db Do not flush PMKSA cache on restoring dedicated per-ESS MAC address
1d4027fdb Make random MAC address style parameters use common enum values
681856c35 Check both sec and usec values to see if MAC address was changed
bdbb6e003 wpa_supplicant: Handle MAC address randomization changes for same ESS
4bd1efe07 dbus: Do not bring down primary interface when removing created AP interface
f4096e7cd EHT: Update EHT Operation element to P802.11be/D2.3 in AP settings
e869fdfee wpa_supplicant: Use MLD address in SAE authentication
8c0f83ae8 SME: Accept Authentication frame from an MLD AP
23039f5e4 SME: Add support for handling association with MLD
8f89661df SME: Add support for handling authentication with MLD
694a1c687 SAE: Make sme_sae_auth() return IE offset
870edfd67 WPA3: Update transition disable bitmap based on port authorized event
8fdf3c447 Sync with wireless-next.git include/uapi/linux/nl80211.h
f9804e306 nl80211: Enforce unique address for AP iftype
87bad8afa dbus: Pass in MAC address in CreateInterface method
b0722cf75 dbus: Fix a memory leak on error path in CreateInterface method
a7f6b8518 crypto: Check if crypto_bignum_to_bin() is successful
2749a2c6b nl80211: Actually get and store TX retries
998aeca3c crypto: Clear secrets from stack in hmac_sha256_vector()
909864ab1 HS 2.0: Restore ifdef for DEFINE_STACK_OF in est.c
af0ab435a PASN: Use the assigned status code from IEEE P802.11az/D7.0
3d798ff2a PASN: Align RSNXE with IEEE P802.11az/D7.0 definitions
ab2cb379d Define all assigned BSS membership selector values
ed0a7b480 wpa_supplicant: Implement HE membership selector check
054fcfab6 hostapd: Add require_he configuration
c46351d10 DFS: Clear cac_started when AP is disabled
3df42cf3c EHT: Use HE operating channel width in MCS length calculation
23e31eb68 SAE: Support cross AKM roaming between SAE AKMs in external auth case
a17026707 PASN: Avoid clearing secure context for the PASN deauthentication event
75a9c4bd4 Add new attributes in SCS rule config QCA vendor subcommand
7d8b96dcf wpa_supplicant: Apply same restrictions for MLD as for 6 GHz BSS
7216f79b9 nl80211: Support get_sta_mlo_info for SME-in-wpa_supplicant drivers
06eb608d5 nl80211: Handle scan results with MLD connection
033a57d26 nl80211: Get MLO support capability
32b745448 wpa_supplicant: Make valid_links u16
a2c4c0b1b nl80211: Support MLD association request
a134b4dc5 nl80211: Add support for MLD authentication
e3e68668c ctrl_iface: Report RNR and ML in BSS command
5f17763ad common: Combine definitions for Multi-Link and per STA profile control
7a7ce9574 dbus: Emit more information over D-Bus
ad4fa5dd3 Add more nl80211 info to struct wpa_signal_info
090f0f8c7 mbssid: Indicate MBSSID information in RNR
a1c4adda1 mbssid: Add nl80211 support
54b1352ef mbssid: Make the AID space shared
10749c3c4 mbssid: Process Known BSSID element
15690faad mbssid: Add MBSSID Configuration element
fc2e4bac5 mbssid: Set extended capabilities
a004bf2cd mbssid: Configure parameters and element data
c5a09b051 mbssid: Add Non-Inheritance element
920b56322 mbssid: Functions for building Multiple BSSID elements
931e5d4f9 mbssid: Configure all BSSes before beacon setup
78d0b9899 mbssid: Retrieve driver capabilities
7452e5447 mbssid: Add new configuration option
bb67d5b52 AP: Add testing option to delay EAPOL Tx
1897abad9 dbus: Add D-Bus property for current MAC address
1a800a940 EAP-TEAP server: Allow tunneled EAP method sequence to be optimized
f791b5bbc EAP-TEAP peer: Process Crypto-Binding TLV before EAP Payload TLV
5a9bd8a06 EAP-TEAP: Use EAP-FAST-MSCHAPv2 in the tunnel
364b6500b EAP-FAST: Move EAP-MSCHAPv2 special MSK handling into MSCHAPv2
81dedfbd7 nl80211: Increase the scan frequencies buffer
9a2781f24 wpa_supplicant: Support throughput estimation for EHT rates
755aaeb97 wpa_supplicant: Add missing memory allocation checks
69725c4cf OpenSSL: Fix BN_rshift() argument order
e9b4ad236 OpenSSL: Apply connection flags before reading certificates
bbd5a4689 SAE: Add an enum for defining sae_pwe parameter values
3a0edb2cd SAE: Enable H2E for 6 GHz BSS
20bfd4feb AP: Enable H2E on 6 GHz when SAE is used
b43e19f3f WPS: Cross band overlap detection with multiple interfaces
e2d88f86e DPP: Expose own and peer bootstrap info ids on authentication success
043dedee8 DPP: Expose enrollee pubkey hash for identification
2d8974e31 DPP: Move DPP_EVENT_AUTH_SUCCESS to a helper
d8d2b3a33 Implement read-only mode for SSIDs from the additional config (-I)
4cb23b66d ACS: Allow selecting a better channel when using 40/80/160 MHz
472101684 ACS: introduce acs_adjust_secondary
60e2934cb ACS: Introduce acs_get_bw_center_chan()
ed8e13dec ACS: Extract bw40/80/160 freqs out of acs_usable_bwXXX_chan()
9025def55 wpa_supplicant: Add support for pregenerated MAC
5da3e1ca4 mesh: Do not allow open mode key in 6 GHz
50a9b7d3d P2P: Include only 6 GHz PSCs in full scan
0d6cd88ee DPP: Use existing TCP connection to replay duplicate Presence Announcement
6af717f73 DPP: Don't close TCP connection for duplicate Presence Announcements
46e6b72b7 Add a callback to notify added PMKSA cache entry details
af1528a12 hostapd: Add RELOAD_BSS
bc2b88b25 hostapd: Add config_id to GET_CONFIG output
b37c3fbad hostapd: Add config_id parameter
46f6a3277 Split BSS-specific hostapd_clear_old_bss() from hostapd_clear_old()
2afb9b1a5 dbus: Add dbus notify when wpa_s->key_mgmt changes
98e9d553f nl80211: Check previous MAC address for locally-generated-deauth
87ffa1bec wpa_supplicant: Convert SSID into printable form before printing
416386060 Mark authorization completed on driver indication during 4-way HS offload
da2ec9459 D-Bus: Split set_cred_properties() into two functions
f5ce680ee D-Bus: Hotspot 2.0 credentials with multiple domains
2f739c71c ctrl: Fix compilation with UDP control interface
6d4548187 RSN: Split EAPOL-Key msg 3/4 processing for WPA(v1)
5b7957b7e RSN: Split EAPOL-Key msg 1/4 processing for WPA(v1)
e5dfce38f RSN: Split EAPOL-Key group msg 1/2 processing more completely for WPA(v1)
5ab43c738 RSN: Split WPA(v1) processing of EAPOL-Key frames into a separate function
f7fd891c7 Fix a typo in driver ops poll() documentation
3268ec0ac HS20: Use required_home_ois in hs20-osu-client
58eb905ad HS20: Support credentials with multiple home OIs
0143dc1cb OpenSSL: Load OpenSSL 3.0 legacy provider but let default be loaded
fef4c6cb0 OpenSSL: Don't provide implementation of DES/RC4 for FIPS builds
1d42dafce RSN: Do not include RC4 use in FIPS builds
df5ae2aad Add more detailed description of RADIUS attributes in EAP user file
0ba266d86 dbus: Add virtual interface create/remove logic to be inline with ctrl_iface
5102d7411 wpa_passphrase: Disable terminal echo when reading from stdin
86ab28217 PASN: Fix passing own address and peer address to pasn_deauthenticate()
a9062432e wpa_cli: Fix PASN control interface commands
b6d3fd05e FT: Use SHA256 to derive PMKID for AKM 00-0F-AC:3 (FT-EAP)
ef70f814a Add a new QCA vendor attribute to configure wifi calling (wfc) state
05ec48568 WPS: Pick WPS AP based on latest received WPS IE
ca4fa867d Enable PMF automatically if OCV is enabled
c823197bd SAE: Use Challenge Failure status code in confirm message failure cases
65c8633d9 Allow a lower priority BSS to be tried after network disabling
e91ac53d5 DFS: Do not allow channel checks to go beyond the channel list
f96dfdeef PASN: Fix missing libraries for libpasn.so on Android
91d148f50 PASN: Fix is_pasn_auth_frame() for mgmt tx status frames
b6c38cee9 Skip CAC if the driver switches channel to non-DFS
080afc03d Add hostapd control interface command to stop logging to file
0fd13c90e Add QCA vendor interface for AP doze mode configuration
4e1f55a11 Roam control configuration for 6 GHz in full scan only on prior discovery
34d93b0c9 HS 2.0: Deauthenticate STA on deauth-imminent more quickly if no URL
2e40f969b nl80211: Fix wrong requested links bitmap in sta_mlo_info.req_links
b6e226496 MLD STA: Fix IGTK and BIGTK MLO KDEs validation
2050130be Add a vendor attribute for roam control configuration for full scan
12f16c27b TLS: Fix unsigned int underflow in internal TLS 1.0/1.1 implementation
802b67bce Update tls_connection_set_verify() documentation to verify_peer=2
0202b9774 DPP: Fix memory leak of intro.peer_key in station handling
f723f7f8a P2P: Check dev pointer consistently when building PD Response
30403e965 WPS: Check NDEF record length fields separately
cd0e8653a TDLS: Use stored FTE length in MIC calculation
7e85e24f3 TDLS: Use stored peer RSNE length in MIC calculation
40a42613e FT: Simplify FTE parsing for FT-SAE-EXT-KEY using MIC Length subfield
5ea7a2f54 DPP: Drop PMKSA entry if AP reject association due to invalid PMKID
4840b45a2 Fix empty pmksa_cache_get()
3abd0c471 SAE: Print rejection of peer element clearly in debug log
9ff778fa4 Check for own address (SPA) match when finding PMKSA entries
9f04a9c8d Store own MAC address (SPA) in supplicant PMKSA cache entries
309765eb6 PASN: Use separate variables for BSSID and peer address
42f0c44d8 PASN: Use peer address instead of BSSID as the destination for initiator
15583802b nl80211: Allow up to 64-byte PMK in NL80211_CMD_SET_PMKSA
bbe5f0c1e FT: Do not try to use FT protocol between mobility domains
b92f61885 Don't use default RSNE/RSNXE when the driver indicates cross SSID roaming
d7febe33f MLO: Remove unnecessary debug prints about clearing AP RSNE/RSNXE
16d913bfd Define AFC vendor commands and events
46f5cf928 OpenSSL: Fix additional HPKE corner cases
bdc35acd5 SAE: Allow loading of the password from an external database
48dd8994a Fix external passwords with 4-way handshake offloading
e5a7c852c systemd: Use interface name in description of interface-specific units
a0628f8a5 OpenSSL: Remove unused assignment from HPKE expand
3e1a04afa nl80211: Check that attribute addition succeeds in offloaded PASN case
0658a22ef GAS: Try to make buffer length determination easier for static analyzers
271ce71c7 FT: Fix PMK-R0 derivation for FT-SAE-EXT-KEY with SHA512
2f61d703a MLD STA: Group key handshake processing for GTK/IGTK/BIGTK rekeying
f0760aa6d MLD STA: Use AP MLD address as destination for 4-way handshake EAPOL-Key frames
8f2e493be MLD STA: Validation of MLO KDEs for 4-way handshake EAPOL-Key frames
f15cc834c MLD STA: Processing of EAPOL-Key msg 3/4 frame when using MLO
08512e5f3 MLD STA: Extend key configuration functions to support Link ID
a4adb2f3e MLD STA: Configure TK to the driver using AP MLD address
fa5cad61a MLD STA: Use AP MLD address in PMKSA entry
052bf8a51 MLD STA: Use AP MLD address to derive pairwise keys
e78437256 MLD STA: Add MLO KDEs for EAPOL-Key msg 2/4 and 4/4
472a0b8d6 MLD STA: Set MLO connection info to wpa_sm
cc2236299 nl80211: Get all requested MLO links information from (re)association events
1ca5c2ec2 PASN: Fix spelling of RSNE in debug messages
a43536a72 PASN: Verify explicitly that elements are present before parsing
7e3852407 PASN: Fix MIC check not to modify const data
8481c7509 PASN: Fix Authentication frame checks
f899d7f37 dbus: Apply PMK properties immediately
c6f8af507 Add option to disable SAE key_mgmt without PMF
7ad757ec0 Document crypto_ec_key_get_subject_public_key() to use compressed format
6527a7656 DPP: Stop listen mode for chirp-initiated Authentication exchange
2e7339442 P2P: Discount current operating frequency when scanning new connection
00a762c26 Do not drop connection attempt when reconnecting to the same ESS
368de263b P2P: Skip Extended Listen timeout to allow scans during group formation
cff55f348 P2P: Clone sae_pwe config to new group interface config
ae517789f P2P: Allow PSC channel to be used for 6 GHz BW40
9c830d917 P2P: Track peer 6 GHz capability more robustly
1ca403a8b Add QCA vendor subcommand to notify about primary netdev
70d89f90e A vendor roam control configuration for delaying hand off for RX
fff81a468 PASN: Change pasn_use_384() to be a non-static function
ea241cbe9 PASN: Rename struct wpas_pasn to pasn_data
6be84343a PASN: Add pairing verification wrapper function for Wi-Fi Aware
325236948 PASN: Mark wpas_pasn_start() comeback argument const
b1ed44b6a PASN: Allow extra elements to be added into PASN Authentication frames
08abcdf4e PASN: Makefile and Android.mk changes for libpasn.so
78c5bb7f5 PASN: Move responder functionality into a separate file
c7edfce79 PASN: Move initiator changes into a separate file
975b7a02c Move SAE comeback token functionality into a separate file
1711fe912 PASN: Compute MIC from RSNE and RSNXE of the frame for Wi-Fi Aware
6f80014b1 PASN: Allow custom PMKID in Authentication frames for Wi-Fi Aware
e99047da2 PASN: Add a handler func to send mgmt frames to the driver from AP
4022ffc5d PASN: Store AKMP in the PTKSA cache
c55eadede PASN: Remove hapd dependency in processing PASN Authentication frames
6dc833bc5 PASN: Remove hapd dependency for PASN and SAE comeback
1861f5716 PASN: Remove hapd dependency for pasn_derive_keys()
1fa266e99 PASN: Remove hapd dependency for SAE and FILS wrapped data
bc9fbe1b2 PASN: Common wpas_pasn structure for initiator and responder
14b5ebce7 PASN: Add a common header file for initiator and responder
af5eec3b3 PASN: Function handler to transmit Authentication frames
629bbc91b PASN: Remove dependency of wpa_ssid for initiator
e7f45ca11 PASN: Remove wpa_s dependency for wpas_pasn_start()
0be131265 PASN: Remove wpa_s dependency for wpas_pasn_build_auth_1()
086ccdc59 PASN: Remove wpa_s dependency for the functions processing RX frames
e2e87b90b PASN: Remove wpa_s dependency for wpas_pasn_auth_tx_status()
de4b73a36 PASN: Remove wpa_s dependency for FILS wrapped data
90bb73c51 PASN: Remove wpa_sm dependency to add an entry to PMKSA cache
5313e5a79 PASN: Remove unused wpa_s parameter for wpas_pasn_sae_setup_pt()
f636cbd04 PASN: Remove wpa_s dependency for SAE wrapped data functions
5535fbcfa PASN: Add wpa_pasn_reset() to eliminate need for struct wpa_supplicant
10e455c44 Enable use of PMKSA caching independent of RSN supplicant state machine
1d0ee1908 Fix the vendor ID assignment for configuring periodic sounding
b17b86da4 QCA vendor attribute to configure periodic sounding
6f3efa21c MLD STA: Fix crash caused by NULL wpa_s->current_ssid
ef5a9a009 nl80211: Fix parsing PASN peer and src addresses from vendor nl attributes
2c55c9273 More debug prints for EAPOL-Key message generation (Authenticator)
90cef4f21 MLD STA: Fully clear MLO info to avoid use of uninitialized members
496a1ced1 MLD STA: Use MLD addresses for sending non-Public Action frames
17ae98873 MLD STA: Support processing of M1 received before association event
9dafad1ea EHT: Definitions for STA Control fields of Basic Multi-Link element
1fbea7d43 EHT: Multi-Link element defragmentation
ec03b71ee common: Refactor element defragmentation
347ea8f0a EHT: Parse Multi-Link elements
73f540b6a MLD STA: Fetch MLO association Link ID info to core wpa_supplicant
ee46b7d6d nl80211: Check MLO link status info in NL80211_CMD_CONNECT
6e015cd45 RADIUS: Add Filter-Id attribute
06800f612 Add QCA vendor attributes for EHT support in external ACS
042368663 Vendor attribute to configure QoS/AC upgrade for UDP frames
e5d15e225 EHT: Allow EHT to be disabled using disable_eht=1 in wpa_supplicant
041f6cea9 SAE: Accept FT and -EXT-KEY AKMs for external auth
b72922796 P2P: Get cached scan results on iface creation to avoid scan
8392ea9e7 SAE: Fix AKM suite selector check for external authentication
ebe6a7c94 FT: Cover variable length KCK in function documentation
eda4ba081 FT: Reassociation Response frame validation for FT-SAE-EXT-KEY
0f7253d35 FT: Response processing for FT-SAE-EXT-KEY
a1eb1bb0e FT: Supplicant side FTE generation for FT-SAE-EXT-KEY
883e33594 FT: Authentication request frame processing for FT-SAE-EXT-KEY
879363bbc FT: Reassociation Request frame parsing for FT-SAE-EXT-KEY
e8f23c948 FT: Association Response frame FTE generation for FT-SAE-EXT-KEY
a76a314c1 FT: Extend PMK-R0 derivation for FT-SAE-EXT-KEY
79cd846b2 FT: Extend PTK derivation for FT-SAE-EXT-KEY
39b60f334 FT: Extend PMK-R1 derivation for FT-SAE-EXT-KEY
fb4fc704c FT: Debug print FTE subelements during parsing
25b52e5f8 FT: Extend FTE parsing for FT-SAE-EXT-KEY
4f58afee9 FT: Extend MIC derivation for FT-SAE-EXT-KEY
dcd46edf5 FT: Extend PMKR1Name derivation for FT-SAE-EXT-KEY
9fd245564 FT: Support longer SAE PMK for FT in INITPSK AP
c41bd98be FT: AP mode FTE writing to support FT-SAE-KEY-EXT
efa0f51d3 FT: Accept 512-bit PMK-R1 from RRB
eb0821c90 Add service class id attribute in SCS rule config vendor subcommand
5607abe2e WNM: Print unsupported neighbor report subelements in debug log
fcdd76fa2 Interworking: Print unsupported inner EAP-TTLS method in debug log
f8a05de66 Move default action from after switch to within
7614fcebe ACS: Filter out 6 GHz channels if HE or EHT is not enabled
1864664ca Android: Delay QCA roam+auth event until NL80211_CMD_ROAM is received
5f3cdc064 Override ieee80211w from pmf for AP mode in wpa_supplicant
2b972a35b DPP: Require PMF when profile is for SAE without PSK
8219d2b7d PASN: Fix CONFIG_PASN=y build without CONFIG_IEEE80211R=y
Change-Id: Ifd6be0d096df54c13162fdda164cd8e804a51692
Merged-In: Ifd6be0d096df54c13162fdda164cd8e804a51692
(cherry picked from commit 38ad1edd94f7b4f3c3937dd21a9b7ef52140babf)
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index be79765..dd4423a 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -279,6 +279,8 @@
"src/ap/ap_config.c",
"src/ap/ap_drv_ops.c",
"src/ap/ap_list.c",
+ "src/ap/comeback_token.c",
+ "src/pasn/pasn_responder.c",
"src/ap/ap_mlme.c",
"src/ap/authsrv.c",
"src/ap/beacon.c",
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 33dabf3..03dc209 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -108,6 +108,7 @@
INCLUDES += $(LOCAL_PATH)/src/tls
INCLUDES += $(LOCAL_PATH)/src/utils
INCLUDES += $(LOCAL_PATH)/src/wps
+INCLUDES += $(LOCAL_PATH)/src/pasn
INCLUDES += system/security/keystore/include
ifdef CONFIG_DRIVER_NL80211
ifneq ($(wildcard external/libnl),)
@@ -420,6 +421,7 @@
NEED_SHA256=y
NEED_SHA384=y
OBJS += src/common/ptksa_cache.c
+OBJS += src/pasn/pasn_initiator.c
OBJS += pasn_supplicant.c
endif
@@ -985,6 +987,8 @@
ifdef NEED_AP_MLME
OBJS += src/ap/wmm.c
OBJS += src/ap/ap_list.c
+OBJS += src/ap/comeback_token.c
+OBJS += src/pasn/pasn_responder.c
OBJS += src/ap/ieee802_11.c
OBJS += src/ap/hw_features.c
OBJS += src/ap/dfs.c
@@ -1757,6 +1761,142 @@
LDO=$(CC)
endif
+PASNOBJS =
+PASNOBJS += src/utils/$(CONFIG_ELOOP).c
+PASNOBJS += src/utils/wpa_debug.c
+PASNOBJS += src/utils/wpabuf.c
+PASNOBJS += src/utils/os_$(CONFIG_OS).c
+PASNOBJS += src/utils/config.c
+PASNOBJS += src/utils/common.c
+
+ifdef NEED_BASE64
+PASNOBJS += src/utils/base64.c
+endif
+
+ifdef CONFIG_WPA_TRACE
+PASNOBJS += src/utils/trace.c
+endif
+
+ifdef CONFIG_EXT_PASSWORD_FILE
+PASNOBJS += src/utils/ext_password_file.c
+endif
+
+ifdef CONFIG_EXT_PASSWORD_TEST
+PASNOBJS += src/utils/ext_password_test.c
+endif
+
+ifdef NEED_EXT_PASSWORD
+PASNOBJS += src/utils/ext_password.c
+endif
+
+ifdef CONFIG_SAE
+PASNOBJS += src/common/sae.c
+endif
+
+ifdef CONFIG_SAE_PK
+PASNOBJS += src/common/sae_pk.c
+endif
+
+ifndef CONFIG_NO_WPA
+PASNOBJS += src/common/wpa_common.c
+endif
+
+PASNOBJS += src/common/ieee802_11_common.c
+
+ifdef NEED_DRAGONFLY
+PASNOBJS += src/common/dragonfly.c
+endif
+
+PASNOBJS += src/common/ptksa_cache.c
+
+ifndef CONFIG_NO_WPA
+PASNOBJS += src/rsn_supp/pmksa_cache.c
+PASNOBJS += src/rsn_supp/wpa_ie.c
+endif
+
+PASNOBJS += src/ap/comeback_token.c
+PASNOBJS += src/ap/pmksa_cache_auth.c
+
+ifdef NEED_EAP_COMMON
+PASNOBJS += src/eap_common/eap_common.c
+endif
+
+ifdef CHAP
+PASNOBJS += src/eap_common/chap.c
+endif
+
+ifdef CONFIG_IEEE8021X_EAPOL
+PASNOBJS += src/eap_peer/eap.c
+PASNOBJS += src/eap_peer/eap_methods.c
+PASNOBJS += src/eapol_supp/eapol_supp_sm.c
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+PASNOBJS += src/crypto/crypto_openssl.c
+ifdef TLS_FUNCS
+PASNOBJS += src/crypto/tls_openssl.c
+#PASNOBJS += -lssl -lcrypto
+NEED_TLS_PRF_SHA256=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+PASNOBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c
+ifdef TLS_FUNCS
+PASNOBJS += src/crypto/tls_gnutls.c
+PASNOBJS += -lgnutls -lgpg-error
+PASNOBJS += -lgcrypt
+endif
+endif
+
+ifdef NEED_TLS_PRF_SHA256
+PASNOBJS += src/crypto/sha256-tlsprf.c
+endif
+
+ifdef NEED_SHA512
+PASNOBJS += src/crypto/sha512-prf.c
+endif
+
+ifdef NEED_SHA384
+PASNOBJS += src/crypto/sha384-prf.c
+endif
+
+PASNOBJS += src/crypto/sha256-prf.c
+
+ifdef NEED_HMAC_SHA512_KDF
+PASNOBJS += src/crypto/sha512-kdf.c
+endif
+
+ifdef NEED_HMAC_SHA384_KDF
+PASNOBJS += src/crypto/sha384-kdf.c
+endif
+
+ifdef NEED_HMAC_SHA256_KDF
+PASNOBJS += src/crypto/sha256-kdf.c
+endif
+
+ifdef NEED_DH_GROUPS
+PASNOBJS += src/crypto/dh_groups.c
+endif
+
+ifdef NEED_AES_SIV
+PASNOBJS += src/crypto/aes-siv.c
+endif
+
+ifdef NEED_AES_CTR
+PASNOBJS += src/crypto/aes-ctr.c
+endif
+
+ifdef NEED_SHA1
+PASNOBJS += src/crypto/sha1-prf.c
+ifdef NEED_TLS_PRF
+PASNOBJS += src/crypto/sha1-tlsprf.c
+endif
+endif
+
+PASNOBJS += src/pasn/pasn_initiator.c
+PASNOBJS += src/pasn/pasn_responder.c
+
########################
include $(CLEAR_VARS)
@@ -1897,3 +2037,14 @@
$(LOCAL_PATH)/aidl
include $(BUILD_STATIC_LIBRARY)
endif # WPA_SUPPLICANT_USE_AIDL == y
+
+#include $(CLEAR_VARS)
+#LOCAL_MODULE = libpasn
+#LOCAL_CFLAGS = $(L_CFLAGS)
+#LOCAL_SRC_FILES = $(PASNOBJS)
+#LOCAL_C_INCLUDES = $(INCLUDES)
+#LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+#ifeq ($(CONFIG_TLS), openssl)
+#LOCAL_SHARED_LIBRARIES := libcrypto libssl
+#endif
+#include $(BUILD_SHARED_LIBRARY)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 0a71558..c682f73 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -12,6 +12,12 @@
CONFIG_FILE=.config
include ../src/build.rules
+ifdef CONFIG_BUILD_PASN_SO
+# add the dependency this way to allow CONFIG_BUILD_PASN_SO
+# being set in the config which is read by build.rules
+_all: libpasn.so
+endif
+
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
@@ -76,6 +82,11 @@
ifndef CONFIG_NO_WPA_PASSPHRASE
install -D wpa_passphrase $(DESTDIR)/$(BINDIR)/wpa_passphrase
endif
+
+ifdef CONFIG_BUILD_PASN_SO
+ install -m 0644 -D libpasn.so $(DESTDIR)/$(LIBDIR)/libpasn.so
+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
@@ -418,6 +429,7 @@
NEED_SHA256=y
NEED_SHA384=y
OBJS += ../src/common/ptksa_cache.o
+OBJS += ../src/pasn/pasn_initiator.o
OBJS += pasn_supplicant.o
endif
@@ -987,6 +999,8 @@
ifdef NEED_AP_MLME
OBJS += ../src/ap/wmm.o
OBJS += ../src/ap/ap_list.o
+OBJS += ../src/ap/comeback_token.o
+OBJS += ../src/pasn/pasn_responder.o
OBJS += ../src/ap/ieee802_11.o
OBJS += ../src/ap/hw_features.o
OBJS += ../src/ap/dfs.o
@@ -2093,6 +2107,157 @@
lcov -c -d $(BUILDDIR) > lcov.info
genhtml lcov.info --output-directory lcov-html
+PASN_CFLAGS := $(CFLAGS)
+PASN_CFLAGS += -DCONFIG_PASN
+
+LIBPASNSO := ../src/utils/$(CONFIG_ELOOP).c
+LIBPASNSO += ../src/utils/wpa_debug.c
+LIBPASNSO += ../src/utils/wpabuf.c
+LIBPASNSO += ../src/utils/os_$(CONFIG_OS).c
+LIBPASNSO += ../src/utils/config.c
+LIBPASNSO += ../src/utils/common.c
+
+ifdef NEED_BASE64
+LIBPASNSO += ../src/utils/base64.c
+endif
+
+ifdef CONFIG_WPA_TRACE
+LIBPASNSO += ../src/utils/trace.c
+endif
+
+ifdef CONFIG_EXT_PASSWORD_FILE
+LIBPASNSO += ../src/utils/ext_password_file.c
+endif
+
+ifdef CONFIG_EXT_PASSWORD_TEST
+LIBPASNSO += ../src/utils/ext_password_test.c
+endif
+
+ifdef NEED_EXT_PASSWORD
+LIBPASNSO += ../src/utils/ext_password.c
+endif
+
+ifdef CONFIG_SAE
+LIBPASNSO += ../src/common/sae.c
+endif
+
+ifdef CONFIG_SAE_PK
+LIBPASNSO += ../src/common/sae_pk.c
+endif
+
+ifndef CONFIG_NO_WPA
+LIBPASNSO += ../src/common/wpa_common.c
+endif
+
+LIBPASNSO += ../src/common/ieee802_11_common.c
+
+ifdef NEED_DRAGONFLY
+LIBPASNSO += ../src/common/dragonfly.c
+endif
+
+LIBPASNSO += ../src/common/ptksa_cache.c
+
+ifndef CONFIG_NO_WPA
+LIBPASNSO += ../src/rsn_supp/pmksa_cache.c
+LIBPASNSO += ../src/rsn_supp/wpa_ie.c
+endif
+
+LIBPASNSO += ../src/ap/comeback_token.c
+LIBPASNSO += ../src/ap/pmksa_cache_auth.c
+
+ifdef NEED_EAP_COMMON
+LIBPASNSO += ../src/eap_common/eap_common.c
+endif
+
+ifdef CHAP
+LIBPASNSO += ../src/eap_common/chap.c
+endif
+
+ifdef CONFIG_IEEE8021X_EAPOL
+LIBPASNSO += ../src/eap_peer/eap.c
+LIBPASNSO += ../src/eap_peer/eap_methods.c
+LIBPASNSO += ../src/eapol_supp/eapol_supp_sm.c
+endif
+
+ifeq ($(CONFIG_TLS), wolfssl)
+LIBPASNSO += ../src/crypto/crypto_wolfssl.c
+ifdef TLS_FUNCS
+LIBPASNSO += ../src/crypto/tls_wolfssl.c
+NEED_TLS_PRF_SHA256=y
+LIBPASNSO += -lwolfssl -lm
+endif
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+LIBPASNSO += ../src/crypto/crypto_openssl.c
+ifdef TLS_FUNCS
+LIBPASNSO += ../src/crypto/tls_openssl.c
+LIBPASNSO += -lssl -lcrypto
+NEED_TLS_PRF_SHA256=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+LIBPASNSO += ../src/crypto/crypto_$(CONFIG_CRYPTO).c
+ifdef TLS_FUNCS
+LIBPASNSO += ../src/crypto/tls_gnutls.c
+LIBPASNSO += -lgnutls -lgpg-error
+LIBPASNSO += -lgcrypt
+endif
+endif
+
+ifdef NEED_TLS_PRF_SHA256
+LIBPASNSO += ../src/crypto/sha256-tlsprf.c
+endif
+
+ifdef NEED_SHA512
+LIBPASNSO += ../src/crypto/sha512-prf.c
+endif
+
+ifdef NEED_SHA384
+LIBPASNSO += ../src/crypto/sha384-prf.c
+endif
+
+LIBPASNSO += ../src/crypto/sha256-prf.c
+
+ifdef NEED_HMAC_SHA512_KDF
+LIBPASNSO += ../src/crypto/sha512-kdf.c
+endif
+
+ifdef NEED_HMAC_SHA384_KDF
+LIBPASNSO += ../src/crypto/sha384-kdf.c
+endif
+
+ifdef NEED_HMAC_SHA256_KDF
+LIBPASNSO += ../src/crypto/sha256-kdf.c
+endif
+
+ifdef NEED_DH_GROUPS
+LIBPASNSO += ../src/crypto/dh_groups.c
+endif
+
+ifdef NEED_AES_SIV
+LIBPASNSO += ../src/crypto/aes-siv.c
+endif
+
+ifdef NEED_AES_CTR
+LIBPASNSO += ../src/crypto/aes-ctr.c
+endif
+
+ifdef NEED_SHA1
+LIBPASNSO += ../src/crypto/sha1-prf.c
+ifdef NEED_TLS_PRF
+LIBPASNSO += ../src/crypto/sha1-tlsprf.c
+endif
+endif
+
+LIBPASNSO += ../src/pasn/pasn_initiator.c
+LIBPASNSO += ../src/pasn/pasn_responder.c
+
+libpasn.so: $(LIBPASNSO)
+ @$(E) " CC $@ ($^)"
+ $(Q)$(CC) $(LDFLAGS) -o $@ $(PASN_CFLAGS) -shared -fPIC -lcrypto $^
+
clean: common-clean
$(MAKE) -C ../src clean
$(MAKE) -C dbus clean
@@ -2103,6 +2268,7 @@
rm -f lcov.info
rm -rf lcov-html
rm -f libwpa_client.a
+ rm -f libpasn.so
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 0cc5f39..7d30e23 100644
--- a/wpa_supplicant/README-HS20
+++ b/wpa_supplicant/README-HS20
@@ -199,7 +199,26 @@
# be used to configure alternative FQDNs that will be considered home
# networks.
#
+# home_ois: Home OI(s)
+# This string field contains one or more comma delimited OIs (hexdump)
+# identifying the access the access points that support authentication
+# with this credential. There are an alternative to the use of the realm
+# parameter. When using Home OIs to match the network, the EAP parameters
+# need to be pre-configured with the credentials since the NAI Realm
+# information may not be available or fetched.
+# A successful authentication with the access point is possible as soon
+# as at least one Home OI from the list matches an OI in the Roaming
+# Consortium advertised by the access point.
+# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOI)
+#
+# required_home_ois: Required Home OI(s)
+# This string field contains the set of Home OI(s) (hexdump) that are
+# required to be advertised by the AP for the credential to be considered
+# matching.
+# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOIRequired)
+#
# roaming_consortium: Roaming Consortium OI
+# Deprecated: use home_ois instead.
# If roaming_consortium_len is non-zero, this field contains the
# Roaming Consortium OI that can be used to determine which access
# points support authentication with this credential. This is an
@@ -209,6 +228,7 @@
# may not be available or fetched.
#
# required_roaming_consortium: Required Roaming Consortium OI
+# Deprecated: use required_home_ois instead.
# If required_roaming_consortium_len is non-zero, this field contains the
# Roaming Consortium OI that is required to be advertised by the AP for
# the credential to be considered matching.
@@ -325,7 +345,7 @@
# password="password"
# ca_cert="/etc/wpa_supplicant/ca.pem"
# domain="example.com"
-# roaming_consortium=223344
+# home_ois="223344"
# roaming_consortiums="112233,4455667788,aabbcc"
# eap=TTLS
# phase2="auth=MSCHAPV2"
diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/aidl_manager.cpp
index f644a39..e2523d4 100644
--- a/wpa_supplicant/aidl/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/aidl_manager.cpp
@@ -472,7 +472,7 @@
// Enable randomized source MAC address for GAS/ANQP
// Set the lifetime to 0, guarantees a unique address for each GAS
// session
- wpa_s->conf->gas_rand_mac_addr = 1;
+ wpa_s->conf->gas_rand_mac_addr = WPAS_MAC_ADDR_STYLE_RANDOM;
wpa_s->conf->gas_rand_addr_lifetime = 0;
}
diff --git a/wpa_supplicant/aidl/misc_utils.h b/wpa_supplicant/aidl/misc_utils.h
index c529e3d..d0330e0 100644
--- a/wpa_supplicant/aidl/misc_utils.h
+++ b/wpa_supplicant/aidl/misc_utils.h
@@ -88,6 +88,7 @@
ss.write((char *) pmksa_entry->pmk, pmksa_entry->pmk_len);
ss.write((char *) pmksa_entry->pmkid, PMKID_LEN);
ss.write((char *) pmksa_entry->aa, ETH_ALEN);
+ ss.write((char *) pmksa_entry->spa, ETH_ALEN);
// Omit wpa_ssid field because the network is created on connecting to a access point.
ss.write((char *) &pmksa_entry->akmp, sizeof(pmksa_entry->akmp));
ss.write((char *) &pmksa_entry->reauth_time, sizeof(pmksa_entry->reauth_time));
@@ -110,7 +111,7 @@
ss.read((char *) &pmksa_entry->pmk_len, sizeof(pmksa_entry->pmk_len));
if ((pmksa_entry->pmk_len > PMK_LEN_MAX) ||
(ss.str().size() < (sizeof(pmksa_entry->pmk_len) + pmksa_entry->pmk_len +
- PMKID_LEN + ETH_ALEN + sizeof(pmksa_entry->akmp) +
+ PMKID_LEN + ETH_ALEN + ETH_ALEN + sizeof(pmksa_entry->akmp) +
sizeof(pmksa_entry->reauth_time) + sizeof(pmksa_entry->expiration) +
sizeof(pmksa_entry->opportunistic) + 1 /* fils_cache_id_set */)))
return -1;
@@ -118,6 +119,7 @@
ss.read((char *) pmksa_entry->pmk, pmksa_entry->pmk_len);
ss.read((char *) pmksa_entry->pmkid, PMKID_LEN);
ss.read((char *) pmksa_entry->aa, ETH_ALEN);
+ ss.read((char *) pmksa_entry->spa, ETH_ALEN);
// Omit wpa_ssid field because the network is created on connecting to a access point.
ss.read((char *) &pmksa_entry->akmp, sizeof(pmksa_entry->akmp));
ss.read((char *) &pmksa_entry->reauth_time, sizeof(pmksa_entry->reauth_time));
diff --git a/wpa_supplicant/aidl/p2p_iface.cpp b/wpa_supplicant/aidl/p2p_iface.cpp
index 9927ba4..2afd75b 100644
--- a/wpa_supplicant/aidl/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/p2p_iface.cpp
@@ -1652,6 +1652,10 @@
"Passphrase is invalid.");
}
+ wpa_printf(MSG_DEBUG,
+ "P2P: Add group with config Role: %s network name: %s freq: %d",
+ joinExistingGroup ? "CLIENT" : "GO",
+ wpa_ssid_txt(ssid.data(), ssid.size()), freq);
if (!joinExistingGroup) {
struct p2p_data *p2p = wpa_s->global->p2p;
os_memcpy(p2p->ssid, ssid.data(), ssid.size());
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index e8c1927..029b99a 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -2070,18 +2070,18 @@
SignalPollResult result;
result.linkId = 0;
- result.currentRssiDbm = mlo_si.links[i].current_signal;
- result.txBitrateMbps = mlo_si.links[i].current_txrate / 1000;
- result.rxBitrateMbps = mlo_si.links[i].current_rxrate / 1000;
+ result.currentRssiDbm = mlo_si.links[i].data.signal;
+ result.txBitrateMbps = mlo_si.links[i].data.current_tx_rate / 1000;
+ result.rxBitrateMbps = mlo_si.links[i].data.current_rx_rate / 1000;
result.frequencyMhz = mlo_si.links[i].frequency;
results.push_back(result);
}
} else if (wpa_drv_signal_poll(wpa_s, &si) == 0) {
SignalPollResult result;
result.linkId = 0;
- result.currentRssiDbm = si.current_signal;
- result.txBitrateMbps = si.current_txrate / 1000;
- result.rxBitrateMbps = si.current_rxrate / 1000;
+ result.currentRssiDbm = si.data.signal;
+ result.txBitrateMbps = si.data.current_tx_rate / 1000;
+ result.rxBitrateMbps = si.data.current_rx_rate / 1000;
result.frequencyMhz = si.frequency;
results.push_back(result);
}
diff --git a/wpa_supplicant/aidl/sta_network.cpp b/wpa_supplicant/aidl/sta_network.cpp
index 5a83b05..4d816e4 100644
--- a/wpa_supplicant/aidl/sta_network.cpp
+++ b/wpa_supplicant/aidl/sta_network.cpp
@@ -2617,13 +2617,13 @@
struct wpa_supplicant *wpa_s = retrieveIfacePtr();
switch (mode) {
case SaeH2eMode::DISABLED:
- wpa_s->conf->sae_pwe = 0;
+ wpa_s->conf->sae_pwe = SAE_PWE_HUNT_AND_PECK;
break;
case SaeH2eMode::H2E_MANDATORY:
- wpa_s->conf->sae_pwe = 1;
+ wpa_s->conf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
break;
case SaeH2eMode::H2E_OPTIONAL:
- wpa_s->conf->sae_pwe = 2;
+ wpa_s->conf->sae_pwe = SAE_PWE_BOTH;
break;
}
resetInternalStateAfterParamsUpdate();
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 16d6c90..f4c3811 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -706,8 +706,12 @@
bss->wpa_group_rekey = 86400;
}
- if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT)
+ if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT) {
bss->ieee80211w = ssid->ieee80211w;
+ } else if (wpa_s->conf->pmf != MGMT_FRAME_PROTECTION_DEFAULT) {
+ if (ssid->mode == WPAS_MODE_AP)
+ bss->ieee80211w = wpa_s->conf->pmf;
+ }
#ifdef CONFIG_OCV
bss->ocv = ssid->ocv;
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index cb732f7..75bdec1 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -422,7 +422,7 @@
/* Poll for signal info to set initial scan interval */
struct wpa_signal_info siginfo;
if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
- siginfo.current_signal >= data->signal_threshold)
+ siginfo.data.signal >= data->signal_threshold)
data->scan_interval = data->long_interval;
}
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index 41a26df..5a8f97c 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -137,7 +137,7 @@
/* Poll for signal info to set initial scan interval */
struct wpa_signal_info siginfo;
if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
- siginfo.current_signal >= data->signal_threshold)
+ siginfo.data.signal >= data->signal_threshold)
data->scan_interval = data->long_interval;
}
wpa_printf(MSG_DEBUG, "bgscan simple: Init scan interval: %d",
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index dcc28be..0f986bb 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -993,6 +993,14 @@
if (wpa_bss_in_use(wpa_s, bss))
continue;
+ if (wpa_s->reassoc_same_ess &&
+ wpa_s->wpa_state != WPA_COMPLETED &&
+ wpa_s->last_ssid &&
+ bss->ssid_len == wpa_s->last_ssid->ssid_len &&
+ os_memcmp(bss->ssid, wpa_s->last_ssid->ssid,
+ bss->ssid_len) == 0)
+ continue;
+
if (os_reltime_before(&bss->last_update, &t)) {
wpa_bss_remove(wpa_s, bss, __func__);
} else
@@ -1438,3 +1446,21 @@
return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
capab);
}
+
+
+/**
+ * wpa_bss_defrag_mle - Get a buffer holding a de-fragmented ML element
+ * @bss: BSS table entry
+ * @type: ML control type
+ */
+struct wpabuf * wpa_bss_defrag_mle(const struct wpa_bss *bss, u8 type)
+{
+ struct ieee802_11_elems elems;
+ const u8 *pos = wpa_bss_ie_ptr(bss);
+ size_t len = bss->ie_len;
+
+ if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
+ return NULL;
+
+ return ieee802_11_defrag_mle(&elems, type);
+}
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index b68fc87..611da88 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -201,4 +201,6 @@
unsigned int age_ms,
struct os_reltime *update_time);
+struct wpabuf * wpa_bss_defrag_mle(const struct wpa_bss *bss, u8 type);
+
#endif /* BSS_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 2b1bdeb..f3e2edb 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2345,6 +2345,50 @@
#endif /* NO_CONFIG_WRITE */
+static int wpa_config_parse_mac_value(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ u8 mac_value[ETH_ALEN];
+
+ if (hwaddr_aton(value, mac_value) == 0) {
+ if (os_memcmp(mac_value, ssid->mac_value, ETH_ALEN) == 0)
+ return 1;
+ os_memcpy(ssid->mac_value, mac_value, ETH_ALEN);
+ return 0;
+ }
+
+ wpa_printf(MSG_ERROR, "Line %d: Invalid MAC address '%s'",
+ line, value);
+ return -1;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_mac_value(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ const size_t size = 3 * ETH_ALEN;
+ char *value;
+ int res;
+
+ if (ssid->mac_addr != WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS)
+ return NULL;
+
+ value = os_malloc(size);
+ if (!value)
+ return NULL;
+ res = os_snprintf(value, size, MACSTR, MAC2STR(ssid->mac_value));
+ if (os_snprintf_error(size, res)) {
+ os_free(value);
+ return NULL;
+ }
+ value[size - 1] = '\0';
+ return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
/* Helper macros for network block parser */
#ifdef OFFSET
@@ -2644,7 +2688,8 @@
{ INT(update_identifier) },
{ STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) },
#endif /* CONFIG_HS20 */
- { INT_RANGE(mac_addr, 0, 2) },
+ { INT_RANGE(mac_addr, 0, 3) },
+ { FUNC_KEY(mac_value) },
{ INT_RANGE(pbss, 0, 2) },
{ INT_RANGE(wps_disabled, 0, 1) },
{ INT_RANGE(fils_dh_group, 0, 65535) },
@@ -2665,6 +2710,7 @@
{ INT_RANGE(beacon_prot, 0, 1) },
{ INT_RANGE(transition_disable, 0, 255) },
{ INT_RANGE(sae_pk, 0, 2) },
+ { INT_RANGE(disable_eht, 0, 1)},
};
#undef OFFSET
@@ -3181,7 +3227,7 @@
#ifdef CONFIG_MACSEC
ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER;
#endif /* CONFIG_MACSEC */
- ssid->mac_addr = -1;
+ ssid->mac_addr = WPAS_MAC_ADDR_STYLE_NOT_SET;
ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH;
}
@@ -3532,53 +3578,62 @@
}
-static int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred,
- const char *value)
+static int
+wpa_config_set_cred_ois(u8 cred_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN],
+ size_t cred_ois_len[MAX_ROAMING_CONS],
+ unsigned int *cred_num_ois,
+ const char *value)
{
- u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
- size_t roaming_consortiums_len[MAX_ROAMING_CONS];
- unsigned int num_roaming_consortiums = 0;
+ u8 ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
+ size_t ois_len[MAX_ROAMING_CONS];
+ unsigned int num_ois = 0;
const char *pos, *end;
size_t len;
- os_memset(roaming_consortiums, 0, sizeof(roaming_consortiums));
- os_memset(roaming_consortiums_len, 0, sizeof(roaming_consortiums_len));
+ len = os_strlen(value);
+ if (len / 2 < 3) {
+ wpa_printf(MSG_ERROR,
+ "Invalid organisation identifier (OI) list: %s",
+ value);
+ return -1;
+ }
+
+ os_memset(ois, 0, sizeof(ois));
+ os_memset(ois_len, 0, sizeof(ois_len));
for (pos = value;;) {
end = os_strchr(pos, ',');
len = end ? (size_t) (end - pos) : os_strlen(pos);
if (!end && len == 0)
break;
- if (len == 0 || (len & 1) != 0 ||
+ if (len / 2 < 3 || (len & 1) != 0 ||
len / 2 > MAX_ROAMING_CONS_OI_LEN ||
hexstr2bin(pos,
- roaming_consortiums[num_roaming_consortiums],
+ ois[num_ois],
len / 2) < 0) {
wpa_printf(MSG_INFO,
- "Invalid roaming_consortiums entry: %s",
+ "Invalid organisation identifier (OI) entry: %s",
pos);
return -1;
}
- roaming_consortiums_len[num_roaming_consortiums] = len / 2;
- num_roaming_consortiums++;
+ ois_len[num_ois] = len / 2;
+ num_ois++;
if (!end)
break;
- if (num_roaming_consortiums >= MAX_ROAMING_CONS) {
+ if (num_ois >= MAX_ROAMING_CONS) {
wpa_printf(MSG_INFO,
- "Too many roaming_consortiums OIs");
+ "Too many OIs");
return -1;
}
pos = end + 1;
}
- os_memcpy(cred->roaming_consortiums, roaming_consortiums,
- sizeof(roaming_consortiums));
- os_memcpy(cred->roaming_consortiums_len, roaming_consortiums_len,
- sizeof(roaming_consortiums_len));
- cred->num_roaming_consortiums = num_roaming_consortiums;
+ os_memcpy(cred_ois, ois, sizeof(ois));
+ os_memcpy(cred_ois_len, ois_len, sizeof(ois_len));
+ *cred_num_ois = num_ois;
return 0;
}
@@ -3813,36 +3868,70 @@
}
if (os_strcmp(var, "roaming_consortium") == 0) {
- if (len < 3 || len > sizeof(cred->roaming_consortium)) {
+ if (len < 3 || len > sizeof(cred->home_ois[0])) {
wpa_printf(MSG_ERROR, "Line %d: invalid "
"roaming_consortium length %d (3..15 "
"expected)", line, (int) len);
os_free(val);
return -1;
}
- os_memcpy(cred->roaming_consortium, val, len);
- cred->roaming_consortium_len = len;
+ wpa_printf(MSG_WARNING,
+ "Line %d: option roaming_consortium is deprecated and will be removed in the future",
+ line);
+ os_memcpy(cred->home_ois[0], val, len);
+ cred->home_ois_len[0] = len;
+ cred->num_home_ois = 1;
os_free(val);
return 0;
}
if (os_strcmp(var, "required_roaming_consortium") == 0) {
- if (len < 3 || len > sizeof(cred->required_roaming_consortium))
- {
+ if (len < 3 || len > sizeof(cred->required_home_ois[0])) {
wpa_printf(MSG_ERROR, "Line %d: invalid "
"required_roaming_consortium length %d "
"(3..15 expected)", line, (int) len);
os_free(val);
return -1;
}
- os_memcpy(cred->required_roaming_consortium, val, len);
- cred->required_roaming_consortium_len = len;
+ wpa_printf(MSG_WARNING,
+ "Line %d: option required_roaming_consortium is deprecated and will be removed in the future",
+ line);
+ os_memcpy(cred->required_home_ois[0], val, len);
+ cred->required_home_ois_len[0] = len;
+ cred->num_required_home_ois = 1;
os_free(val);
return 0;
}
+ if (os_strcmp(var, "home_ois") == 0) {
+ res = wpa_config_set_cred_ois(cred->home_ois,
+ cred->home_ois_len,
+ &cred->num_home_ois,
+ val);
+ if (res < 0)
+ wpa_printf(MSG_ERROR, "Line %d: invalid home_ois",
+ line);
+ os_free(val);
+ return res;
+ }
+
+ if (os_strcmp(var, "required_home_ois") == 0) {
+ res = wpa_config_set_cred_ois(cred->required_home_ois,
+ cred->required_home_ois_len,
+ &cred->num_required_home_ois,
+ val);
+ if (res < 0)
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid required_home_ois", line);
+ os_free(val);
+ return res;
+ }
+
if (os_strcmp(var, "roaming_consortiums") == 0) {
- res = wpa_config_set_cred_roaming_consortiums(cred, val);
+ res = wpa_config_set_cred_ois(cred->roaming_consortiums,
+ cred->roaming_consortiums_len,
+ &cred->num_roaming_consortiums,
+ val);
if (res < 0)
wpa_printf(MSG_ERROR,
"Line %d: invalid roaming_consortiums",
@@ -4162,14 +4251,14 @@
size_t buflen;
char *buf;
- if (!cred->roaming_consortium_len)
+ if (!cred->num_home_ois || !cred->home_ois_len[0])
return NULL;
- buflen = cred->roaming_consortium_len * 2 + 1;
+ buflen = cred->home_ois_len[0] * 2 + 1;
buf = os_malloc(buflen);
if (buf == NULL)
return NULL;
- wpa_snprintf_hex(buf, buflen, cred->roaming_consortium,
- cred->roaming_consortium_len);
+ wpa_snprintf_hex(buf, buflen, cred->home_ois[0],
+ cred->home_ois_len[0]);
return buf;
}
@@ -4177,14 +4266,64 @@
size_t buflen;
char *buf;
- if (!cred->required_roaming_consortium_len)
+ if (!cred->num_required_home_ois ||
+ !cred->required_home_ois_len[0])
return NULL;
- buflen = cred->required_roaming_consortium_len * 2 + 1;
+ buflen = cred->required_home_ois_len[0] * 2 + 1;
buf = os_malloc(buflen);
if (buf == NULL)
return NULL;
- wpa_snprintf_hex(buf, buflen, cred->required_roaming_consortium,
- cred->required_roaming_consortium_len);
+ wpa_snprintf_hex(buf, buflen, cred->required_home_ois[0],
+ cred->required_home_ois_len[0]);
+ return buf;
+ }
+
+ if (os_strcmp(var, "home_ois") == 0) {
+ size_t buflen;
+ char *buf, *pos;
+ size_t i;
+
+ if (!cred->num_home_ois)
+ return NULL;
+ buflen = cred->num_home_ois * MAX_ROAMING_CONS_OI_LEN * 2 + 1;
+ buf = os_malloc(buflen);
+ if (!buf)
+ return NULL;
+ pos = buf;
+ for (i = 0; i < cred->num_home_ois; i++) {
+ if (i > 0)
+ *pos++ = ',';
+ pos += wpa_snprintf_hex(
+ pos, buf + buflen - pos,
+ cred->home_ois[i],
+ cred->home_ois_len[i]);
+ }
+ *pos = '\0';
+ return buf;
+ }
+
+ if (os_strcmp(var, "required_home_ois") == 0) {
+ size_t buflen;
+ char *buf, *pos;
+ size_t i;
+
+ if (!cred->num_required_home_ois)
+ return NULL;
+ buflen = cred->num_required_home_ois *
+ MAX_ROAMING_CONS_OI_LEN * 2 + 1;
+ buf = os_malloc(buflen);
+ if (!buf)
+ return NULL;
+ pos = buf;
+ for (i = 0; i < cred->num_required_home_ois; i++) {
+ if (i > 0)
+ *pos++ = ',';
+ pos += wpa_snprintf_hex(
+ pos, buf + buflen - pos,
+ cred->required_home_ois[i],
+ cred->required_home_ois_len[i]);
+ }
+ *pos = '\0';
return buf;
}
@@ -5288,6 +5427,7 @@
{ INT_RANGE(auto_interworking, 0, 1), 0 },
{ INT(okc), 0 },
{ INT(pmf), 0 },
+ { INT_RANGE(sae_check_mfp, 0, 1), 0 },
{ FUNC(sae_groups), 0 },
{ INT_RANGE(sae_pwe, 0, 3), 0 },
{ INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
@@ -5306,9 +5446,9 @@
{ STR(osu_dir), 0 },
{ STR(wowlan_triggers), CFG_CHANGED_WOWLAN_TRIGGERS },
{ INT(p2p_search_delay), 0},
- { INT(mac_addr), 0 },
+ { INT_RANGE(mac_addr, 0, 2), 0 },
{ INT(rand_addr_lifetime), 0 },
- { INT(preassoc_mac_addr), 0 },
+ { INT_RANGE(preassoc_mac_addr, 0, 2), 0 },
{ INT(key_mgmt_offload), 0},
{ INT(passive_scan), 0 },
{ INT(reassoc_same_bss_optim), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 0316e9b..dbb79dd 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -272,36 +272,50 @@
size_t num_domain;
/**
- * roaming_consortium - Roaming Consortium OI
+ * home_ois - Home OIs
*
- * If roaming_consortium_len is non-zero, this field contains the
- * Roaming Consortium OI that can be used to determine which access
- * points support authentication with this credential. This is an
- * alternative to the use of the realm parameter. When using Roaming
- * Consortium to match the network, the EAP parameters need to be
- * pre-configured with the credential since the NAI Realm information
- * may not be available or fetched.
+ * If num_home_ois is non-zero, this field contains the set of Home OIs
+ * that can be use to determine which access points support
+ * authentication with this credential. These are an alternative to the
+ * use of the realm parameter. When using Home OIs to match the network,
+ * the EAP parameters need to be pre-configured with the credentials
+ * since the NAI Realm information may not be available or fetched.
+ * A successful authentication with the access point is possible as soon
+ * as at least one Home OI from the list matches an OI in the Roaming
+ * Consortium list advertised by the access point.
+ * (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOI)
*/
- u8 roaming_consortium[15];
+ u8 home_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
/**
- * roaming_consortium_len - Length of roaming_consortium
+ * home_ois_len - Length of home_ois[i]
*/
- size_t roaming_consortium_len;
+ size_t home_ois_len[MAX_ROAMING_CONS];
/**
- * required_roaming_consortium - Required Roaming Consortium OI
+ * num_home_ois - Number of entries in home_ois
+ */
+ unsigned int num_home_ois;
+
+ /**
+ * required_home_ois - Required Home OI(s)
*
- * If required_roaming_consortium_len is non-zero, this field contains
- * the Roaming Consortium OI that is required to be advertised by the AP
- * for the credential to be considered matching.
+ * If required_home_ois_len is non-zero, this field contains the set of
+ * Home OI(s) that are required to be advertised by the AP for the
+ * credential to be considered matching.
+ * (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOIRequired)
*/
- u8 required_roaming_consortium[15];
+ u8 required_home_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN];
/**
- * required_roaming_consortium_len - Length of required_roaming_consortium
+ * required_home_ois_len - Length of required_home_ois
*/
- size_t required_roaming_consortium_len;
+ size_t required_home_ois_len[MAX_ROAMING_CONS];
+
+ /**
+ * num_required_home_ois - Number of entries in required_home_ois
+ */
+ unsigned int num_required_home_ois;
/**
* roaming_consortiums - Roaming Consortium OI(s) memberships
@@ -1253,6 +1267,25 @@
enum mfp_options pmf;
/**
+ * sae_check_mfp - Whether to limit SAE based on PMF capabilities
+ *
+ * With this check SAE key_mgmt will not be selected if PMF is
+ * not enabled.
+ * Scenarios where enabling this check will limit SAE:
+ * 1) ieee8011w=0 is set for the network.
+ * 2) The AP does not have PMF enabled.
+ * 3) ieee8011w for the network is the default(3), pmf=1 is enabled
+ * globally and the device does not support the BIP cipher.
+ *
+ * Useful to allow the BIP cipher check that occurs for ieee80211w=3
+ * and pmf=1 to also avoid using SAE key_mgmt.
+ * Useful when hardware does not support BIP to still to allow
+ * connecting to sae_require_mfp=1 WPA2+WPA3-Personal transition mode
+ *access points by automatically selecting PSK instead of SAE.
+ */
+ int sae_check_mfp;
+
+ /**
* sae_groups - Preference list of enabled groups for SAE
*
* By default (if this parameter is not set), the mandatory group 19
@@ -1268,7 +1301,7 @@
* 1 = hash-to-element only
* 2 = both hunting-and-pecking loop and hash-to-element enabled
*/
- int sae_pwe;
+ enum sae_pwe sae_pwe;
/**
* sae_pmkid_in_assoc - Whether to include PMKID in SAE Assoc Req
@@ -1388,7 +1421,7 @@
* the per-network mac_addr parameter. Global mac_addr=1 can be used to
* change this default behavior.
*/
- int mac_addr;
+ enum wpas_mac_addr_style mac_addr;
/**
* rand_addr_lifetime - Lifetime of random MAC address in seconds
@@ -1402,7 +1435,7 @@
* 1 = use random MAC address
* 2 = like 1, but maintain OUI (with local admin bit set)
*/
- int preassoc_mac_addr;
+ enum wpas_mac_addr_style preassoc_mac_addr;
/**
* key_mgmt_offload - Use key management offload
@@ -1611,7 +1644,7 @@
* 1 = use random MAC address
* 2 = like 1, but maintain OUI (with local admin bit set)
*/
- int gas_rand_mac_addr;
+ enum wpas_mac_addr_style gas_rand_mac_addr;
/**
* dpp_config_processing - How to process DPP configuration
@@ -1836,6 +1869,7 @@
* @name: Name of the configuration (e.g., path and file name for the
* configuration file)
* @cfgp: Pointer to previously allocated configuration data or %NULL if none
+ * @ro: Whether to mark networks from this configuration as read-only
* Returns: Pointer to allocated configuration data or %NULL on failure
*
* This function reads configuration data, parses its contents, and allocates
@@ -1844,7 +1878,8 @@
*
* Each configuration backend needs to implement this function.
*/
-struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp);
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp,
+ bool ro);
/**
* wpa_config_write - Write or update configuration data
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 372a57b..1b8526b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -53,6 +53,13 @@
ssid->group_cipher &= ~WPA_CIPHER_CCMP;
}
+ if (is_6ghz_freq(ssid->frequency) && ssid->mode == WPAS_MODE_MESH &&
+ ssid->key_mgmt == WPA_KEY_MGMT_NONE) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: key_mgmt for mesh network in 6 GHz should be SAE",
+ line);
+ errors++;
+ }
if (ssid->mode == WPAS_MODE_MESH &&
(ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
ssid->key_mgmt != WPA_KEY_MGMT_SAE)) {
@@ -289,7 +296,8 @@
#endif /* CONFIG_NO_CONFIG_BLOBS */
-struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp,
+ bool ro)
{
FILE *f;
char buf[512], *pos;
@@ -331,6 +339,7 @@
while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
if (os_strcmp(pos, "network={") == 0) {
ssid = wpa_config_read_network(f, &line, id++);
+ ssid->ro = ro;
if (ssid == NULL) {
wpa_printf(MSG_ERROR, "Line %d: failed to "
"parse network block.", line);
@@ -880,6 +889,7 @@
#ifdef CONFIG_HE_OVERRIDES
INT(disable_he);
#endif /* CONFIG_HE_OVERRIDES */
+ INT(disable_eht);
#undef STR
#undef INT
@@ -921,12 +931,6 @@
if (cred->domain_suffix_match)
fprintf(f, "\tdomain_suffix_match=\"%s\"\n",
cred->domain_suffix_match);
- if (cred->roaming_consortium_len) {
- fprintf(f, "\troaming_consortium=");
- for (i = 0; i < cred->roaming_consortium_len; i++)
- fprintf(f, "%02x", cred->roaming_consortium[i]);
- fprintf(f, "\n");
- }
if (cred->eap_method) {
const char *name;
name = eap_get_name(cred->eap_method[0].vendor,
@@ -1002,12 +1006,32 @@
}
}
- if (cred->required_roaming_consortium_len) {
- fprintf(f, "\trequired_roaming_consortium=");
- for (i = 0; i < cred->required_roaming_consortium_len; i++)
- fprintf(f, "%02x",
- cred->required_roaming_consortium[i]);
- fprintf(f, "\n");
+ if (cred->num_home_ois) {
+ size_t j;
+
+ fprintf(f, "\thome_ois=\"");
+ for (i = 0; i < cred->num_home_ois; i++) {
+ if (i > 0)
+ fprintf(f, ",");
+ for (j = 0; j < cred->home_ois_len[i]; j++)
+ fprintf(f, "%02x",
+ cred->home_ois[i][j]);
+ }
+ fprintf(f, "\"\n");
+ }
+
+ if (cred->num_required_home_ois) {
+ size_t j;
+
+ fprintf(f, "\trequired_home_ois=\"");
+ for (i = 0; i < cred->num_required_home_ois; i++) {
+ if (i > 0)
+ fprintf(f, ",");
+ for (j = 0; j < cred->required_home_ois_len[i]; j++)
+ fprintf(f, "%02x",
+ cred->required_home_ois[i][j]);
+ }
+ fprintf(f, "\"\n");
}
if (cred->num_roaming_consortiums) {
@@ -1358,6 +1382,9 @@
if (config->beacon_int)
fprintf(f, "beacon_int=%d\n", config->beacon_int);
+ if (config->sae_check_mfp)
+ fprintf(f, "sae_check_mfp=%d\n", config->sae_check_mfp);
+
if (config->sae_groups) {
int i;
fprintf(f, "sae_groups=");
@@ -1634,7 +1661,8 @@
}
for (ssid = config->ssid; ssid; ssid = ssid->next) {
- if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
+ if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary ||
+ ssid->ro)
continue; /* do not save temporary networks */
if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt) &&
!ssid->psk_set && !ssid->passphrase)
diff --git a/wpa_supplicant/config_none.c b/wpa_supplicant/config_none.c
index 0bc977e..01e7aad 100644
--- a/wpa_supplicant/config_none.c
+++ b/wpa_supplicant/config_none.c
@@ -17,7 +17,8 @@
#include "base64.h"
-struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp,
+ bool ro)
{
struct wpa_config *config;
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index adc1a06..33b46e5 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -46,7 +46,7 @@
#define DEFAULT_MAX_OPER_CHWIDTH -1
/* Consider global sae_pwe for SAE mechanism for PWE derivation */
-#define DEFAULT_SAE_PWE 4
+#define DEFAULT_SAE_PWE SAE_PWE_NOT_SET
struct psk_list_entry {
struct dl_list list;
@@ -70,6 +70,14 @@
SAE_PK_MODE_DISABLED = 2,
};
+enum wpas_mac_addr_style {
+ WPAS_MAC_ADDR_STYLE_NOT_SET = -1,
+ WPAS_MAC_ADDR_STYLE_PERMANENT = 0,
+ WPAS_MAC_ADDR_STYLE_RANDOM = 1,
+ WPAS_MAC_ADDR_STYLE_RANDOM_SAME_OUI = 2,
+ WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS = 3,
+};
+
/**
* struct wpa_ssid - Network configuration data
*
@@ -107,6 +115,21 @@
int id;
/**
+ * ro - Whether a network is declared as read-only
+ *
+ * Every network which is defined in a config file that is passed to
+ * wpa_supplicant using the -I option will be marked as read-only
+ * using this flag. It has the effect that it won't be written to
+ * /etc/wpa_supplicant.conf (from -c argument) if, e.g., wpa_gui tells
+ * the daemon to save all changed configs.
+ *
+ * This is necessary because networks from /etc/wpa_supplicant.conf
+ * have a higher priority and changes from an alternative file would be
+ * silently overwritten without this.
+ */
+ bool ro;
+
+ /**
* priority - Priority group
*
* By default, all networks will get same priority group (0). If some
@@ -837,6 +860,14 @@
struct os_reltime disabled_until;
/**
+ * disabled_due_to - BSSID of the disabling failure
+ *
+ * This identifies the BSS that failed the connection attempt that
+ * resulted in the network being temporarily disabled.
+ */
+ u8 disabled_due_to[ETH_ALEN];
+
+ /**
* parent_cred - Pointer to parent wpa_cred entry
*
* This pointer can be used to delete temporary networks when a wpa_cred
@@ -965,12 +996,21 @@
* 0 = use permanent MAC address
* 1 = use random MAC address for each ESS connection
* 2 = like 1, but maintain OUI (with local admin bit set)
+ * 3 = use dedicated/pregenerated MAC address (see mac_value)
*
* Internally, special value -1 is used to indicate that the parameter
* was not specified in the configuration (i.e., default behavior is
* followed).
*/
- int mac_addr;
+ enum wpas_mac_addr_style mac_addr;
+
+ /**
+ * mac_value - Specific MAC address to be used
+ *
+ * When mac_addr policy is equal to 3 this is the value of the MAC
+ * address that should be used.
+ */
+ u8 mac_value[ETH_ALEN];
/**
* no_auto_peer - Do not automatically peer with compatible mesh peers
@@ -1190,7 +1230,15 @@
* 1 = hash-to-element only
* 2 = both hunting-and-pecking loop and hash-to-element enabled
*/
- int sae_pwe;
+ enum sae_pwe sae_pwe;
+
+ /**
+ * disable_eht - Disable EHT (IEEE 802.11be) for this network
+ *
+ * By default, use it if it is available, but this can be configured
+ * to 1 to have it disabled.
+ */
+ int disable_eht;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index b27c6cf..05e6e37 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -446,7 +446,8 @@
}
-struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
+struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp,
+ bool ro)
{
TCHAR buf[256];
int errors = 0;
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 7586feb..27397e9 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -833,8 +833,6 @@
wpa_s->sae_commit_override = wpabuf_parse_bin(value);
} else if (os_strcasecmp(cmd, "driver_signal_override") == 0) {
ret = wpas_ctrl_iface_set_dso(wpa_s, value);
- } else if (os_strcasecmp(cmd, "force_hunting_and_pecking_pwe") == 0) {
- wpa_s->force_hunting_and_pecking_pwe = (atoi(value) != 0) ? 1 : 0;
} else if (os_strcasecmp(cmd, "disable_scs_support") == 0) {
wpa_s->disable_scs_support = !!atoi(value);
} else if (os_strcasecmp(cmd, "disable_mscs_support") == 0) {
@@ -1319,6 +1317,7 @@
u8 target_ap[ETH_ALEN];
struct wpa_bss *bss;
const u8 *mdie;
+ bool force = os_strstr(addr, " force") != NULL;
if (hwaddr_aton(addr, target_ap)) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
@@ -1334,7 +1333,7 @@
else
mdie = NULL;
- return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
+ return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie, force);
}
#endif /* CONFIG_IEEE80211R */
@@ -5002,6 +5001,250 @@
#endif /* CONFIG_FILS */
+static int print_rnr(struct wpa_bss *bss, char *pos, char *end)
+{
+ char *start = pos;
+ const u8 *ie, *ie_end;
+ unsigned int n = 0;
+ int ret;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT);
+ if (!ie)
+ return 0;
+
+ ie_end = ie + 2 + ie[1];
+ ie += 2;
+
+ while (ie < ie_end) {
+ const struct ieee80211_neighbor_ap_info *info =
+ (const struct ieee80211_neighbor_ap_info *) ie;
+ const u8 *tbtt_start;
+ size_t left = ie_end - ie;
+
+ if (left < sizeof(struct ieee80211_neighbor_ap_info))
+ return 0;
+
+ left -= sizeof(struct ieee80211_neighbor_ap_info);
+ if (left < info->tbtt_info_len)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos,
+ "ap_info[%u]: tbtt_info: hdr=0x%x, len=%u, op_c=%u, channel=%u, ",
+ n, *ie, info->tbtt_info_len,
+ info->op_class, info->channel);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ ie += sizeof(struct ieee80211_neighbor_ap_info);
+ tbtt_start = ie;
+ if (info->tbtt_info_len >= 1) {
+ ret = os_snprintf(pos, end - pos,
+ "tbtt_offset=%u, ", *ie);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+
+ ie++;
+ pos += ret;
+ }
+
+ if (info->tbtt_info_len >= 7) {
+ ret = os_snprintf(pos, end - pos,
+ "bssid=" MACSTR ", ",
+ MAC2STR(ie));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+
+ ie += ETH_ALEN;
+ pos += ret;
+ }
+
+ if (info->tbtt_info_len >= 11) {
+ ret = os_snprintf(pos, end - pos,
+ "short SSID=0x%x, ",
+ WPA_GET_LE32(ie));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+
+ ie += 4;
+ pos += ret;
+ }
+
+ if (info->tbtt_info_len >= 12) {
+ ret = os_snprintf(pos, end - pos,
+ "bss_params=0x%x, ", *ie);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+
+ ie++;
+ pos += ret;
+ }
+
+ if (info->tbtt_info_len >= 13) {
+ ret = os_snprintf(pos, end - pos,
+ "PSD=0x%x, ", *ie);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+
+ ie++;
+ pos += ret;
+ }
+
+ if (info->tbtt_info_len >= 16) {
+ ret = os_snprintf(pos, end - pos,
+ "mld ID=%u, link ID=%u",
+ *ie, *(ie + 1) & 0xF);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+
+ ie += 3;
+ pos += ret;
+ }
+
+ ie = tbtt_start + info->tbtt_info_len;
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ n++;
+ }
+
+ return pos - start;
+}
+
+
+static int print_ml(struct wpa_bss *bss, char *pos, char *end)
+{
+ const struct ieee80211_eht_ml *ml;
+ char *start = pos;
+ const u8 *ie, *ie_end;
+ u16 ml_control;
+ u8 common_info_length;
+ int ret;
+
+ ie = get_ml_ie(wpa_bss_ie_ptr(bss), bss->ie_len,
+ MULTI_LINK_CONTROL_TYPE_BASIC);
+ if (!ie)
+ return 0;
+
+ ie_end = ie + 2 + ie[1];
+ ie += 3;
+ ml = (const struct ieee80211_eht_ml *) ie;
+
+ /* control + common info length + MLD MAC Address */
+ if (ie_end - ie < 2 + 1 + ETH_ALEN)
+ return 0;
+
+ ml_control = le_to_host16(ml->ml_control);
+
+ common_info_length = *(ie + 2);
+ ret = os_snprintf(pos, end - pos,
+ "multi-link: control=0x%x, common info len=%u",
+ ml_control, common_info_length);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ ie += 2;
+ if (ie_end - ie < common_info_length)
+ return 0;
+
+ ie++;
+ common_info_length--;
+
+ if (common_info_length < ETH_ALEN)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos, ", MLD addr=" MACSTR, MAC2STR(ie));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ ie += ETH_ALEN;
+ common_info_length -= ETH_ALEN;
+
+ if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID) {
+ if (common_info_length < 1)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos, ", link ID=%u", *ie & 0x0f);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie++;
+ common_info_length--;
+ }
+
+ if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT) {
+ if (common_info_length < 1)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos,
+ ", BSS change parameters=0x%x", *ie);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie++;
+ common_info_length--;
+ }
+
+ if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) {
+ if (common_info_length < 2)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos, ", MSD Info=0x%x",
+ WPA_GET_LE16(ie));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie += 2;
+ common_info_length -= 2;
+ }
+
+ if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) {
+ if (common_info_length < 2)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos, ", EML capabilities=0x%x",
+ WPA_GET_LE16(ie));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie += 2;
+ common_info_length -= 2;
+ }
+
+ if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) {
+ if (common_info_length < 2)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos, ", MLD capabilities=0x%x",
+ WPA_GET_LE16(ie));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie += 2;
+ common_info_length -= 2;
+ }
+
+ if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID) {
+ if (common_info_length < 1)
+ return 0;
+
+ ret = os_snprintf(pos, end - pos, ", MLD ID=0x%x\n", *ie);
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ ie += 1;
+ common_info_length--;
+ }
+
+ return pos - start;
+}
+
+
static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
unsigned long mask, char *buf, size_t buflen)
{
@@ -5452,6 +5695,12 @@
pos += ret;
}
+ if (mask & WPA_BSS_MASK_RNR)
+ pos += print_rnr(bss, pos, end);
+
+ if (mask & WPA_BSS_MASK_ML)
+ pos += print_ml(bss, pos, end);
+
if (mask & WPA_BSS_MASK_DELIM) {
ret = os_snprintf(pos, end - pos, "====\n");
if (os_snprintf_error(end - pos, ret))
@@ -5657,23 +5906,23 @@
{
wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
/* MLME-DELETEKEYS.request */
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL,
0, KEY_FLAG_GROUP);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL,
0, KEY_FLAG_GROUP);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL,
0, KEY_FLAG_GROUP);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL,
0, KEY_FLAG_GROUP);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL,
0, KEY_FLAG_GROUP);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL,
0, KEY_FLAG_GROUP);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
- 0, KEY_FLAG_PAIRWISE);
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0,
+ NULL, 0, KEY_FLAG_PAIRWISE);
if (wpa_sm_ext_key_id(wpa_s->wpa))
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, 0,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, wpa_s->bssid, 1, 0,
NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
@@ -8102,9 +8351,9 @@
pos = buf;
end = buf + buflen;
- ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n"
+ ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%lu\n"
"NOISE=%d\nFREQUENCY=%u\n",
- si.current_signal, si.current_txrate / 1000,
+ si.data.signal, si.data.current_tx_rate / 1000,
si.current_noise, si.frequency);
if (os_snprintf_error(end - pos, ret))
return -1;
@@ -8134,17 +8383,18 @@
pos += ret;
}
- if (si.avg_signal) {
+ if (si.data.avg_signal) {
ret = os_snprintf(pos, end - pos,
- "AVG_RSSI=%d\n", si.avg_signal);
+ "AVG_RSSI=%d\n", si.data.avg_signal);
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
- if (si.avg_beacon_signal) {
+ if (si.data.avg_beacon_signal) {
ret = os_snprintf(pos, end - pos,
- "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal);
+ "AVG_BEACON_RSSI=%d\n",
+ si.data.avg_beacon_signal);
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
@@ -9998,14 +10248,15 @@
/* First, use a zero key to avoid any possible duplicate key avoidance
* in the driver. */
- if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
+ if (wpa_drv_set_key(wpa_s, -1, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
wpa_s->last_tk_key_idx, 1, zero, 6,
zero, wpa_s->last_tk_len,
KEY_FLAG_PAIRWISE_RX_TX) < 0)
return -1;
/* Set the previously configured key to reset its TSC/RSC */
- return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
+ return wpa_drv_set_key(wpa_s, -1, wpa_s->last_tk_alg,
+ wpa_s->last_tk_addr,
wpa_s->last_tk_key_idx, 1, zero, 6,
wpa_s->last_tk, wpa_s->last_tk_len,
KEY_FLAG_PAIRWISE_RX_TX);
@@ -10700,6 +10951,7 @@
entry->reauth_time = now.sec + reauth_time;
entry->network_ctx = ssid;
+ os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN);
entry->external = true;
@@ -11564,10 +11816,10 @@
continue;
ret = os_snprintf(pos, end - pos,
- "LINK_ID=%d\nRSSI=%d\nLINKSPEED=%d\n"
+ "LINK_ID=%d\nRSSI=%d\nLINKSPEED=%lu\n"
"NOISE=%d\nFREQUENCY=%u\n",
- i, mlo_si.links[i].current_signal,
- mlo_si.links[i].current_txrate / 1000,
+ i, mlo_si.links[i].data.signal,
+ mlo_si.links[i].data.current_tx_rate / 1000,
mlo_si.links[i].current_noise,
mlo_si.links[i].frequency);
if (os_snprintf_error(end - pos, ret))
@@ -11599,19 +11851,19 @@
pos += ret;
}
- if (mlo_si.links[i].avg_signal) {
+ if (mlo_si.links[i].data.avg_signal) {
ret = os_snprintf(pos, end - pos,
"AVG_RSSI=%d\n",
- mlo_si.links[i].avg_signal);
+ mlo_si.links[i].data.avg_signal);
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
- if (mlo_si.links[i].avg_beacon_signal) {
- ret = os_snprintf(pos, end - pos,
- "AVG_BEACON_RSSI=%d\n",
- mlo_si.links[i].avg_beacon_signal);
+ if (mlo_si.links[i].data.avg_beacon_signal) {
+ ret = os_snprintf(
+ pos, end - pos, "AVG_BEACON_RSSI=%d\n",
+ mlo_si.links[i].data.avg_beacon_signal);
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
@@ -12818,8 +13070,11 @@
return 0;
fail:
- if (create_iface)
+ if (create_iface) {
+ /* wpa_supplicant does not create multi-BSS AP, so collapse to
+ * WPA_IF_STATION to avoid unwanted clean up in the driver. */
wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname);
+ }
return -1;
}
@@ -12841,6 +13096,8 @@
if (!ret && delete_iface) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE deleting the interface '%s'",
cmd);
+ /* wpa_supplicant does not create multi-BSS AP, so collapse to
+ * WPA_IF_STATION to avoid unwanted clean up in the driver. */
ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd);
}
return ret;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 1178f40..1cbf7fa 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -337,9 +337,6 @@
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/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index e4e9b8d..0e47534 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -299,6 +299,25 @@
/**
+ * Add a 64-bit unsigned integer entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * wpa_dbus_dict_open_write()
+ * @param key The key of the dict item
+ * @param value The 64-bit unsigned integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_uint64_t value)
+{
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
+ &value);
+}
+
+
+/**
* Add a DBus object path entry to the dict.
*
* @param iter_dict A valid DBusMessageIter returned from
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index 94a0efd..44685ea 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -46,6 +46,10 @@
const char *key,
const dbus_uint32_t value);
+dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_uint64_t value);
+
dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
const char *key,
const char *value);
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 9279ae4..9c23588 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -2344,6 +2344,12 @@
case WPAS_DBUS_PROP_BSS_TM_STATUS:
prop = "BSSTMStatus";
break;
+ case WPAS_DBUS_PROP_MAC_ADDRESS:
+ prop = "MACAddress";
+ break;
+ case WPAS_DBUS_PROP_SIGNAL_CHANGE:
+ prop = "SignalChange";
+ break;
default:
wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d",
__func__, property);
@@ -3939,6 +3945,11 @@
wpas_dbus_setter_mac_address_randomization_mask,
NULL
},
+ { "MACAddress", WPAS_DBUS_NEW_IFACE_INTERFACE, "ay",
+ wpas_dbus_getter_mac_address,
+ NULL,
+ NULL,
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -4521,6 +4532,11 @@
NULL,
NULL
},
+ { "SignalChange", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
+ wpas_dbus_getter_signal_change,
+ NULL,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 26bdcb5..ca8506f 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -38,6 +38,8 @@
WPAS_DBUS_PROP_ROAM_COMPLETE,
WPAS_DBUS_PROP_SESSION_LENGTH,
WPAS_DBUS_PROP_BSS_TM_STATUS,
+ WPAS_DBUS_PROP_MAC_ADDRESS,
+ WPAS_DBUS_PROP_SIGNAL_CHANGE,
};
enum wpas_dbus_bss_prop {
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 26f7738..67ce970 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -152,7 +152,7 @@
#ifdef CONFIG_INTERWORKING
"roaming_consortium", "required_roaming_consortium",
#endif /* CONFIG_INTERWORKING */
- NULL
+ "mac_value", NULL
};
static dbus_bool_t should_quote_opt(const char *key)
@@ -206,6 +206,8 @@
struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
DBusMessageIter iter_dict;
char *value = NULL;
+ bool mac_addr3_set = false;
+ bool mac_value_set = false;
if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
return FALSE;
@@ -315,12 +317,30 @@
else if (os_strcmp(entry.key, "priority") == 0)
wpa_config_update_prio_list(wpa_s->conf);
+ /*
+ * MAC address policy "3" needs to come with mac_value in
+ * the message so make sure that it is present (checked after
+ * the loop - here we just note what has been supplied).
+ */
+ if (os_strcmp(entry.key, "mac_addr") == 0 &&
+ atoi(value) == 3)
+ mac_addr3_set = true;
+ if (os_strcmp(entry.key, "mac_value") == 0)
+ mac_value_set = true;
+
skip_update:
os_free(value);
value = NULL;
wpa_dbus_dict_entry_clear(&entry);
}
+ if (mac_addr3_set && !mac_value_set) {
+ wpa_printf(MSG_INFO, "dbus: Invalid mac_addr policy config");
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "Invalid mac_addr policy config");
+ return FALSE;
+ }
+
return TRUE;
error:
@@ -332,6 +352,118 @@
}
+static int set_cred_property(struct wpa_cred *cred,
+ struct wpa_dbus_dict_entry *entry)
+{
+ size_t size;
+ int ret;
+ char *value;
+
+ if (entry->type == DBUS_TYPE_ARRAY &&
+ entry->array_type == DBUS_TYPE_STRING) {
+ dbus_uint32_t i;
+
+ if (entry->array_len <= 0)
+ return -1;
+
+ for (i = 0; i < entry->array_len; i++) {
+ if (should_quote_opt(entry->key)) {
+ size = os_strlen(entry->strarray_value[i]);
+
+ size += 3;
+ value = os_zalloc(size);
+ if (!value)
+ return -1;
+
+ ret = os_snprintf(value, size, "\"%s\"",
+ entry->strarray_value[i]);
+ if (os_snprintf_error(size, ret)) {
+ os_free(value);
+ return -1;
+ }
+ } else {
+ value = os_strdup(entry->strarray_value[i]);
+ if (!value)
+ return -1;
+ }
+
+ ret = wpa_config_set_cred(cred, entry->key, value, 0);
+ os_free(value);
+ if (ret < 0)
+ return -1;
+ }
+ return 0;
+ }
+
+ if (entry->type == DBUS_TYPE_ARRAY &&
+ entry->array_type == DBUS_TYPE_BYTE) {
+ if (entry->array_len <= 0)
+ return -1;
+
+ size = entry->array_len * 2 + 1;
+ value = os_zalloc(size);
+ if (!value)
+ return -1;
+
+ ret = wpa_snprintf_hex(value, size,
+ (u8 *) entry->bytearray_value,
+ entry->array_len);
+ if (ret <= 0) {
+ os_free(value);
+ return -1;
+ }
+ } else if (entry->type == DBUS_TYPE_STRING) {
+ if (should_quote_opt(entry->key)) {
+ size = os_strlen(entry->str_value);
+
+ size += 3;
+ value = os_zalloc(size);
+ if (!value)
+ return -1;
+
+ ret = os_snprintf(value, size, "\"%s\"",
+ entry->str_value);
+ if (os_snprintf_error(size, ret)) {
+ os_free(value);
+ return -1;
+ }
+ } else {
+ value = os_strdup(entry->str_value);
+ if (!value)
+ return -1;
+ }
+ } else if (entry->type == DBUS_TYPE_UINT32) {
+ size = 50;
+ value = os_zalloc(size);
+ if (!value)
+ return -1;
+
+ ret = os_snprintf(value, size, "%u", entry->uint32_value);
+ if (os_snprintf_error(size, ret)) {
+ os_free(value);
+ return -1;
+ }
+ } else if (entry->type == DBUS_TYPE_INT32) {
+ size = 50;
+ value = os_zalloc(size);
+ if (!value)
+ return -1;
+
+ ret = os_snprintf(value, size, "%d", entry->int32_value);
+ if (os_snprintf_error(size, ret)) {
+ os_free(value);
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+
+ ret = wpa_config_set_cred(cred, entry->key, value, 0);
+ os_free(value);
+ return ret;
+}
+
+
/**
* set_cred_properties - Set the properties of a configured credential
* @wpa_s: wpa_supplicant structure for a network interface
@@ -348,91 +480,28 @@
{
struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
DBusMessageIter iter_dict;
- char *value = NULL;
if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
return FALSE;
while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
- size_t size = 50;
- int ret;
+ int res;
- if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
- goto error;
-
- value = NULL;
- if (entry.type == DBUS_TYPE_ARRAY &&
- entry.array_type == DBUS_TYPE_BYTE) {
- if (entry.array_len <= 0)
- goto error;
-
- size = entry.array_len * 2 + 1;
- value = os_zalloc(size);
- if (!value)
- goto error;
-
- ret = wpa_snprintf_hex(value, size,
- (u8 *) entry.bytearray_value,
- entry.array_len);
- if (ret <= 0)
- goto error;
- } else if (entry.type == DBUS_TYPE_STRING) {
- if (should_quote_opt(entry.key)) {
- size = os_strlen(entry.str_value);
-
- size += 3;
- value = os_zalloc(size);
- if (!value)
- goto error;
-
- ret = os_snprintf(value, size, "\"%s\"",
- entry.str_value);
- if (os_snprintf_error(size, ret))
- goto error;
- } else {
- value = os_strdup(entry.str_value);
- if (!value)
- goto error;
- }
- } else if (entry.type == DBUS_TYPE_UINT32) {
- value = os_zalloc(size);
- if (!value)
- goto error;
-
- ret = os_snprintf(value, size, "%u",
- entry.uint32_value);
- if (os_snprintf_error(size, ret))
- goto error;
- } else if (entry.type == DBUS_TYPE_INT32) {
- value = os_zalloc(size);
- if (!value)
- goto error;
-
- ret = os_snprintf(value, size, "%d",
- entry.int32_value);
- if (os_snprintf_error(size, ret))
- goto error;
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+ res = -1;
} else {
- goto error;
+ res = set_cred_property(cred, &entry);
+ wpa_dbus_dict_entry_clear(&entry);
}
- ret = wpa_config_set_cred(cred, entry.key, value, 0);
- if (ret < 0)
- goto error;
-
- os_free(value);
- value = NULL;
- wpa_dbus_dict_entry_clear(&entry);
+ if (res < 0) {
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "invalid message format");
+ return FALSE;
+ }
}
return TRUE;
-
-error:
- os_free(value);
- wpa_dbus_dict_entry_clear(&entry);
- dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
- "invalid message format");
- return FALSE;
}
@@ -704,6 +773,9 @@
char *ifname = NULL;
char *confname = NULL;
char *bridge_ifname = NULL;
+ bool create_iface = false;
+ u8 *if_addr = NULL;
+ enum wpa_driver_if_type if_type = WPA_IF_STATION;
dbus_message_iter_init(message, &iter);
@@ -740,6 +812,33 @@
wpa_dbus_dict_entry_clear(&entry);
if (bridge_ifname == NULL)
goto oom;
+ } else if (os_strcmp(entry.key, "Create") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ create_iface = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "Type") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (os_strcmp(entry.str_value, "sta") == 0) {
+ if_type = WPA_IF_STATION;
+ } else if (os_strcmp(entry.str_value, "ap") == 0) {
+ if_type = WPA_IF_AP_BSS;
+ } else {
+ wpa_dbus_dict_entry_clear(&entry);
+ goto error;
+ }
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "Address") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if_addr = os_malloc(ETH_ALEN);
+ if (if_addr == NULL) {
+ wpa_dbus_dict_entry_clear(&entry);
+ goto oom;
+ }
+ if (hwaddr_aton(entry.str_value, if_addr)) {
+ wpa_dbus_dict_entry_clear(&entry);
+ goto error;
+ }
+ wpa_dbus_dict_entry_clear(&entry);
} else {
wpa_dbus_dict_entry_clear(&entry);
goto error;
@@ -761,6 +860,23 @@
struct wpa_supplicant *wpa_s;
struct wpa_interface iface;
+ if (create_iface) {
+ u8 mac_addr[ETH_ALEN];
+
+ wpa_printf(MSG_DEBUG,
+ "%s[dbus]: creating an interface '%s'",
+ __func__, ifname);
+ if (!global->ifaces ||
+ wpa_drv_if_add(global->ifaces, if_type, ifname,
+ if_addr, NULL, NULL, mac_addr,
+ NULL) < 0) {
+ reply = wpas_dbus_error_unknown_error(
+ message,
+ "interface creation failed.");
+ goto out;
+ }
+ }
+
os_memset(&iface, 0, sizeof(iface));
iface.driver = driver;
iface.ifname = ifname;
@@ -771,6 +887,7 @@
if (wpa_s && wpa_s->dbus_new_path) {
const char *path = wpa_s->dbus_new_path;
+ wpa_s->added_vif = create_iface;
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
&path, DBUS_TYPE_INVALID);
@@ -778,6 +895,13 @@
reply = wpas_dbus_error_unknown_error(
message,
"wpa_supplicant couldn't grab this interface.");
+ if (create_iface) {
+ /* wpa_supplicant does not create multi-BSS AP,
+ * so collapse to WPA_IF_STATION to avoid
+ * unwanted clean up in the driver. */
+ wpa_drv_if_remove(global->ifaces,
+ WPA_IF_STATION, ifname);
+ }
}
}
@@ -786,6 +910,7 @@
os_free(ifname);
os_free(confname);
os_free(bridge_ifname);
+ os_free(if_addr);
return reply;
error:
@@ -814,19 +939,38 @@
struct wpa_supplicant *wpa_s;
char *path;
DBusMessage *reply = NULL;
+ bool delete_iface;
dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID);
wpa_s = get_iface_by_dbus_path(global, path);
- if (wpa_s == NULL)
+ if (!wpa_s) {
reply = wpas_dbus_error_iface_unknown(message);
- else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
+ goto out;
+ }
+ delete_iface = wpa_s->added_vif;
+ if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"wpa_supplicant couldn't remove this interface.");
+ goto out;
}
+ if (delete_iface) {
+ wpa_printf(MSG_DEBUG, "%s[dbus]: deleting the interface '%s'",
+ __func__, wpa_s->ifname);
+ /* wpa_supplicant does not create multi-BSS AP, so collapse to
+ * WPA_IF_STATION to avoid unwanted clean up in the driver. */
+ if (wpa_drv_if_remove(global->ifaces, WPA_IF_STATION,
+ wpa_s->ifname)) {
+ reply = wpas_dbus_error_unknown_error(
+ message,
+ "wpa_supplicant couldn't delete this interface.");
+ }
+ }
+
+out:
return reply;
}
@@ -1826,7 +1970,7 @@
{
struct wpa_signal_info si;
DBusMessage *reply = NULL;
- DBusMessageIter iter, iter_dict, variant_iter;
+ DBusMessageIter iter;
int ret;
ret = wpa_drv_signal_poll(wpa_s, &si);
@@ -1841,31 +1985,7 @@
dbus_message_iter_init_append(reply, &iter);
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
- "a{sv}", &variant_iter) ||
- !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
- !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
- si.current_signal) ||
- !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
- si.current_txrate / 1000) ||
- !wpa_dbus_dict_append_int32(&iter_dict, "noise",
- si.current_noise) ||
- !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
- si.frequency) ||
- (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
- !wpa_dbus_dict_append_string(
- &iter_dict, "width",
- channel_width_to_string(si.chanwidth))) ||
- (si.center_frq1 > 0 && si.center_frq2 > 0 &&
- (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
- si.center_frq1) ||
- !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
- si.center_frq2))) ||
- (si.avg_signal &&
- !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
- si.avg_signal)) ||
- !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
- !dbus_message_iter_close_container(&iter, &variant_iter))
+ if (wpas_dbus_new_from_signal_information(&iter, &si) != 0)
goto nomem;
return reply;
@@ -4324,6 +4444,7 @@
const char *new_value = NULL;
char buf[250];
size_t combined_len;
+ int wpa_sm_param;
int ret;
if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
@@ -4342,6 +4463,35 @@
if (!new_value[0])
new_value = "NULL";
+ wpa_sm_param = -1;
+ if (os_strcmp(property_desc->data, "dot11RSNAConfigPMKLifetime") == 0)
+ wpa_sm_param = RSNA_PMK_LIFETIME;
+ else if (os_strcmp(property_desc->data,
+ "dot11RSNAConfigPMKReauthThreshold") == 0)
+ wpa_sm_param = RSNA_PMK_REAUTH_THRESHOLD;
+ else if (os_strcmp(property_desc->data, "dot11RSNAConfigSATimeout") == 0)
+ wpa_sm_param = RSNA_SA_TIMEOUT;
+
+ if (wpa_sm_param != -1) {
+ char *end;
+ int val;
+
+ val = strtol(new_value, &end, 0);
+ if (*end) {
+ dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+ "Invalid value for property %s",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+
+ if (wpa_sm_set_param(wpa_s->wpa, wpa_sm_param, val)) {
+ dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+ "Failed to apply interface property %s",
+ property_desc->dbus_property);
+ return FALSE;
+ }
+ }
+
ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data,
new_value);
if (os_snprintf_error(combined_len, ret)) {
@@ -4600,6 +4750,27 @@
/**
+ * wpas_dbus_getter_mac_address - Get MAC address of an interface
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: a list of stations
+ *
+ * Getter for "MACAddress" property.
+ */
+dbus_bool_t wpas_dbus_getter_mac_address(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+
+ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+ wpa_s->own_addr, ETH_ALEN,
+ error);
+}
+
+
+/**
* wpas_dbus_getter_sta_address - Return the address of a connected station
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -5945,3 +6116,28 @@
}
#endif /* CONFIG_MESH */
+
+
+/**
+ * wpas_dbus_getter_signal_change - Get signal change
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Getter for "SignalChange" property.
+ */
+dbus_bool_t wpas_dbus_getter_signal_change(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ struct wpa_signal_info si = wpa_s->last_signal_info;
+
+ if (wpas_dbus_new_from_signal_information(iter, &si) != 0) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: error constructing reply", __func__);
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index a421083..97fa337 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -196,6 +196,7 @@
DECLARE_ACCESSOR(wpas_dbus_getter_stas);
DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask);
DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask);
+DECLARE_ACCESSOR(wpas_dbus_getter_mac_address);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
@@ -246,6 +247,8 @@
DECLARE_ACCESSOR(wpas_dbus_getter_mesh_peers);
DECLARE_ACCESSOR(wpas_dbus_getter_mesh_group);
+DECLARE_ACCESSOR(wpas_dbus_getter_signal_change);
+
DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message,
struct wpa_supplicant *wpa_s);
DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message,
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index d9009ba..e21f912 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "drivers/driver.h"
#include "dbus_common.h"
#include "dbus_common_i.h"
#include "dbus_new.h"
@@ -1023,3 +1024,131 @@
}
return NULL;
}
+
+
+/**
+ * wpas_dbus_new_from_signal_information - Adds a wpa_signal_info
+ * to a DBusMessage.
+ * @msg: Pointer to message to append fields to
+ * @si: Pointer to wpa_signal_info to add to the message
+ * Returns: 0 on success, otherwise, an errorcode
+ *
+ * Adds all the pertinent fields from a wpa_signal_info to a DBusMessage.
+ * The same logic is useful in both responding to signal_poll calls, and
+ * sending signal_change signals.
+ */
+int wpas_dbus_new_from_signal_information(DBusMessageIter *iter,
+ struct wpa_signal_info *si)
+{
+ DBusMessageIter iter_dict, variant_iter;
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ "a{sv}", &variant_iter) ||
+ !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
+ si->data.signal) ||
+ !wpa_dbus_dict_append_uint32(&iter_dict, "linkspeed",
+ si->data.current_tx_rate / 1000) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "noise",
+ si->current_noise) ||
+ !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
+ si->frequency) ||
+ (si->chanwidth != CHAN_WIDTH_UNKNOWN &&
+ !wpa_dbus_dict_append_string(
+ &iter_dict, "width",
+ channel_width_to_string(si->chanwidth))) ||
+ (si->center_frq1 > 0 && si->center_frq2 > 0 &&
+ (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
+ si->center_frq1) ||
+ !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
+ si->center_frq2))) ||
+ (si->data.avg_signal &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
+ si->data.avg_signal)) ||
+ (si->data.rx_bytes &&
+ !wpa_dbus_dict_append_uint64(&iter_dict, "rx-bytes",
+ si->data.rx_bytes)) ||
+ (si->data.tx_bytes &&
+ !wpa_dbus_dict_append_uint64(&iter_dict, "tx-bytes",
+ si->data.tx_bytes)) ||
+ (si->data.rx_packets &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "rx-packets",
+ si->data.rx_packets)) ||
+ (si->data.tx_packets &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "tx-packets",
+ si->data.tx_packets)) ||
+ (si->data.beacons_count &&
+ !wpa_dbus_dict_append_uint64(&iter_dict, "beacons",
+ si->data.beacons_count)) ||
+ (si->data.current_rx_rate &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "linkrxspeed",
+ si->data.current_rx_rate)) ||
+ (si->data.current_rx_rate &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "linktxspeed",
+ si->data.current_tx_rate)) ||
+ (si->data.tx_retry_failed &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "retries-failed",
+ si->data.tx_retry_failed)) ||
+ (si->data.tx_retry_count &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "retries",
+ si->data.tx_retry_count)) ||
+ (si->data.last_ack_rssi &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "last-ack-rssi",
+ si->data.last_ack_rssi)) ||
+ (si->data.fcs_error_count &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "fcs-errors",
+ si->data.fcs_error_count)) ||
+ (si->data.beacon_loss_count &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "beacon-losses",
+ si->data.beacon_loss_count)) ||
+ (si->data.expected_throughput &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "expected-throughput",
+ si->data.expected_throughput)) ||
+ (si->data.rx_drop_misc &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "rx-drop-misc",
+ si->data.rx_drop_misc)) ||
+ (si->data.rx_mpdus &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "rx-mpdus",
+ si->data.rx_mpdus)) ||
+ (si->data.rx_hemcs &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "rx-he-mcs",
+ si->data.rx_hemcs)) ||
+ (si->data.tx_hemcs &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "tx-he-mcs",
+ si->data.tx_hemcs)) ||
+ (si->data.rx_vhtmcs &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "rx-vht-mcs",
+ si->data.rx_vhtmcs)) ||
+ (si->data.tx_vhtmcs &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "tx-vht-mcs",
+ si->data.tx_vhtmcs)) ||
+ (si->data.rx_mcs &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "rx-mcs",
+ si->data.rx_mcs)) ||
+ (si->data.tx_mcs &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "tx-mcs",
+ si->data.tx_mcs)) ||
+ (si->data.rx_he_nss &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "rx-he-nss",
+ si->data.rx_he_nss)) ||
+ (si->data.tx_he_nss &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "tx-he-nss",
+ si->data.tx_he_nss)) ||
+ (si->data.rx_vht_nss &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "rx-vht-nss",
+ si->data.rx_vht_nss)) ||
+ (si->data.tx_vht_nss &&
+ !wpa_dbus_dict_append_uint32(&iter_dict, "tx-vht-nss",
+ si->data.tx_vht_nss)) ||
+ (si->data.avg_beacon_signal &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "avg-beacon-rssi",
+ si->data.avg_beacon_signal)) ||
+ (si->data.avg_ack_signal &&
+ !wpa_dbus_dict_append_int32(&iter_dict, "avg-ack-rssi",
+ si->data.avg_ack_signal)) ||
+ !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+ !dbus_message_iter_close_container(iter, &variant_iter))
+ return -ENOMEM;
+
+ return 0;
+}
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index 7b63b28..c8d44a0 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -12,6 +12,8 @@
#include <dbus/dbus.h>
+struct wpa_signal_info;
+
typedef DBusMessage * (*WPADBusMethodHandler)(DBusMessage *message,
void *user_data);
typedef void (*WPADBusArgumentFreeFunction)(void *handler_arg);
@@ -151,4 +153,7 @@
const char *fallback_name,
const char *fallback_string);
+int wpas_dbus_new_from_signal_information(DBusMessageIter *iter,
+ struct wpa_signal_info *si);
+
#endif /* WPA_DBUS_CTRL_H */
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index d13a8d0..895d5fa 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -1353,7 +1353,10 @@
if (dpp_akm_sae(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE;
- ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+ if (dpp_akm_psk(conf->akm))
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
+ else
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
if (conf->passphrase[0]) {
if (wpa_config_set_quoted(ssid, "psk",
conf->passphrase) < 0)
@@ -1923,7 +1926,7 @@
static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator)
{
wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator);
+ dpp_notify_auth_success(wpa_s->dpp_auth, initiator);
wpas_notify_dpp_auth_success(wpa_s);
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) {
@@ -2301,6 +2304,7 @@
u16 r_bootstrap_len;
struct dpp_bootstrap_info *peer_bi;
struct dpp_authentication *auth;
+ unsigned int wait_time, max_wait_time;
if (!wpa_s->dpp)
return;
@@ -2332,6 +2336,9 @@
return;
}
+ wpa_printf(MSG_DEBUG, "DPP: Start Authentication exchange with " MACSTR
+ " based on the received Presence Announcement",
+ MAC2STR(src));
auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL,
DPP_CAPAB_CONFIGURATOR, freq, NULL, 0);
if (!auth)
@@ -2348,6 +2355,13 @@
* MAC address information from the bootstrapping information. */
os_memcpy(auth->peer_mac_addr, src, ETH_ALEN);
+ wait_time = wpa_s->max_remain_on_chan;
+ max_wait_time = wpa_s->dpp_resp_wait_time ?
+ wpa_s->dpp_resp_wait_time : 2000;
+ if (wait_time > max_wait_time)
+ wait_time = max_wait_time;
+ wpas_dpp_stop_listen_for_tx(wpa_s, freq, wait_time);
+
wpa_s->dpp_auth = auth;
if (wpas_dpp_auth_init_next(wpa_s) < 0) {
dpp_auth_deinit(wpa_s->dpp_auth);
@@ -2642,6 +2656,8 @@
return;
}
+ os_memset(&intro, 0, sizeof(intro));
+
trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
&trans_id_len);
if (!trans_id || trans_id_len != 1) {
@@ -2693,7 +2709,7 @@
ssid->dpp_netaccesskey_len,
ssid->dpp_csign,
ssid->dpp_csign_len,
- connector, connector_len, &expiry);
+ connector, connector_len, &expiry, NULL);
if (res != DPP_STATUS_OK) {
wpa_printf(MSG_INFO,
"DPP: Network Introduction protocol resulted in failure");
@@ -2709,6 +2725,7 @@
if (!entry)
goto fail;
os_memcpy(entry->aa, src, ETH_ALEN);
+ os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN);
os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
entry->pmk_len = intro.pmk_len;
@@ -2752,7 +2769,7 @@
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
fail:
- os_memset(&intro, 0, sizeof(intro));
+ dpp_peer_intro_deinit(&intro);
}
@@ -3845,7 +3862,7 @@
ssid->dpp_netaccesskey_len,
ssid->dpp_csign,
ssid->dpp_csign_len,
- connector, connector_len, &expiry);
+ connector, connector_len, &expiry, NULL);
if (res != DPP_STATUS_OK) {
wpa_printf(MSG_INFO,
"DPP: Network Introduction protocol resulted in failure");
@@ -3871,6 +3888,7 @@
goto fail;
entry->dpp_pfs = peer_version >= 2;
os_memcpy(entry->aa, src, ETH_ALEN);
+ os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN);
os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
entry->pmk_len = intro.pmk_len;
@@ -4087,7 +4105,7 @@
* TX status handler, but since there was no such handler call
* yet, simply send out the event message and proceed with
* exchange. */
- wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1");
+ dpp_notify_auth_success(auth, 1);
wpa_s->dpp_auth_ok_on_ack = 0;
}
@@ -4380,7 +4398,7 @@
if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
!(ied.key_mgmt & WPA_KEY_MGMT_DPP))
return 0; /* AP does not support DPP AKM - continue */
- if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid))
+ if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, wpa_s->own_addr, ssid))
return 0; /* PMKSA exists for DPP AKM - continue */
if (!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 6be117c..5dd2a51 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -143,7 +143,7 @@
return -1;
}
-static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
+static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, int link_id,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
@@ -163,6 +163,7 @@
params.key = key;
params.key_len = key_len;
params.key_flag = key_flag;
+ params.link_id = link_id;
if (alg != WPA_ALG_NONE) {
/* keyidx = 1 can be either a broadcast or--with
@@ -406,20 +407,10 @@
return 0;
}
-static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
- unsigned int freq,
- unsigned int wait,
- const u8 *dst, const u8 *src,
- const u8 *bssid,
- const u8 *data, size_t data_len,
- int no_cck)
-{
- if (wpa_s->driver->send_action)
- return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
- wait, dst, src, bssid,
- data, data_len, no_cck);
- return -1;
-}
+int wpa_drv_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int wait, const u8 *dst, const u8 *src,
+ const u8 *bssid, const u8 *data, size_t data_len,
+ int no_cck);
static inline void wpa_drv_send_action_cancel_wait(struct wpa_supplicant *wpa_s)
{
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index efec31c..9641062 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -1472,7 +1472,7 @@
dl_list_init(&wpa_s.bss);
dl_list_init(&wpa_s.bss_id);
if (conf)
- wpa_s.conf = wpa_config_read(conf, NULL);
+ wpa_s.conf = wpa_config_read(conf, NULL, false);
else
wpa_s.conf = wpa_config_alloc_empty(ctrl_iface, NULL);
if (wpa_s.conf == NULL) {
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 6c82b66..3275b64 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -140,7 +140,7 @@
struct wpa_bss *bss = NULL;
struct wpa_ssid *ssid = wpa_s->current_ssid;
- if (ssid->ssid_len > 0)
+ if (ssid && ssid->ssid_len > 0)
bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
if (!bss)
bss = wpa_bss_get_bssid(wpa_s, bssid);
@@ -183,7 +183,8 @@
}
-static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
+static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
{
struct wpa_ssid *ssid, *old_ssid;
u8 drv_ssid[SSID_MAX_LEN];
@@ -256,8 +257,15 @@
if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
u8 wpa_ie[80];
size_t wpa_ie_len = sizeof(wpa_ie);
+ bool skip_default_rsne;
+
+ /* Do not override RSNE/RSNXE with the default values if the
+ * driver indicated the actual values used in the
+ * (Re)Association Request frame. */
+ skip_default_rsne = data && data->assoc_info.req_ies;
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
- wpa_ie, &wpa_ie_len) < 0)
+ wpa_ie, &wpa_ie_len,
+ skip_default_rsne) < 0)
wpa_dbg(wpa_s, MSG_DEBUG, "Could not set WPA suites");
} else {
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
@@ -301,16 +309,15 @@
}
-static void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s)
+void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s)
{
- int i;
-
if (!wpa_s->valid_links)
return;
wpa_s->valid_links = 0;
- for (i = 0; i < MAX_NUM_MLD_LINKS; i++)
- wpa_s->links[i].bss = NULL;
+ wpa_s->mlo_assoc_link_id = 0;
+ os_memset(wpa_s->ap_mld_addr, 0, ETH_ALEN);
+ os_memset(wpa_s->links, 0, sizeof(wpa_s->links));
}
@@ -382,6 +389,7 @@
if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
wpa_s->enabled_4addr_mode = 0;
+ wpa_s->wps_scan_done = false;
wpas_reset_mlo_info(wpa_s);
}
@@ -601,7 +609,8 @@
#ifdef CONFIG_WEP
int wep_ok;
#endif /* CONFIG_WEP */
- bool is_6ghz_bss = is_6ghz_freq(bss->freq);
+ bool is_6ghz_bss_or_mld = is_6ghz_freq(bss->freq) ||
+ !is_zero_ether_addr(bss->mld_addr);
ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
if (ret >= 0)
@@ -616,10 +625,10 @@
#endif /* CONFIG_WEP */
rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
- if (is_6ghz_bss && !rsn_ie) {
+ if (is_6ghz_bss_or_mld && !rsn_ie) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - 6 GHz BSS without RSNE");
+ " skip - 6 GHz/MLD BSS without RSNE");
return 0;
}
@@ -637,7 +646,7 @@
if (!ie.has_group)
ie.group_cipher = wpa_default_rsn_cipher(bss->freq);
- if (is_6ghz_bss) {
+ if (is_6ghz_bss_or_mld) {
/* WEP and TKIP are not allowed on 6 GHz */
ie.pairwise_cipher &= ~(WPA_CIPHER_WEP40 |
WPA_CIPHER_WEP104 |
@@ -688,12 +697,12 @@
break;
}
- if (is_6ghz_bss) {
+ if (is_6ghz_bss_or_mld) {
/* 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");
+ " skip RSNE - 6 GHz/MLD without MFPC");
break;
}
@@ -733,10 +742,10 @@
return 1;
}
- if (is_6ghz_bss) {
+ if (is_6ghz_bss_or_mld) {
if (debug_print)
wpa_dbg(wpa_s, MSG_DEBUG,
- " skip - 6 GHz BSS without matching RSNE");
+ " skip - 6 GHz/MLD BSS without matching RSNE");
return 0;
}
@@ -956,10 +965,22 @@
continue;
}
+ if (flagged && ((rate_ie[j] & 0x7f) ==
+ BSS_MEMBERSHIP_SELECTOR_HE_PHY)) {
+ if (!he_supported(mode, IEEE80211_MODE_INFRA)) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " hardware does not support HE PHY");
+ return 0;
+ }
+ continue;
+ }
+
#ifdef CONFIG_SAE
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
- if (wpa_s->conf->sae_pwe == 0 &&
+ if (wpa_s->conf->sae_pwe ==
+ SAE_PWE_HUNT_AND_PECK &&
!ssid->sae_password_id &&
wpa_key_mgmt_sae(ssid->key_mgmt)) {
if (debug_print)
@@ -1393,9 +1414,10 @@
#ifdef CONFIG_SAE
/* 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) &&
+ if ((wpa_s->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
+ is_6ghz_freq(bss->freq) || ssid->sae_password_id) &&
+ wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
!(wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) &&
#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
@@ -1511,7 +1533,8 @@
#ifdef CONFIG_DPP
if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) &&
- !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) &&
+ !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, wpa_s->own_addr,
+ ssid) &&
(!ssid->dpp_connector || !ssid->dpp_netaccesskey ||
!ssid->dpp_csign)) {
if (debug_print)
@@ -1802,10 +1825,12 @@
struct wpa_bss *selected,
struct wpa_ssid *ssid)
{
- if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
+ if (wpas_wps_partner_link_overlap_detect(wpa_s) ||
+ wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
"PBC session overlap");
wpas_notify_wps_event_pbc_overlap(wpa_s);
+ wpa_s->wps_overlap = true;
#ifdef CONFIG_P2P
if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT ||
wpa_s->p2p_in_provisioning) {
@@ -1994,9 +2019,9 @@
* information about our currently associated AP.
*/
if (wpa_drv_signal_poll(wpa_s, &si) == 0 &&
- (si.avg_beacon_signal || si.avg_signal)) {
- cur_level = si.avg_beacon_signal ? si.avg_beacon_signal :
- si.avg_signal;
+ (si.data.avg_beacon_signal || si.data.avg_signal)) {
+ cur_level = si.data.avg_beacon_signal ?
+ si.data.avg_beacon_signal : si.data.avg_signal;
cur_snr = wpas_get_snr_signal_info(si.frequency, cur_level,
si.current_noise);
@@ -2309,6 +2334,9 @@
}
}
+ if (wpa_s->supp_pbc_active && !wpas_wps_partner_link_scan_done(wpa_s))
+ return ret;
+
return wpas_select_network_from_last_scan(wpa_s, 1, own_request);
scan_work_done:
@@ -2375,6 +2403,8 @@
wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
return -1;
}
+ wpa_s->supp_pbc_active = false;
+
if (new_scan)
wpa_supplicant_rsn_preauth_scan_results(wpa_s);
/*
@@ -2409,9 +2439,9 @@
if (res == 1)
return 0;
- if (wpas_p2p_retry_limit_exceeded(wpa_s)) {
+ if (wpas_p2p_retry_limit_exceeded(wpa_s))
return 0;
- }
+
if (wpa_s->p2p_in_provisioning ||
wpa_s->show_group_started ||
wpa_s->p2p_in_invitation) {
@@ -2545,6 +2575,17 @@
#endif /* CONFIG_NO_SCAN_PROCESSING */
}
+
+int wpa_wps_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+ return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
+ return wpas_select_network_from_last_scan(wpa_s, 1, 1);
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
+
#ifdef CONFIG_WNM
static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
@@ -2844,15 +2885,15 @@
if (!ssid->psk_set) {
wpa_dbg(wpa_s, MSG_INFO,
"No PSK available for association");
- wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE");
+ wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE", NULL);
return -1;
}
wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL, NULL);
if (wpa_s->conf->key_mgmt_offload &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD) &&
- wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, NULL, 0, ssid->psk,
- PMK_LEN, KEY_FLAG_PMK))
+ wpa_drv_set_key(wpa_s, -1, 0, NULL, 0, 0, NULL, 0,
+ ssid->psk, PMK_LEN, KEY_FLAG_PMK))
wpa_dbg(wpa_s, MSG_ERROR,
"WPA: Cannot set PMK for key management offload");
}
@@ -3453,7 +3494,7 @@
struct driver_sta_mlo_info mlo;
int i;
- mlo.valid_links = 0;
+ os_memset(&mlo, 0, sizeof(mlo));
if (wpas_drv_get_sta_mlo_info(wpa_s, &mlo)) {
wpa_dbg(wpa_s, MSG_ERROR, "Failed to get MLO link info");
wpa_supplicant_deauthenticate(wpa_s,
@@ -3480,13 +3521,14 @@
}
}
- if (match &&
+ if (match && wpa_s->mlo_assoc_link_id == mlo.assoc_link_id &&
os_memcmp(wpa_s->ap_mld_addr, mlo.ap_mld_addr,
ETH_ALEN) == 0)
return 0;
}
wpa_s->valid_links = mlo.valid_links;
+ wpa_s->mlo_assoc_link_id = mlo.assoc_link_id;
os_memcpy(wpa_s->ap_mld_addr, mlo.ap_mld_addr, ETH_ALEN);
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
if (!(wpa_s->valid_links & BIT(i)))
@@ -3502,6 +3544,66 @@
}
+static int wpa_sm_set_ml_info(struct wpa_supplicant *wpa_s)
+{
+ struct driver_sta_mlo_info drv_mlo;
+ struct wpa_sm_mlo wpa_mlo;
+ const u8 *bss_rsn = NULL, *bss_rsnx = NULL;
+ int i;
+
+ os_memset(&drv_mlo, 0, sizeof(drv_mlo));
+ if (wpas_drv_get_sta_mlo_info(wpa_s, &drv_mlo)) {
+ wpa_dbg(wpa_s, MSG_INFO, "Failed to get MLO link info");
+ return -1;
+ }
+
+ os_memset(&wpa_mlo, 0, sizeof(wpa_mlo));
+ if (!drv_mlo.valid_links)
+ goto out;
+
+ os_memcpy(wpa_mlo.ap_mld_addr, drv_mlo.ap_mld_addr, ETH_ALEN);
+ wpa_mlo.assoc_link_id = drv_mlo.assoc_link_id;
+ wpa_mlo.valid_links = drv_mlo.valid_links;
+ wpa_mlo.req_links = drv_mlo.req_links;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ struct wpa_bss *bss;
+
+ if (!(drv_mlo.req_links & BIT(i)))
+ continue;
+
+ bss = wpa_supplicant_get_new_bss(wpa_s, drv_mlo.links[i].bssid);
+ if (!bss) {
+ wpa_supplicant_update_scan_results(wpa_s);
+ bss = wpa_supplicant_get_new_bss(
+ wpa_s, drv_mlo.links[i].bssid);
+ }
+
+ if (!bss) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "Failed to get MLO link %d BSS", i);
+ return -1;
+ }
+
+ bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+
+ wpa_mlo.links[i].ap_rsne = bss_rsn ? (u8 *) bss_rsn : NULL;
+ wpa_mlo.links[i].ap_rsne_len = bss_rsn ? 2 + bss_rsn[1] : 0;
+ wpa_mlo.links[i].ap_rsnxe = bss_rsnx ? (u8 *) bss_rsnx : NULL;
+ wpa_mlo.links[i].ap_rsnxe_len = bss_rsnx ? 2 + bss_rsnx[1] : 0;
+
+ os_memcpy(wpa_mlo.links[i].bssid, drv_mlo.links[i].bssid,
+ ETH_ALEN);
+ os_memcpy(wpa_mlo.links[i].addr, drv_mlo.links[i].addr,
+ ETH_ALEN);
+ }
+
+out:
+ return wpa_sm_set_mlo_params(wpa_s->wpa, &wpa_mlo);
+}
+
+
static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
@@ -3631,7 +3733,7 @@
if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) {
wpa_clear_keys(wpa_s, bssid);
}
- if (wpa_supplicant_select_config(wpa_s) < 0) {
+ if (wpa_supplicant_select_config(wpa_s, data) < 0) {
wpa_supplicant_deauthenticate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
return;
@@ -3668,6 +3770,15 @@
wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid);
}
wpa_sm_notify_assoc(wpa_s->wpa, bssid);
+
+ if (wpa_sm_set_ml_info(wpa_s)) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "Failed to set MLO connection info to wpa_sm");
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ return;
+ }
+
if (wpa_s->l2)
l2_packet_notify_auth_start(wpa_s->l2);
@@ -3737,12 +3848,12 @@
eapol_sm_notify_portValid(wpa_s->eapol, true);
eapol_sm_notify_eap_success(wpa_s->eapol, true);
} else {
- /* Update port, WPA_COMPLETED state from
- * EVENT_PORT_AUTHORIZED context when driver is done
- * with 4way handshake.
+ /* Update port, WPA_COMPLETED state from the
+ * EVENT_PORT_AUTHORIZED handler when the driver is done
+ * with the 4-way handshake.
*/
- wpa_msg(wpa_s, MSG_INFO, "ASSOC INFO: wait for driver port "
- "authorized indication");
+ wpa_msg(wpa_s, MSG_INFO,
+ "ASSOC INFO: wait for driver port authorized indication");
}
} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
@@ -3792,8 +3903,9 @@
os_get_reltime(&now);
os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
if (age.sec == 0 && age.usec < 200000 &&
- os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
- 0) {
+ os_memcmp(wpa_s->pending_eapol_rx_src,
+ wpa_s->valid_links ? wpa_s->ap_mld_addr : bssid,
+ ETH_ALEN) == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL "
"frame that was received just before "
"association notification");
@@ -3973,7 +4085,7 @@
"pre-shared key may be incorrect");
if (wpas_p2p_4way_hs_failed(wpa_s) > 0)
return; /* P2P group removed */
- wpas_auth_failed(wpa_s, "WRONG_KEY");
+ wpas_auth_failed(wpa_s, "WRONG_KEY", prev_pending_bssid);
#ifdef CONFIG_DPP2
wpas_dpp_send_conn_status_result(wpa_s,
DPP_STATUS_AUTH_FAILURE);
@@ -4477,7 +4589,7 @@
(wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
eapol_sm_failed(wpa_s->eapol))) &&
!wpa_s->eap_expected_failure))
- wpas_auth_failed(wpa_s, "AUTH_FAILED");
+ wpas_auth_failed(wpa_s, "AUTH_FAILED", addr);
#ifdef CONFIG_P2P
if (deauth && reason_code > 0) {
@@ -5372,6 +5484,7 @@
os_reltime_sub(&now, &wpa_s->scan_start_time, &diff);
wpa_s->scan_start_time.sec = 0;
wpa_s->scan_start_time.usec = 0;
+ wpa_s->wps_scan_done = true;
wpa_dbg(wpa_s, MSG_DEBUG, "Scan completed in %ld.%06ld seconds",
diff.sec, diff.usec);
}
@@ -5821,18 +5934,21 @@
break;
case EVENT_SIGNAL_CHANGE:
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SIGNAL_CHANGE
- "above=%d signal=%d noise=%d txrate=%d",
+ "above=%d signal=%d noise=%d txrate=%lu",
data->signal_change.above_threshold,
- data->signal_change.current_signal,
+ data->signal_change.data.signal,
data->signal_change.current_noise,
- data->signal_change.current_txrate);
+ data->signal_change.data.current_tx_rate);
wpa_bss_update_level(wpa_s->current_bss,
- data->signal_change.current_signal);
+ data->signal_change.data.signal);
bgscan_notify_signal_change(
wpa_s, data->signal_change.above_threshold,
- data->signal_change.current_signal,
+ data->signal_change.data.signal,
data->signal_change.current_noise,
- data->signal_change.current_txrate);
+ data->signal_change.data.current_tx_rate);
+ os_memcpy(&wpa_s->last_signal_info, data,
+ sizeof(struct wpa_signal_info));
+ wpas_notify_signal_change(wpa_s);
break;
case EVENT_INTERFACE_MAC_CHANGED:
wpa_supplicant_update_mac_addr(wpa_s);
@@ -6099,6 +6215,15 @@
break;
#endif /* CONFIG_PASN */
case EVENT_PORT_AUTHORIZED:
+#ifndef CONFIG_NO_WPA
+ if (data->port_authorized.td_bitmap_len) {
+ wpa_printf(MSG_DEBUG,
+ "WPA3: Transition Disable bitmap from the driver event: 0x%x",
+ data->port_authorized.td_bitmap[0]);
+ wpas_transition_disable(
+ wpa_s, data->port_authorized.td_bitmap[0]);
+ }
+#endif /* CONFIG_NO_WPA */
wpa_supplicant_event_port_authorized(wpa_s);
break;
case EVENT_STATION_OPMODE_CHANGED:
diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py
index 8e865f3..6cffe71 100755
--- a/wpa_supplicant/examples/dpp-nfc.py
+++ b/wpa_supplicant/examples/dpp-nfc.py
@@ -359,7 +359,7 @@
summary("NFC Handover Request message for DPP: " + str(message))
if handover.peer_crn is not None and not alt:
- summary("NFC handover request from peer was already received - do not send own")
+ summary("NFC handover request from peer was already received - do not send own[1]")
return
if handover.client:
summary("Use already started handover client")
@@ -382,7 +382,8 @@
handover.client = client
if handover.peer_crn is not None and not alt:
- summary("NFC handover request from peer was already received - do not send own")
+ summary("NFC handover request from peer was already received - do not send own[2] (except alt)")
+ run_client_alt(handover, alt)
return
summary("Sending handover request")
@@ -876,6 +877,11 @@
if init_on_touch:
summary("Starting handover client (init_on_touch)")
dpp_handover_client(handover)
+ summary("llcp_worker init_on_touch processing completed: try_own={} hs_sent={} no_alt_proposal={} start_client_alt={}".format(handover.try_own, handover.hs_sent, handover.no_alt_proposal, handover.start_client_alt))
+ if handover.start_client_alt and not handover.hs_sent:
+ summary("Try alternative handover request before exiting llcp_worker")
+ handover.start_client_alt = False
+ dpp_handover_client(handover, alt=True)
summary("Exiting llcp_worker thread (init_on_touch)")
return
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 802f120..c301f74 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -404,14 +404,14 @@
static void gas_query_rx_initial(struct gas_query *gas,
struct gas_query_pending *query,
- const u8 *adv_proto, const u8 *resp,
- size_t len, u16 comeback_delay)
+ const u8 *adv_proto, size_t adv_proto_len,
+ const u8 *resp, size_t len, u16 comeback_delay)
{
wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
MACSTR " (dialog_token=%u comeback_delay=%u)",
MAC2STR(query->addr), query->dialog_token, comeback_delay);
- query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]);
+ query->adv_proto = wpabuf_alloc_copy(adv_proto, adv_proto_len);
if (query->adv_proto == NULL) {
gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
return;
@@ -436,9 +436,9 @@
static void gas_query_rx_comeback(struct gas_query *gas,
struct gas_query_pending *query,
- const u8 *adv_proto, const u8 *resp,
- size_t len, u8 frag_id, u8 more_frags,
- u16 comeback_delay)
+ const u8 *adv_proto, size_t adv_proto_len,
+ const u8 *resp, size_t len, u8 frag_id,
+ u8 more_frags, u16 comeback_delay)
{
wpa_printf(MSG_DEBUG, "GAS: Received comeback response from "
MACSTR " (dialog_token=%u frag_id=%u more_frags=%u "
@@ -447,7 +447,7 @@
more_frags, comeback_delay);
eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query);
- if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
+ if (adv_proto_len != wpabuf_len(query->adv_proto) ||
os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
wpabuf_len(query->adv_proto)) != 0) {
wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed "
@@ -516,6 +516,7 @@
u8 action, dialog_token, frag_id = 0, more_frags = 0;
u16 comeback_delay, resp_len;
const u8 *pos, *adv_proto;
+ size_t adv_proto_len;
int prot, pmf;
unsigned int left;
@@ -596,22 +597,26 @@
pos += 2;
/* Advertisement Protocol element */
- if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) {
+ adv_proto = pos;
+ left = data + len - adv_proto;
+ if (left < 2 || adv_proto[1] > left - 2) {
wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement "
"Protocol element in the response from " MACSTR,
MAC2STR(sa));
return 0;
}
- if (*pos != WLAN_EID_ADV_PROTO) {
+ if (*adv_proto != WLAN_EID_ADV_PROTO) {
wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement "
"Protocol element ID %u in response from " MACSTR,
- *pos, MAC2STR(sa));
+ *adv_proto, MAC2STR(sa));
return 0;
}
+ adv_proto_len = 2 + adv_proto[1];
+ if (adv_proto_len > (size_t) (data + len - pos))
+ return 0; /* unreachable due to an earlier check */
- adv_proto = pos;
- pos += 2 + pos[1];
+ pos += adv_proto_len;
/* Query Response Length */
if (pos + 2 > data + len) {
@@ -635,11 +640,12 @@
}
if (action == WLAN_PA_GAS_COMEBACK_RESP)
- gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len,
- frag_id, more_frags, comeback_delay);
+ gas_query_rx_comeback(gas, query, adv_proto, adv_proto_len,
+ pos, resp_len, frag_id, more_frags,
+ comeback_delay);
else
- gas_query_rx_initial(gas, query, adv_proto, pos, resp_len,
- comeback_delay);
+ gas_query_rx_initial(gas, query, adv_proto, adv_proto_len,
+ pos, resp_len, comeback_delay);
return 0;
}
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 874c2bf..5b31f7b 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -143,7 +143,7 @@
}
-static int supp_set_key(void *ctx, enum wpa_alg alg,
+static int supp_set_key(void *ctx, int link_id, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len, enum key_flag key_flag)
@@ -172,8 +172,9 @@
if (is_broadcast_ether_addr(addr))
addr = peer->addr;
- return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
- set_tx, seq, seq_len, key, key_len, key_flag);
+ return wpa_drv_set_key(peer->ibss_rsn->wpa_s, link_id, alg, addr,
+ key_idx, set_tx, seq, seq_len, key, key_len,
+ key_flag);
}
@@ -352,7 +353,7 @@
}
}
- return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
+ return wpa_drv_set_key(ibss_rsn->wpa_s, -1, alg, addr, idx,
1, seq, 6, key, key_len, key_flag);
}
@@ -868,7 +869,7 @@
* still have a pairwise key configured. */
wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
MACSTR, MAC2STR(addr));
- wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
+ wpa_drv_set_key(ibss_rsn->wpa_s, -1, WPA_ALG_NONE, addr, 0, 0,
NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index acd9044..4d0fc63 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -144,9 +144,9 @@
struct wpa_cred *cred;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- if (cred->roaming_consortium_len)
+ if (cred->num_home_ois)
return 1;
- if (cred->required_roaming_consortium_len)
+ if (cred->num_required_home_ois)
return 1;
if (cred->num_roaming_consortiums)
return 1;
@@ -421,6 +421,11 @@
case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Unsupported EAP-TTLS inner method %u",
+ *pos);
+ break;
}
break;
case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
@@ -1098,8 +1103,7 @@
}
-static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
- size_t rc_len)
+static int oi_element_match(const u8 *ie, const u8 *oi, size_t oi_len)
{
const u8 *pos, *end;
u8 lens;
@@ -1124,24 +1128,24 @@
if ((lens & 0x0f) + (lens >> 4) > end - pos)
return 0;
- if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ if ((lens & 0x0f) == oi_len && os_memcmp(pos, oi, oi_len) == 0)
return 1;
pos += lens & 0x0f;
- if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ if ((lens >> 4) == oi_len && os_memcmp(pos, oi, oi_len) == 0)
return 1;
pos += lens >> 4;
- if (pos < end && (size_t) (end - pos) == rc_len &&
- os_memcmp(pos, rc_id, rc_len) == 0)
+ if (pos < end && (size_t) (end - pos) == oi_len &&
+ os_memcmp(pos, oi, oi_len) == 0)
return 1;
return 0;
}
-static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
- const u8 *rc_id, size_t rc_len)
+static int oi_anqp_match(const struct wpabuf *anqp, const u8 *oi,
+ size_t oi_len)
{
const u8 *pos, *end;
u8 len;
@@ -1157,7 +1161,7 @@
len = *pos++;
if (len > end - pos)
break;
- if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ if (len == oi_len && os_memcmp(pos, oi, oi_len) == 0)
return 1;
pos += len;
}
@@ -1166,11 +1170,26 @@
}
-static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
- const u8 *rc_id, size_t rc_len)
+static int oi_match(const u8 *ie, const struct wpabuf *anqp,
+ const u8 *oi, size_t oi_len)
{
- return roaming_consortium_element_match(ie, rc_id, rc_len) ||
- roaming_consortium_anqp_match(anqp, rc_id, rc_len);
+ return oi_element_match(ie, oi, oi_len) ||
+ oi_anqp_match(anqp, oi, oi_len);
+}
+
+
+static int cred_home_ois_match(const u8 *ie, const struct wpabuf *anqp,
+ const struct wpa_cred *cred) {
+ unsigned int i;
+
+ /* There's a match if at least one of the home OI matches. */
+ for (i = 0; i < cred->num_home_ois; i++) {
+ if (oi_match(ie, anqp, cred->home_ois[i],
+ cred->home_ois_len[i]))
+ return 1;
+ }
+
+ return 0;
}
@@ -1181,9 +1200,8 @@
unsigned int i;
for (i = 0; i < cred->num_roaming_consortiums; i++) {
- if (roaming_consortium_match(ie, anqp,
- cred->roaming_consortiums[i],
- cred->roaming_consortiums_len[i]))
+ if (oi_match(ie, anqp, cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]))
return 1;
}
@@ -1194,8 +1212,9 @@
static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
{
const u8 *ie;
+ unsigned int i;
- if (cred->required_roaming_consortium_len == 0)
+ if (cred->num_required_home_ois == 0)
return 0;
ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
@@ -1204,11 +1223,16 @@
(bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
return 1;
- return !roaming_consortium_match(ie,
- bss->anqp ?
- bss->anqp->roaming_consortium : NULL,
- cred->required_roaming_consortium,
- cred->required_roaming_consortium_len);
+ /* According to Passpoint specification, there must be a match for
+ * each required home OI provided. */
+ for (i = 0; i < cred->num_required_home_ois; i++) {
+ if (!oi_match(ie, bss->anqp ?
+ bss->anqp->roaming_consortium : NULL,
+ cred->required_home_ois[i],
+ cred->required_home_ois_len[i]))
+ return 1;
+ }
+ return 0;
}
@@ -1408,26 +1432,24 @@
return NULL;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
- if (cred->roaming_consortium_len == 0 &&
+ if (cred->num_home_ois == 0 &&
+ cred->num_required_home_ois == 0 &&
cred->num_roaming_consortiums == 0)
continue;
if (!cred->eap_method)
continue;
- if ((cred->roaming_consortium_len == 0 ||
- !roaming_consortium_match(ie, anqp,
- cred->roaming_consortium,
- cred->roaming_consortium_len)) &&
- !cred_roaming_consortiums_match(ie, anqp, cred) &&
- (cred->required_roaming_consortium_len == 0 ||
- !roaming_consortium_match(
- ie, anqp, cred->required_roaming_consortium,
- cred->required_roaming_consortium_len)))
+ /* If there's required home OIs, there must be a match for each
+ * required OI (see Passpoint v3.2 - 9.1.2 - RequiredHomeOI). */
+ if (cred->num_required_home_ois > 0 &&
+ cred_no_required_oi_match(cred, bss))
continue;
- if (cred_no_required_oi_match(cred, bss))
+ if (!cred_home_ois_match(ie, anqp, cred) &&
+ !cred_roaming_consortiums_match(ie, anqp, cred))
continue;
+
if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss))
continue;
if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss))
@@ -1642,9 +1664,8 @@
ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL;
for (i = 0; (ie || anqp) && i < cred->num_roaming_consortiums; i++) {
- if (!roaming_consortium_match(
- ie, anqp, cred->roaming_consortiums[i],
- cred->roaming_consortiums_len[i]))
+ if (!oi_match(ie, anqp, cred->roaming_consortiums[i],
+ cred->roaming_consortiums_len[i]))
continue;
ssid->roaming_consortium_selection =
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 2eb9a7e..c1ed8c4 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -879,7 +879,8 @@
if (conf->security & MESH_CONF_SEC_AMPE) {
wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
- wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
+ wpa_drv_set_key(wpa_s, -1,
+ wpa_cipher_to_alg(conf->pairwise_cipher),
sta->addr, 0, 0, seq, sizeof(seq),
sta->mtk, sta->mtk_len,
KEY_FLAG_PAIRWISE_RX_TX);
@@ -888,7 +889,8 @@
sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK",
sta->mgtk, sta->mgtk_len);
- wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
+ wpa_drv_set_key(wpa_s, -1,
+ wpa_cipher_to_alg(conf->group_cipher),
sta->addr, sta->mgtk_key_id, 0,
sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
sta->mgtk, sta->mgtk_len,
@@ -900,7 +902,7 @@
wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK",
sta->igtk, sta->igtk_len);
wpa_drv_set_key(
- wpa_s,
+ wpa_s, -1,
wpa_cipher_to_alg(conf->mgmt_group_cipher),
sta->addr, sta->igtk_key_id, 0,
sta->igtk_rsc, sizeof(sta->igtk_rsc),
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 65daa77..12dcc30 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -118,7 +118,7 @@
}
wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
- return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
+ return wpa_drv_set_key(mesh_rsn->wpa_s, -1, alg, addr, idx,
1, seq, 6, key, key_len, key_flag);
}
@@ -194,7 +194,7 @@
/* group mgmt */
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
rsn->igtk, rsn->igtk_len);
- wpa_drv_set_key(rsn->wpa_s,
+ wpa_drv_set_key(rsn->wpa_s, -1,
wpa_cipher_to_alg(rsn->mgmt_group_cipher),
broadcast_ether_addr,
rsn->igtk_key_id, 1,
@@ -205,7 +205,7 @@
/* group privacy / data frames */
wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
rsn->mgtk, rsn->mgtk_len);
- wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher),
+ wpa_drv_set_key(rsn->wpa_s, -1, wpa_cipher_to_alg(rsn->group_cipher),
broadcast_ether_addr,
rsn->mgtk_key_id, 1, seq, sizeof(seq),
rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT);
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 76f2232..32ddf1f 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -16,6 +16,7 @@
#include "dbus/dbus_common.h"
#include "dbus/dbus_new.h"
#include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
#include "fst/fst.h"
#include "crypto/tls.h"
#include "bss.h"
@@ -237,6 +238,15 @@
}
+void wpas_notify_mac_address_changed(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_MAC_ADDRESS);
+}
+
+
void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_mgmt)
@@ -447,11 +457,6 @@
wpas_notify_persistent_group_removed(wpa_s, ssid);
wpas_p2p_network_removed(wpa_s, ssid);
-
-#ifdef CONFIG_PASN
- if (wpa_s->pasn.ssid == ssid)
- wpa_s->pasn.ssid = NULL;
-#endif /* CONFIG_PASN */
}
@@ -1357,3 +1362,9 @@
{
return wpas_aidl_get_certificate(alias, value);
}
+
+
+void wpas_notify_signal_change(struct wpa_supplicant *wpa_s)
+{
+ wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SIGNAL_CHANGE);
+}
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 9a818ef..b1824ec 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -19,6 +19,7 @@
struct wps_event_fail;
struct tls_cert_data;
struct wpa_cred;
+struct rsn_pmksa_cache_entry;
int wpas_notify_supplicant_initialized(struct wpa_global *global);
void wpas_notify_supplicant_deinitialized(struct wpa_global *global);
@@ -39,6 +40,7 @@
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
+void wpas_notify_mac_address_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s);
void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
@@ -199,8 +201,6 @@
const char *channel_list, unsigned short band_list[], int size);
void wpas_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s);
void wpas_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s);
-void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
- struct rsn_pmksa_cache_entry *entry);
void wpas_notify_transition_disable(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
u8 bitmap);
@@ -222,5 +222,8 @@
struct dscp_policy_data *policies, int num_policies);
void wpas_notify_frequency_changed(struct wpa_supplicant *wpa_s, int frequency);
ssize_t wpas_get_certificate(const char *alias, uint8_t** value);
+void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s,
+ struct rsn_pmksa_cache_entry *entry);
+void wpas_notify_signal_change(struct wpa_supplicant *wpa_s);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index a505e4f..926ba7a 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -192,7 +192,7 @@
return -1;
num = get_shared_radio_freqs(wpa_s, freqs,
- wpa_s->num_multichan_concurrent);
+ wpa_s->num_multichan_concurrent, false);
os_free(freqs);
unused = wpa_s->num_multichan_concurrent - num;
@@ -219,7 +219,8 @@
return 0;
num = get_shared_radio_freqs_data(wpa_s, freqs,
- wpa_s->num_multichan_concurrent);
+ wpa_s->num_multichan_concurrent,
+ false);
os_memset(p2p_freqs, 0, sizeof(struct wpa_used_freq_data) * len);
@@ -339,6 +340,23 @@
}
+void wpas_p2p_scan_freqs(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ bool include_6ghz)
+{
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+ params, false, false, false);
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G,
+ params, false, false, false);
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211AD,
+ params, false, false, false);
+ if (!wpa_s->conf->p2p_6ghz_disable &&
+ is_p2p_allow_6ghz(wpa_s->global->p2p) && include_6ghz)
+ wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A,
+ params, true, true, false);
+}
+
+
static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
{
struct wpa_supplicant *wpa_s = work->wpa_s;
@@ -361,14 +379,9 @@
params->only_new_results = 1;
}
- if (!params->p2p_include_6ghz && !params->freqs) {
- wpa_printf(MSG_DEBUG,
- "P2P: Exclude 6 GHz channels - update the scan frequency list");
- wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
- false, false);
- wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
- false, false);
- }
+ if (!params->freqs)
+ wpas_p2p_scan_freqs(wpa_s, params, params->p2p_include_6ghz);
+
ret = wpa_drv_scan(wpa_s, params);
if (ret == 0)
wpa_s->curr_scan_cookie = params->scan_cookie;
@@ -447,6 +460,13 @@
num_req_dev_types, req_dev_types);
if (wps_ie == NULL)
goto fail;
+
+ /*
+ * In case 6 GHz channels are requested as part of the P2P scan, only
+ * the PSCs would be included as P2P GOs are not expected to be
+ * collocated, i.e., they would not be announced in the RNR element of
+ * other APs.
+ */
if (!wpa_s->conf->p2p_6ghz_disable)
params->p2p_include_6ghz = include_6ghz;
switch (type) {
@@ -533,9 +553,9 @@
return WPA_IF_P2P_GO;
case P2P_GROUP_INTERFACE_CLIENT:
return WPA_IF_P2P_CLIENT;
+ default:
+ return WPA_IF_P2P_GROUP;
}
-
- return WPA_IF_P2P_GROUP;
}
@@ -2090,7 +2110,7 @@
ssid->auth_alg |= WPA_AUTH_ALG_SAE;
ssid->key_mgmt = WPA_KEY_MGMT_SAE;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
- ssid->sae_pwe = 1;
+ ssid->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use SAE auth_alg and key_mgmt");
} else {
p2p_set_6ghz_dev_capab(wpa_s->global->p2p, false);
@@ -2181,6 +2201,7 @@
d->passive_scan = s->passive_scan;
d->pmf = s->pmf;
d->p2p_6ghz_disable = s->p2p_6ghz_disable;
+ d->sae_pwe = s->sae_pwe;
if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey &&
!d->wps_nfc_pw_from_config) {
@@ -2412,9 +2433,9 @@
bool wpas_p2p_retry_limit_exceeded(struct wpa_supplicant *wpa_s)
{
if (!wpa_s->p2p_in_invitation || !wpa_s->p2p_retry_limit ||
- wpa_s->p2p_in_invitation <= wpa_s->p2p_retry_limit) {
+ wpa_s->p2p_in_invitation <= wpa_s->p2p_retry_limit)
return false;
- }
+
wpa_printf(MSG_DEBUG, "P2P: Group join retry limit exceeded");
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->p2pdev, NULL);
@@ -3997,8 +4018,7 @@
for (op = 0; global_op_class[op].op_class; op++) {
const struct oper_class_map *o = &global_op_class[op];
- u16 ch;
- int chan = channel;
+ u16 ch = 0;
/* Allow DFS channels marked as NO_P2P_SUPP to be used with
* driver offloaded DFS. */
@@ -4009,15 +4029,22 @@
wpa_s->conf->p2p_6ghz_disable))
continue;
+ /* IEEE Std 802.11ax-2021 26.17.2.3.2: "A 6 GHz-only AP should
+ * set up the BSS with a primary 20 MHz channel that coincides
+ * with a preferred scanning channel (PSC)."
+ * 6 GHz BW40 operation class 132 in wpa_supplicant uses the
+ * lowest 20 MHz channel for simplicity, so increase ch by 4 to
+ * match the PSC.
+ */
if (is_6ghz_op_class(o->op_class) && o->bw == BW40 &&
get_6ghz_sec_channel(channel) < 0)
- chan = channel - 4;
+ ch = 4;
- for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+ for (ch += o->min_chan; ch <= o->max_chan; ch += o->inc) {
if (o->mode != HOSTAPD_MODE_IEEE80211A ||
(o->bw != BW40PLUS && o->bw != BW40MINUS &&
o->bw != BW40) ||
- ch != chan)
+ ch != channel)
continue;
ret = wpas_p2p_verify_channel(wpa_s, mode, o->op_class,
ch, o->bw);
@@ -5557,14 +5584,8 @@
if (freq > 0) {
freqs[0] = freq;
params.freqs = freqs;
- } else if (wpa_s->conf->p2p_6ghz_disable ||
- !is_p2p_allow_6ghz(wpa_s->global->p2p)) {
- wpa_printf(MSG_DEBUG,
- "P2P: 6 GHz disabled - update the scan frequency list");
- wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, ¶ms,
- false, false);
- wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, ¶ms,
- false, false);
+ } else {
+ wpas_p2p_scan_freqs(wpa_s, ¶ms, true);
}
ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
@@ -6541,7 +6562,8 @@
return -1;
num = get_shared_radio_freqs_data(wpa_s, freqs,
- wpa_s->num_multichan_concurrent);
+ wpa_s->num_multichan_concurrent,
+ false);
if (wpa_s->current_ssid &&
wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO &&
@@ -8426,7 +8448,7 @@
if (!freqs)
return;
- num = get_shared_radio_freqs_data(wpa_s, freqs, num);
+ num = get_shared_radio_freqs_data(wpa_s, freqs, num, false);
os_memset(&chan, 0, sizeof(chan));
os_memset(&cli_chan, 0, sizeof(cli_chan));
@@ -8612,6 +8634,10 @@
"in group formation",
wpa_s->global->p2p_group_formation->ifname);
ret = 1;
+ } else if (wpa_s->global->p2p_group_formation == wpa_s) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Skip Extended Listen timeout and allow scans on current interface for group formation");
+ ret = 2;
}
}
@@ -9973,7 +9999,7 @@
if (!freqs)
return;
- num = get_shared_radio_freqs_data(wpa_s, freqs, num);
+ num = get_shared_radio_freqs_data(wpa_s, freqs, num, false);
/* Previous attempt to move a GO was not possible -- try again. */
wpas_p2p_consider_moving_gos(wpa_s, freqs, num,
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index c87e1bf..e113c62 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -147,6 +147,9 @@
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr);
int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
+void wpas_p2p_scan_freqs(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ bool include_6ghz);
int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode,
u8 channel);
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index 2e6d9a7..edecfde 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -30,7 +30,7 @@
struct wpa_pasn_auth_work {
u8 own_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
+ u8 peer_addr[ETH_ALEN];
int akmp;
int cipher;
u16 group;
@@ -39,6 +39,15 @@
};
+static int wpas_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
+ int noack, unsigned int freq, unsigned int wait)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait);
+}
+
+
static void wpas_pasn_free_auth_work(struct wpa_pasn_auth_work *awork)
{
wpabuf_free(awork->comeback);
@@ -68,7 +77,8 @@
}
-static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid,
+static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr,
int akmp, int cipher, u8 status,
struct wpabuf *comeback,
u16 comeback_after)
@@ -84,7 +94,7 @@
wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
" akmp=%s, status=%u comeback_after=%u comeback=%s",
- MAC2STR(bssid),
+ MAC2STR(peer_addr),
wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
status, comeback_after, comeback_txt);
@@ -95,176 +105,15 @@
wpa_msg(wpa_s, MSG_INFO,
PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
- MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
+ MAC2STR(peer_addr), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
status);
}
#ifdef CONFIG_SAE
-static struct wpabuf * wpas_pasn_wd_sae_commit(struct wpa_supplicant *wpa_s)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- struct wpabuf *buf = NULL;
- int ret;
-
- ret = sae_set_group(&pasn->sae, pasn->group);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group");
- return NULL;
- }
-
- ret = sae_prepare_commit_pt(&pasn->sae, pasn->ssid->pt,
- pasn->own_addr, pasn->bssid,
- NULL, NULL);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit");
- return NULL;
- }
-
- /* Need to add the entire Authentication frame body */
- buf = wpabuf_alloc(6 + SAE_COMMIT_MAX_LEN);
- if (!buf) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
- return NULL;
- }
-
- wpabuf_put_le16(buf, WLAN_AUTH_SAE);
- wpabuf_put_le16(buf, 1);
- wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
-
- sae_write_commit(&pasn->sae, buf, NULL, 0);
- pasn->sae.state = SAE_COMMITTED;
-
- return buf;
-}
-
-
-static int wpas_pasn_wd_sae_rx(struct wpa_supplicant *wpa_s, struct wpabuf *wd)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- const u8 *data;
- size_t buf_len;
- u16 len, res, alg, seq, status;
- int groups[] = { pasn->group, 0 };
- int ret;
-
- if (!wd)
- return -1;
-
- data = wpabuf_head_u8(wd);
- buf_len = wpabuf_len(wd);
-
- /* first handle the commit message */
- if (buf_len < 2) {
- wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short (commit)");
- return -1;
- }
-
- len = WPA_GET_LE16(data);
- if (len < 6 || buf_len - 2 < len) {
- wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short for commit");
- return -1;
- }
-
- buf_len -= 2;
- data += 2;
-
- alg = WPA_GET_LE16(data);
- seq = WPA_GET_LE16(data + 2);
- status = WPA_GET_LE16(data + 4);
-
- wpa_printf(MSG_DEBUG, "PASN: SAE: commit: alg=%u, seq=%u, status=%u",
- alg, seq, status);
-
- if (alg != WLAN_AUTH_SAE || seq != 1 ||
- status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) {
- wpa_printf(MSG_DEBUG, "PASN: SAE: dropping peer commit");
- return -1;
- }
-
- res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, 0, groups,
- 1);
- if (res != WLAN_STATUS_SUCCESS) {
- wpa_printf(MSG_DEBUG, "PASN: SAE failed parsing commit");
- return -1;
- }
-
- /* Process the commit message and derive the PMK */
- ret = sae_process_commit(&pasn->sae);
- if (ret) {
- wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
- return -1;
- }
-
- buf_len -= len;
- data += len;
-
- /* Handle the confirm message */
- if (buf_len < 2) {
- wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short (confirm)");
- return -1;
- }
-
- len = WPA_GET_LE16(data);
- if (len < 6 || buf_len - 2 < len) {
- wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short for confirm");
- return -1;
- }
-
- buf_len -= 2;
- data += 2;
-
- alg = WPA_GET_LE16(data);
- seq = WPA_GET_LE16(data + 2);
- status = WPA_GET_LE16(data + 4);
-
- wpa_printf(MSG_DEBUG, "PASN: SAE confirm: alg=%u, seq=%u, status=%u",
- alg, seq, status);
-
- if (alg != WLAN_AUTH_SAE || seq != 2 || status != WLAN_STATUS_SUCCESS) {
- wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE confirm");
- return -1;
- }
-
- res = sae_check_confirm(&pasn->sae, data + 6, len - 6);
- if (res != WLAN_STATUS_SUCCESS) {
- wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm");
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "PASN: SAE completed successfully");
- pasn->sae.state = SAE_ACCEPTED;
-
- return 0;
-}
-
-
-static struct wpabuf * wpas_pasn_wd_sae_confirm(struct wpa_supplicant *wpa_s)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- struct wpabuf *buf = NULL;
-
- /* Need to add the entire authentication frame body */
- buf = wpabuf_alloc(6 + SAE_CONFIRM_MAX_LEN);
- if (!buf) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to allocate SAE buffer");
- return NULL;
- }
-
- wpabuf_put_le16(buf, WLAN_AUTH_SAE);
- wpabuf_put_le16(buf, 2);
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
-
- sae_write_confirm(&pasn->sae, buf);
- pasn->sae.state = SAE_CONFIRMED;
-
- return buf;
-}
-
-
-static int wpas_pasn_sae_setup_pt(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid, int group)
+static struct sae_pt *
+wpas_pasn_sae_derive_pt(struct wpa_ssid *ssid, int group)
{
const char *password = ssid->sae_password;
int groups[2] = { group, 0 };
@@ -274,15 +123,26 @@
if (!password) {
wpa_printf(MSG_DEBUG, "PASN: SAE without a password");
+ return NULL;
+ }
+
+ return sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+ (const u8 *) password, os_strlen(password),
+ ssid->sae_password_id);
+}
+
+
+static int wpas_pasn_sae_setup_pt(struct wpa_ssid *ssid, int group)
+{
+ if (!ssid->sae_password && !ssid->passphrase) {
+ wpa_printf(MSG_DEBUG, "PASN: SAE without a password");
return -1;
}
if (ssid->pt)
return 0; /* PT already derived */
- ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
- (const u8 *) password, os_strlen(password),
- ssid->sae_password_id);
+ ssid->pt = wpas_pasn_sae_derive_pt(ssid, group);
return ssid->pt ? 0 : -1;
}
@@ -302,12 +162,12 @@
struct wpa_ssid *ssid = NULL;
size_t ssid_str_len = 0;
const u8 *ssid_str = NULL;
- const u8 *bssid = peer->peer_addr;
+ const u8 *peer_addr = peer->peer_addr;
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid(wpa_s, peer_addr);
if (!bss) {
wpa_supplicant_update_scan_results(wpa_s);
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid(wpa_s, peer_addr);
if (!bss) {
wpa_printf(MSG_DEBUG, "PASN: BSS not found");
return -1;
@@ -394,13 +254,13 @@
} else if ((sel & WPA_KEY_MGMT_SAE_EXT_KEY) &&
(ieee802_11_rsnx_capab(rsnxe,
WLAN_RSNX_CAPAB_SAE_H2E)) &&
- (wpas_pasn_sae_setup_pt(wpa_s, ssid, group) == 0)) {
+ (wpas_pasn_sae_setup_pt(ssid, group) == 0)) {
key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE (ext key)");
} else if ((sel & WPA_KEY_MGMT_SAE) &&
(ieee802_11_rsnx_capab(rsnxe,
WLAN_RSNX_CAPAB_SAE_H2E)) &&
- (wpas_pasn_sae_setup_pt(wpa_s, ssid, group) == 0)) {
+ (wpas_pasn_sae_setup_pt(ssid, group) == 0)) {
key_mgmt = WPA_KEY_MGMT_SAE;
wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE");
#endif /* CONFIG_SAE */
@@ -447,15 +307,16 @@
static int wpas_pasn_set_keys_from_cache(struct wpa_supplicant *wpa_s,
- const u8 *own_addr, const u8 *bssid,
+ const u8 *own_addr,
+ const u8 *peer_addr,
int cipher, int akmp)
{
struct ptksa_cache_entry *entry;
- entry = ptksa_cache_get(wpa_s->ptksa, bssid, cipher);
+ entry = ptksa_cache_get(wpa_s->ptksa, peer_addr, cipher);
if (!entry) {
wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
- " not present in PTKSA cache", MAC2STR(bssid));
+ " not present in PTKSA cache", MAC2STR(peer_addr));
return -1;
}
@@ -468,8 +329,8 @@
}
wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
- MAC2STR(bssid));
- wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, bssid, cipher,
+ MAC2STR(peer_addr));
+ wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, cipher,
entry->ptk.tk_len,
entry->ptk.tk,
entry->ptk.ltf_keyseed_len,
@@ -559,871 +420,59 @@
for (i = 0; i < pasn_params->num_peers; i++) {
peer = &pasn_params->peer[i];
- wpas_pasn_deauthenticate(wpa_s, peer->own_addr,
- peer->peer_addr);
+ ptksa_cache_flush(wpa_s->ptksa, peer->peer_addr,
+ WPA_CIPHER_NONE);
}
}
-#ifdef CONFIG_FILS
-
-static struct wpabuf * wpas_pasn_fils_build_auth(struct wpa_supplicant *wpa_s)
+static void wpas_pasn_initiate_eapol(struct pasn_data *pasn,
+ struct wpa_ssid *ssid)
{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- struct wpabuf *buf = NULL;
- struct wpabuf *erp_msg;
- int ret;
-
- erp_msg = eapol_sm_build_erp_reauth_start(wpa_s->eapol);
- if (!erp_msg) {
- wpa_printf(MSG_DEBUG,
- "PASN: FILS: ERP EAP-Initiate/Re-auth unavailable");
- return NULL;
- }
-
- if (random_get_bytes(pasn->fils.nonce, FILS_NONCE_LEN) < 0 ||
- random_get_bytes(pasn->fils.session, FILS_SESSION_LEN) < 0)
- goto fail;
-
- wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", pasn->fils.nonce,
- FILS_NONCE_LEN);
-
- wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", pasn->fils.session,
- FILS_SESSION_LEN);
-
- buf = wpabuf_alloc(1500);
- if (!buf)
- goto fail;
-
- /* Add the authentication algorithm */
- wpabuf_put_le16(buf, WLAN_AUTH_FILS_SK);
-
- /* Authentication Transaction seq# */
- wpabuf_put_le16(buf, 1);
-
- /* Status Code */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
-
- /* Own RSNE */
- wpa_pasn_add_rsne(buf, NULL, pasn->akmp, pasn->cipher);
-
- /* FILS Nonce */
- wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
- wpabuf_put_u8(buf, 1 + FILS_NONCE_LEN);
- wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_NONCE);
- wpabuf_put_data(buf, pasn->fils.nonce, FILS_NONCE_LEN);
-
- /* FILS Session */
- wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
- wpabuf_put_u8(buf, 1 + FILS_SESSION_LEN);
- wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION);
- wpabuf_put_data(buf, pasn->fils.session, FILS_SESSION_LEN);
-
- /* Wrapped Data (ERP) */
- wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
- wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg));
- wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA);
- wpabuf_put_buf(buf, erp_msg);
-
- /*
- * Calculate pending PMKID here so that we do not need to maintain a
- * copy of the EAP-Initiate/Reauth message.
- */
- ret = fils_pmkid_erp(pasn->akmp, wpabuf_head(erp_msg),
- wpabuf_len(erp_msg),
- pasn->fils.erp_pmkid);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ERP PMKID");
- goto fail;
- }
-
- wpabuf_free(erp_msg);
- erp_msg = NULL;
-
- wpa_hexdump_buf(MSG_DEBUG, "PASN: FILS: Authentication frame", buf);
- return buf;
-fail:
- wpabuf_free(erp_msg);
- wpabuf_free(buf);
- return NULL;
-}
-
-
-static void wpas_pasn_initiate_eapol(struct wpa_supplicant *wpa_s)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
struct eapol_config eapol_conf;
- struct wpa_ssid *ssid = pasn->ssid;
wpa_printf(MSG_DEBUG, "PASN: FILS: Initiating EAPOL");
- eapol_sm_notify_eap_success(wpa_s->eapol, false);
- eapol_sm_notify_eap_fail(wpa_s->eapol, false);
- eapol_sm_notify_portControl(wpa_s->eapol, Auto);
+ eapol_sm_notify_eap_success(pasn->eapol, false);
+ eapol_sm_notify_eap_fail(pasn->eapol, false);
+ eapol_sm_notify_portControl(pasn->eapol, Auto);
os_memset(&eapol_conf, 0, sizeof(eapol_conf));
- eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+ eapol_conf.fast_reauth = pasn->fast_reauth;
eapol_conf.workaround = ssid->eap_workaround;
- eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
-}
-
-
-static struct wpabuf * wpas_pasn_wd_fils_auth(struct wpa_supplicant *wpa_s)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- struct wpa_bss *bss;
- const u8 *indic;
- u16 fils_info;
-
- wpa_printf(MSG_DEBUG, "PASN: FILS: wrapped data - completed=%u",
- pasn->fils.completed);
-
- /* Nothing to add as we are done */
- if (pasn->fils.completed)
- return NULL;
-
- if (!pasn->ssid) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: No network block");
- return NULL;
- }
-
- bss = wpa_bss_get_bssid(wpa_s, pasn->bssid);
- if (!bss) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: BSS not found");
- return NULL;
- }
-
- indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
- if (!indic || indic[1] < 2) {
- wpa_printf(MSG_DEBUG, "PASN: Missing FILS Indication IE");
- return NULL;
- }
-
- fils_info = WPA_GET_LE16(indic + 2);
- if (!(fils_info & BIT(9))) {
- wpa_printf(MSG_DEBUG,
- "PASN: FILS auth without PFS not supported");
- return NULL;
- }
-
- wpas_pasn_initiate_eapol(wpa_s);
-
- return wpas_pasn_fils_build_auth(wpa_s);
-}
-
-
-static int wpas_pasn_wd_fils_rx(struct wpa_supplicant *wpa_s, struct wpabuf *wd)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- struct ieee802_11_elems elems;
- struct wpa_ie_data rsne_data;
- u8 rmsk[ERP_MAX_KEY_LEN];
- size_t rmsk_len;
- u8 anonce[FILS_NONCE_LEN];
- const u8 *data;
- size_t buf_len;
- struct wpabuf *fils_wd = NULL;
- u16 alg, seq, status;
- int ret;
-
- if (!wd)
- return -1;
-
- data = wpabuf_head(wd);
- buf_len = wpabuf_len(wd);
-
- wpa_hexdump(MSG_DEBUG, "PASN: FILS: Authentication frame len=%zu",
- data, buf_len);
-
- /* first handle the header */
- if (buf_len < 6) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short");
- return -1;
- }
-
- alg = WPA_GET_LE16(data);
- seq = WPA_GET_LE16(data + 2);
- status = WPA_GET_LE16(data + 4);
-
- wpa_printf(MSG_DEBUG, "PASN: FILS: commit: alg=%u, seq=%u, status=%u",
- alg, seq, status);
-
- if (alg != WLAN_AUTH_FILS_SK || seq != 2 ||
- status != WLAN_STATUS_SUCCESS) {
- wpa_printf(MSG_DEBUG,
- "PASN: FILS: Dropping peer authentication");
- return -1;
- }
-
- data += 6;
- buf_len -= 6;
-
- if (ieee802_11_parse_elems(data, buf_len, &elems, 1) == ParseFailed) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Could not parse elements");
- return -1;
- }
-
- if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce ||
- !elems.wrapped_data) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs");
- return -1;
- }
-
- ret = wpa_parse_wpa_ie(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
- &rsne_data);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Failed parsing RNSE");
- return -1;
- }
-
- ret = wpa_pasn_validate_rsne(&rsne_data);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE");
- return -1;
- }
-
- if (rsne_data.num_pmkid) {
- wpa_printf(MSG_DEBUG,
- "PASN: FILS: Not expecting PMKID in RSNE");
- return -1;
- }
-
- wpa_hexdump(MSG_DEBUG, "PASN: FILS: ANonce", elems.fils_nonce,
- FILS_NONCE_LEN);
- os_memcpy(anonce, elems.fils_nonce, FILS_NONCE_LEN);
-
- wpa_hexdump(MSG_DEBUG, "PASN: FILS: FILS Session", elems.fils_session,
- FILS_SESSION_LEN);
-
- if (os_memcmp(pasn->fils.session, elems.fils_session,
- FILS_SESSION_LEN)) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Session mismatch");
- return -1;
- }
-
- fils_wd = ieee802_11_defrag(&elems, WLAN_EID_EXTENSION,
- WLAN_EID_EXT_WRAPPED_DATA);
-
- if (!fils_wd) {
- wpa_printf(MSG_DEBUG,
- "PASN: FILS: Failed getting wrapped data");
- return -1;
- }
-
- eapol_sm_process_erp_finish(wpa_s->eapol, wpabuf_head(fils_wd),
- wpabuf_len(fils_wd));
-
- wpabuf_free(fils_wd);
- fils_wd = NULL;
-
- if (eapol_sm_failed(wpa_s->eapol)) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: ERP finish failed");
- return -1;
- }
-
- rmsk_len = ERP_MAX_KEY_LEN;
- ret = eapol_sm_get_key(wpa_s->eapol, rmsk, rmsk_len);
-
- if (ret == PMK_LEN) {
- rmsk_len = PMK_LEN;
- ret = eapol_sm_get_key(wpa_s->eapol, rmsk, rmsk_len);
- }
-
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Failed getting RMSK");
- return -1;
- }
-
- ret = fils_rmsk_to_pmk(pasn->akmp, rmsk, rmsk_len,
- pasn->fils.nonce, anonce, NULL, 0,
- pasn->pmk, &pasn->pmk_len);
-
- forced_memzero(rmsk, sizeof(rmsk));
-
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PMK");
- return -1;
- }
-
- wpa_hexdump(MSG_DEBUG, "PASN: FILS: PMKID", pasn->fils.erp_pmkid,
- PMKID_LEN);
-
- wpa_printf(MSG_DEBUG, "PASN: FILS: ERP processing succeeded");
-
- wpa_pasn_pmksa_cache_add(wpa_s->wpa, pasn->pmk,
- pasn->pmk_len, pasn->fils.erp_pmkid,
- pasn->bssid, pasn->akmp);
-
- pasn->fils.completed = true;
- return 0;
-}
-
-#endif /* CONFIG_FILS */
-
-
-static struct wpabuf * wpas_pasn_get_wrapped_data(struct wpa_supplicant *wpa_s)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
-
- if (pasn->using_pmksa)
- return NULL;
-
- switch (pasn->akmp) {
- case WPA_KEY_MGMT_PASN:
- /* no wrapped data */
- return NULL;
- case WPA_KEY_MGMT_SAE:
-#ifdef CONFIG_SAE
- if (pasn->trans_seq == 0)
- return wpas_pasn_wd_sae_commit(wpa_s);
- if (pasn->trans_seq == 2)
- return wpas_pasn_wd_sae_confirm(wpa_s);
-#endif /* CONFIG_SAE */
- wpa_printf(MSG_ERROR,
- "PASN: SAE: Cannot derive wrapped data");
- return NULL;
- case WPA_KEY_MGMT_FILS_SHA256:
- case WPA_KEY_MGMT_FILS_SHA384:
-#ifdef CONFIG_FILS
- return wpas_pasn_wd_fils_auth(wpa_s);
-#endif /* CONFIG_FILS */
- case WPA_KEY_MGMT_FT_PSK:
- case WPA_KEY_MGMT_FT_IEEE8021X:
- case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
- /*
- * Wrapped data with these AKMs is optional and is only needed
- * for further validation of FT security parameters. For now do
- * not use them.
- */
- return NULL;
- default:
- wpa_printf(MSG_ERROR,
- "PASN: TODO: Wrapped data for akmp=0x%x",
- pasn->akmp);
- return NULL;
- }
-}
-
-
-static u8 wpas_pasn_get_wrapped_data_format(struct wpas_pasn *pasn)
-{
- if (pasn->using_pmksa)
- return WPA_PASN_WRAPPED_DATA_NO;
-
- /* Note: Valid AKMP is expected to already be validated */
- switch (pasn->akmp) {
- case WPA_KEY_MGMT_SAE:
- return WPA_PASN_WRAPPED_DATA_SAE;
- case WPA_KEY_MGMT_FILS_SHA256:
- case WPA_KEY_MGMT_FILS_SHA384:
- return WPA_PASN_WRAPPED_DATA_FILS_SK;
- case WPA_KEY_MGMT_FT_PSK:
- case WPA_KEY_MGMT_FT_IEEE8021X:
- case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
- /*
- * Wrapped data with these AKMs is optional and is only needed
- * for further validation of FT security parameters. For now do
- * not use them.
- */
- return WPA_PASN_WRAPPED_DATA_NO;
- case WPA_KEY_MGMT_PASN:
- default:
- return WPA_PASN_WRAPPED_DATA_NO;
- }
-}
-
-
-static struct wpabuf * wpas_pasn_build_auth_1(struct wpa_supplicant *wpa_s,
- const struct wpabuf *comeback)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL;
- const u8 *pmkid;
- u8 wrapped_data;
- int ret;
- u16 capab;
-
- wpa_printf(MSG_DEBUG, "PASN: Building frame 1");
-
- if (pasn->trans_seq)
- return NULL;
-
- buf = wpabuf_alloc(1500);
- if (!buf)
- goto fail;
-
- /* Get public key */
- pubkey = crypto_ecdh_get_pubkey(pasn->ecdh, 0);
- pubkey = wpabuf_zeropad(pubkey, crypto_ecdh_prime_len(pasn->ecdh));
- if (!pubkey) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to get pubkey");
- goto fail;
- }
-
- wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
-
- wpa_pasn_build_auth_header(buf, pasn->bssid,
- pasn->own_addr, pasn->bssid,
- pasn->trans_seq + 1, WLAN_STATUS_SUCCESS);
-
- pmkid = NULL;
- if (wpa_key_mgmt_ft(pasn->akmp)) {
- ret = wpa_pasn_ft_derive_pmk_r1(wpa_s->wpa, pasn->akmp,
- pasn->bssid,
- pasn->pmk_r1,
- &pasn->pmk_r1_len,
- pasn->pmk_r1_name);
- if (ret) {
- wpa_printf(MSG_DEBUG,
- "PASN: FT: Failed to derive keys");
- goto fail;
- }
-
- pmkid = pasn->pmk_r1_name;
- } else if (wrapped_data != WPA_PASN_WRAPPED_DATA_NO) {
- struct rsn_pmksa_cache_entry *pmksa;
-
- pmksa = wpa_sm_pmksa_cache_get(wpa_s->wpa, pasn->bssid,
- NULL, NULL, pasn->akmp);
- if (pmksa)
- pmkid = pmksa->pmkid;
-
- /*
- * Note: Even when PMKSA is available, also add wrapped data as
- * it is possible that the PMKID is no longer valid at the AP.
- */
- wrapped_data_buf = wpas_pasn_get_wrapped_data(wpa_s);
- }
-
- if (wpa_pasn_add_rsne(buf, pmkid, pasn->akmp, pasn->cipher) < 0)
- goto fail;
-
- if (!wrapped_data_buf)
- wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
-
- wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
- pubkey, true, comeback, -1);
-
- if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
- goto fail;
-
- /* Add own RNSXE */
- capab = 0;
- capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
- if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA)
- capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
- if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_STA)
- capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
- if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA)
- capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG);
- wpa_pasn_add_rsnxe(buf, capab);
-
- ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher,
- wpabuf_head_u8(buf) + IEEE80211_HDRLEN,
- wpabuf_len(buf) - IEEE80211_HDRLEN,
- pasn->hash);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to compute hash");
- goto fail;
- }
-
- pasn->trans_seq++;
-
- wpabuf_free(wrapped_data_buf);
- wpabuf_free(pubkey);
-
- wpa_printf(MSG_DEBUG, "PASN: Frame 1: Success");
- return buf;
-fail:
- pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
- wpabuf_free(wrapped_data_buf);
- wpabuf_free(pubkey);
- wpabuf_free(buf);
- return NULL;
-}
-
-
-static struct wpabuf * wpas_pasn_build_auth_3(struct wpa_supplicant *wpa_s)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- struct wpabuf *buf, *wrapped_data_buf = NULL;
- u8 mic[WPA_PASN_MAX_MIC_LEN];
- u8 mic_len, data_len;
- const u8 *data;
- u8 *ptr;
- u8 wrapped_data;
- int ret;
-
- wpa_printf(MSG_DEBUG, "PASN: Building frame 3");
-
- if (pasn->trans_seq != 2)
- return NULL;
-
- buf = wpabuf_alloc(1500);
- if (!buf)
- goto fail;
-
- wrapped_data = wpas_pasn_get_wrapped_data_format(pasn);
-
- wpa_pasn_build_auth_header(buf, pasn->bssid,
- pasn->own_addr, pasn->bssid,
- pasn->trans_seq + 1, WLAN_STATUS_SUCCESS);
-
- wrapped_data_buf = wpas_pasn_get_wrapped_data(wpa_s);
-
- if (!wrapped_data_buf)
- wrapped_data = WPA_PASN_WRAPPED_DATA_NO;
-
- wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data,
- NULL, false, NULL, -1);
-
- if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
- goto fail;
- wpabuf_free(wrapped_data_buf);
- wrapped_data_buf = NULL;
-
- /* Add the MIC */
- mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
- wpabuf_put_u8(buf, WLAN_EID_MIC);
- wpabuf_put_u8(buf, mic_len);
- ptr = wpabuf_put(buf, mic_len);
-
- os_memset(ptr, 0, mic_len);
-
- data = wpabuf_head_u8(buf) + IEEE80211_HDRLEN;
- data_len = wpabuf_len(buf) - IEEE80211_HDRLEN;
-
- ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
- pasn->own_addr, pasn->bssid,
- pasn->hash, mic_len * 2, data, data_len, mic);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: frame 3: Failed MIC calculation");
- goto fail;
- }
-
-#ifdef CONFIG_TESTING_OPTIONS
- if (wpa_s->conf->pasn_corrupt_mic) {
- wpa_printf(MSG_DEBUG, "PASN: frame 3: Corrupt MIC");
- mic[0] = ~mic[0];
- }
-#endif /* CONFIG_TESTING_OPTIONS */
-
- os_memcpy(ptr, mic, mic_len);
-
- pasn->trans_seq++;
-
- wpa_printf(MSG_DEBUG, "PASN: frame 3: Success");
- return buf;
-fail:
- pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
- wpabuf_free(wrapped_data_buf);
- wpabuf_free(buf);
- return NULL;
+ eapol_sm_notify_config(pasn->eapol, &ssid->eap, &eapol_conf);
}
static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
{
- struct wpas_pasn *pasn = &wpa_s->pasn;
-
- wpa_printf(MSG_DEBUG, "PASN: Reset");
-
- crypto_ecdh_deinit(pasn->ecdh);
- pasn->ecdh = NULL;
+ struct pasn_data *pasn = &wpa_s->pasn;
wpas_pasn_cancel_auth_work(wpa_s);
wpa_s->pasn_auth_work = NULL;
-
eloop_cancel_timeout(wpas_pasn_auth_work_timeout, wpa_s, NULL);
- pasn->akmp = 0;
- pasn->cipher = 0;
- pasn->group = 0;
- pasn->trans_seq = 0;
- pasn->pmk_len = 0;
- pasn->using_pmksa = false;
-
- forced_memzero(pasn->pmk, sizeof(pasn->pmk));
- forced_memzero(&pasn->ptk, sizeof(pasn->ptk));
- forced_memzero(&pasn->hash, sizeof(pasn->hash));
-
- wpabuf_free(pasn->beacon_rsne_rsnxe);
- pasn->beacon_rsne_rsnxe = NULL;
-
- wpabuf_free(pasn->comeback);
- pasn->comeback = NULL;
- pasn->comeback_after = 0;
-
-#ifdef CONFIG_SAE
- sae_clear_data(&pasn->sae);
-#endif /* CONFIG_SAE */
-
-#ifdef CONFIG_FILS
- os_memset(&pasn->fils, 0, sizeof(pasn->fils));
-#endif /* CONFIG_FILS*/
-
-#ifdef CONFIG_IEEE80211R
- forced_memzero(pasn->pmk_r1, sizeof(pasn->pmk_r1));
- pasn->pmk_r1_len = 0;
- os_memset(pasn->pmk_r1_name, 0, sizeof(pasn->pmk_r1_name));
-#endif /* CONFIG_IEEE80211R */
- pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
-}
-
-
-static int wpas_pasn_set_pmk(struct wpa_supplicant *wpa_s,
- struct wpa_ie_data *rsn_data,
- struct wpa_pasn_params_data *pasn_data,
- struct wpabuf *wrapped_data)
-{
- static const u8 pasn_default_pmk[] = {'P', 'M', 'K', 'z'};
- struct wpas_pasn *pasn = &wpa_s->pasn;
-
- os_memset(pasn->pmk, 0, sizeof(pasn->pmk));
- pasn->pmk_len = 0;
-
- if (pasn->akmp == WPA_KEY_MGMT_PASN) {
- wpa_printf(MSG_DEBUG, "PASN: Using default PMK");
-
- pasn->pmk_len = WPA_PASN_PMK_LEN;
- os_memcpy(pasn->pmk, pasn_default_pmk,
- sizeof(pasn_default_pmk));
- return 0;
- }
-
- if (wpa_key_mgmt_ft(pasn->akmp)) {
-#ifdef CONFIG_IEEE80211R
- wpa_printf(MSG_DEBUG, "PASN: FT: Using PMK-R1");
- pasn->pmk_len = pasn->pmk_r1_len;
- os_memcpy(pasn->pmk, pasn->pmk_r1, pasn->pmk_r1_len);
- pasn->using_pmksa = true;
- return 0;
-#else /* CONFIG_IEEE80211R */
- wpa_printf(MSG_DEBUG, "PASN: FT: Not supported");
- return -1;
-#endif /* CONFIG_IEEE80211R */
- }
-
- if (rsn_data->num_pmkid) {
- struct rsn_pmksa_cache_entry *pmksa;
-
- pmksa = wpa_sm_pmksa_cache_get(wpa_s->wpa, pasn->bssid,
- rsn_data->pmkid, NULL,
- pasn->akmp);
- if (pmksa) {
- wpa_printf(MSG_DEBUG, "PASN: Using PMKSA");
-
- pasn->pmk_len = pmksa->pmk_len;
- os_memcpy(pasn->pmk, pmksa->pmk, pmksa->pmk_len);
- pasn->using_pmksa = true;
-
- return 0;
- }
- }
-
-#ifdef CONFIG_SAE
- if (pasn->akmp == WPA_KEY_MGMT_SAE) {
- int ret;
-
- ret = wpas_pasn_wd_sae_rx(wpa_s, wrapped_data);
- if (ret) {
- wpa_printf(MSG_DEBUG,
- "PASN: Failed processing SAE wrapped data");
- pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "PASN: Success deriving PMK with SAE");
- pasn->pmk_len = PMK_LEN;
- os_memcpy(pasn->pmk, pasn->sae.pmk, PMK_LEN);
-
- wpa_pasn_pmksa_cache_add(wpa_s->wpa, pasn->pmk,
- pasn->pmk_len, pasn->sae.pmkid,
- pasn->bssid, pasn->akmp);
- return 0;
- }
-#endif /* CONFIG_SAE */
-
-#ifdef CONFIG_FILS
- if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
- pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) {
- int ret;
-
- ret = wpas_pasn_wd_fils_rx(wpa_s, wrapped_data);
- if (ret) {
- wpa_printf(MSG_DEBUG,
- "PASN: Failed processing FILS wrapped data");
- pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
- return -1;
- }
-
- return 0;
- }
-#endif /* CONFIG_FILS */
-
- /* TODO: Derive PMK based on wrapped data */
- wpa_printf(MSG_DEBUG, "PASN: Missing implementation to derive PMK");
- pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
- return -1;
-}
-
-
-static int wpas_pasn_start(struct wpa_supplicant *wpa_s, const u8 *own_addr,
- const u8 *bssid, int akmp, int cipher, u16 group,
- int freq, const u8 *beacon_rsne, u8 beacon_rsne_len,
- const u8 *beacon_rsnxe, u8 beacon_rsnxe_len,
- int network_id, struct wpabuf *comeback)
-{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- 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)) {
- wpa_printf(MSG_DEBUG,
- "PASN: Reject unsuitable group %u", group);
- return -1;
- }
-
- ssid = wpa_config_get_network(wpa_s->conf, network_id);
-
- switch (akmp) {
- case WPA_KEY_MGMT_PASN:
- break;
-#ifdef CONFIG_SAE
- case WPA_KEY_MGMT_SAE:
- if (!ssid) {
- wpa_printf(MSG_DEBUG,
- "PASN: No network profile found for SAE");
- return -1;
- }
-
- if (!ieee802_11_rsnx_capab(beacon_rsnxe,
- WLAN_RSNX_CAPAB_SAE_H2E)) {
- wpa_printf(MSG_DEBUG,
- "PASN: AP does not support SAE H2E");
- return -1;
- }
-
- if (wpas_pasn_sae_setup_pt(wpa_s, ssid, group) < 0) {
- wpa_printf(MSG_DEBUG,
- "PASN: Failed to derive PT");
- return -1;
- }
-
- pasn->sae.state = SAE_NOTHING;
- pasn->sae.send_confirm = 0;
- pasn->ssid = ssid;
- break;
-#endif /* CONFIG_SAE */
-#ifdef CONFIG_FILS
- case WPA_KEY_MGMT_FILS_SHA256:
- case WPA_KEY_MGMT_FILS_SHA384:
- pasn->ssid = ssid;
- break;
-#endif /* CONFIG_FILS */
-#ifdef CONFIG_IEEE80211R
- case WPA_KEY_MGMT_FT_PSK:
- case WPA_KEY_MGMT_FT_IEEE8021X:
- case WPA_KEY_MGMT_FT_IEEE8021X_SHA384:
- break;
-#endif /* CONFIG_IEEE80211R */
- default:
- wpa_printf(MSG_ERROR, "PASN: Unsupported AKMP=0x%x", akmp);
- return -1;
- }
-
- pasn->ecdh = crypto_ecdh_init(group);
- if (!pasn->ecdh) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");
- goto fail;
- }
-
- pasn->beacon_rsne_rsnxe = wpabuf_alloc(beacon_rsne_len +
- beacon_rsnxe_len);
- if (!pasn->beacon_rsne_rsnxe) {
- wpa_printf(MSG_DEBUG, "PASN: Failed storing beacon RSNE/RSNXE");
- goto fail;
- }
-
- wpabuf_put_data(pasn->beacon_rsne_rsnxe, beacon_rsne, beacon_rsne_len);
- if (beacon_rsnxe && beacon_rsnxe_len)
- wpabuf_put_data(pasn->beacon_rsne_rsnxe, beacon_rsnxe,
- beacon_rsnxe_len);
-
- pasn->akmp = akmp;
- pasn->cipher = cipher;
- pasn->group = group;
- pasn->freq = freq;
-
- derive_kdk = (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
- 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;
- wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
-
- if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
- ieee802_11_rsnx_capab(beacon_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))
- pasn->secure_ltf = true;
- else
- pasn->secure_ltf = false;
-
- os_memcpy(pasn->own_addr, own_addr, ETH_ALEN);
- os_memcpy(pasn->bssid, bssid, ETH_ALEN);
-
- wpa_printf(MSG_DEBUG,
- "PASN: Init: " MACSTR " akmp=0x%x, cipher=0x%x, group=%u",
- MAC2STR(pasn->bssid), pasn->akmp, pasn->cipher,
- pasn->group);
-
- frame = wpas_pasn_build_auth_1(wpa_s, comeback);
- if (!frame) {
- wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame");
- goto fail;
- }
-
- ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(frame), wpabuf_len(frame), 0,
- pasn->freq, 1000);
-
- wpabuf_free(frame);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed sending 1st auth frame");
- goto fail;
- }
-
- eloop_register_timeout(2, 0, wpas_pasn_auth_work_timeout, wpa_s, NULL);
- return 0;
-
-fail:
- return -1;
+ wpa_pasn_reset(pasn);
}
static struct wpa_bss * wpas_pasn_allowed(struct wpa_supplicant *wpa_s,
- const u8 *bssid, int akmp, int cipher)
+ const u8 *peer_addr, int akmp,
+ int cipher)
{
struct wpa_bss *bss;
const u8 *rsne;
struct wpa_ie_data rsne_data;
int ret;
- if (os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) == 0) {
+ if (os_memcmp(wpa_s->bssid, peer_addr, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"PASN: Not doing authentication with current BSS");
return NULL;
}
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid(wpa_s, peer_addr);
if (!bss) {
wpa_printf(MSG_DEBUG, "PASN: BSS not found");
return NULL;
@@ -1456,8 +505,14 @@
{
struct wpa_supplicant *wpa_s = work->wpa_s;
struct wpa_pasn_auth_work *awork = work->ctx;
+ struct pasn_data *pasn = &wpa_s->pasn;
+ struct wpa_ssid *ssid;
struct wpa_bss *bss;
const u8 *rsne, *rsnxe;
+ const u8 *indic;
+ u16 fils_info;
+ u16 capab = 0;
+ bool derive_kdk;
int ret;
wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: deinit=%d", deinit);
@@ -1478,7 +533,7 @@
* authentication is not allowed, e.g., a connection with the AP was
* established.
*/
- bss = wpas_pasn_allowed(wpa_s, awork->bssid, awork->akmp,
+ bss = wpas_pasn_allowed(wpa_s, awork->peer_addr, awork->akmp,
awork->cipher);
if (!bss) {
wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: Not allowed");
@@ -1493,16 +548,115 @@
rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
- ret = wpas_pasn_start(wpa_s, awork->own_addr, awork->bssid, awork->akmp,
- awork->cipher, awork->group, bss->freq,
- rsne, *(rsne + 1) + 2,
+ derive_kdk = (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
+ ieee802_11_rsnx_capab(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;
+ wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
+
+ if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
+ ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))
+ pasn->secure_ltf = true;
+ else
+ pasn->secure_ltf = false;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ pasn->corrupt_mic = wpa_s->conf->pasn_corrupt_mic;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_STA)
+ capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA)
+ capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
+ pasn->rsnxe_capab = capab;
+ pasn->send_mgmt = wpas_pasn_send_mlme;
+
+ ssid = wpa_config_get_network(wpa_s->conf, awork->network_id);
+
+#ifdef CONFIG_SAE
+ if (awork->akmp == WPA_KEY_MGMT_SAE) {
+ if (!ssid) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: No network profile found for SAE");
+ goto fail;
+ }
+ pasn->pt = wpas_pasn_sae_derive_pt(ssid, awork->group);
+ if (!pasn->pt) {
+ wpa_printf(MSG_DEBUG, "PASN: Failed to derive PT");
+ goto fail;
+ }
+ pasn->network_id = ssid->id;
+ }
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_FILS
+ /* Prepare needed information for wpas_pasn_wd_fils_auth(). */
+ if (awork->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
+ awork->akmp == WPA_KEY_MGMT_FILS_SHA384) {
+ indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
+ if (!ssid) {
+ wpa_printf(MSG_DEBUG, "PASN: FILS: No network block");
+ } else if (!indic || indic[1] < 2) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Missing FILS Indication IE");
+ } else {
+ fils_info = WPA_GET_LE16(indic + 2);
+ if ((fils_info & BIT(9)) && ssid) {
+ pasn->eapol = wpa_s->eapol;
+ pasn->network_id = ssid->id;
+ wpas_pasn_initiate_eapol(pasn, ssid);
+ pasn->fils_eapol = true;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FILS auth without PFS not supported");
+ }
+ }
+ pasn->fast_reauth = wpa_s->conf->fast_reauth;
+ }
+#endif /* CONFIG_FILS */
+
+ pasn->cb_ctx = wpa_s;
+ pasn->pmksa = wpa_sm_get_pmksa_cache(wpa_s->wpa);
+
+ if (wpa_key_mgmt_ft(awork->akmp)) {
+#ifdef CONFIG_IEEE80211R
+ ret = wpa_pasn_ft_derive_pmk_r1(wpa_s->wpa, awork->akmp,
+ awork->peer_addr,
+ pasn->pmk_r1,
+ &pasn->pmk_r1_len,
+ pasn->pmk_r1_name);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: FT: Failed to derive keys");
+ goto fail;
+ }
+#else /* CONFIG_IEEE80211R */
+ goto fail;
+#endif /* CONFIG_IEEE80211R */
+ }
+
+
+ ret = wpas_pasn_start(pasn, awork->own_addr, awork->peer_addr,
+ awork->peer_addr, awork->akmp, awork->cipher,
+ awork->group, bss->freq, rsne, *(rsne + 1) + 2,
rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
- awork->network_id, awork->comeback);
+ awork->comeback);
if (ret) {
wpa_printf(MSG_DEBUG,
"PASN: Failed to start PASN authentication");
goto fail;
}
+ eloop_register_timeout(2, 0, wpas_pasn_auth_work_timeout, wpa_s, NULL);
/* comeback token is no longer needed at this stage */
wpabuf_free(awork->comeback);
@@ -1518,7 +672,7 @@
int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
- const u8 *own_addr, const u8 *bssid,
+ const u8 *own_addr, const u8 *peer_addr,
int akmp, int cipher, u16 group, int network_id,
const u8 *comeback, size_t comeback_len)
{
@@ -1526,7 +680,7 @@
struct wpa_bss *bss;
wpa_printf(MSG_DEBUG, "PASN: Start: " MACSTR " akmp=0x%x, cipher=0x%x",
- MAC2STR(bssid), akmp, cipher);
+ MAC2STR(peer_addr), akmp, cipher);
/*
* TODO: Consider modifying the offchannel logic to handle additional
@@ -1550,7 +704,7 @@
return -1;
}
- bss = wpas_pasn_allowed(wpa_s, bssid, akmp, cipher);
+ bss = wpas_pasn_allowed(wpa_s, peer_addr, akmp, cipher);
if (!bss)
return -1;
@@ -1561,7 +715,7 @@
return -1;
os_memcpy(awork->own_addr, own_addr, ETH_ALEN);
- os_memcpy(awork->bssid, bssid, ETH_ALEN);
+ os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN);
awork->akmp = akmp;
awork->cipher = cipher;
awork->group = group;
@@ -1588,14 +742,14 @@
void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
{
- struct wpas_pasn *pasn = &wpa_s->pasn;
+ struct pasn_data *pasn = &wpa_s->pasn;
if (!wpa_s->pasn.ecdh)
return;
wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
- wpas_pasn_auth_status(wpa_s, pasn->bssid, pasn->akmp, pasn->cipher,
+ wpas_pasn_auth_status(wpa_s, pasn->peer_addr, pasn->akmp, pasn->cipher,
pasn->status, pasn->comeback,
pasn->comeback_after);
@@ -1604,23 +758,22 @@
static int wpas_pasn_immediate_retry(struct wpa_supplicant *wpa_s,
- struct wpas_pasn *pasn,
+ struct pasn_data *pasn,
struct wpa_pasn_params_data *params)
{
int akmp = pasn->akmp;
int cipher = pasn->cipher;
u16 group = pasn->group;
u8 own_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- int network_id = pasn->ssid ? pasn->ssid->id : 0;
+ u8 peer_addr[ETH_ALEN];
wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
os_memcpy(own_addr, pasn->own_addr, ETH_ALEN);
- os_memcpy(bssid, pasn->bssid, ETH_ALEN);
+ os_memcpy(peer_addr, pasn->peer_addr, ETH_ALEN);
wpas_pasn_reset(wpa_s);
- return wpas_pasn_auth_start(wpa_s, own_addr, bssid, akmp, cipher, group,
- network_id,
+ return wpas_pasn_auth_start(wpa_s, own_addr, peer_addr, akmp, cipher,
+ group, pasn->network_id,
params->comeback, params->comeback_len);
}
@@ -1628,279 +781,51 @@
static void wpas_pasn_deauth_cb(struct ptksa_cache_entry *entry)
{
struct wpa_supplicant *wpa_s = entry->ctx;
+ u8 own_addr[ETH_ALEN];
+ u8 peer_addr[ETH_ALEN];
- wpas_pasn_deauthenticate(wpa_s, entry->own_addr, entry->addr);
+ /* Use a copy of the addresses from the entry to avoid issues with the
+ * entry getting freed during deauthentication processing. */
+ os_memcpy(own_addr, entry->own_addr, ETH_ALEN);
+ os_memcpy(peer_addr, entry->addr, ETH_ALEN);
+ wpas_pasn_deauthenticate(wpa_s, own_addr, peer_addr);
}
int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
const struct ieee80211_mgmt *mgmt, size_t len)
{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- struct ieee802_11_elems elems;
- struct wpa_ie_data rsn_data;
- struct wpa_pasn_params_data pasn_params;
- struct wpabuf *wrapped_data = NULL, *secret = NULL, *frame = NULL;
- u8 mic[WPA_PASN_MAX_MIC_LEN], out_mic[WPA_PASN_MAX_MIC_LEN];
- u8 mic_len;
- u16 status;
- int ret, inc_y;
- u16 fc = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
- (WLAN_FC_STYPE_AUTH << 4));
+ struct pasn_data *pasn = &wpa_s->pasn;
+ struct wpa_pasn_params_data pasn_data;
+ int ret;
- if (!wpa_s->pasn_auth_work || !mgmt ||
- len < offsetof(struct ieee80211_mgmt, u.auth.variable))
+ if (!wpa_s->pasn_auth_work)
return -2;
- /* Not an Authentication frame; do nothing */
- if ((mgmt->frame_control & fc) != fc)
- return -2;
+ pasn->cb_ctx = wpa_s;
+ ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data);
+ if (ret == 0) {
+ ptksa_cache_add(wpa_s->ptksa, pasn->own_addr, pasn->peer_addr,
+ pasn->cipher, dot11RSNAConfigPMKLifetime,
+ &pasn->ptk,
+ wpa_s->pasn_params ? wpas_pasn_deauth_cb : NULL,
+ wpa_s->pasn_params ? wpa_s : NULL, pasn->akmp);
- /* Not our frame; do nothing */
- if (os_memcmp(mgmt->da, pasn->own_addr, ETH_ALEN) != 0 ||
- os_memcmp(mgmt->sa, pasn->bssid, ETH_ALEN) != 0 ||
- os_memcmp(mgmt->bssid, pasn->bssid, ETH_ALEN) != 0)
- return -2;
-
- /* Not PASN; do nothing */
- if (mgmt->u.auth.auth_alg != host_to_le16(WLAN_AUTH_PASN))
- return -2;
-
- if (mgmt->u.auth.auth_transaction !=
- host_to_le16(pasn->trans_seq + 1)) {
- wpa_printf(MSG_DEBUG,
- "PASN: RX: Invalid transaction sequence: (%u != %u)",
- le_to_host16(mgmt->u.auth.auth_transaction),
- pasn->trans_seq + 1);
- return -1;
+ if (pasn->pmksa_entry)
+ wpa_sm_set_cur_pmksa(wpa_s->wpa, pasn->pmksa_entry);
}
- status = le_to_host16(mgmt->u.auth.status_code);
-
- if (status != WLAN_STATUS_SUCCESS &&
- status != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
- wpa_printf(MSG_DEBUG,
- "PASN: Authentication rejected - status=%u", status);
- goto fail;
- }
-
- if (ieee802_11_parse_elems(mgmt->u.auth.variable,
- len - offsetof(struct ieee80211_mgmt,
- u.auth.variable),
- &elems, 0) == ParseFailed) {
- wpa_printf(MSG_DEBUG,
- "PASN: Failed parsing Authentication frame");
- goto fail;
- }
-
- /* Check that the MIC IE exists. Save it and zero out the memory */
- mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
- if (status == WLAN_STATUS_SUCCESS) {
- if (!elems.mic || elems.mic_len != mic_len) {
- wpa_printf(MSG_DEBUG,
- "PASN: Invalid MIC. Expecting len=%u",
- mic_len);
- goto fail;
- } else {
- os_memcpy(mic, elems.mic, mic_len);
- /* TODO: Clean this up.. Should not be modifying the
- * received message buffer. */
- os_memset((u8 *) elems.mic, 0, mic_len);
- }
- }
-
- if (!elems.pasn_params || !elems.pasn_params_len) {
- wpa_printf(MSG_DEBUG,
- "PASN: Missing PASN Parameters IE");
- goto fail;
- }
-
- ret = wpa_pasn_parse_parameter_ie(elems.pasn_params - 3,
- elems.pasn_params_len + 3,
- true, &pasn_params);
- if (ret) {
- wpa_printf(MSG_DEBUG,
- "PASN: Failed validation PASN of Parameters IE");
- goto fail;
- }
-
- if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
- wpa_printf(MSG_DEBUG,
- "PASN: Authentication temporarily rejected");
-
- if (pasn_params.comeback && pasn_params.comeback_len) {
- wpa_printf(MSG_DEBUG,
- "PASN: Comeback token available. After=%u",
- pasn_params.after);
-
- if (!pasn_params.after)
- return wpas_pasn_immediate_retry(wpa_s, pasn,
- &pasn_params);
-
- pasn->comeback = wpabuf_alloc_copy(
- pasn_params.comeback, pasn_params.comeback_len);
- if (pasn->comeback)
- pasn->comeback_after = pasn_params.after;
- }
-
- pasn->status = status;
- goto fail;
- }
-
- ret = wpa_parse_wpa_ie(elems.rsn_ie - 2, elems.rsn_ie_len + 2,
- &rsn_data);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed parsing RNSE");
- goto fail;
- }
-
- ret = wpa_pasn_validate_rsne(&rsn_data);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed validating RSNE");
- goto fail;
- }
-
- if (pasn->akmp != rsn_data.key_mgmt ||
- pasn->cipher != rsn_data.pairwise_cipher) {
- wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher");
- goto fail;
- }
-
- if (pasn->group != pasn_params.group) {
- wpa_printf(MSG_DEBUG, "PASN: Mismatch in group");
- goto fail;
- }
-
- if (!pasn_params.pubkey || !pasn_params.pubkey_len) {
- wpa_printf(MSG_DEBUG, "PASN: Invalid public key");
- goto fail;
- }
-
- if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) {
- inc_y = 1;
- } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 ||
- pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) {
- inc_y = 0;
- } else {
- wpa_printf(MSG_DEBUG,
- "PASN: Invalid first octet in pubkey=0x%x",
- pasn_params.pubkey[0]);
- goto fail;
- }
-
- secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y,
- pasn_params.pubkey + 1,
- pasn_params.pubkey_len - 1);
-
- if (!secret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret");
- goto fail;
- }
-
- if (pasn_params.wrapped_data_format != WPA_PASN_WRAPPED_DATA_NO) {
- wrapped_data = ieee802_11_defrag(&elems,
- WLAN_EID_EXTENSION,
- WLAN_EID_EXT_WRAPPED_DATA);
-
- if (!wrapped_data) {
- wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data");
- goto fail;
- }
- }
-
- ret = wpas_pasn_set_pmk(wpa_s, &rsn_data, &pasn_params, wrapped_data);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to set PMK");
- goto fail;
- }
-
- ret = pasn_pmk_to_ptk(pasn->pmk, pasn->pmk_len,
- pasn->own_addr, pasn->bssid,
- wpabuf_head(secret), wpabuf_len(secret),
- &pasn->ptk, pasn->akmp, pasn->cipher,
- pasn->kdk_len);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
- goto fail;
- }
-
- if (pasn->secure_ltf) {
- ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, pasn->cipher);
- if (ret) {
- wpa_printf(MSG_DEBUG,
- "PASN: Failed to derive LTF keyseed");
- goto fail;
- }
- }
-
- wpabuf_free(wrapped_data);
- wrapped_data = NULL;
- wpabuf_free(secret);
- secret = NULL;
-
- /* Verify the MIC */
- ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher,
- pasn->bssid, pasn->own_addr,
- wpabuf_head(pasn->beacon_rsne_rsnxe),
- wpabuf_len(pasn->beacon_rsne_rsnxe),
- (u8 *) &mgmt->u.auth,
- len - offsetof(struct ieee80211_mgmt, u.auth),
- out_mic);
-
- wpa_hexdump_key(MSG_DEBUG, "PASN: Frame MIC", mic, mic_len);
- if (ret || os_memcmp(mic, out_mic, mic_len) != 0) {
- wpa_printf(MSG_DEBUG, "PASN: Failed MIC verification");
- goto fail;
- }
-
- pasn->trans_seq++;
-
- wpa_printf(MSG_DEBUG, "PASN: Success verifying Authentication frame");
-
- frame = wpas_pasn_build_auth_3(wpa_s);
- if (!frame) {
- wpa_printf(MSG_DEBUG, "PASN: Failed building 3rd auth frame");
- goto fail;
- }
-
- ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(frame), wpabuf_len(frame), 0,
- pasn->freq, 100);
- wpabuf_free(frame);
- if (ret) {
- wpa_printf(MSG_DEBUG, "PASN: Failed sending 3st auth frame");
- goto fail;
- }
-
- wpa_printf(MSG_DEBUG, "PASN: Success sending last frame. Store PTK");
-
- ptksa_cache_add(wpa_s->ptksa, pasn->own_addr, pasn->bssid,
- pasn->cipher, dot11RSNAConfigPMKLifetime, &pasn->ptk,
- wpa_s->pasn_params ? wpas_pasn_deauth_cb : NULL,
- wpa_s->pasn_params ? wpa_s : NULL);
-
forced_memzero(&pasn->ptk, sizeof(pasn->ptk));
- pasn->status = WLAN_STATUS_SUCCESS;
- return 0;
-fail:
- wpa_printf(MSG_DEBUG, "PASN: Failed RX processing - terminating");
- wpabuf_free(wrapped_data);
- wpabuf_free(secret);
+ if (ret == -1) {
+ wpas_pasn_auth_stop(wpa_s);
+ wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE);
+ }
- /*
- * TODO: In case of an error the standard allows to silently drop
- * the frame and terminate the authentication exchange. However, better
- * reply to the AP with an error status.
- */
- if (status == WLAN_STATUS_SUCCESS)
- pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
- else
- pasn->status = status;
+ if (ret == 1)
+ ret = wpas_pasn_immediate_retry(wpa_s, pasn, &pasn_data);
- wpas_pasn_auth_stop(wpa_s);
-
- wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE);
- return -1;
+ return ret;
}
@@ -1961,12 +886,8 @@
const u8 *data, size_t data_len, u8 acked)
{
- struct wpas_pasn *pasn = &wpa_s->pasn;
- const struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) data;
- u16 fc = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
- (WLAN_FC_STYPE_AUTH << 4));
-
- wpa_printf(MSG_DEBUG, "PASN: auth_tx_status: acked=%u", acked);
+ struct pasn_data *pasn = &wpa_s->pasn;
+ int ret;
if (!wpa_s->pasn_auth_work) {
wpa_printf(MSG_DEBUG,
@@ -1974,87 +895,46 @@
return -1;
}
- if (!mgmt ||
- data_len < offsetof(struct ieee80211_mgmt, u.auth.variable))
- return -1;
+ ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked);
+ if (ret != 1)
+ return ret;
- /* Not an authentication frame; do nothing */
- if ((mgmt->frame_control & fc) != fc)
- return -1;
-
- /* Not our frame; do nothing */
- if (os_memcmp(mgmt->da, pasn->bssid, ETH_ALEN) ||
- os_memcmp(mgmt->sa, pasn->own_addr, ETH_ALEN) ||
- os_memcmp(mgmt->bssid, pasn->bssid, ETH_ALEN))
- return -1;
-
- /* Not PASN; do nothing */
- if (mgmt->u.auth.auth_alg != host_to_le16(WLAN_AUTH_PASN))
- return -1;
-
- if (mgmt->u.auth.auth_transaction != host_to_le16(pasn->trans_seq)) {
- wpa_printf(MSG_ERROR,
- "PASN: Invalid transaction sequence: (%u != %u)",
- pasn->trans_seq,
- le_to_host16(mgmt->u.auth.auth_transaction));
+ if (!wpa_s->pasn_params) {
+ wpas_pasn_auth_stop(wpa_s);
return 0;
}
- wpa_printf(MSG_ERROR,
- "PASN: auth with trans_seq=%u, acked=%u", pasn->trans_seq,
- acked);
-
- /*
- * Even if the frame was not acked, do not treat this is an error, and
- * try to complete the flow, relying on the PASN timeout callback to
- * clean up.
- */
- if (pasn->trans_seq == 3) {
- wpa_printf(MSG_DEBUG, "PASN: auth complete with: " MACSTR,
- MAC2STR(pasn->bssid));
- /*
- * Either frame was not ACKed or it was ACKed but the trans_seq
- * != 1, i.e., not expecting an RX frame, so we are done.
- */
- if (!wpa_s->pasn_params) {
- wpas_pasn_auth_stop(wpa_s);
- return 0;
- }
-
- wpas_pasn_set_keys_from_cache(wpa_s, pasn->own_addr,
- pasn->bssid, pasn->cipher,
- pasn->akmp);
- wpas_pasn_auth_stop(wpa_s);
-
- wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_SUCCESS);
- }
+ wpas_pasn_set_keys_from_cache(wpa_s, pasn->own_addr, pasn->peer_addr,
+ pasn->cipher, pasn->akmp);
+ wpas_pasn_auth_stop(wpa_s);
+ wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_SUCCESS);
return 0;
}
int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *own_addr,
- const u8 *bssid)
+ const u8 *peer_addr)
{
struct wpa_bss *bss;
struct wpabuf *buf;
struct ieee80211_mgmt *deauth;
int ret;
- if (os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) == 0) {
+ if (os_memcmp(wpa_s->bssid, peer_addr, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"PASN: Cannot deauthenticate from current BSS");
return -1;
}
- wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, bssid, 0, 0, NULL, 0,
- NULL, 1);
+ wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, 0, 0, NULL,
+ 0, NULL, 1);
wpa_printf(MSG_DEBUG, "PASN: deauth: Flushing all PTKSA entries for "
- MACSTR, MAC2STR(bssid));
- ptksa_cache_flush(wpa_s->ptksa, bssid, WPA_CIPHER_NONE);
+ MACSTR, MAC2STR(peer_addr));
+ ptksa_cache_flush(wpa_s->ptksa, peer_addr, WPA_CIPHER_NONE);
- bss = wpa_bss_get_bssid(wpa_s, bssid);
+ bss = wpa_bss_get_bssid(wpa_s, peer_addr);
if (!bss) {
wpa_printf(MSG_DEBUG, "PASN: deauth: BSS not found");
return -1;
@@ -2072,9 +952,9 @@
deauth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
(WLAN_FC_STYPE_DEAUTH << 4));
- os_memcpy(deauth->da, bssid, ETH_ALEN);
+ os_memcpy(deauth->da, peer_addr, ETH_ALEN);
os_memcpy(deauth->sa, own_addr, ETH_ALEN);
- os_memcpy(deauth->bssid, bssid, ETH_ALEN);
+ os_memcpy(deauth->bssid, peer_addr, ETH_ALEN);
deauth->u.deauth.reason_code =
host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c
index 3ae99da..3aa6675 100644
--- a/wpa_supplicant/preauth_test.c
+++ b/wpa_supplicant/preauth_test.c
@@ -131,7 +131,7 @@
}
-static int wpa_supplicant_set_key(void *wpa_s, enum wpa_alg alg,
+static int wpa_supplicant_set_key(void *wpa_s, int link_id, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len,
@@ -318,7 +318,7 @@
}
os_memset(&wpa_s, 0, sizeof(wpa_s));
- wpa_s.conf = wpa_config_read(argv[1], NULL);
+ wpa_s.conf = wpa_config_read(argv[1], NULL, false);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", argv[1]);
return -1;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index faa97e0..88d7e6e 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -299,6 +299,8 @@
return -1;
}
+ wpa_s->wps_scan_done = false;
+
return 0;
}
@@ -476,25 +478,28 @@
wpa_s->p2p_invite_go_freq > 0) {
if (wpa_s->p2p_invite_go_freq == 2 ||
wpa_s->p2p_invite_go_freq == 5) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred band %d GHz during invitation",
- wpa_s->p2p_invite_go_freq);
enum hostapd_hw_mode mode;
- if (wpa_s->hw.modes == NULL)
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Scan only GO preferred band %d GHz during invitation",
+ wpa_s->p2p_invite_go_freq);
+
+ if (!wpa_s->hw.modes)
return;
mode = wpa_s->p2p_invite_go_freq == 5 ?
- HOSTAPD_MODE_IEEE80211A :
- HOSTAPD_MODE_IEEE80211G;
+ HOSTAPD_MODE_IEEE80211A :
+ HOSTAPD_MODE_IEEE80211G;
if (wpa_s->p2p_in_invitation <= 2)
wpa_add_scan_freqs_list(wpa_s, mode,
params, false,
- true);
- if (params->freqs == NULL ||
- (params->freqs && params->freqs[0] == 0))
+ false, true);
+ if (!params->freqs || params->freqs[0] == 0)
wpa_add_scan_freqs_list(wpa_s, mode,
params, false,
- false);
+ false, false);
} else {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation",
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Scan only GO preferred frequency %d MHz during invitation",
wpa_s->p2p_invite_go_freq);
params->freqs = os_calloc(2, sizeof(int));
if (params->freqs)
@@ -757,7 +762,8 @@
int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
enum hostapd_hw_mode band,
- struct wpa_driver_scan_params *params, bool is_6ghz,
+ struct wpa_driver_scan_params *params,
+ bool is_6ghz, bool only_6ghz_psc,
bool exclude_radar)
{
/* Include only supported channels for the specified band */
@@ -766,7 +772,7 @@
int *freqs, i;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz);
- if (!mode)
+ if (!mode || !mode->num_channels)
return -1;
if (params->freqs) {
@@ -783,8 +789,14 @@
for (i = 0; i < mode->num_channels; i++) {
if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
continue;
- if (exclude_radar && (mode->channels[i].flag & HOSTAPD_CHAN_RADAR))
+ if (exclude_radar &&
+ (mode->channels[i].flag & HOSTAPD_CHAN_RADAR))
continue;
+
+ if (is_6ghz && only_6ghz_psc &&
+ !is_6ghz_psc_frequency(mode->channels[i].freq))
+ continue;
+
params->freqs[num_chans++] = mode->channels[i].freq;
}
params->freqs[num_chans] = 0;
@@ -803,13 +815,13 @@
if (wpa_s->setband_mask & WPA_SETBAND_5G)
wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
- false, false);
+ false, false, false);
if (wpa_s->setband_mask & WPA_SETBAND_2G)
wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params,
- false, false);
+ false, false, false);
if (wpa_s->setband_mask & WPA_SETBAND_6G)
wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params,
- true, false);
+ true, false, false);
}
@@ -1318,7 +1330,8 @@
params.freqs = os_calloc(num + 1, sizeof(int));
if (params.freqs) {
- num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+ num = get_shared_radio_freqs(wpa_s, params.freqs, num,
+ false);
if (num > 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the "
"current operating channels since "
@@ -1408,7 +1421,13 @@
params.freqs = os_calloc(num + 1, sizeof(int));
if (params.freqs) {
- num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+ /*
+ * Exclude the operating frequency of the current
+ * interface since we're looking to transition off of
+ * it.
+ */
+ num = get_shared_radio_freqs(wpa_s, params.freqs, num,
+ true);
if (num > 0 && num == wpa_s->num_multichan_concurrent) {
wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used");
} else {
@@ -1418,18 +1437,9 @@
}
}
- if (!params.freqs &&
- (wpa_s->p2p_in_invitation || wpa_s->p2p_in_provisioning) &&
- !is_p2p_allow_6ghz(wpa_s->global->p2p) &&
- is_6ghz_supported(wpa_s)) {
- /* Exclude 6 GHz channels from the full scan for P2P connection
- * since the 6 GHz band is disabled for P2P uses. */
- wpa_printf(MSG_DEBUG,
- "P2P: 6 GHz disabled - update the scan frequency list");
- wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, ¶ms, false, false);
- wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, ¶ms, false, false);
- wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211AD, ¶ms, false, false);
- }
+ if (!params.freqs && is_6ghz_supported(wpa_s) &&
+ (wpa_s->p2p_in_invitation || wpa_s->p2p_in_provisioning))
+ wpas_p2p_scan_freqs(wpa_s, ¶ms, true);
#endif /* CONFIG_P2P */
ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
@@ -2418,6 +2428,8 @@
{ -1, 780000 } /* SNR > 37 */
};
+/* EHT needs to be enabled in order to achieve MCS12 and MCS13 rates. */
+#define EHT_MCS 12
static const struct minsnr_bitrate_entry he20_table[] = {
{ 0, 0 },
@@ -2433,7 +2445,9 @@
{ 31, 114700 }, /* HE20 MCS9 */
{ 34, 129000 }, /* HE20 MCS10 */
{ 36, 143400 }, /* HE20 MCS11 */
- { -1, 143400 } /* SNR > 29 */
+ { 39, 154900 }, /* EHT20 MCS12 */
+ { 42, 172100 }, /* EHT20 MCS13 */
+ { -1, 172100 } /* SNR > 42 */
};
static const struct minsnr_bitrate_entry he40_table[] = {
@@ -2450,7 +2464,9 @@
{ 34, 229400 }, /* HE40 MCS9 */
{ 37, 258100 }, /* HE40 MCS10 */
{ 39, 286800 }, /* HE40 MCS11 */
- { -1, 286800 } /* SNR > 34 */
+ { 42, 309500 }, /* EHT40 MCS12 */
+ { 45, 344100 }, /* EHT40 MCS13 */
+ { -1, 344100 } /* SNR > 45 */
};
static const struct minsnr_bitrate_entry he80_table[] = {
@@ -2467,7 +2483,9 @@
{ 37, 480400 }, /* HE80 MCS9 */
{ 40, 540400 }, /* HE80 MCS10 */
{ 42, 600500 }, /* HE80 MCS11 */
- { -1, 600500 } /* SNR > 37 */
+ { 45, 648500 }, /* EHT80 MCS12 */
+ { 48, 720600 }, /* EHT80 MCS13 */
+ { -1, 720600 } /* SNR > 48 */
};
@@ -2485,9 +2503,31 @@
{ 40, 960800 }, /* HE160 MCS9 */
{ 43, 1080900 }, /* HE160 MCS10 */
{ 45, 1201000 }, /* HE160 MCS11 */
- { -1, 1201000 } /* SNR > 37 */
+ { 48, 1297100 }, /* EHT160 MCS12 */
+ { 51, 1441200 }, /* EHT160 MCS13 */
+ { -1, 1441200 } /* SNR > 51 */
};
+/* See IEEE P802.11be/D2.0, Table 36-86: EHT-MCSs for 4x996-tone RU, NSS,u = 1
+ */
+static const struct minsnr_bitrate_entry eht320_table[] = {
+ { 0, 0 },
+ { 14, 144100 }, /* EHT320 MCS0 */
+ { 17, 288200 }, /* EHT320 MCS1 */
+ { 21, 432400 }, /* EHT320 MCS2 */
+ { 23, 576500 }, /* EHT320 MCS3 */
+ { 27, 864700 }, /* EHT320 MCS4 */
+ { 30, 1152900 }, /* EHT320 MCS5 */
+ { 32, 1297100 }, /* EHT320 MCS6 */
+ { 37, 1441200 }, /* EHT320 MCS7 */
+ { 41, 1729400 }, /* EHT320 MCS8 */
+ { 43, 1921500 }, /* EHT320 MCS9 */
+ { 46, 2161800 }, /* EHT320 MCS10 */
+ { 48, 2401900 }, /* EHT320 MCS11 */
+ { 51, 2594100 }, /* EHT320 MCS12 */
+ { 54, 2882400 }, /* EHT320 MCS13 */
+ { -1, 2882400 } /* SNR > 54 */
+};
static unsigned int interpolate_rate(int snr, int snr0, int snr1,
int rate0, int rate1)
@@ -2539,17 +2579,18 @@
}
-static unsigned int max_he_rate(const struct minsnr_bitrate_entry table[],
- int snr)
+static unsigned int max_he_eht_rate(const struct minsnr_bitrate_entry table[],
+ int snr, bool eht)
{
const struct minsnr_bitrate_entry *prev, *entry = table;
- while (entry->minsnr != -1 && snr >= entry->minsnr)
+ while (entry->minsnr != -1 && snr >= entry->minsnr &&
+ (eht || entry - table <= EHT_MCS))
entry++;
if (entry == table)
return 0;
prev = entry - 1;
- if (entry->minsnr == -1)
+ if (entry->minsnr == -1 || (!eht && entry - table > EHT_MCS))
return prev->bitrate;
return interpolate_rate(snr, prev->minsnr, entry->minsnr,
prev->bitrate, entry->bitrate);
@@ -2687,8 +2728,11 @@
if (hw_mode && hw_mode->he_capab[IEEE80211_MODE_INFRA].he_supported) {
/* Use +2 to assume HE is always faster than HT/VHT */
struct ieee80211_he_capabilities *he;
+ struct ieee80211_eht_capabilities *eht;
struct he_capabilities *own_he;
- u8 cw;
+ u8 cw, boost = 2;
+ const u8 *eht_ie;
+ bool is_eht = false;
ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_HE_CAPABILITIES);
if (!ie || (ie[1] < 1 + IEEE80211_HE_CAPAB_MIN_LEN))
@@ -2696,7 +2740,18 @@
he = (struct ieee80211_he_capabilities *) &ie[3];
own_he = &hw_mode->he_capab[IEEE80211_MODE_INFRA];
- tmp = max_he_rate(he20_table, snr) + 2;
+ /* Use +3 to assume EHT is always faster than HE */
+ if (hw_mode->eht_capab[IEEE80211_MODE_INFRA].eht_supported) {
+ eht_ie = get_ie_ext(ies, ies_len,
+ WLAN_EID_EXT_EHT_CAPABILITIES);
+ if (eht_ie &&
+ (eht_ie[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN)) {
+ is_eht = true;
+ boost = 3;
+ }
+ }
+
+ tmp = max_he_eht_rate(he20_table, snr, is_eht) + boost;
if (tmp > est)
est = tmp;
@@ -2705,14 +2760,14 @@
if (cw &
(IS_2P4GHZ(freq) ? HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G :
HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
- tmp = max_he_rate(he40_table, snr) + 2;
+ tmp = max_he_eht_rate(he40_table, snr, is_eht) + boost;
if (tmp > est)
est = tmp;
}
if (!IS_2P4GHZ(freq) &&
(cw & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) {
- tmp = max_he_rate(he80_table, snr) + 2;
+ tmp = max_he_eht_rate(he80_table, snr, is_eht) + boost;
if (tmp > est)
est = tmp;
}
@@ -2720,7 +2775,20 @@
if (!IS_2P4GHZ(freq) &&
(cw & (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))) {
- tmp = max_he_rate(he160_table, snr) + 2;
+ tmp = max_he_eht_rate(he160_table, snr, is_eht) + boost;
+ if (tmp > est)
+ est = tmp;
+ }
+
+ if (!is_eht)
+ return est;
+
+ eht = (struct ieee80211_eht_capabilities *) &eht_ie[3];
+
+ if (is_6ghz_freq(freq) &&
+ (eht->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) {
+ tmp = max_he_eht_rate(eht320_table, snr, true);
if (tmp > est)
est = tmp;
}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 52d2696..30f4395 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -92,7 +92,7 @@
int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s,
enum hostapd_hw_mode band,
struct wpa_driver_scan_params *params,
- bool is_6ghz,
+ bool is_6ghz, bool only_6ghz_psc,
bool exclude_radar);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index a847e2f..406e357 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "utils/eloop.h"
+#include "utils/ext_password.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/ocv.h"
@@ -53,7 +54,7 @@
}
-static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
+static int sme_set_sae_group(struct wpa_supplicant *wpa_s, bool external)
{
int *groups = wpa_s->conf->sae_groups;
int default_groups[] = { 19, 20, 21, 0 };
@@ -72,7 +73,8 @@
if (sae_set_group(&wpa_s->sme.sae, group) == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
wpa_s->sme.sae.group);
- wpa_s->sme.sae.akmp = wpa_s->key_mgmt;
+ wpa_s->sme.sae.akmp = external ?
+ wpa_s->sme.ext_auth_key_mgmt : wpa_s->key_mgmt;
return 0;
}
wpa_s->sme.sae_group_index++;
@@ -84,17 +86,22 @@
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- const u8 *bssid, int external,
+ const u8 *bssid,
+ const u8 *mld_addr,
+ int external,
int reuse, int *ret_use_pt,
bool *ret_use_pk)
{
struct wpabuf *buf;
size_t len;
- const char *password;
+ char *password = NULL;
struct wpa_bss *bss;
int use_pt = 0;
bool use_pk = false;
u8 rsnxe_capa = 0;
+ int key_mgmt = external ? wpa_s->sme.ext_auth_key_mgmt :
+ wpa_s->key_mgmt;
+ const u8 *addr = mld_addr ? mld_addr : bssid;
if (ret_use_pt)
*ret_use_pt = 0;
@@ -106,7 +113,7 @@
wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override");
buf = wpabuf_alloc(4 + wpabuf_len(wpa_s->sae_commit_override));
if (!buf)
- return NULL;
+ goto fail;
if (!external) {
wpabuf_put_le16(buf, 1); /* Transaction seq# */
wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
@@ -116,25 +123,58 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
- password = ssid->sae_password;
- if (!password)
- password = ssid->passphrase;
+ if (ssid->sae_password) {
+ password = os_strdup(ssid->sae_password);
+ if (!password) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "SAE: Failed to allocate password");
+ goto fail;
+ }
+ }
+ if (!password && ssid->passphrase) {
+ password = os_strdup(ssid->passphrase);
+ if (!password) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "SAE: Failed to allocate password");
+ goto fail;
+ }
+ }
+ if (!password && ssid->ext_psk) {
+ struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
+ ssid->ext_psk);
+
+ if (!pw) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "SAE: No password found from external storage");
+ goto fail;
+ }
+
+ password = os_malloc(wpabuf_len(pw) + 1);
+ if (!password) {
+ wpa_dbg(wpa_s, MSG_INFO,
+ "SAE: Failed to allocate password");
+ goto fail;
+ }
+ os_memcpy(password, wpabuf_head(pw), wpabuf_len(pw));
+ password[wpabuf_len(pw)] = '\0';
+ ext_password_free(pw);
+ }
if (!password) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
- return NULL;
+ goto fail;
}
if (reuse && wpa_s->sme.sae.tmp &&
- os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
+ os_memcmp(addr, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"SAE: Reuse previously generated PWE on a retry with the same AP");
use_pt = wpa_s->sme.sae.h2e;
use_pk = wpa_s->sme.sae.pk;
goto reuse_data;
}
- if (sme_set_sae_group(wpa_s) < 0) {
+ if (sme_set_sae_group(wpa_s, external) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to select group");
- return NULL;
+ goto fail;
}
bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
@@ -152,10 +192,11 @@
rsnxe_capa = rsnxe[2];
}
- if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3)
+ if (ssid->sae_password_id &&
+ wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
use_pt = 1;
- if (wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt) &&
- wpa_s->conf->sae_pwe != 3)
+ if (wpa_key_mgmt_sae_ext_key(key_mgmt) &&
+ wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
use_pt = 1;
#ifdef CONFIG_SAE_PK
if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
@@ -171,43 +212,45 @@
if (ssid->sae_pk == SAE_PK_MODE_ONLY && !use_pk) {
wpa_printf(MSG_DEBUG,
"SAE: Cannot use PK with the selected AP");
- return NULL;
+ goto fail;
}
#endif /* CONFIG_SAE_PK */
- if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
+ if (use_pt || wpa_s->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
+ wpa_s->conf->sae_pwe == SAE_PWE_BOTH) {
use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E));
- if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id ||
- wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) &&
- wpa_s->conf->sae_pwe != 3 &&
+ if ((wpa_s->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
+ ssid->sae_password_id ||
+ wpa_key_mgmt_sae_ext_key(key_mgmt)) &&
+ wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
!use_pt) {
wpa_printf(MSG_DEBUG,
"SAE: Cannot use H2E with the selected AP");
- return NULL;
+ goto fail;
}
}
if (use_pt &&
sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
- wpa_s->own_addr, bssid,
+ wpa_s->own_addr, addr,
wpa_s->sme.sae_rejected_groups, NULL) < 0)
- return NULL;
+ goto fail;
if (!use_pt &&
sae_prepare_commit(wpa_s->own_addr, bssid,
(u8 *) password, os_strlen(password),
&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE");
- return NULL;
+ goto fail;
}
if (wpa_s->sme.sae.tmp) {
- os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN);
+ os_memcpy(wpa_s->sme.sae.tmp->bssid, addr, ETH_ALEN);
if (use_pt && use_pk)
wpa_s->sme.sae.pk = 1;
#ifdef CONFIG_SAE_PK
os_memcpy(wpa_s->sme.sae.tmp->own_addr, wpa_s->own_addr,
ETH_ALEN);
- os_memcpy(wpa_s->sme.sae.tmp->peer_addr, bssid, ETH_ALEN);
+ os_memcpy(wpa_s->sme.sae.tmp->peer_addr, addr, ETH_ALEN);
sae_pk_set_password(&wpa_s->sme.sae, password);
#endif /* CONFIG_SAE_PK */
}
@@ -218,7 +261,7 @@
len += 4 + os_strlen(ssid->sae_password_id);
buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
if (buf == NULL)
- return NULL;
+ goto fail;
if (!external) {
wpabuf_put_le16(buf, 1); /* Transaction seq# */
if (use_pk)
@@ -231,14 +274,19 @@
if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
ssid->sae_password_id) < 0) {
wpabuf_free(buf);
- return NULL;
+ goto fail;
}
if (ret_use_pt)
*ret_use_pt = use_pt;
if (ret_use_pk)
*ret_use_pk = use_pk;
+ str_clear_free(password);
return buf;
+
+fail:
+ str_clear_free(password);
+ return NULL;
}
@@ -325,6 +373,188 @@
}
+static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ struct wpabuf *mlbuf;
+ const u8 *rnr_ie, *pos;
+ u8 ml_ie_len, rnr_ie_len;
+ const struct ieee80211_eht_ml *eht_ml;
+ const struct eht_ml_basic_common_info *ml_basic_common_info;
+ u8 i;
+ const u16 control =
+ host_to_le16(MULTI_LINK_CONTROL_TYPE_BASIC |
+ BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
+ BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
+ BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA);
+ bool ret = false;
+
+ if (!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO))
+ return false;
+
+ mlbuf = wpa_bss_defrag_mle(bss, MULTI_LINK_CONTROL_TYPE_BASIC);
+ if (!mlbuf) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No ML element");
+ return false;
+ }
+
+ ml_ie_len = wpabuf_len(mlbuf);
+
+ /* control + common info len + MLD address + MLD link information */
+ if (ml_ie_len < 2 + 1 + ETH_ALEN + 1)
+ goto out;
+
+ eht_ml = wpabuf_head(mlbuf);
+ if ((eht_ml->ml_control & control) != control) {
+ wpa_printf(MSG_DEBUG, "MLD: Unexpected ML element control=0x%x",
+ eht_ml->ml_control);
+ goto out;
+ }
+
+ ml_basic_common_info =
+ (const struct eht_ml_basic_common_info *) eht_ml->variable;
+
+ /* common info length should be valid (self, mld_addr, link_id) */
+ if (ml_basic_common_info->len < 1 + ETH_ALEN + 1)
+ goto out;
+
+ /* get the MLD address and MLD link ID */
+ os_memcpy(wpa_s->ap_mld_addr, ml_basic_common_info->mld_addr,
+ ETH_ALEN);
+ wpa_s->mlo_assoc_link_id = ml_basic_common_info->variable[0] &
+ EHT_ML_LINK_ID_MSK;
+
+ os_memcpy(wpa_s->links[wpa_s->mlo_assoc_link_id].bssid, bss->bssid,
+ ETH_ALEN);
+ wpa_s->links[wpa_s->mlo_assoc_link_id].freq = bss->freq;
+
+ wpa_printf(MSG_DEBUG, "MLD: address=" MACSTR ", link ID=%u",
+ MAC2STR(wpa_s->ap_mld_addr), wpa_s->mlo_assoc_link_id);
+
+ wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id);
+
+ rnr_ie = wpa_bss_get_ie(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT);
+ if (!rnr_ie) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RNR element");
+ ret = true;
+ goto out;
+ }
+
+ rnr_ie_len = rnr_ie[1];
+ pos = rnr_ie + 2;
+
+ while (rnr_ie_len > sizeof(struct ieee80211_neighbor_ap_info)) {
+ const struct ieee80211_neighbor_ap_info *ap_info =
+ (const struct ieee80211_neighbor_ap_info *) pos;
+ const u8 *data = ap_info->data;
+ size_t len = sizeof(struct ieee80211_neighbor_ap_info) +
+ ap_info->tbtt_info_len;
+
+ wpa_printf(MSG_DEBUG, "MLD: op_class=%u, channel=%u",
+ ap_info->op_class, ap_info->channel);
+
+ if (len > rnr_ie_len)
+ break;
+
+ if (ap_info->tbtt_info_len < 16) {
+ rnr_ie_len -= len;
+ pos += len;
+ continue;
+ }
+
+ data += 13;
+
+ wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u",
+ *data, *(data + 1) & 0xF);
+
+ if (*data) {
+ wpa_printf(MSG_DEBUG,
+ "MLD: Reported link not part of MLD");
+ } else {
+ struct wpa_bss *neigh_bss =
+ wpa_bss_get_bssid(wpa_s, ap_info->data + 1);
+ u8 link_id = *(data + 1) & 0xF;
+
+ if (neigh_bss) {
+ if (wpa_scan_res_match(wpa_s, 0, neigh_bss,
+ wpa_s->current_ssid,
+ 1, 0)) {
+ wpa_s->valid_links |= BIT(link_id);
+ os_memcpy(wpa_s->links[link_id].bssid,
+ ap_info->data + 1, ETH_ALEN);
+ wpa_s->links[link_id].freq =
+ neigh_bss->freq;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLD: Neighbor doesn't match current SSID - skip link");
+ }
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLD: Neighbor not found in scan");
+ }
+ }
+
+ rnr_ie_len -= len;
+ pos += len;
+ }
+
+ wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%x", wpa_s->valid_links);
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(wpa_s->valid_links & BIT(i)))
+ continue;
+
+ wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR,
+ i, MAC2STR(wpa_s->links[i].bssid));
+ }
+
+ ret = true;
+out:
+ wpabuf_free(mlbuf);
+ return ret;
+}
+
+
+static void wpas_sme_ml_auth(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data,
+ int ie_offset)
+{
+ struct ieee802_11_elems elems;
+ const u8 *mld_addr;
+
+ if (!wpa_s->valid_links)
+ return;
+
+ if (ieee802_11_parse_elems(data->auth.ies + ie_offset,
+ data->auth.ies_len - ie_offset,
+ &elems, 0) != ParseOK) {
+ wpa_printf(MSG_DEBUG, "MLD: Failed parsing elements");
+ goto out;
+ }
+
+ if (!elems.basic_mle || !elems.basic_mle_len) {
+ wpa_printf(MSG_DEBUG, "MLD: No ML element in authentication");
+ goto out;
+ }
+
+ mld_addr = get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len);
+ if (!mld_addr)
+ goto out;
+
+ wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR, MAC2STR(mld_addr));
+
+ if (os_memcmp(wpa_s->ap_mld_addr, mld_addr, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected "
+ MACSTR ")", MAC2STR(wpa_s->ap_mld_addr));
+ goto out;
+ }
+
+ return;
+out:
+ wpa_printf(MSG_DEBUG, "MLD: Authentication - clearing MLD state");
+ wpas_reset_mlo_info(wpa_s);
+}
+
+
static void sme_send_authentication(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
int start)
@@ -369,6 +599,13 @@
params.ssid_len = bss->ssid_len;
params.p2p = ssid->p2p_group;
+ if (wpas_ml_element(wpa_s, bss)) {
+ wpa_printf(MSG_DEBUG, "MLD: In authentication");
+ params.mld = true;
+ params.mld_link_id = wpa_s->mlo_assoc_link_id;
+ params.ap_mld_addr = wpa_s->ap_mld_addr;
+ }
+
if (wpa_s->sme.ssid_len != params.ssid_len ||
os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0)
wpa_s->sme.prev_bssid_set = 0;
@@ -413,8 +650,13 @@
#endif /* CONFIG_DPP */
} else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
wpa_key_mgmt_sae(ied.key_mgmt)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
- params.auth_alg = WPA_AUTH_ALG_SAE;
+ if (wpas_is_sae_avoided(wpa_s, ssid, &ied)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "SAE enabled, but disallowing SAE auth_alg without PMF");
+ } else {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
+ params.auth_alg = WPA_AUTH_ALG_SAE;
+ }
} else {
wpa_dbg(wpa_s, MSG_DEBUG,
"SAE enabled, but target BSS does not advertise SAE AKM for RSN");
@@ -449,7 +691,9 @@
if (wpa_key_mgmt_fils(ssid->key_mgmt))
cache_id = wpa_bss_get_fils_cache_id(bss);
#endif /* CONFIG_FILS */
- if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+ if (pmksa_cache_set_current(wpa_s->wpa, NULL,
+ params.mld ? params.ap_mld_addr :
+ bss->bssid,
wpa_s->current_ssid,
try_opportunistic, cache_id,
0) == 0)
@@ -457,7 +701,8 @@
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
wpa_s->sme.assoc_req_ie,
- &wpa_s->sme.assoc_req_ie_len)) {
+ &wpa_s->sme.assoc_req_ie_len,
+ false)) {
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
"key management and encryption suites");
wpas_connect_work_done(wpa_s);
@@ -470,7 +715,8 @@
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
wpa_s->sme.assoc_req_ie,
- &wpa_s->sme.assoc_req_ie_len)) {
+ &wpa_s->sme.assoc_req_ie_len,
+ false)) {
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
"key management and encryption suites");
wpas_connect_work_done(wpa_s);
@@ -490,7 +736,8 @@
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
wpa_s->sme.assoc_req_ie,
- &wpa_s->sme.assoc_req_ie_len)) {
+ &wpa_s->sme.assoc_req_ie_len,
+ false)) {
wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA "
"key management and encryption suites (no "
"scan results)");
@@ -572,7 +819,7 @@
if (wpa_s->sme.prev_bssid_set && wpa_s->sme.ft_used &&
os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 &&
- wpa_sm_has_ptk(wpa_s->wpa)) {
+ wpa_sm_has_ft_keys(wpa_s->wpa, md)) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
"over-the-air");
params.auth_alg = WPA_AUTH_ALG_FT;
@@ -752,7 +999,10 @@
#ifdef CONFIG_SAE
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE &&
- pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0,
+ pmksa_cache_set_current(wpa_s->wpa, NULL,
+ params.mld ? params.ap_mld_addr :
+ bss->bssid,
+ ssid, 0,
NULL,
wpa_key_mgmt_sae(wpa_s->key_mgmt) ?
wpa_s->key_mgmt :
@@ -767,7 +1017,10 @@
if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE) {
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
- bss->bssid, 0,
+ bss->bssid,
+ params.mld ?
+ params.ap_mld_addr :
+ NULL, 0,
start == 2, NULL,
NULL);
else
@@ -846,7 +1099,9 @@
goto no_fils;
}
- if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+ if (pmksa_cache_set_current(wpa_s->wpa, NULL,
+ params.mld ? params.ap_mld_addr :
+ bss->bssid,
ssid, 0,
wpa_bss_get_fils_cache_id(bss),
0) == 0)
@@ -899,7 +1154,7 @@
*/
if (wpa_s->num_multichan_concurrent < 2) {
int freq, num;
- num = get_shared_radio_freqs(wpa_s, &freq, 1);
+ num = get_shared_radio_freqs(wpa_s, &freq, 1, false);
if (num > 0 && freq > 0 && freq != params.freq) {
wpa_printf(MSG_DEBUG,
"Conflicting frequency found (%d != %d)",
@@ -984,6 +1239,7 @@
wpa_s->rsnxe_len = 0;
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
+ wpas_notify_auth_changed(wpa_s);
}
@@ -1081,8 +1337,8 @@
bool use_pk;
u16 status;
- resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt,
- &use_pk);
+ resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, NULL,
+ 1, 0, &use_pt, &use_pk);
if (!resp) {
wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit");
return -1;
@@ -1186,11 +1442,41 @@
}
+static bool is_sae_key_mgmt_suite(struct wpa_supplicant *wpa_s, u32 suite)
+{
+ /* suite is supposed to be the selector value in host byte order with
+ * the OUI in three most significant octets. However, the initial
+ * implementation swapped that byte order and did not work with drivers
+ * that followed the expected byte order. Keep a workaround here to
+ * match that initial implementation so that already deployed use cases
+ * remain functional. */
+ if (RSN_SELECTOR_GET(&suite) == RSN_AUTH_KEY_MGMT_SAE) {
+ /* Old drivers which follow initial implementation send SAE AKM
+ * for both SAE and FT-SAE connections. In that case, determine
+ * the actual AKM from wpa_s->key_mgmt. */
+ wpa_s->sme.ext_auth_key_mgmt = wpa_s->key_mgmt;
+ return true;
+ }
+
+ if (suite == RSN_AUTH_KEY_MGMT_SAE)
+ wpa_s->sme.ext_auth_key_mgmt = WPA_KEY_MGMT_SAE;
+ else if (suite == RSN_AUTH_KEY_MGMT_FT_SAE)
+ wpa_s->sme.ext_auth_key_mgmt = WPA_KEY_MGMT_FT_SAE;
+ else if (suite == RSN_AUTH_KEY_MGMT_SAE_EXT_KEY)
+ wpa_s->sme.ext_auth_key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
+ else if (suite == RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY)
+ wpa_s->sme.ext_auth_key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
+ else
+ return false;
+
+ return true;
+}
+
+
void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- if (RSN_SELECTOR_GET(&data->external_auth.key_mgmt_suite) !=
- RSN_AUTH_KEY_MGMT_SAE)
+ if (!is_sae_key_mgmt_suite(wpa_s, data->external_auth.key_mgmt_suite))
return;
if (data->external_auth.action == EXT_AUTH_START) {
@@ -1264,7 +1550,7 @@
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
u16 status_code, const u8 *data, size_t len,
- int external, const u8 *sa)
+ int external, const u8 *sa, int *ie_offset)
{
int *groups;
@@ -1328,7 +1614,17 @@
}
token_len = elen - 1;
}
+
+ if (ie_offset)
+ *ie_offset = token_pos + token_len - data;
+
wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len);
+ if (!wpa_s->sme.sae_token) {
+ wpa_dbg(wpa_s, MSG_ERROR,
+ "SME: Failed to allocate SAE token");
+ return -1;
+ }
+
wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token",
wpa_s->sme.sae_token);
if (!external)
@@ -1350,7 +1646,7 @@
int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
wpa_s->sme.sae.group);
wpa_s->sme.sae_group_index++;
- if (sme_set_sae_group(wpa_s) < 0)
+ if (sme_set_sae_group(wpa_s, external) < 0)
return -1; /* no other groups enabled */
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
if (!external)
@@ -1423,7 +1719,8 @@
res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
groups, status_code ==
WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
- status_code == WLAN_STATUS_SAE_PK);
+ status_code == WLAN_STATUS_SAE_PK,
+ ie_offset);
if (res == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message due to reflection attack");
@@ -1458,7 +1755,8 @@
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
if (wpa_s->sme.sae.state != SAE_CONFIRMED)
return -1;
- if (sae_check_confirm(&wpa_s->sme.sae, data, len) < 0)
+ if (sae_check_confirm(&wpa_s->sme.sae, data, len,
+ ie_offset) < 0)
return -1;
wpa_s->sme.sae.state = SAE_ACCEPTED;
sae_clear_temp_data(&wpa_s->sme.sae);
@@ -1530,7 +1828,7 @@
wpa_s, le_to_host16(header->u.auth.auth_transaction),
le_to_host16(header->u.auth.status_code),
header->u.auth.variable,
- len - auth_length, 1, header->sa);
+ len - auth_length, 1, header->sa, NULL);
if (res < 0) {
/* Notify failure to the driver */
sme_send_external_auth_status(
@@ -1554,6 +1852,7 @@
void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int ie_offset = 0;
if (ssid == NULL) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event "
@@ -1567,7 +1866,9 @@
return;
}
- if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0) {
+ if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0 &&
+ !(wpa_s->valid_links &&
+ os_memcmp(wpa_s->ap_mld_addr, data->auth.peer, ETH_ALEN) == 0)) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication with "
"unexpected peer " MACSTR,
MAC2STR(data->auth.peer));
@@ -1585,10 +1886,13 @@
#ifdef CONFIG_SAE
if (data->auth.auth_type == WLAN_AUTH_SAE) {
+ const u8 *addr = wpa_s->pending_bssid;
int res;
+
res = sme_sae_auth(wpa_s, data->auth.auth_transaction,
data->auth.status_code, data->auth.ies,
- data->auth.ies_len, 0, data->auth.peer);
+ data->auth.ies_len, 0, data->auth.peer,
+ &ie_offset);
if (res < 0) {
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
@@ -1597,7 +1901,10 @@
if (res != 1)
return;
- if (sme_sae_set_pmk(wpa_s, wpa_s->pending_bssid) < 0)
+ if (wpa_s->valid_links)
+ addr = wpa_s->ap_mld_addr;
+
+ if (sme_sae_set_pmk(wpa_s, addr) < 0)
return;
}
#endif /* CONFIG_SAE */
@@ -1725,6 +2032,11 @@
}
#endif /* CONFIG_FILS */
+ /* TODO: Support additional auth_type values as well */
+ if (data->auth.auth_type == WLAN_AUTH_OPEN ||
+ data->auth.auth_type == WLAN_AUTH_SAE)
+ wpas_sme_ml_auth(wpa_s, data, ie_offset);
+
sme_associate(wpa_s, ssid->mode, data->auth.peer,
data->auth.auth_type);
}
@@ -2014,6 +2326,7 @@
#ifdef CONFIG_HE_OVERRIDES
wpa_supplicant_apply_he_overrides(wpa_s, ssid, ¶ms);
#endif /* CONFIG_HE_OVERRIDES */
+ wpa_supplicant_apply_eht_overrides(wpa_s, ssid, ¶ms);
#ifdef CONFIG_IEEE80211R
if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies &&
get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len,
@@ -2142,6 +2455,31 @@
else
params.uapsd = -1;
+ if (wpa_s->valid_links) {
+ unsigned int i;
+
+ wpa_printf(MSG_DEBUG,
+ "MLD: In association. assoc_link_id=%u, valid_links=0x%x",
+ wpa_s->mlo_assoc_link_id, wpa_s->valid_links);
+
+ params.mld_params.mld_addr = wpa_s->ap_mld_addr;
+ params.mld_params.valid_links = wpa_s->valid_links;
+ params.mld_params.assoc_link_id = wpa_s->mlo_assoc_link_id;
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(wpa_s->valid_links & BIT(i)))
+ continue;
+
+ params.mld_params.mld_links[i].bssid =
+ wpa_s->links[i].bssid;
+ params.mld_params.mld_links[i].freq =
+ wpa_s->links[i].freq;
+
+ wpa_printf(MSG_DEBUG, "MLD: id=%u, freq=%d, " MACSTR,
+ i, wpa_s->links[i].freq,
+ MAC2STR(wpa_s->links[i].bssid));
+ }
+ }
+
if (wpa_drv_associate(wpa_s, ¶ms) < 0) {
wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the "
"driver failed");
@@ -2239,6 +2577,34 @@
}
#endif /* CONFIG_SAE */
+#ifdef CONFIG_DPP
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP &&
+ !data->assoc_reject.timed_out &&
+ data->assoc_reject.status_code == WLAN_STATUS_INVALID_PMKID) {
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = pmksa_cache_get_current(wpa_s->wpa);
+ if (pmksa) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "DPP: Drop PMKSA cache entry for the BSS due to invalid PMKID report");
+ wpa_sm_pmksa_cache_remove(wpa_s->wpa, pmksa);
+ }
+ wpa_sm_aborted_cached(wpa_s->wpa);
+ if (wpa_s->current_bss) {
+ struct wpa_bss *bss = wpa_s->current_bss;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "DPP: Try network introduction again");
+ wpas_connect_work_done(wpa_s);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ wpa_supplicant_connect(wpa_s, bss, ssid);
+ return;
+ }
+ }
+#endif /* CONFIG_DPP */
+
/*
* For now, unconditionally terminate the previous authentication. In
* theory, this should not be needed, but mac80211 gets quite confused
diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
index da69a87..4eab335 100644
--- a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
@@ -1,5 +1,5 @@
[Unit]
-Description=WPA supplicant daemon (interface- and nl80211 driver-specific version)
+Description=WPA supplicant daemon (for interface %I using nl80211)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
Before=network.target
diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
index 55d2b9c..b0d610f 100644
--- a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
+++ b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
@@ -1,5 +1,5 @@
[Unit]
-Description=WPA supplicant daemon (interface-specific version)
+Description=WPA supplicant daemon (for interface %I)
Requires=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
Before=network.target
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 5393f1c..72a119d 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -524,6 +524,11 @@
rep->mul_bssid->subelem_len = elen - 1;
os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1);
break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "WNM: Unsupported neighbor report subelement id %u",
+ id);
+ break;
}
}
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 197efe0..bfdc42d 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -503,7 +503,7 @@
"autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey",
"wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend",
"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
- "sae_groups", "dtim_period", "beacon_int",
+ "sae_check_mfp", "sae_groups", "dtim_period", "beacon_int",
"ap_vendor_elements", "ignore_old_scan_res", "freq_list",
"scan_cur_freq", "scan_res_valid_for_connect",
"sched_scan_interval",
@@ -602,6 +602,7 @@
"go_venue_group", "go_venue_type",
"wps_nfc_dev_pw_id", "ext_password_backend",
"p2p_go_max_inactivity", "auto_interworking", "okc", "pmf",
+ "sae_check_mfp",
"dtim_period", "beacon_int", "ignore_old_scan_res",
"scan_cur_freq", "scan_res_valid_for_connect",
"sched_scan_interval",
@@ -1479,6 +1480,7 @@
#ifdef CONFIG_HE_OVERRIDES
"disable_he",
#endif /* CONFIG_HE_OVERRIDES */
+ "disable_eht",
"ap_max_inactivity", "dtim_period", "beacon_int",
#ifdef CONFIG_MACSEC
"macsec_policy",
@@ -3260,19 +3262,18 @@
#ifdef CONFIG_PASN
-static int wpa_cli_cmd_pasn_auth_start(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int wpa_cli_cmd_pasn_start(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- return wpa_cli_cmd(ctrl, "PASN_AUTH_START", 4, argc, argv);
+ return wpa_cli_cmd(ctrl, "PASN_START", 4, argc, argv);
}
-static int wpa_cli_cmd_pasn_auth_stop(struct wpa_ctrl *ctrl, int argc,
- char *argv[])
+static int wpa_cli_cmd_pasn_stop(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- return wpa_cli_cmd(ctrl, "PASN_AUTH_STOP", 0, argc, argv);
+ return wpa_cli_cmd(ctrl, "PASN_STOP", 0, argc, argv);
}
+
static int wpa_cli_cmd_ptksa_cache_list(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -4024,10 +4025,10 @@
{ "all_bss", wpa_cli_cmd_all_bss, NULL, cli_cmd_flag_none,
"= list all BSS entries (scan results)" },
#ifdef CONFIG_PASN
- { "pasn_auth_start", wpa_cli_cmd_pasn_auth_start, NULL,
+ { "pasn_start", wpa_cli_cmd_pasn_start, NULL,
cli_cmd_flag_none,
"bssid=<BSSID> akmp=<WPA key mgmt> cipher=<WPA cipher> group=<group> nid=<network id> = Start PASN authentication" },
- { "pasn_auth_stop", wpa_cli_cmd_pasn_auth_stop, NULL,
+ { "pasn_stop", wpa_cli_cmd_pasn_stop, NULL,
cli_cmd_flag_none,
"= Stop PASN authentication" },
{ "ptksa_cache_list", wpa_cli_cmd_ptksa_cache_list, NULL,
diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index d9c07e6..cfab4f1 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -7,6 +7,7 @@
*/
#include "includes.h"
+#include <termios.h>
#include "common.h"
#include "crypto/sha1.h"
@@ -14,6 +15,7 @@
int main(int argc, char *argv[])
{
+ struct termios term;
unsigned char psk[32];
int i;
char *ssid, *passphrase, buf[64], *pos;
@@ -31,11 +33,28 @@
if (argc > 2) {
passphrase = argv[2];
} else {
+ bool ctrl_echo;
+
fprintf(stderr, "# reading passphrase from stdin\n");
+ if (tcgetattr(STDIN_FILENO, &term) < 0) {
+ perror("tcgetattr");
+ return 1;
+ }
+ ctrl_echo = term.c_lflag & ECHO;
+ term.c_lflag &= ~ECHO;
+ if (ctrl_echo && tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0) {
+ perror("tcsetattr:error disabling echo");
+ return 1;
+ }
if (fgets(buf, sizeof(buf), stdin) == NULL) {
fprintf(stderr, "Failed to read passphrase\n");
return 1;
}
+ term.c_lflag |= ECHO;
+ if (ctrl_echo && tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0) {
+ perror("tcsetattr:error enabling echo");
+ return 1;
+ }
buf[sizeof(buf) - 1] = '\0';
pos = buf;
while (*pos != '\0') {
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index ff1fb67..31a9af6 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -414,6 +414,7 @@
p.key = params->key_len ? params->key : NULL;
p.key_len = params->key_len;
p.key_flag = params->key_flag;
+ p.link_id = -1;
res = iface->driver->set_key(iface->drv_priv, &p);
wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 7d896f4..521ff90 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -143,7 +143,7 @@
continue;
set = 1;
- wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_WEP, NULL,
i, i == ssid->wep_tx_keyidx, NULL, 0,
ssid->wep_key[i], ssid->wep_key_len[i],
i == ssid->wep_tx_keyidx ?
@@ -207,7 +207,7 @@
/* TODO: should actually remember the previously used seq#, both for TX
* and RX from each STA.. */
- ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen,
+ ret = wpa_drv_set_key(wpa_s, -1, alg, NULL, 0, 1, seq, 6, key, keylen,
KEY_FLAG_GROUP_RX_TX_DEFAULT);
os_memset(key, 0, sizeof(key));
return ret;
@@ -404,6 +404,7 @@
#ifdef CONFIG_WEP
int i;
#endif /* CONFIG_WEP */
+ struct wpa_sm_mlo mlo;
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
@@ -444,6 +445,8 @@
wpa_s->mgmt_group_cipher);
pmksa_cache_clear_current(wpa_s->wpa);
+ os_memset(&mlo, 0, sizeof(mlo));
+ wpa_sm_set_mlo_params(wpa_s->wpa, &mlo);
}
@@ -766,18 +769,18 @@
for (i = 0; i < max; i++) {
if (wpa_s->keys_cleared & BIT(i))
continue;
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
NULL, 0, KEY_FLAG_GROUP);
}
/* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */
if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr &&
!is_zero_ether_addr(addr)) {
if (!(wpa_s->keys_cleared & BIT(0)))
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL,
- 0, NULL, 0, KEY_FLAG_PAIRWISE);
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 0, 0,
+ NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
if (!(wpa_s->keys_cleared & BIT(15)))
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, 0, NULL,
- 0, NULL, 0, KEY_FLAG_PAIRWISE);
+ wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 1, 0,
+ NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
/* MLME-SETPROTECTION.request(None) */
wpa_drv_mlme_setprotection(
wpa_s, addr,
@@ -1158,14 +1161,14 @@
if (wpa_s->confname == NULL)
return -1;
- conf = wpa_config_read(wpa_s->confname, NULL);
+ conf = wpa_config_read(wpa_s->confname, NULL, false);
if (conf == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
"file '%s' - exiting", wpa_s->confname);
return -1;
}
if (wpa_s->confanother &&
- !wpa_config_read(wpa_s->confanother, conf)) {
+ !wpa_config_read(wpa_s->confanother, conf, true)) {
wpa_msg(wpa_s, MSG_ERROR,
"Failed to parse the configuration file '%s' - exiting",
wpa_s->confanother);
@@ -1350,6 +1353,108 @@
wpas_get_ssid_pmf(wpa_s, ssid));
}
+/**
+ * wpa_supplicant_get_psk - Get PSK from config or external database
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Scan results for the selected BSS, or %NULL if not available
+ * @ssid: Configuration data for the selected network
+ * @psk: Buffer for the PSK
+ * Returns: 0 on success or -1 if configuration parsing failed
+ *
+ * This function obtains the PSK for a network, either included inline in the
+ * config or retrieved from an external database.
+ */
+static int wpa_supplicant_get_psk(struct wpa_supplicant *wpa_s,
+ struct wpa_bss *bss, struct wpa_ssid *ssid,
+ u8 *psk)
+{
+ if (ssid->psk_set) {
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
+ ssid->psk, PMK_LEN);
+ os_memcpy(psk, ssid->psk, PMK_LEN);
+ return 0;
+ }
+
+#ifndef CONFIG_NO_PBKDF2
+ if (bss && ssid->bssid_set && ssid->ssid_len == 0 && ssid->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);
+ return 0;
+ }
+#endif /* CONFIG_NO_PBKDF2 */
+
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->ext_psk) {
+ struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
+ ssid->ext_psk);
+ char pw_str[64 + 1];
+
+ if (!pw) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "EXT PW: No PSK found from external storage");
+ return -1;
+ }
+
+ if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "EXT PW: Unexpected PSK length %d in external storage",
+ (int) wpabuf_len(pw));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
+ pw_str[wpabuf_len(pw)] = '\0';
+
+#ifndef CONFIG_NO_PBKDF2
+ if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
+ {
+ 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()");
+ forced_memzero(pw_str, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "PSK (from external passphrase)",
+ psk, PMK_LEN);
+ } else
+#endif /* CONFIG_NO_PBKDF2 */
+ if (wpabuf_len(pw) == 2 * PMK_LEN) {
+ if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "EXT PW: Invalid PSK hex string");
+ forced_memzero(pw_str, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from external PSK)",
+ psk, PMK_LEN);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO,
+ "EXT PW: No suitable PSK available");
+ forced_memzero(pw_str, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ forced_memzero(pw_str, sizeof(pw_str));
+ ext_password_free(pw);
+
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
+ return -1;
+}
+
static void wpas_update_allowed_key_mgmt(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
@@ -1434,7 +1539,8 @@
return;
}
- if (wpa_s->conf->sae_pwe)
+ if (wpa_s->conf->sae_pwe != SAE_PWE_HUNT_AND_PECK &&
+ wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
#ifdef CONFIG_SAE_PK
if (ssid->sae_pk)
@@ -1464,6 +1570,7 @@
* @wpa_ie: Buffer for the WPA/RSN IE
* @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
* used buffer length in case the functions returns success.
+ * @skip_default_rsne: Whether to skip setting of the default RSNE/RSNXE
* Returns: 0 on success or -1 on failure
*
* This function is used to configure authentication and encryption parameters
@@ -1472,10 +1579,12 @@
*/
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
- u8 *wpa_ie, size_t *wpa_ie_len)
+ u8 *wpa_ie, size_t *wpa_ie_len,
+ bool skip_default_rsne)
{
struct wpa_ie_data ie;
- int sel, proto, sae_pwe;
+ int sel, proto;
+ enum sae_pwe sae_pwe;
const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) {
@@ -1655,7 +1764,8 @@
sel = ie.key_mgmt & ssid->key_mgmt;
#ifdef CONFIG_SAE
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) ||
+ wpas_is_sae_avoided(wpa_s, ssid, &ie))
sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY |
WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY);
#endif /* CONFIG_SAE */
@@ -1793,7 +1903,8 @@
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
- wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
+ (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED ||
+ (bss && is_6ghz_freq(bss->freq)))) {
wpa_msg(wpa_s, MSG_INFO,
"RSN: Management frame protection required but the selected AP does not enable it");
return -1;
@@ -1808,18 +1919,14 @@
sae_pwe = wpa_s->conf->sae_pwe;
if ((ssid->sae_password_id ||
wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) &&
- sae_pwe != 3)
- sae_pwe = 1;
- if (bss && is_6ghz_freq(bss->freq)) {
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: force hash-to-element mode for 6GHz BSS.");
- sae_pwe = 1;
+ sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
+ sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+ if (bss && is_6ghz_freq(bss->freq) &&
+ sae_pwe == SAE_PWE_HUNT_AND_PECK) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "RSN: Enable SAE hash-to-element mode for 6 GHz BSS");
+ sae_pwe = SAE_PWE_BOTH;
}
-#ifdef CONFIG_TESTING_OPTIONS
- if (wpa_s->force_hunting_and_pecking_pwe) {
- wpa_dbg(wpa_s, MSG_DEBUG, "WPA: force hunting and pecking mode.");
- sae_pwe = 0;
- }
-#endif
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe);
#ifdef CONFIG_SAE_PK
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PK,
@@ -1830,6 +1937,12 @@
(!ssid->sae_password && ssid->passphrase &&
sae_pk_valid_password(ssid->passphrase))));
#endif /* CONFIG_SAE_PK */
+ if (bss && is_6ghz_freq(bss->freq) &&
+ wpas_get_ssid_pmf(wpa_s, ssid) != MGMT_FRAME_PROTECTION_REQUIRED) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Force MFPR=1 on 6 GHz");
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+ MGMT_FRAME_PROTECTION_REQUIRED);
+ }
#ifdef CONFIG_TESTING_OPTIONS
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED,
wpa_s->ft_rsnxe_used);
@@ -1869,16 +1982,21 @@
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0);
}
- if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
- wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
- return -1;
- }
+ if (!skip_default_rsne) {
+ if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie,
+ wpa_ie_len)) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "RSN: Failed to generate RSNE/WPA IE");
+ return -1;
+ }
- wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
- if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
- &wpa_s->rsnxe_len)) {
- wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
- return -1;
+ wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+ if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+ &wpa_s->rsnxe_len)) {
+ wpa_msg(wpa_s, MSG_WARNING,
+ "RSN: Failed to generate RSNXE");
+ return -1;
+ }
}
if (0) {
@@ -1892,120 +2010,27 @@
#endif /* CONFIG_DPP */
} else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
int psk_set = 0;
- int sae_only;
- sae_only = (ssid->key_mgmt & (WPA_KEY_MGMT_PSK |
- WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_PSK_SHA256)) == 0;
+ if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) {
+ u8 psk[PMK_LEN];
- if (ssid->psk_set && !sae_only) {
- wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
- ssid->psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
- NULL);
- psk_set = 1;
+ if (wpa_supplicant_get_psk(wpa_s, bss, ssid,
+ psk) == 0) {
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
+ NULL);
+ psk_set = 1;
+ }
+ forced_memzero(psk, sizeof(psk));
}
if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
- (ssid->sae_password || ssid->passphrase))
+ (ssid->sae_password || ssid->passphrase || ssid->ext_psk))
psk_set = 1;
-#ifndef CONFIG_NO_PBKDF2
- if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
- ssid->passphrase && !sae_only) {
- u8 psk[PMK_LEN];
-
- 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;
- os_memset(psk, 0, sizeof(psk));
- }
-#endif /* CONFIG_NO_PBKDF2 */
-#ifdef CONFIG_EXT_PASSWORD
- if (ssid->ext_psk && !sae_only) {
- struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
- ssid->ext_psk);
- char pw_str[64 + 1];
- u8 psk[PMK_LEN];
-
- if (pw == NULL) {
- wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
- "found from external storage");
- return -1;
- }
-
- if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
- wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
- "PSK length %d in external storage",
- (int) wpabuf_len(pw));
- ext_password_free(pw);
- return -1;
- }
-
- os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
- pw_str[wpabuf_len(pw)] = '\0';
-
-#ifndef CONFIG_NO_PBKDF2
- if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
- {
- 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)",
- psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
- NULL);
- psk_set = 1;
- os_memset(psk, 0, sizeof(psk));
- } else
-#endif /* CONFIG_NO_PBKDF2 */
- if (wpabuf_len(pw) == 2 * PMK_LEN) {
- if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
- wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
- "Invalid PSK hex string");
- os_memset(pw_str, 0, sizeof(pw_str));
- ext_password_free(pw);
- return -1;
- }
- wpa_hexdump_key(MSG_MSGDUMP,
- "PSK (from external PSK)",
- psk, PMK_LEN);
- wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
- NULL);
- psk_set = 1;
- os_memset(psk, 0, sizeof(psk));
- } else {
- wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
- "PSK available");
- os_memset(pw_str, 0, sizeof(pw_str));
- ext_password_free(pw);
- return -1;
- }
-
- os_memset(pw_str, 0, sizeof(pw_str));
- ext_password_free(pw);
- }
-#endif /* CONFIG_EXT_PASSWORD */
-
if (!psk_set) {
wpa_msg(wpa_s, MSG_INFO,
"No PSK available for association");
- wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE");
+ wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE", NULL);
return -1;
}
#ifdef CONFIG_OWE
@@ -2228,31 +2253,53 @@
}
-int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
+int wpas_update_random_addr(struct wpa_supplicant *wpa_s,
+ enum wpas_mac_addr_style style,
+ struct wpa_ssid *ssid)
{
struct os_reltime now;
u8 addr[ETH_ALEN];
os_get_reltime(&now);
- if (wpa_s->last_mac_addr_style == style &&
- wpa_s->last_mac_addr_change.sec != 0 &&
- !os_reltime_expired(&now, &wpa_s->last_mac_addr_change,
- wpa_s->conf->rand_addr_lifetime)) {
- wpa_msg(wpa_s, MSG_DEBUG,
- "Previously selected random MAC address has not yet expired");
- return 0;
+ /* Random addresses are valid within a given ESS so check
+ * expiration/value only when continuing to use the same ESS. */
+ if (wpa_s->last_mac_addr_style == style && wpa_s->reassoc_same_ess) {
+ if (style == WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS) {
+ /* Pregenerated addresses do not expire but their value
+ * might have changed, so let's check that. */
+ if (os_memcmp(wpa_s->own_addr, ssid->mac_value,
+ ETH_ALEN) == 0)
+ return 0;
+ } else if ((wpa_s->last_mac_addr_change.sec != 0 ||
+ wpa_s->last_mac_addr_change.usec != 0) &&
+ !os_reltime_expired(
+ &now,
+ &wpa_s->last_mac_addr_change,
+ wpa_s->conf->rand_addr_lifetime)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Previously selected random MAC address has not yet expired");
+ return 0;
+ }
}
switch (style) {
- case 1:
+ case WPAS_MAC_ADDR_STYLE_RANDOM:
if (random_mac_addr(addr) < 0)
return -1;
break;
- case 2:
+ case WPAS_MAC_ADDR_STYLE_RANDOM_SAME_OUI:
os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN);
if (random_mac_addr_keep_oui(addr) < 0)
return -1;
break;
+ case WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS:
+ if (!ssid) {
+ wpa_msg(wpa_s, MSG_INFO,
+ "Invalid 'ssid' for address policy 3");
+ return -1;
+ }
+ os_memcpy(addr, ssid->mac_value, ETH_ALEN);
+ break;
default:
return -1;
}
@@ -2276,7 +2323,7 @@
wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
MAC2STR(addr));
- return 0;
+ return 1;
}
@@ -2286,7 +2333,8 @@
!wpa_s->conf->preassoc_mac_addr)
return 0;
- return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr);
+ return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr,
+ NULL);
}
@@ -2305,10 +2353,10 @@
password = ssid->passphrase;
if (!password ||
- (conf->sae_pwe == 0 && !ssid->sae_password_id &&
+ (conf->sae_pwe == SAE_PWE_HUNT_AND_PECK && !ssid->sae_password_id &&
!wpa_key_mgmt_sae_ext_key(ssid->key_mgmt) &&
!sae_pk_valid_password(password)) ||
- conf->sae_pwe == 3) {
+ conf->sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) {
/* PT derivation not needed */
sae_deinit_pt(ssid->pt);
ssid->pt = NULL;
@@ -2378,7 +2426,7 @@
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
struct wpa_connect_work *cwork;
- int rand_style;
+ enum wpas_mac_addr_style rand_style;
wpa_s->own_disconnect_req = 0;
wpa_s->own_reconnect_req = 0;
@@ -2390,7 +2438,7 @@
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = NULL;
- if (ssid->mac_addr == -1)
+ if (ssid->mac_addr == WPAS_MAC_ADDR_STYLE_NOT_SET)
rand_style = wpa_s->conf->mac_addr;
else
rand_style = ssid->mac_addr;
@@ -2422,11 +2470,16 @@
wpa_s_setup_sae_pt(wpa_s->conf, ssid);
#endif /* CONFIG_SAE */
- if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
- if (wpas_update_random_addr(wpa_s, rand_style) < 0)
+ if (rand_style > WPAS_MAC_ADDR_STYLE_PERMANENT) {
+ int status = wpas_update_random_addr(wpa_s, rand_style, ssid);
+
+ if (status < 0)
return;
- wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
- } else if (rand_style == 0 && wpa_s->mac_addr_changed) {
+ if (rand_style != WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS &&
+ status > 0) /* MAC changed */
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+ } else if (rand_style == WPAS_MAC_ADDR_STYLE_PERMANENT &&
+ wpa_s->mac_addr_changed) {
if (wpas_restore_permanent_mac_addr(wpa_s) < 0)
return;
}
@@ -3123,6 +3176,10 @@
wpa_key_mgmt_wpa(ssid->key_mgmt)) {
int try_opportunistic;
const u8 *cache_id = NULL;
+ const u8 *addr = bss->bssid;
+
+ if (wpa_s->valid_links)
+ addr = wpa_s->ap_mld_addr;
try_opportunistic = (ssid->proactive_key_caching < 0 ?
wpa_s->conf->okc :
@@ -3132,7 +3189,7 @@
if (wpa_key_mgmt_fils(ssid->key_mgmt))
cache_id = wpa_bss_get_fils_cache_id(bss);
#endif /* CONFIG_FILS */
- if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+ if (pmksa_cache_set_current(wpa_s->wpa, NULL, addr,
ssid, try_opportunistic,
cache_id, 0) == 0) {
eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
@@ -3142,7 +3199,7 @@
}
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
- wpa_ie, &wpa_ie_len)) {
+ wpa_ie, &wpa_ie_len, false)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
"key management and encryption suites");
os_free(wpa_ie);
@@ -3154,7 +3211,7 @@
/* No PMKSA caching, but otherwise similar to RSN/WPA */
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
- wpa_ie, &wpa_ie_len)) {
+ wpa_ie, &wpa_ie_len, false)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
"key management and encryption suites");
os_free(wpa_ie);
@@ -3174,7 +3231,7 @@
} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
wpa_ie_len = max_wpa_ie_len;
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
- wpa_ie, &wpa_ie_len)) {
+ wpa_ie, &wpa_ie_len, false)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
"key management and encryption suites (no "
"scan results)");
@@ -3499,7 +3556,7 @@
}
#ifdef CONFIG_SME
if (len > 0 && wpa_s->sme.ft_used &&
- wpa_sm_has_ptk(wpa_s->wpa)) {
+ wpa_sm_has_ft_keys(wpa_s->wpa, md)) {
wpa_dbg(wpa_s, MSG_DEBUG,
"SME: Trying to use FT over-the-air");
algs |= WPA_AUTH_ALG_FT;
@@ -3783,6 +3840,7 @@
int use_crypt, ret, bssid_changed;
unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
struct wpa_driver_associate_params params;
+ u8 psk[PMK_LEN];
#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL)
int wep_keys_set = 0;
#endif /* CONFIG_WEP || IEEE8021X_EAPOL */
@@ -4080,8 +4138,8 @@
(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)))) {
#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
params.passphrase = ssid->passphrase;
- if (ssid->psk_set)
- params.psk = ssid->psk;
+ if (wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0)
+ params.psk = psk;
}
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
@@ -4110,8 +4168,8 @@
if ((wpa_key_mgmt_wpa_psk_no_sae(params.key_mgmt_suite) ||
wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts)) &&
#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
- ssid->psk_set)
- params.psk = ssid->psk;
+ wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0)
+ params.psk = psk;
}
params.drop_unencrypted = use_crypt;
@@ -4159,6 +4217,7 @@
#ifdef CONFIG_HE_OVERRIDES
wpa_supplicant_apply_he_overrides(wpa_s, ssid, ¶ms);
#endif /* CONFIG_HE_OVERRIDES */
+ wpa_supplicant_apply_eht_overrides(wpa_s, ssid, ¶ms);
#ifdef CONFIG_P2P
/*
@@ -4168,7 +4227,7 @@
*/
if (wpa_s->num_multichan_concurrent < 2) {
int freq, num;
- num = get_shared_radio_freqs(wpa_s, &freq, 1);
+ num = get_shared_radio_freqs(wpa_s, &freq, 1, false);
if (num > 0 && freq > 0 && freq != params.freq.freq) {
wpa_printf(MSG_DEBUG,
"Assoc conflicting freq found (%d != %d)",
@@ -4192,6 +4251,7 @@
#endif /* CONFIG_SAE */
ret = wpa_drv_associate(wpa_s, ¶ms);
+ forced_memzero(psk, sizeof(psk));
os_free(wpa_ie);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -4273,6 +4333,8 @@
wpa_supplicant_initiate_eapol(wpa_s);
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+ wpas_notify_auth_changed(wpa_s);
}
@@ -5184,6 +5246,8 @@
enum frame_encryption encrypted)
{
struct wpa_supplicant *wpa_s = ctx;
+ const u8 *connected_addr = wpa_s->valid_links ?
+ wpa_s->ap_mld_addr : wpa_s->bssid;
wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " (encrypted=%d)",
MAC2STR(src_addr), encrypted);
@@ -5209,7 +5273,7 @@
#ifdef CONFIG_AP
!wpa_s->ap_iface &&
#endif /* CONFIG_AP */
- os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
+ os_memcmp(src_addr, connected_addr, ETH_ALEN) != 0)) {
/*
* There is possible race condition between receiving the
* association event and the EAPOL frame since they are coming
@@ -5222,10 +5286,11 @@
* Authenticator uses BSSID as the src_addr (which is not the
* case with wired IEEE 802.1X).
*/
- wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
- "of received EAPOL frame (state=%s bssid=" MACSTR ")",
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Not associated - Delay processing of received EAPOL frame (state=%s connected_addr="
+ MACSTR ")",
wpa_supplicant_state_txt(wpa_s->wpa_state),
- MAC2STR(wpa_s->bssid));
+ MAC2STR(connected_addr));
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
if (wpa_s->pending_eapol_rx) {
@@ -5238,7 +5303,7 @@
}
wpa_s->last_eapol_matches_bssid =
- os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;
+ os_memcmp(src_addr, connected_addr, ETH_ALEN) == 0;
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -5354,6 +5419,10 @@
int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
{
+ u8 prev_mac_addr[ETH_ALEN];
+
+ os_memcpy(prev_mac_addr, wpa_s->own_addr, ETH_ALEN);
+
if ((!wpa_s->p2p_mgmt ||
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
@@ -5391,6 +5460,9 @@
fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
#endif /* CONFIG_FST */
+ if (os_memcmp(prev_mac_addr, wpa_s->own_addr, ETH_ALEN) != 0)
+ wpas_notify_mac_address_changed(wpa_s);
+
return 0;
}
@@ -5957,6 +6029,17 @@
#endif /* CONFIG_HE_OVERRIDES */
+void wpa_supplicant_apply_eht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ if (!ssid)
+ return;
+
+ params->disable_eht = ssid->disable_eht;
+}
+
+
static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
{
#ifdef PCSC_FUNCS
@@ -6774,7 +6857,7 @@
#else /* CONFIG_BACKEND_FILE */
wpa_s->confname = os_strdup(iface->confname);
#endif /* CONFIG_BACKEND_FILE */
- wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
+ wpa_s->conf = wpa_config_read(wpa_s->confname, NULL, false);
if (wpa_s->conf == NULL) {
wpa_printf(MSG_ERROR, "Failed to read or parse "
"configuration '%s'.", wpa_s->confname);
@@ -6782,7 +6865,7 @@
}
wpa_s->confanother = os_rel2abs_path(iface->confanother);
if (wpa_s->confanother &&
- !wpa_config_read(wpa_s->confanother, wpa_s->conf)) {
+ !wpa_config_read(wpa_s->confanother, wpa_s->conf, true)) {
wpa_printf(MSG_ERROR,
"Failed to read or parse configuration '%s'.",
wpa_s->confanother);
@@ -6797,12 +6880,24 @@
os_free(wpa_s->conf->ctrl_interface);
wpa_s->conf->ctrl_interface =
os_strdup(iface->ctrl_interface);
+ if (!wpa_s->conf->ctrl_interface) {
+ wpa_printf(MSG_ERROR,
+ "Failed to duplicate control interface '%s'.",
+ iface->ctrl_interface);
+ return -1;
+ }
}
if (iface->driver_param) {
os_free(wpa_s->conf->driver_param);
wpa_s->conf->driver_param =
os_strdup(iface->driver_param);
+ if (!wpa_s->conf->driver_param) {
+ wpa_printf(MSG_ERROR,
+ "Failed to duplicate driver param '%s'.",
+ iface->driver_param);
+ return -1;
+ }
}
if (iface->p2p_mgmt && !iface->ctrl_interface) {
@@ -7571,26 +7666,63 @@
global->params.daemonize = params->daemonize;
global->params.wait_for_monitor = params->wait_for_monitor;
global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
- if (params->pid_file)
+
+ if (params->pid_file) {
global->params.pid_file = os_strdup(params->pid_file);
- if (params->ctrl_interface)
+ if (!global->params.pid_file) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
+ if (params->ctrl_interface) {
global->params.ctrl_interface =
os_strdup(params->ctrl_interface);
- if (params->ctrl_interface_group)
+ if (!global->params.ctrl_interface) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
+ if (params->ctrl_interface_group) {
global->params.ctrl_interface_group =
os_strdup(params->ctrl_interface_group);
- if (params->override_driver)
+ if (!global->params.ctrl_interface_group) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
+ if (params->override_driver) {
global->params.override_driver =
os_strdup(params->override_driver);
- if (params->override_ctrl_interface)
+ if (!global->params.override_driver) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
+ if (params->override_ctrl_interface) {
global->params.override_ctrl_interface =
os_strdup(params->override_ctrl_interface);
+ if (!global->params.override_ctrl_interface) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
#ifdef CONFIG_MATCH_IFACE
global->params.match_iface_count = params->match_iface_count;
if (params->match_iface_count) {
global->params.match_ifaces =
os_calloc(params->match_iface_count,
sizeof(struct wpa_interface));
+ if (!global->params.match_ifaces) {
+ wpa_printf(MSG_ERROR,
+ "Failed to allocate match interfaces");
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
os_memcpy(global->params.match_ifaces,
params->match_ifaces,
params->match_iface_count *
@@ -7598,9 +7730,15 @@
}
#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_P2P
- if (params->conf_p2p_dev)
+ if (params->conf_p2p_dev) {
global->params.conf_p2p_dev =
os_strdup(params->conf_p2p_dev);
+ if (!global->params.conf_p2p_dev) {
+ wpa_printf(MSG_ERROR, "Failed to allocate conf p2p");
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
#endif /* CONFIG_P2P */
wpa_debug_level = global->params.wpa_debug_level =
params->wpa_debug_level;
@@ -7935,7 +8073,7 @@
if (wpa_s->consecutive_conn_failures > 3 && wpa_s->current_ssid) {
wpa_printf(MSG_DEBUG, "Continuous association failures - "
"consider temporary network disabling");
- wpas_auth_failed(wpa_s, "CONN_FAILED");
+ wpas_auth_failed(wpa_s, "CONN_FAILED", bssid);
}
/*
* Multiple consecutive connection failures mean that other APs are
@@ -8112,6 +8250,8 @@
case WPA_CTRL_REQ_EAP_PASSWORD:
bin_clear_free(eap->password, eap->password_len);
eap->password = (u8 *) os_strdup(value);
+ if (!eap->password)
+ return -1;
eap->password_len = value_len;
eap->pending_req_password = 0;
if (ssid == wpa_s->current_ssid)
@@ -8120,6 +8260,8 @@
case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
bin_clear_free(eap->new_password, eap->new_password_len);
eap->new_password = (u8 *) os_strdup(value);
+ if (!eap->new_password)
+ return -1;
eap->new_password_len = value_len;
eap->pending_req_new_password = 0;
if (ssid == wpa_s->current_ssid)
@@ -8128,6 +8270,8 @@
case WPA_CTRL_REQ_EAP_PIN:
str_clear_free(eap->cert.pin);
eap->cert.pin = os_strdup(value);
+ if (!eap->cert.pin)
+ return -1;
eap->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -8135,6 +8279,8 @@
case WPA_CTRL_REQ_EAP_OTP:
bin_clear_free(eap->otp, eap->otp_len);
eap->otp = (u8 *) os_strdup(value);
+ if (!eap->otp)
+ return -1;
eap->otp_len = value_len;
os_free(eap->pending_req_otp);
eap->pending_req_otp = NULL;
@@ -8143,6 +8289,8 @@
case WPA_CTRL_REQ_EAP_PASSPHRASE:
str_clear_free(eap->cert.private_key_passwd);
eap->cert.private_key_passwd = os_strdup(value);
+ if (!eap->cert.private_key_passwd)
+ return -1;
eap->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -8150,6 +8298,8 @@
case WPA_CTRL_REQ_SIM:
str_clear_free(eap->external_sim_resp);
eap->external_sim_resp = os_strdup(value);
+ if (!eap->external_sim_resp)
+ return -1;
eap->pending_req_sim = 0;
break;
case WPA_CTRL_REQ_PSK_PASSPHRASE:
@@ -8277,6 +8427,13 @@
return NO_MGMT_FRAME_PROTECTION;
}
+#ifdef CONFIG_OCV
+ /* Enable PMF if OCV is being enabled */
+ if (wpa_s->conf->pmf == NO_MGMT_FRAME_PROTECTION &&
+ ssid && ssid->ocv)
+ return MGMT_FRAME_PROTECTION_OPTIONAL;
+#endif /* CONFIG_OCV */
+
return wpa_s->conf->pmf;
}
@@ -8284,6 +8441,19 @@
}
+#ifdef CONFIG_SAE
+bool wpas_is_sae_avoided(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const struct wpa_ie_data *ie)
+{
+ return wpa_s->conf->sae_check_mfp &&
+ (!(ie->capabilities &
+ (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) ||
+ wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION);
+}
+#endif /* CONFIG_SAE */
+
+
int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr)
{
if (wpa_s->current_ssid == NULL ||
@@ -8304,7 +8474,8 @@
}
-void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason)
+void wpas_auth_failed(struct wpa_supplicant *wpa_s, const char *reason,
+ const u8 *bssid)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
int dur;
@@ -8374,6 +8545,9 @@
ssid->auth_failures, dur, reason);
wpas_notify_ssid_temp_disabled(wpa_s, msg);
os_free(msg);
+
+ if (bssid)
+ os_memcpy(ssid->disabled_due_to, bssid, ETH_ALEN);
}
@@ -8390,8 +8564,15 @@
}
ssid->disabled_until.sec = 0;
ssid->disabled_until.usec = 0;
- if (clear_failures)
+ if (clear_failures) {
ssid->auth_failures = 0;
+ } else if (!is_zero_ether_addr(ssid->disabled_due_to)) {
+ wpa_printf(MSG_DEBUG, "Mark BSSID " MACSTR
+ " ignored to allow a lower priority BSS, if any, to be tried next",
+ MAC2STR(ssid->disabled_due_to));
+ wpa_bssid_ignore_add(wpa_s, ssid->disabled_due_to);
+ os_memset(ssid->disabled_due_to, 0, ETH_ALEN);
+ }
}
@@ -8505,7 +8686,7 @@
*/
int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
struct wpa_used_freq_data *freqs_data,
- unsigned int len)
+ unsigned int len, bool exclude_current)
{
struct wpa_supplicant *ifs;
u8 bssid[ETH_ALEN];
@@ -8521,6 +8702,9 @@
if (idx == len)
break;
+ if (exclude_current && ifs == wpa_s)
+ continue;
+
if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
continue;
@@ -8558,7 +8742,8 @@
* are using the same radio as the current interface.
*/
int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
- int *freq_array, unsigned int len)
+ int *freq_array, unsigned int len,
+ bool exclude_current)
{
struct wpa_used_freq_data *freqs_data;
int num, i;
@@ -8569,7 +8754,8 @@
if (!freqs_data)
return -1;
- num = get_shared_radio_freqs_data(wpa_s, freqs_data, len);
+ num = get_shared_radio_freqs_data(wpa_s, freqs_data, len,
+ exclude_current);
for (i = 0; i < num; i++)
freq_array[i] = freqs_data[i].freq;
@@ -8894,17 +9080,17 @@
continue;
wpa_printf(MSG_DEBUG,
"Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d",
- si->current_signal,
+ si->data.signal,
dso->si_current_signal,
- si->avg_signal,
+ si->data.avg_signal,
dso->si_avg_signal,
- si->avg_beacon_signal,
+ si->data.avg_beacon_signal,
dso->si_avg_beacon_signal,
si->current_noise,
dso->si_current_noise);
- si->current_signal = dso->si_current_signal;
- si->avg_signal = dso->si_avg_signal;
- si->avg_beacon_signal = dso->si_avg_beacon_signal;
+ si->data.signal = dso->si_current_signal;
+ si->data.avg_signal = dso->si_avg_signal;
+ si->data.avg_beacon_signal = dso->si_avg_beacon_signal;
si->current_noise = dso->si_current_noise;
break;
}
@@ -8955,3 +9141,43 @@
return scan_res;
}
+
+
+static bool wpas_ap_link_address(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+ int i;
+
+ if (!wpa_s->valid_links)
+ return false;
+
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(wpa_s->valid_links & BIT(i)))
+ continue;
+
+ if (os_memcmp(wpa_s->links[i].bssid, addr, ETH_ALEN) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+
+int wpa_drv_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+ unsigned int wait, const u8 *dst, const u8 *src,
+ const u8 *bssid, const u8 *data, size_t data_len,
+ int no_cck)
+{
+ if (!wpa_s->driver->send_action)
+ return -1;
+
+ if (data_len > 0 && data[0] != WLAN_ACTION_PUBLIC) {
+ if (wpas_ap_link_address(wpa_s, dst))
+ dst = wpa_s->ap_mld_addr;
+
+ if (wpas_ap_link_address(wpa_s, bssid))
+ bssid = wpa_s->ap_mld_addr;
+ }
+
+ return wpa_s->driver->send_action(wpa_s->drv_priv, freq, wait, dst, src,
+ bssid, data, data_len, no_cck);
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index b6a1a74..7a5f9cb 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -419,6 +419,34 @@
# RSN.
#pmf=0
+# sae_check_mfp: Require PMF support to select SAE key_mgmt
+# 0 = Do not check PMF for SAE (default)
+# 1 = Limit SAE when PMF is not enabled
+#
+# When enabled SAE will not be selected if PMF will not be used
+# for the connection.
+# Scenarios where this check will limit SAE:
+# 1) ieee80211w=0 is set for the network
+# 2) The AP does not have PMF enabled.
+# 3) ieee80211w is unset, pmf=1 is enabled globally, and
+# the device does not support the BIP cipher.
+# Consider the configuration of global parameterss sae_check_mfp=1, pmf=1 and a
+# network configured with ieee80211w unset and key_mgmt=SAE WPA-PSK.
+# In the example WPA-PSK will be used if the device does not support
+# the BIP cipher or the AP has PMF disabled.
+# Limiting SAE with this check can avoid failing to associate to an AP
+# that is configured with sae_requires_mfp=1 if the device does
+# not support PMF due to lack of the BIP cipher.
+#
+# Enabling this check helps with compliance of the WPA3
+# specification for WPA3-Personal transition mode.
+# The WPA3 specification section 2.3 "WPA3-Personal transition mode" item 8
+# states "A STA shall negotiate PMF when associating to an AP using SAE".
+# With this check WPA3 capable devices when connecting
+# to transition mode APs that do not advertise PMF support
+# will not use SAE and instead fallback to PSK.
+#sae_check_mfp=0
+
# Enabled SAE finite cyclic groups in preference order
# By default (if this parameter is not set), the mandatory group 19 (ECC group
# defined over a 256-bit prime order field, NIST P-256) is preferred and groups
@@ -655,7 +683,26 @@
# be used to configure alternative FQDNs that will be considered home
# networks.
#
+# home_ois: Home OI(s)
+# This string field contains one or more comma delimited OIs (hexdump)
+# identifying the access the access points that support authentication
+# with this credential. There are an alternative to the use of the realm
+# parameter. When using Home OIs to match the network, the EAP parameters
+# need to be pre-configured with the credentials since the NAI Realm
+# information may not be available or fetched.
+# A successful authentication with the access point is possible as soon
+# as at least one Home OI from the list matches an OI in the Roaming
+# Consortium advertised by the access point.
+# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOI)
+#
+# required_home_ois: Required Home OI(s)
+# This string field contains the set of Home OI(s) (hexdump) that are
+# required to be advertised by the AP for the credential to be considered
+# matching.
+# (Hotspot 2.0 PerProviderSubscription/<X+>/HomeSP/HomeOIList/<X+>/HomeOIRequired)
+#
# roaming_consortium: Roaming Consortium OI
+# Deprecated: use home_ois instead.
# If roaming_consortium_len is non-zero, this field contains the
# Roaming Consortium OI that can be used to determine which access
# points support authentication with this credential. This is an
@@ -665,6 +712,7 @@
# may not be available or fetched.
#
# required_roaming_consortium: Required Roaming Consortium OI
+# Deprecated: use required_home_ois instead.
# If required_roaming_consortium_len is non-zero, this field contains the
# Roaming Consortium OI that is required to be advertised by the AP for
# the credential to be considered matching.
@@ -770,7 +818,7 @@
# password="password"
# ca_cert="/etc/wpa_supplicant/ca.pem"
# domain="example.com"
-# roaming_consortium=223344
+# home_ois="223344"
# eap=TTLS
# phase2="auth=MSCHAPV2"
#}
@@ -1635,6 +1683,10 @@
# 2: MCS 0-9
# 3: not supported
+# disable_eht: Whether EHT should be disabled.
+# 0 = EHT enabled (if supported) (default)
+# 1 = EHT disabled
+
# multi_ap_backhaul_sta: Multi-AP backhaul STA functionality
# 0 = normal STA (default)
# 1 = backhaul STA
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index e673a9c..d364212 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -22,6 +22,7 @@
#include "wmm_ac.h"
#include <netinet/in.h>
#include <netinet/in6.h>
+#include "pasn/pasn_common.h"
extern const char *const wpa_supplicant_version;
extern const char *const wpa_supplicant_license;
@@ -541,61 +542,6 @@
int num_policies;
};
-#ifdef CONFIG_PASN
-
-struct pasn_fils {
- u8 nonce[FILS_NONCE_LEN];
- u8 anonce[FILS_NONCE_LEN];
- u8 session[FILS_SESSION_LEN];
- u8 erp_pmkid[PMKID_LEN];
- bool completed;
-};
-
-struct wpas_pasn {
- int akmp;
- int cipher;
- u16 group;
- bool secure_ltf;
- int freq;
- size_t kdk_len;
-
- u8 trans_seq;
- u8 status;
-
- u8 own_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- size_t pmk_len;
- u8 pmk[PMK_LEN_MAX];
- bool using_pmksa;
-
- u8 hash[SHA384_MAC_LEN];
-
- struct wpabuf *beacon_rsne_rsnxe;
- struct wpa_ptk ptk;
- struct crypto_ecdh *ecdh;
-
- struct wpabuf *comeback;
- u16 comeback_after;
-
-#ifdef CONFIG_SAE
- struct sae_data sae;
-#endif /* CONFIG_SAE */
-
- struct wpa_ssid *ssid;
-
-#ifdef CONFIG_FILS
- struct pasn_fils fils;
-#endif /* CONFIG_FILS */
-
-#ifdef CONFIG_IEEE80211R
- u8 pmk_r1[PMK_LEN_MAX];
- size_t pmk_r1_len;
- u8 pmk_r1_name[WPA_PMK_NAME_LEN];
-#endif /* CONFIG_IEEE80211R */
-};
-#endif /* CONFIG_PASN */
-
-
enum ip_version {
IPV4 = 4,
IPV6 = 6,
@@ -757,8 +703,9 @@
int ap_ies_from_associnfo;
unsigned int assoc_freq;
u8 ap_mld_addr[ETH_ALEN];
- u8 valid_links; /* bitmap of valid MLO link IDs */
- struct {
+ u8 mlo_assoc_link_id;
+ u16 valid_links; /* bitmap of valid MLO link IDs */
+ struct ml_sta_link_info {
u8 addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
unsigned int freq;
@@ -1002,7 +949,7 @@
unsigned int connection_11b_only:1;
struct os_reltime last_mac_addr_change;
- int last_mac_addr_style;
+ enum wpas_mac_addr_style last_mac_addr_style;
struct ibss_rsn *ibss_rsn;
@@ -1054,6 +1001,7 @@
struct wpa_ssid *ext_auth_wpa_ssid;
u8 ext_auth_ssid[SSID_MAX_LEN];
size_t ext_auth_ssid_len;
+ int ext_auth_key_mgmt;
int *sae_rejected_groups;
#endif /* CONFIG_SAE */
} sme;
@@ -1389,7 +1337,6 @@
unsigned int oci_freq_override_ft_assoc;
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 */
@@ -1580,8 +1527,12 @@
struct robust_av_data robust_av;
bool mscs_setup_done;
+ bool wps_scan_done; /* Set upon receiving scan results event */
+ bool supp_pbc_active; /* Set for interface when PBC is triggered */
+ bool wps_overlap;
+
#ifdef CONFIG_PASN
- struct wpas_pasn pasn;
+ struct pasn_data pasn;
struct wpa_radio_work *pasn_auth_work;
unsigned int pasn_count;
struct pasn_auth *pasn_params;
@@ -1599,6 +1550,8 @@
unsigned int enable_dscp_policy_capa:1;
unsigned int connection_dscp:1;
unsigned int wait_for_dscp_req:1;
+
+ struct wpa_signal_info last_signal_info;
};
@@ -1612,6 +1565,9 @@
void wpa_supplicant_apply_he_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params);
+void wpa_supplicant_apply_eht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params);
int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
@@ -1628,7 +1584,8 @@
struct wpa_ssid *ssid, struct wpa_ie_data *ie);
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid,
- u8 *wpa_ie, size_t *wpa_ie_len);
+ u8 *wpa_ie, size_t *wpa_ie_len,
+ bool skip_default_rsne);
int wpas_restore_permanent_mac_addr(struct wpa_supplicant *wpa_s);
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss,
@@ -1706,7 +1663,8 @@
void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
-void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason);
+void wpas_auth_failed(struct wpa_supplicant *wpa_s, const char *reason,
+ const u8 *bssid);
void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int clear_failures);
int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid);
@@ -1715,7 +1673,8 @@
void wpas_request_connection(struct wpa_supplicant *wpa_s);
void wpas_request_disconnection(struct wpa_supplicant *wpa_s);
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
-int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
+int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style,
+ struct wpa_ssid *ssid);
int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
void add_freq(int *freqs, int *num_freqs, int freq);
@@ -1840,6 +1799,7 @@
void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
+int wpa_wps_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
struct wpa_ssid **selected_ssid);
int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
@@ -1848,6 +1808,7 @@
int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
struct wpa_bss *current_bss,
struct wpa_bss *seleceted);
+void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s);
/* eap_register.c */
int eap_register_methods(void);
@@ -1885,6 +1846,10 @@
int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr);
void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid);
+bool wpas_is_sae_avoided(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const struct wpa_ie_data *ie);
+
int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
@@ -1893,9 +1858,10 @@
int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
struct wpa_used_freq_data *freqs_data,
- unsigned int len);
+ unsigned int len, bool exclude_current);
int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
- int *freq_array, unsigned int len);
+ int *freq_array, unsigned int len,
+ bool exclude_current);
void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 556f9cf..7d5ea4c 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -250,7 +250,7 @@
else
wpa_s->group_cipher = cipher;
}
- return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
+ return wpa_drv_set_key(wpa_s, -1, WPA_ALG_WEP,
unicast ? wpa_s->bssid : NULL,
keyidx, unicast, NULL, 0, key, keylen,
unicast ? KEY_FLAG_PAIRWISE_RX_TX :
@@ -375,7 +375,7 @@
wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way "
"handshake", pmk, pmk_len);
- if (wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, NULL, 0, pmk,
+ if (wpa_drv_set_key(wpa_s, -1, 0, NULL, 0, 0, NULL, 0, pmk,
pmk_len, KEY_FLAG_PMK)) {
wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
}
@@ -537,7 +537,7 @@
}
-static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
+static int wpa_supplicant_set_key(void *_wpa_s, int link_id, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len,
@@ -566,8 +566,8 @@
wpa_s->last_tk_len = key_len;
}
#endif /* CONFIG_TESTING_OPTIONS */
- return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
- key, key_len, key_flag);
+ return wpa_drv_set_key(wpa_s, link_id, alg, addr, key_idx, set_tx, seq,
+ seq_len, key, key_len, key_flag);
}
@@ -952,28 +952,9 @@
void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
const char *field_name, const char *txt)
{
- char *buf;
- size_t buflen;
- int len;
-
- buflen = 100 + os_strlen(txt) + ssid->ssid_len;
- buf = os_malloc(buflen);
- if (buf == NULL)
- return;
- len = os_snprintf(buf, buflen, "%s-%d:%s needed for SSID ",
- field_name, ssid->id, txt);
- if (os_snprintf_error(buflen, len)) {
- os_free(buf);
- return;
- }
- if (ssid->ssid && buflen > len + ssid->ssid_len) {
- os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
- len += ssid->ssid_len;
- buf[len] = '\0';
- }
- buf[buflen - 1] = '\0';
- wpa_msg(wpa_s, MSG_INFO, WPA_CTRL_REQ "%s", buf);
- os_free(buf);
+ wpa_msg(wpa_s, MSG_INFO, WPA_CTRL_REQ "%s-%d:%s needed for SSID %s",
+ field_name, ssid->id, txt,
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
}
@@ -1294,7 +1275,7 @@
if (wpa_s->conf->key_mgmt_offload &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
- return wpa_drv_set_key(wpa_s, 0, NULL, 0, 0,
+ return wpa_drv_set_key(wpa_s, -1, 0, NULL, 0, 0,
NULL, 0, pmk, pmk_len, KEY_FLAG_PMK);
else
return 0;
@@ -1342,9 +1323,8 @@
}
-static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
+void wpas_transition_disable(struct wpa_supplicant *wpa_s, u8 bitmap)
{
- struct wpa_supplicant *wpa_s = _wpa_s;
struct wpa_ssid *ssid;
int changed = 0;
@@ -1427,13 +1407,20 @@
}
+static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap)
+{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+ wpas_transition_disable(wpa_s, bitmap);
+}
+
+
static void wpa_supplicant_store_ptk(void *ctx, u8 *addr, int cipher,
u32 life_time, const struct wpa_ptk *ptk)
{
struct wpa_supplicant *wpa_s = ctx;
ptksa_cache_add(wpa_s->ptksa, wpa_s->own_addr, addr, cipher, life_time,
- ptk, NULL, NULL);
+ ptk, NULL, NULL, 0);
}
#endif /* CONFIG_NO_WPA */
@@ -1454,6 +1441,16 @@
#endif /* CONFIG_PASN */
+static void
+wpa_supplicant_notify_pmksa_cache_entry(void *_wpa_s,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ struct wpa_supplicant *wpa_s = _wpa_s;
+
+ wpas_notify_pmk_cache_added(wpa_s, entry);
+}
+
+
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_WPA
@@ -1519,6 +1516,7 @@
#ifdef CONFIG_PASN
ctx->set_ltf_keyseed = wpa_supplicant_set_ltf_keyseed;
#endif /* CONFIG_PASN */
+ ctx->notify_pmksa_cache_entry = wpa_supplicant_notify_pmksa_cache_entry;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
diff --git a/wpa_supplicant/wpas_glue.h b/wpa_supplicant/wpas_glue.h
index 338af4e..dd692b9 100644
--- a/wpa_supplicant/wpas_glue.h
+++ b/wpa_supplicant/wpas_glue.h
@@ -27,4 +27,6 @@
void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
const char *field_name, const char *txt);
+void wpas_transition_disable(struct wpa_supplicant *wpa_s, u8 bitmap);
+
#endif /* WPAS_GLUE_H */
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 7428f02..de7dc98 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -79,6 +79,18 @@
}
+static struct wpabuf * wpas_wps_get_wps_ie(struct wpa_bss *bss)
+{
+ /* Return the latest receive WPS IE from the AP regardless of whether
+ * it was from a Beacon frame or Probe Response frame to avoid using
+ * stale information. */
+ if (bss->beacon_newer)
+ return wpa_bss_get_vendor_ie_multi_beacon(bss,
+ WPS_IE_VENDOR_TYPE);
+ return wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+}
+
+
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
{
if (wpas_p2p_wps_eapol_cb(wpa_s) > 0)
@@ -141,8 +153,7 @@
struct wpabuf *wps;
struct wps_parse_attr attr;
- wps = wpa_bss_get_vendor_ie_multi(bss,
- WPS_IE_VENDOR_TYPE);
+ wps = wpas_wps_get_wps_ie(bss);
if (wps && wps_parse_msg(wps, &attr) == 0 &&
attr.wps_state &&
*attr.wps_state == WPS_STATE_CONFIGURED)
@@ -1002,6 +1013,7 @@
* during an EAP-WSC exchange).
*/
wpas_notify_wps_event_fail(wpa_s, &data.fail);
+ wpa_s->supp_pbc_active = false;
wpas_clear_wps(wpa_s);
}
@@ -1204,6 +1216,8 @@
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
if (multi_ap_backhaul_sta)
ssid->multi_ap_backhaul_sta = 1;
+ wpa_s->supp_pbc_active = true;
+ wpa_s->wps_overlap = false;
wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
@@ -1371,6 +1385,7 @@
wpas_clear_wps(wpa_s);
}
+ wpa_s->supp_pbc_active = false;
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL);
wpa_s->after_wps = 0;
@@ -1705,7 +1720,7 @@
if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
return -1;
- wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+ wps_ie = wpas_wps_get_wps_ie(bss);
if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
if (!wps_ie) {
wpa_printf(MSG_DEBUG, " skip - non-WPS AP");
@@ -1779,13 +1794,13 @@
int ret = 0;
if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
- wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+ wps_ie = wpas_wps_get_wps_ie(bss);
if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
/* allow wildcard SSID for WPS PBC */
ret = 1;
}
} else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
- wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+ wps_ie = wpas_wps_get_wps_ie(bss);
if (wps_ie &&
(wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) ||
wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) {
@@ -1828,9 +1843,40 @@
}
+static bool wpas_wps_is_pbc_overlap(struct wps_ap_info *ap,
+ struct wpa_bss *selected,
+ struct wpa_ssid *ssid,
+ const u8 *sel_uuid)
+{
+ if (!ap->pbc_active ||
+ os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
+ return false;
+
+ if (!is_zero_ether_addr(ssid->bssid) &&
+ os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
+ " in active PBC mode due to local BSSID limitation",
+ MAC2STR(ap->bssid));
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " MACSTR,
+ MAC2STR(ap->bssid));
+ wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
+ ap->uuid, UUID_LEN);
+ if (!sel_uuid || os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0)
+ return true;
+
+ /* TODO: verify that this is reasonable dual-band situation */
+
+ return false;
+}
+
+
int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected, struct wpa_ssid *ssid)
{
+ struct wpa_supplicant *iface;
const u8 *sel_uuid;
struct wpabuf *wps_ie;
int ret = 0;
@@ -1859,36 +1905,21 @@
sel_uuid = NULL;
}
- for (i = 0; i < wpa_s->num_wps_ap; i++) {
- struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+ for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+ for (i = 0; i < iface->num_wps_ap; i++) {
+ struct wps_ap_info *ap = &iface->wps_ap[i];
- if (!ap->pbc_active ||
- os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0)
- continue;
-
- if (!is_zero_ether_addr(ssid->bssid) &&
- os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) {
- wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR
- " in active PBC mode due to local BSSID limitation",
- MAC2STR(ap->bssid));
- continue;
+ if (wpas_wps_is_pbc_overlap(ap, selected, ssid,
+ sel_uuid)) {
+ ret = 1; /* PBC overlap */
+ wpa_msg(iface, MSG_INFO,
+ "WPS: PBC overlap detected: "
+ MACSTR " and " MACSTR,
+ MAC2STR(selected->bssid),
+ MAC2STR(ap->bssid));
+ break;
+ }
}
-
- wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: "
- MACSTR, MAC2STR(ap->bssid));
- wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
- ap->uuid, UUID_LEN);
- if (sel_uuid == NULL ||
- os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0) {
- ret = 1; /* PBC overlap */
- wpa_msg(wpa_s, MSG_INFO, "WPS: PBC overlap detected: "
- MACSTR " and " MACSTR,
- MAC2STR(selected->bssid),
- MAC2STR(ap->bssid));
- break;
- }
-
- /* TODO: verify that this is reasonable dual-band situation */
}
wpabuf_free(wps_ie);
@@ -1907,7 +1938,8 @@
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
struct wpabuf *ie;
- ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+
+ ie = wpas_wps_get_wps_ie(bss);
if (!ie)
continue;
if (wps_is_selected_pbc_registrar(ie))
@@ -2995,6 +3027,48 @@
}
+bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_global *global = wpa_s->global;
+ struct wpa_supplicant *iface;
+
+ for (iface = global->ifaces; iface; iface = iface->next) {
+ if (iface == wpa_s)
+ continue;
+
+ if (!iface->supp_pbc_active)
+ continue;
+
+ /* Scan results are available for both links. While the current
+ * link will proceed for network selection, ensure the partner
+ * link also gets an attempt at network selection and connect
+ * with the selected BSS. */
+ if (iface->wps_scan_done)
+ wpa_wps_supplicant_fast_associate(iface);
+ else
+ return false;
+ }
+
+ return true;
+}
+
+
+bool wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_global *global = wpa_s->global;
+ struct wpa_supplicant *iface;
+
+ for (iface = global->ifaces; iface; iface = iface->next) {
+ if (iface == wpa_s)
+ continue;
+ if (iface->wps_overlap)
+ return true;
+ }
+
+ return false;
+}
+
+
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wps_ap_info *ap;
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 41b9298..5c8b833 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -87,6 +87,8 @@
const struct wpabuf *sel);
void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res);
+bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s);
+bool wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s);
void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s);
@@ -146,6 +148,17 @@
{
}
+static inline bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s)
+{
+ return true;
+}
+
+static inline bool
+wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s)
+{
+ return false;
+}
+
static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
const u8 *bssid)
{