cumilative patch from commit 95ad71157
Bug: 341971059
Bug: 394110783
Test: Connect to open, WPA2, WPA3 and OWE
Test: Establish P2P connection
Test: Basic SoftAp tests
Test: Ran above tests on Pixel6
Test: Regression test (401126565)
Fixed the TLS failure caused by 400b89162294f0344d82334218e8950fd01bb12f
95ad71157 P2P2: Get ID of device identity block from wpas_p2p_validate_dira()
f02e1d777 nl80211: Determine capability for P2P-R2 and PCC mode
c144dcbdf P2P2: Add support to fetch the P2P2 and PCC capability
d0528fb5e Add QCA vendor feature flags to indicate P2P-R2 and PCC support
b3b0297d8 P2P2: Indicate bootstrapping comeback response to upper layers
5ec339723 nl80211: Fix typo in SAE PWE debug message
d0213ad1e AP MLD: Fix hostapd crash during interface deinit with non-ML BSS
de49e55d7 BSS: Validate partner link BSSs while parsing Basic MLE
800e481bd MLD: Verify Per-STA Profile subelement length in reconf MLE
351089daa MLD: Fix Reconfiguration Multi-Link element parsing on non-AP MLD
53303bb3e Update the link BSS pointer during BSS reallocation on scan results
a4d2288de MACsec: Add option to always include ICV Indicator
ed423e44f authsrv: Log RADIUS accounting data
96dd8a03b RADIUS server: Add accounting message callback
373378f89 EAP-pwd: Do not include MS_FUNCS in CONFIG_FIPS=y builds
67feaa563 OpenSSL: Enable HMAC with short salt in FIPS configuration
0f92c8d8c OpenSSL: Use default provider instead of fips provider for DH group 5
6a15737b3 OpenSSL: Allow MD5 if FIPS mode or FIPS provider is set externally
573e9c1bb OpenSSL: Disable FIPS mode if MD4 is needed
1592d3416 OpenSSL: Print more failure details for EC failures
3b5b19e9c OpenSSL: Make debug log clearer on TLS initialization failure
651370325 SAE: Add an explicit debug print for failure to derive PWE
1af015a5d DPP: Remove a duplicated check for priv_key
c0b180d94 DPP: Add an explicit debug print for failed to build DPPEnvelopedData
ccc841470 SAE: Do not mark SAE enabled network disabled if PSK is not set
26c19188b OpenSSL: More debug prints on EVP digest/cipher failures
c063724b9 RADIUS: Check MD5 processing result
c073f61c4 Define additional QCA vendor roam trigger attribute values
f85a79cea Share wpa_init() error path handling
4c1ae9101 AP MLD: Search MLD-level and per-link PMKSA caches
0de2f1865 AP MLD: Store PMKSA from DPP to both per-link and MLD-level cache
4645fac93 AP MLD: Store PMKSA from control interface to both caches
c4dcf7577 AP MLD: List PMKSA entries from MLD-level cache too
a56d2bd97 AP MLD: Mark STA as MLD before checking association IEs
0d71e041b AP MLD: Store OWE/FILS PMKSA into the MLD-level PMKSA cache for MLO
8e326cabc AP MLD: Also remove from ml_pmksa when removing a PMKSA entry
c439291fc AP MLD: Store PMKSA generated from SAE authentication into ml_pmksa
799cc8eca AP MLD: Define a new MLD-level PMKSA cache shared by all links
1993770a5 Fix current_bss use in checking whether SSID has been verified
870d13f97 ERP: Initialize hapd->erp_keys earlier to avoid undefined behavior
caa22873c OpenSSL: Avoid undefined behavior in altSubjectName matching
616d85a42 Avoid undefined behavior in get_vendor_ie()
4cb1b7c31 trace: Avoid undefined behavior in backtrace search
449135c26 Remove undefined behavior from ieee802_11_defrag()
d185ab38f Fix wpa_supplicant global config bool reading/writing
e0baab3b6 mesh: Fix mesh_external_pmksa_cache initialization to cover error cases
47ff1b68f FT: Do not discard EAPOL-Start frame during initial MD association
012a893c4 wolfssl: Update suiteb ciphersuites
2ed980627 wpa_gui: Port to Qt6
39c7ef222 nl80211: Mark HT disabled on channel switch to a 6 GHz channel
b49542f42 nl80211: Fix hostapd crash when managing AP MLD interfaces
daeb5e111 EAP-TEAP: Check session_id length explicitly to avoid warnings
1bfd4398f RNR: Silence static analyzer warnings
dc05cbc46 WPS: Use 0xffff instead of -1 to set all u16 bits to 1
bc3ee85e5 AP MLD: Bounds checking for own Probe Response to silence analyzers
41398a873 nl80211: Debug print setsockopt() failures for NETLINK_EXT_ACK
97c4999f1 MLD: Try to avoid static analyzer warnings about tainted variable
a90f2f7a8 Use pointer to Action frame body instead of Category field
cb3a47247 Check random_get_bytes() output even in testing case
1c3b564af SME: Use a helper function for adding wpabuf to AssocReq IEs
bf936cdd1 P2P2: Check ssid != NULL more consistently in wpas_p2p_invite()
86dc3e369 mka: Simplify dl_list entry freeing
a36577c82 Make eht_cap != NULL check explicit to help static analyzers
553e114e0 PASN: Make ssid != NULL check easier for static analyzers
fab6e6546 P2P: Initialize new_ssid explicitly to make this easier for analyzers
741d23c3c P2P: Make sure go_dev_addr is initialized
12cd887c4 P2P2: Check peer_addr being available more consistently
714734135 Check network configuration availability before use in MAC randomization
ecf62b4d1 HS 2.0: Remove subscription remediation notification
7bb11e35d HS 2.0: Remove OSU related ANQP operations
e83528859 OSEN: Remove all OSEN functionality
f61b5faa4 XML: Remove now unused code
e960c3741 HTTP: Remove now unused code
b76b896d9 HS 2.0 client: Remove OSU/SPP/OMA-DM/EST functionality
3462d242a HS 2.0 server: Remove example OSU SPP server
326f093b9 Interworking: Prefer cred realm over realm in username for anonymous NAI
ca9f86a19 SAE: Multiple default password iteration
3e592a1a7 nl80211: Fix PASN auth alg check on big-endian CPUs
ff5248a8e nl80211: Fix HE 6 GHz capability fetching on big-endian CPUs
dacfb3956 MLD: Fix MLE parsing in for association on big-endian CPUs
7d2d4c1bd wpa_supplicant: Fix VHT SGI disabling on big-endian CPUs
4fd90f61d wpa_supplicant: Fix HT STBC capability overriding on big-endian CPUs
6b837f61b dbus: Remove unused wpas_dbus_sta_signal_prop_changed()
6dcc4c795 OpenSSL: Use proper ANSI C function declaration
f1425f2e1 RNR: Mark internal functions static
6fe387ad5 OCV: Fix HT/VHT capability check on big-endian CPUs
43dae6b35 PASN: Use NULL instead of 0 as a pointer
be7beba15 DPP: Mark internal functions static
33381b724 trace: Mark wpa_trace_test_fail static
3e4782549 SME: MLD: Fix byte order for the link reconfig MLE control field
ebfe8be3a Convert one-bit signed bitfield to unsigned
9db8ed4b9 SCS: Convert endianness of MAC Capabilities Information before use
ad8d30e0a AP MLD: Request MLO Group KDEs for a subset of links
00dc99117 nl80211: Remove support for use_monitor
539648699 AP MLD: Set WLAN_STA_ASSOC flag before copying STA entry (SME-in-driver)
90856b195 DPP: Send connection status result if disconnected during 4-way HS
ab3791d91 AP MLD: Allow new link to be added through control interface
00a7cad9c Make sure wpa_sm has correct PMK when PMKSA cache used by driver
298592db0 AP MLD: Cancel ap_sta_assoc_timeout for partner links
25876e936 Define a QCA vendor subcmd to set periodic probe response config
a971fa5b5 P2P: Check IEs buffer before use more consistently
f2bf0a638 nl80211: Avoid uninitialized err_info on test failure path
5066a39e0 Simplify supported rates and BSS membership selectors generation
ea626cb8c AP: Remove xrates_supported config
71c5ceb21 MBSSID: Add Extended Supported Rates element in MBSSID profile
085e5fa07 MBSSID: Correctly compute the Extended Supported Rates element length
2605fbc81 MBSSID: Fix Non-Inheritance element length calculation
5edbb257d GAS: Fix eloop timeout clearing on random MAC address error path
c8c7d56a3 P2P2: Reject P2P_VALIDATE_DIRA without nonce or tag
6fe367d6c EAP-pwd: Make code easier for static analyzers
c3fefaf41 JSON: More explicit check for depth in arrays/objects
50330cb91 SHA-PRF: Make code easier for static analyzers
218659c58 BSS: Clear wpa_bss pointers on bss entry removal
39b6e6efe P2P: Clear pending_listen_freq if listen failed
ec50904c1 Fix a typo in documentation of a configuration parameter
8ead26ff5 wolfSSL: Include asn.h to fix build with some library configs
13a30f10c drivers: RX-only configuration of the next TK during 4-way handshake
a58a0c592 MLD: Fix Multi-Link element parsing for association failures
a9eb687c0 AP MLD: Fix STA Info field parsing in Basic Multi-Link element
104e47a60 AP MLD: Simplify MLD MAC Address parsing from Multi-Link element
038cb0fc5 AP MLD: Fix Multi-Link element parsing in (Re)Association Request frame
2ba179722 P2P: Add Group ID info into P2P invitation control interface events
37b618743 EHT: Fix 6 GHz HE operation bandwidth for 320 MHz with puncturing
e35a79ab0 Fix crash due to iteratively calling radio_remove_works()
58ea0a652 nl80211: Fix compilation error due to uninitialized variable
5546f0ac0 Remove extra statement terminators
339a33455 RADIUS: Fix pending request dropping
b25769e48 QCA vendor values for traffic types for browsing and aperiodic bursts
f4c7c13ec Add QCA vendor test config attribute for link reconfiguration
dac63d98b Add QCA vendor attribute to enable/disable link reconfiguration support
8a8d66f00 Add QCA vendor command to trigger primary link migration
c12fc97e3 wolfssl: wc_PBKDF2() in FIPS requires unlocking the private key
e41e91a43 wolfSSL: Implement openssl_ecdh_curves
a1150cc60 wolfSSL: Simplify option setting in tls_set_conn_flags()
7bd855f34 wolfssl: Verify that session ticket setup does not fail
c38150cfe wolfssl: Actually use ocsp_stapling_response
b870181d4 wolfssl: Implement check_cert_subject
5c07e9be0 wolfssl: Add missing return in tls_init() in an error case
26e2ff781 wolfssl: Remove unused and non-compiling code for OCSP
77f82dcb3 wolfssl: Log error number on failure
0797fd2ab wolfssl: Remove unnecessary WOLFSSL_X509_STORE manipulation
59c3bd658 wolfssl: Generate events when OCSP status is revoked
49d0c323a wolfssl: Set additional sigalgs when using anonymous cipher
f50f530da wolfssl: Implement SuiteB ciphersuites
99239d08d wolfssl: Implement RSA-OAEP-SHA256 for EAP-AKA privacy protection
5ed2778db wolfssl: Support tod policy
34914311c wolfssl: Fix get_x509_cert()
d83903545 wolfssl: Use defines for ex_data access
a3890142d wolfssl: Simplify tls_get_cipher()
400b89162 OpenSSL: Use pkcs11-provider when OPENSSL_NO_ENGINE is defined
d37045e85 AP: Fix disconnect from EAPOL state machine handling
c924335ad AP: Include the Probe Request frame inside RX_PROBE_REQUEST event
5545ca8f9 GnuTLS: Do not override priority string on shutdown for reauth
26d64d737 GnuTLS: Use standard comment for falling through switch case
4a504c4e5 GnuTLS: Disable TLS 1.3 if instructed
5543f5efa wpa_supplicant: Use wpa_dbg() for "Successfully set 4addr mode"
9693a9018 Extend QCA vendor attributes for PASN offload from driver to userspace
24ef9862f nl80211: Send a list of BSS membership selectors supported by SME
2d2c42a47 AP: Only include SAE H2E BSS membership selector if SAE is required
bb6b2b854 Sync with wireless-next.git include/uapi/linux/nl80211.h
82c60dd54 STA: Support SPP A-MSDU negotiation
9c03bb14d nl80211: Option to tell the driver about SPP A-MSDUs in assoc params
61f505078 AP: Support SPP A-MSDU negotiation
27aedf346 AP: Add spp_amsdu configuration parameter
72ffc71d5 nl80211: SPP A-MSDU driver capability
f8d02941b RSNXE definition of SPP A-MSDU Capable
43c65f8a5 AP: Add a csa_ie_only testing option
4ba989fd3 NAN USD: Add NAN_UNPAUSE_PUBLISH to cancel pauseState
5b0201a27 hostapd: Fix 'start_disabled' option being ignored
0ca781b93 build: Disable some optimizations if TRACE_BFD is enabled
92cea9a77 P2P: Provide better failure reason for group formation errors
1ce37105d ext_password_file: Ensure full key match with password file entries
77ff2b61a STA: Known STA Identification to skip association comeback mechanism
e62c2dc09 AP: Known STA Identification to skip association comeback mechanism
726432d76 RADIUS: Drop pending request only when accepting the response
6799809ee P2P2: Bootstrapping through wpas_p2p_prov_disc()
9f7dc9c30 P2P2: Control interface command to validate DIRA info
fee68c237 P2P2: Control interface command to get DIRA info of a P2P device
99de77c57 P2P2: Save the latest nonce and tag from a P2P USD discovery frame
7c9081685 wlantest: Parse Link Reconfiguration Request/Response
9e95f0d38 AP MLD: Skip over Extended MLD Capabilities And Operations field
b375b7630 Do not write mesh_fwding network parameter if it has default value
b6cab22c2 P2P2: Update P2P_INVITE processing for SSID randomization
374353d31 P2P2: SSID randomization on group reinvoke
ce193d6e1 P2P: Make p2p_build_ssid() available outside src/p2p
ec4569174 P2P2: Store ID of Device Identity block in network block
c96fd75b1 P2P2: Add USD service hash in the P2P2 PASN M1 frame
4845c87eb P2P2: Random PMKID in pairing verification
99905ab44 P2P2: Return ID of identity block for p2p_validate_dira()
f92959500 P2P2: Add DIRA to PASN-M1 during pairing verification
ee41bacfa OWE: Consider the currently associated transition mode SSID known
b0f587944 Do not remove a currently used BSS entry when removing oldest unknown BSS
c78295c35 nl80211: Fix compilation error when CONFIG_DRIVER_NL80211_BRCM is enabled
d73ad8cbc Enable beacon protection if IEEE 802.11be/EHT is enabled for BSS
9cb7b0bce DPP: Discard DPP Action frame in AP mode if no global DPP context
12f1edc9e RSNO: Generate IGTK if any of the RSN variants has PMF enabled
dd65d13ce Add QCA vendor attribute for BTM reject support
001a728fe Add QCA vendor attribute for extra EHT-LTF support
c54f4aab6 Add QCA vendor attribute for triggered SU BF support
BYPASS_INCLUSIVE_LANGUAGE_REASON=Merged from open source
Change-Id: I0e1b0cda9e035d946283b6a83a1f6d796b882bb7
Signed-off-by: Sunil Ravi <sunilravi@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index c8fbb6a..69550cf 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -793,6 +793,8 @@
#ifdef CONFIG_SAE_PK
sae_deinit_pk(tmp->pk);
#endif /* CONFIG_SAE_PK */
+ os_free(tmp->success_mac);
+ os_free(tmp->fail_mac);
os_free(tmp);
}
}
@@ -931,31 +933,6 @@
os_free(conf->hs20_wan_metrics);
os_free(conf->hs20_connection_capability);
os_free(conf->hs20_operating_class);
- os_free(conf->hs20_icons);
- if (conf->hs20_osu_providers) {
- for (i = 0; i < conf->hs20_osu_providers_count; i++) {
- struct hs20_osu_provider *p;
- size_t j;
- p = &conf->hs20_osu_providers[i];
- os_free(p->friendly_name);
- os_free(p->server_uri);
- os_free(p->method_list);
- for (j = 0; j < p->icons_count; j++)
- os_free(p->icons[j]);
- os_free(p->icons);
- os_free(p->osu_nai);
- os_free(p->osu_nai2);
- os_free(p->service_desc);
- }
- os_free(conf->hs20_osu_providers);
- }
- if (conf->hs20_operator_icon) {
- for (i = 0; i < conf->hs20_operator_icon_count; i++)
- os_free(conf->hs20_operator_icon[i]);
- os_free(conf->hs20_operator_icon);
- }
- os_free(conf->subscr_remediation_url);
- os_free(conf->hs20_sim_provisioning_url);
os_free(conf->t_c_filename);
os_free(conf->t_c_server_url);
#endif /* CONFIG_HS20 */
@@ -1513,6 +1490,13 @@
wpa_printf(MSG_INFO,
"Disabling IEEE 802.11be as IEEE 802.11ax is disabled for this BSS");
}
+
+ if (full_config && conf->ieee80211be && !bss->disable_11be &&
+ !bss->beacon_prot && ap_pmf_enabled(bss)) {
+ bss->beacon_prot = 1;
+ wpa_printf(MSG_INFO,
+ "Enabling beacon protection as IEEE 802.11be is enabled for this BSS");
+ }
#endif /* CONFIG_IEEE80211BE */
if (full_config && bss->ignore_broadcast_ssid && conf->mbssid) {
@@ -1521,6 +1505,13 @@
return -1;
}
+ /* Do not advertise SPP A-MSDU support if not using CCMP/GCMP */
+ if (full_config && bss->spp_amsdu &&
+ !(bss->wpa &&
+ bss->rsn_pairwise & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
+ WPA_CIPHER_GCMP_256 | WPA_CIPHER_GCMP)))
+ bss->spp_amsdu = false;
+
return 0;
}
@@ -1687,11 +1678,6 @@
if (full_config)
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
#endif /* CONFIG_WEP */
- } else if (bss->osen) {
- bss->ssid.security_policy = SECURITY_OSEN;
- bss->wpa_group = WPA_CIPHER_CCMP;
- bss->wpa_pairwise = 0;
- bss->rsn_pairwise = WPA_CIPHER_CCMP;
} else {
bss->ssid.security_policy = SECURITY_PLAINTEXT;
if (full_config) {
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index d33ba9d..a587b96 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -93,7 +93,6 @@
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4,
- SECURITY_OSEN = 5
} secpolicy;
struct hostapd_ssid {
@@ -189,7 +188,6 @@
unsigned int wildcard_prefix:1;
unsigned int password_hash:1; /* whether password is hashed with
* nt_password_hash() */
- unsigned int remediation:1;
unsigned int macacl:1;
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
struct hostapd_radius_attr *accept_attr;
@@ -260,6 +258,10 @@
int vlan_id;
struct sae_pt *pt;
struct sae_pk *pk;
+ u8 *success_mac;
+ unsigned int num_success_mac, next_success_mac;
+ u8 *fail_mac;
+ unsigned int num_fail_mac, next_fail_mac;
};
struct dpp_controller_conf {
@@ -465,6 +467,7 @@
char *radius_server_clients;
int radius_server_auth_port;
int radius_server_acct_port;
+ int radius_server_acct_log;
int radius_server_ipv6;
int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
@@ -620,7 +623,6 @@
u8 qos_map_set[16 + 2 * 21];
unsigned int qos_map_set_len;
- int osen;
int proxy_arp;
int na_mcast_to_ucast;
@@ -636,37 +638,7 @@
size_t hs20_connection_capability_len;
u8 *hs20_operating_class;
u8 hs20_operating_class_len;
- struct hs20_icon {
- u16 width;
- u16 height;
- char language[3];
- char type[256];
- char name[256];
- char file[256];
- } *hs20_icons;
- size_t hs20_icons_count;
- u8 osu_ssid[SSID_MAX_LEN];
- size_t osu_ssid_len;
- struct hs20_osu_provider {
- unsigned int friendly_name_count;
- struct hostapd_lang_string *friendly_name;
- char *server_uri;
- int *method_list;
- char **icons;
- size_t icons_count;
- char *osu_nai;
- char *osu_nai2;
- unsigned int service_desc_count;
- struct hostapd_lang_string *service_desc;
- } *hs20_osu_providers, *last_osu;
- size_t hs20_osu_providers_count;
- size_t hs20_osu_providers_nai_count;
- char **hs20_operator_icon;
- size_t hs20_operator_icon_count;
unsigned int hs20_deauth_req_timeout;
- char *subscr_remediation_url;
- u8 subscr_remediation_method;
- char *hs20_sim_provisioning_url;
char *t_c_filename;
u32 t_c_timestamp;
char *t_c_server_url;
@@ -688,6 +660,7 @@
enum sae_pwe sae_pwe;
int *sae_groups;
struct sae_password_entry *sae_passwords;
+ int sae_track_password;
char *wowlan_triggers; /* Wake-on-WLAN triggers */
@@ -919,6 +892,14 @@
int macsec_csindex;
/**
+ * macsec_icv_indicator - Always include ICV Indicator
+ * (for compatibility with older MACsec switches)
+ *
+ * Range: 0-1 (default: 0)
+ */
+ int macsec_icv_indicator;
+
+ /**
* mka_ckn - MKA pre-shared CKN
*/
#define MACSEC_CKN_MAX_LEN 32
@@ -972,9 +953,9 @@
u8 rnr;
char *config_id;
- bool xrates_supported;
bool ssid_protection;
+ bool known_sta_identification;
#ifdef CONFIG_IEEE80211BE
/* The AP is part of an AP MLD */
@@ -995,6 +976,8 @@
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */
int mbssid_index;
+
+ bool spp_amsdu;
};
/**
@@ -1152,9 +1135,10 @@
double ignore_assoc_probability;
double ignore_reassoc_probability;
double corrupt_gtk_rekey_mic_probability;
- int ecsa_ie_only;
unsigned int skip_send_eapol;
unsigned int enable_eapol_large_timeout;
+ int ecsa_ie_only;
+ int csa_ie_only;
bool delay_eapol_tx;
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 65e83f4..d342132 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -39,6 +39,8 @@
res |= WPA_STA_AUTHENTICATED;
if (flags & WLAN_STA_ASSOC)
res |= WPA_STA_ASSOCIATED;
+ if (flags & WLAN_STA_SPP_AMSDU)
+ res |= WPA_STA_SPP_AMSDU;
return res;
}
@@ -183,11 +185,6 @@
if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
add_buf_data(&proberesp, buf, pos - buf) < 0)
goto fail;
-
- pos = hostapd_eid_osen(hapd, buf);
- if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
- add_buf_data(&proberesp, buf, pos - buf) < 0)
- goto fail;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index cbb8044..b527636 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -491,6 +491,6 @@
int hostapd_drv_add_pmkid(struct hostapd_data *hapd,
struct wpa_pmkid_params *params);
int hostapd_add_pmkid(struct hostapd_data *hapd, const u8 *bssid, const u8 *pmk,
- size_t pmk_len, const u8 *pmkid, int akmp);;
+ size_t pmk_len, const u8 *pmkid, int akmp);
#endif /* AP_DRV_OPS */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 630cef6..3e80318 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -14,6 +14,7 @@
#include "eap_server/eap.h"
#include "eap_server/eap_sim_db.h"
#include "eapol_auth/eapol_auth_sm.h"
+#include "radius/radius.h"
#include "radius/radius_server.h"
#include "hostapd.h"
#include "ap_config.h"
@@ -89,7 +90,6 @@
user->force_version = eap_user->force_version;
user->macacl = eap_user->macacl;
user->ttls_auth = eap_user->ttls_auth;
- user->remediation = eap_user->remediation;
user->accept_attr = eap_user->accept_attr;
user->t_c_timestamp = eap_user->t_c_timestamp;
rv = 0;
@@ -102,6 +102,114 @@
}
+/**
+ * hostapd_radius_log_acct_req - Callback for logging received RADIUS
+ * accounting requests
+ * @ctx: Context (struct hostapd_data)
+ * @msg: Received RADIUS accounting request
+ * @status_type: Status type from the message (parsed Acct-Status-Type
+ * attribute)
+ * Returns: 0 on success, -1 on failure
+ */
+static int hostapd_radius_log_acct_req(void *ctx, struct radius_msg *msg,
+ u32 status_type)
+{
+ char nas_id[RADIUS_MAX_ATTR_LEN + 1] = "";
+ char session_id[RADIUS_MAX_ATTR_LEN + 1] = "";
+ char username[RADIUS_MAX_ATTR_LEN + 1] = "";
+ char calling_station_id[3 * ETH_ALEN] = "";
+ u32 session_time = 0, terminate_cause = 0,
+ bytes_in = 0, bytes_out = 0,
+ packets_in = 0, packets_out = 0,
+ gigawords_in = 0, gigawords_out = 0;
+ unsigned long long total_bytes_in = 0, total_bytes_out = 0;
+
+ /* Parse NAS identification (required by RFC 2866, section 4.1) */
+ if (radius_msg_get_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, (u8 *) nas_id,
+ sizeof(nas_id) - 1))
+ nas_id[0] = '\0';
+
+ /* Process Accounting-On and Accounting-Off messages separately */
+ if (status_type == RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON ||
+ status_type == RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF) {
+ wpa_printf(MSG_INFO, "RADIUS ACCT: NAS='%s' status='%s'",
+ nas_id,
+ status_type == RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON
+ ? "Accounting-On" : "Accounting-Off");
+ return 0;
+ }
+
+ /* Parse session ID (required by RFC 2866, section 5.5) */
+ if (radius_msg_get_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+ (u8 *) session_id,
+ sizeof(session_id) - 1) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS ACCT: request doesn't include session ID");
+ return -1;
+ }
+
+ /* Parse user name */
+ radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) username,
+ sizeof(username) - 1);
+
+ /* Parse device identifier */
+ radius_msg_get_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ (u8 *) calling_station_id,
+ sizeof(calling_station_id) - 1);
+
+ switch (status_type) {
+ case RADIUS_ACCT_STATUS_TYPE_START:
+ wpa_printf(MSG_INFO,
+ "RADIUS ACCT: NAS='%s' session='%s' status='Accounting-Start' station='%s' username='%s'",
+ nas_id, session_id, calling_station_id, username);
+ break;
+ case RADIUS_ACCT_STATUS_TYPE_STOP:
+ case RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE:
+ /* Parse counters */
+ radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
+ &session_time);
+ radius_msg_get_attr_int32(msg,
+ RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
+ &terminate_cause);
+ radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INPUT_OCTETS,
+ &bytes_in);
+ radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
+ &bytes_out);
+ radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INPUT_PACKETS,
+ &packets_in);
+ radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
+ &packets_out);
+ radius_msg_get_attr_int32(msg,
+ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
+ &gigawords_in);
+ radius_msg_get_attr_int32(msg,
+ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
+ &gigawords_out);
+
+ /* RFC 2869, section 5.1 and 5.2 */
+ total_bytes_in = ((u64) gigawords_in << 32) + bytes_in;
+ total_bytes_out = ((u64) gigawords_out << 32) + bytes_out;
+
+ wpa_printf(MSG_INFO,
+ "RADIUS ACCT: NAS='%s' session='%s' status='%s' station='%s' username='%s' session_time=%u term_cause=%u pck_in=%u pck_out=%u bytes_in=%llu bytes_out=%llu",
+ nas_id, session_id,
+ status_type == RADIUS_ACCT_STATUS_TYPE_STOP ?
+ "Accounting-Stop" : "Accounting-Interim-Update",
+ calling_station_id, username, session_time,
+ terminate_cause, packets_in, packets_out,
+ total_bytes_in, total_bytes_out);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "RADIUS ACCT: Unknown request status type %u",
+ status_type);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
{
struct radius_server_conf srv;
@@ -129,6 +237,8 @@
srv.conf_ctx = hapd;
srv.ipv6 = conf->radius_server_ipv6;
srv.get_eap_user = hostapd_radius_get_eap_user;
+ if (conf->radius_server_acct_log)
+ srv.acct_req_cb = hostapd_radius_log_acct_req;
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
srv.sqlite_file = conf->eap_user_sqlite;
@@ -136,9 +246,6 @@
srv.dump_msk_file = conf->dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
#ifdef CONFIG_HS20
- srv.subscr_remediation_url = conf->subscr_remediation_url;
- srv.subscr_remediation_method = conf->subscr_remediation_method;
- srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url;
srv.t_c_server_url = conf->t_c_server_url;
#endif /* CONFIG_HS20 */
srv.erp_domain = conf->erp_domain;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 542768d..a7d7ecd 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -403,19 +403,6 @@
}
-static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len)
-{
- const u8 *ie;
-
- ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE);
- if (!ie || 2U + ie[1] > len)
- return pos;
-
- os_memcpy(pos, ie, 2 + ie[1]);
- return pos + 2 + ie[1];
-}
-
-
static u8 * hostapd_get_rsne_override(struct hostapd_data *hapd, u8 *pos,
size_t len)
{
@@ -516,6 +503,11 @@
if (!hapd->cs_freq_params.channel || !hapd->iface->cs_oper_class)
return eid;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (hapd->iconf->csa_ie_only)
+ return eid;
+#endif /* CONFIG_TESTING_OPTIONS */
+
*eid++ = WLAN_EID_EXT_CHANSWITCH_ANN;
*eid++ = 4;
*eid++ = hapd->cs_block_tx;
@@ -593,7 +585,6 @@
size_t len, rnr_len = 0;
u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end;
u8 rnr_elem_count = 0, *rnr_elem = NULL, **rnr_elem_offset = NULL;
- size_t i;
if (!iface->mbssid_max_interfaces ||
iface->num_bss > iface->mbssid_max_interfaces ||
@@ -601,14 +592,6 @@
!iface->ema_max_periodicity))
goto fail;
- /* Make sure bss->xrates_supported is set for all BSSs to know whether
- * it need to be non-inherited. */
- for (i = 0; i < iface->num_bss; i++) {
- u8 buf[100];
-
- hostapd_eid_ext_supp_rates(iface->bss[i], buf);
- }
-
tx_bss = hostapd_mbssid_get_tx_bss(hapd);
len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count,
NULL, 0, &rnr_len);
@@ -959,9 +942,8 @@
pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
- /* WPA / OSEN */
+ /* WPA */
pos = hostapd_get_wpa_ie(hapd, pos, epos - pos);
- pos = hostapd_get_osen_ie(hapd, pos, epos - pos);
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -1427,6 +1409,7 @@
size_t csa_offs_len;
struct radius_sta rad_info;
struct probe_resp_params params;
+ char *hex = NULL;
#ifdef CONFIG_IEEE80211BE
int mld_id;
u16 links;
@@ -1659,8 +1642,20 @@
if (hapd != hostapd_mbssid_get_tx_bss(hapd) && res != EXACT_SSID_MATCH)
return;
+ if (hapd->conf->notify_mgmt_frames) {
+ size_t hex_len;
+
+ hex_len = len * 2 + 1;
+ hex = os_malloc(hex_len);
+ if (hex)
+ wpa_snprintf_hex(hex, hex_len, (const u8 *) mgmt, len);
+ }
+
wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR
- " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
+ " signal=%d%s%s", MAC2STR(mgmt->sa), ssi_signal,
+ hex ? " buf=" : "", hex ? hex : "");
+
+ os_free(hex);
os_memset(¶ms, 0, sizeof(params));
@@ -2414,9 +2409,8 @@
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
- /* WPA / OSEN */
+ /* WPA */
tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos);
- tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos);
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
@@ -2588,10 +2582,6 @@
#endif /* CONFIG_P2P */
#ifdef CONFIG_HS20
params->disable_dgaf = hapd->conf->disable_dgaf;
- if (hapd->conf->osen) {
- params->privacy = 1;
- params->osen = 1;
- }
#endif /* CONFIG_HS20 */
params->multicast_to_unicast = hapd->conf->multicast_to_unicast;
params->pbss = hapd->conf->pbss;
@@ -3111,7 +3101,7 @@
{
bool tx_vap = hapd == hostapd_mbssid_get_tx_bss(hapd);
size_t link_data_len, sta_profile_len;
- size_t own_data_len;
+ size_t own_data_len, fixed;
struct probe_resp_params link_params;
struct probe_resp_params own_params;
struct ieee80211_mgmt *link_data;
@@ -3139,7 +3129,10 @@
own_data_len = own_params.resp_len;
/* Consider the length of the variable fields */
- own_data_len -= offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ fixed = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ if (own_data_len < fixed)
+ goto fail;
+ own_data_len -= fixed;
for_each_mld_link(link_bss, hapd) {
if (link_bss == hapd || !link_bss->started)
@@ -3164,8 +3157,10 @@
link_data_len = link_params.resp_len;
/* Consider length of the variable fields */
- link_data_len -= offsetof(struct ieee80211_mgmt,
- u.probe_resp.variable);
+ fixed = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ if (link_data_len < fixed)
+ continue;
+ link_data_len -= fixed;
sta_profile = hostapd_gen_sta_profile(link_data, link_data_len,
own_data, own_data_len,
@@ -3198,6 +3193,7 @@
os_free(link_params.resp);
}
+fail:
os_free(own_params.resp);
}
@@ -3248,7 +3244,8 @@
continue;
#endif /* CONFIG_IEEE80211BE */
- if (other->bss[i] && other->bss[i]->started)
+ if (other->bss[i] && other->bss[i]->started &&
+ other->bss[i]->beacon_set_done)
__ieee802_11_set_beacon(other->bss[i]);
}
}
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 4a51e63..441995b 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1198,6 +1198,7 @@
size_t pmk_len;
char *pos, *pos2;
int akmp = 0, expiration = 0;
+ int ret;
/*
* Entry format:
@@ -1233,8 +1234,18 @@
if (sscanf(pos, "%d %d", &expiration, &akmp) != 2)
return -1;
- return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
- pmkid, expiration, akmp, NULL);
+ ret = wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
+ pmkid, expiration, akmp, NULL, false);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap)
+ ret = wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len,
+ pmkid, expiration, akmp, NULL, true);
+#endif /* CONFIG_IEEE80211BE */
+
+ return ret;
}
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index 3dc4639..d94ca9e 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -2160,11 +2160,22 @@
if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
intro.pmkid, expiration,
- WPA_KEY_MGMT_DPP, pkhash) < 0) {
+ WPA_KEY_MGMT_DPP, pkhash, false) < 0) {
wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
goto done;
}
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap &&
+ wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
+ intro.pmkid, expiration,
+ WPA_KEY_MGMT_DPP, pkhash, true) < 0) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to add PMKSA cache entry (MLD)");
+ goto done;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
DPP_STATUS_OK);
done:
@@ -2934,11 +2945,22 @@
if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
intro.pmkid, expiration,
- WPA_KEY_MGMT_DPP, pkhash) < 0) {
+ WPA_KEY_MGMT_DPP, pkhash, false) < 0) {
wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
goto done;
}
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap &&
+ wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
+ intro.pmkid, expiration,
+ WPA_KEY_MGMT_DPP, pkhash, true) < 0) {
+ wpa_printf(MSG_ERROR,
+ "DPP: Failed to add PMKSA cache entry (MLD)");
+ goto done;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction completed with "
MACSTR, MAC2STR(src));
@@ -2958,6 +2980,10 @@
const u8 *hdr;
unsigned int pkex_t;
+ /* Discard DPP Action frames if there is no global DPP context */
+ if (!hapd->iface->interfaces || !hapd->iface->interfaces->dpp)
+ return;
+
if (len < DPP_HDR_LEN)
return;
if (WPA_GET_BE24(buf) != OUI_WFA || buf[3] != DPP_OUI_TYPE)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 82a922e..0b4613e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -366,12 +366,6 @@
ie = elems.wpa_ie - 2;
ielen = elems.wpa_ie_len + 2;
wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
-#ifdef CONFIG_HS20
- } else if (elems.osen) {
- ie = elems.osen - 2;
- ielen = elems.osen_len + 2;
- wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
-#endif /* CONFIG_HS20 */
} else {
ie = NULL;
ielen = 0;
@@ -579,7 +573,8 @@
elems.rsnxe ? elems.rsnxe - 2 : NULL,
elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
- elems.owe_dh, elems.owe_dh_len, NULL);
+ elems.owe_dh, elems.owe_dh_len, NULL,
+ ap_sta_is_mld(hapd, sta));
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
switch (res) {
@@ -649,6 +644,11 @@
else
sta->flags &= ~WLAN_STA_MFP;
+ if (wpa_auth_uses_spp_amsdu(sta->wpa_sm))
+ sta->flags |= WLAN_STA_SPP_AMSDU;
+ else
+ sta->flags &= ~WLAN_STA_SPP_AMSDU;
+
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
@@ -713,29 +713,6 @@
sta->flags |= WLAN_STA_MAYBE_WPS;
wpabuf_free(wps);
#endif /* CONFIG_WPS */
-#ifdef CONFIG_HS20
- } else if (hapd->conf->osen) {
- if (elems.osen == NULL) {
- hostapd_logger(
- hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO,
- "No HS 2.0 OSEN element in association request");
- return WLAN_STATUS_INVALID_IE;
- }
-
- wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
- if (sta->wpa_sm == NULL)
- sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
- sta->addr, NULL);
- if (sta->wpa_sm == NULL) {
- wpa_printf(MSG_WARNING,
- "Failed to initialize WPA state machine");
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
- if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
- elems.osen - 2, elems.osen_len + 2) < 0)
- return WLAN_STATUS_INVALID_IE;
-#endif /* CONFIG_HS20 */
}
#ifdef CONFIG_WPS
skip_wpa_check:
@@ -918,6 +895,12 @@
}
#endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
+
+ hostapd_set_sta_flags(hapd, sta);
+
#ifdef CONFIG_IEEE80211BE
if (hostapd_process_assoc_ml_info(hapd, sta, req_ies, req_ies_len,
!!reassoc, WLAN_STATUS_SUCCESS,
@@ -928,11 +911,6 @@
}
#endif /* CONFIG_IEEE80211BE */
- new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
- sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
- sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
-
- hostapd_set_sta_flags(hapd, sta);
if (updated)
ap_sta_set_authorized_event(hapd, sta, 1);
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
index a510ee3..c0e9030 100644
--- a/src/ap/eap_user_db.c
+++ b/src/ap/eap_user_db.c
@@ -89,8 +89,6 @@
user->next = (void *) 1;
} else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
set_user_methods(user, argv[i]);
- } else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
- user->remediation = strlen(argv[i]) > 0;
} else if (os_strcmp(col[i], "t_c_timestamp") == 0 && argv[i]) {
user->t_c_timestamp = strtol(argv[i], NULL, 10);
}
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 4642e49..13cf766 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -179,14 +179,6 @@
wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
if (hapd->conf->hs20_operating_class)
wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
- if (hapd->conf->hs20_osu_providers_count)
- wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
- if (hapd->conf->hs20_osu_providers_nai_count)
- wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
- if (hapd->conf->hs20_icons_count)
- wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
- if (hapd->conf->hs20_operator_icon_count)
- wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
gas_anqp_set_element_len(buf, len);
}
#endif /* CONFIG_HS20 */
@@ -706,232 +698,6 @@
}
}
-
-static void anqp_add_icon(struct wpabuf *buf, struct hostapd_bss_config *bss,
- const char *name)
-{
- size_t j;
- struct hs20_icon *icon = NULL;
-
- for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
- if (os_strcmp(name, bss->hs20_icons[j].name) == 0)
- icon = &bss->hs20_icons[j];
- }
- if (!icon)
- return; /* icon info not found */
-
- wpabuf_put_le16(buf, icon->width);
- wpabuf_put_le16(buf, icon->height);
- wpabuf_put_data(buf, icon->language, 3);
- wpabuf_put_u8(buf, os_strlen(icon->type));
- wpabuf_put_str(buf, icon->type);
- wpabuf_put_u8(buf, os_strlen(icon->name));
- wpabuf_put_str(buf, icon->name);
-}
-
-
-static void anqp_add_osu_provider(struct wpabuf *buf,
- struct hostapd_bss_config *bss,
- struct hs20_osu_provider *p)
-{
- u8 *len, *len2, *count;
- unsigned int i;
-
- len = wpabuf_put(buf, 2); /* OSU Provider Length to be filled */
-
- /* OSU Friendly Name Duples */
- len2 = wpabuf_put(buf, 2);
- for (i = 0; i < p->friendly_name_count; i++) {
- struct hostapd_lang_string *s = &p->friendly_name[i];
- wpabuf_put_u8(buf, 3 + s->name_len);
- wpabuf_put_data(buf, s->lang, 3);
- wpabuf_put_data(buf, s->name, s->name_len);
- }
- WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
-
- /* OSU Server URI */
- if (p->server_uri) {
- wpabuf_put_u8(buf, os_strlen(p->server_uri));
- wpabuf_put_str(buf, p->server_uri);
- } else
- wpabuf_put_u8(buf, 0);
-
- /* OSU Method List */
- count = wpabuf_put(buf, 1);
- for (i = 0; p->method_list && p->method_list[i] >= 0; i++)
- wpabuf_put_u8(buf, p->method_list[i]);
- *count = i;
-
- /* Icons Available */
- len2 = wpabuf_put(buf, 2);
- for (i = 0; i < p->icons_count; i++)
- anqp_add_icon(buf, bss, p->icons[i]);
- WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
-
- /* OSU_NAI */
- if (p->osu_nai) {
- wpabuf_put_u8(buf, os_strlen(p->osu_nai));
- wpabuf_put_str(buf, p->osu_nai);
- } else
- wpabuf_put_u8(buf, 0);
-
- /* OSU Service Description Duples */
- len2 = wpabuf_put(buf, 2);
- for (i = 0; i < p->service_desc_count; i++) {
- struct hostapd_lang_string *s = &p->service_desc[i];
- wpabuf_put_u8(buf, 3 + s->name_len);
- wpabuf_put_data(buf, s->lang, 3);
- wpabuf_put_data(buf, s->name, s->name_len);
- }
- WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
-
- WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
-}
-
-
-static void anqp_add_osu_providers_list(struct hostapd_data *hapd,
- struct wpabuf *buf)
-{
- if (hapd->conf->hs20_osu_providers_count) {
- size_t i;
- u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
- wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
- wpabuf_put_u8(buf, 0); /* Reserved */
-
- /* OSU SSID */
- wpabuf_put_u8(buf, hapd->conf->osu_ssid_len);
- wpabuf_put_data(buf, hapd->conf->osu_ssid,
- hapd->conf->osu_ssid_len);
-
- /* Number of OSU Providers */
- wpabuf_put_u8(buf, hapd->conf->hs20_osu_providers_count);
-
- for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
- anqp_add_osu_provider(
- buf, hapd->conf,
- &hapd->conf->hs20_osu_providers[i]);
- }
-
- gas_anqp_set_element_len(buf, len);
- }
-}
-
-
-static void anqp_add_osu_provider_nai(struct wpabuf *buf,
- struct hs20_osu_provider *p)
-{
- /* OSU_NAI for shared BSS (Single SSID) */
- if (p->osu_nai2) {
- wpabuf_put_u8(buf, os_strlen(p->osu_nai2));
- wpabuf_put_str(buf, p->osu_nai2);
- } else {
- wpabuf_put_u8(buf, 0);
- }
-}
-
-
-static void anqp_add_osu_providers_nai_list(struct hostapd_data *hapd,
- struct wpabuf *buf)
-{
- if (hapd->conf->hs20_osu_providers_nai_count) {
- size_t i;
- u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
- wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
- wpabuf_put_u8(buf, 0); /* Reserved */
-
- for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
- anqp_add_osu_provider_nai(
- buf, &hapd->conf->hs20_osu_providers[i]);
- }
-
- gas_anqp_set_element_len(buf, len);
- }
-}
-
-
-static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
- struct wpabuf *buf,
- const u8 *name, size_t name_len)
-{
- struct hs20_icon *icon;
- size_t i;
- u8 *len;
-
- wpa_hexdump_ascii(MSG_DEBUG, "HS 2.0: Requested Icon Filename",
- name, name_len);
- for (i = 0; i < hapd->conf->hs20_icons_count; i++) {
- icon = &hapd->conf->hs20_icons[i];
- if (name_len == os_strlen(icon->name) &&
- os_memcmp(name, icon->name, name_len) == 0)
- break;
- }
-
- if (i < hapd->conf->hs20_icons_count)
- icon = &hapd->conf->hs20_icons[i];
- else
- icon = NULL;
-
- len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
- wpabuf_put_u8(buf, HS20_STYPE_ICON_BINARY_FILE);
- wpabuf_put_u8(buf, 0); /* Reserved */
-
- if (icon) {
- char *data;
- size_t data_len;
-
- data = os_readfile(icon->file, &data_len);
- if (data == NULL || data_len > 65535) {
- wpabuf_put_u8(buf, 2); /* Download Status:
- * Unspecified file error */
- wpabuf_put_u8(buf, 0);
- wpabuf_put_le16(buf, 0);
- } else {
- wpabuf_put_u8(buf, 0); /* Download Status: Success */
- wpabuf_put_u8(buf, os_strlen(icon->type));
- wpabuf_put_str(buf, icon->type);
- wpabuf_put_le16(buf, data_len);
- wpabuf_put_data(buf, data, data_len);
- }
- os_free(data);
- } else {
- wpabuf_put_u8(buf, 1); /* Download Status: File not found */
- wpabuf_put_u8(buf, 0);
- wpabuf_put_le16(buf, 0);
- }
-
- gas_anqp_set_element_len(buf, len);
-}
-
-
-static void anqp_add_operator_icon_metadata(struct hostapd_data *hapd,
- struct wpabuf *buf)
-{
- struct hostapd_bss_config *bss = hapd->conf;
- size_t i;
- u8 *len;
-
- if (!bss->hs20_operator_icon_count)
- return;
-
- len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
-
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
- wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_ICON_METADATA);
- wpabuf_put_u8(buf, 0); /* Reserved */
-
- for (i = 0; i < bss->hs20_operator_icon_count; i++)
- anqp_add_icon(buf, bss, bss->hs20_operator_icon[i]);
-
- gas_anqp_set_element_len(buf, len);
-}
-
#endif /* CONFIG_HS20 */
@@ -973,7 +739,6 @@
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request,
const u8 *home_realm, size_t home_realm_len,
- const u8 *icon_name, size_t icon_name_len,
const u16 *extra_req,
unsigned int num_extra_req)
{
@@ -984,8 +749,6 @@
len = 1400;
if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
len += 1000;
- if (request & ANQP_REQ_ICON_REQUEST)
- len += 65536;
#ifdef CONFIG_FILS
if (request & ANQP_FILS_REALM_INFO)
len += 2 * dl_list_len(&hapd->conf->fils_realms);
@@ -1054,14 +817,6 @@
anqp_add_connection_capability(hapd, buf);
if (request & ANQP_REQ_OPERATING_CLASS)
anqp_add_operating_class(hapd, buf);
- if (request & ANQP_REQ_OSU_PROVIDERS_LIST)
- anqp_add_osu_providers_list(hapd, buf);
- if (request & ANQP_REQ_ICON_REQUEST)
- anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
- if (request & ANQP_REQ_OPERATOR_ICON_METADATA)
- anqp_add_operator_icon_metadata(hapd, buf);
- if (request & ANQP_REQ_OSU_PROVIDERS_NAI_LIST)
- anqp_add_osu_providers_nai_list(hapd, buf);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MBO
@@ -1079,8 +834,6 @@
unsigned int request;
const u8 *home_realm_query;
size_t home_realm_query_len;
- const u8 *icon_name;
- size_t icon_name_len;
int p2p_sd;
u16 extra_req[ANQP_MAX_EXTRA_REQ];
unsigned int num_extra_req;
@@ -1245,20 +998,6 @@
set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
hapd->conf->hs20_operating_class != NULL, qi);
break;
- case HS20_STYPE_OSU_PROVIDERS_LIST:
- set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
- hapd->conf->hs20_osu_providers_count, qi);
- break;
- case HS20_STYPE_OPERATOR_ICON_METADATA:
- set_anqp_req(ANQP_REQ_OPERATOR_ICON_METADATA,
- "Operator Icon Metadata",
- hapd->conf->hs20_operator_icon_count, qi);
- break;
- case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
- set_anqp_req(ANQP_REQ_OSU_PROVIDERS_NAI_LIST,
- "OSU Providers NAI List",
- hapd->conf->hs20_osu_providers_nai_count, qi);
- break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
subtype);
@@ -1284,23 +1023,6 @@
}
-static void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
- const u8 *pos, const u8 *end,
- struct anqp_query_info *qi)
-{
- qi->request |= ANQP_REQ_ICON_REQUEST;
- qi->icon_name = pos;
- qi->icon_name_len = end - pos;
- if (hapd->conf->hs20_icons_count) {
- wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query "
- "(local)");
- } else {
- wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query not "
- "available");
- }
-}
-
-
static void rx_anqp_vendor_specific_hs20(struct hostapd_data *hapd,
const u8 *pos, const u8 *end,
struct anqp_query_info *qi)
@@ -1323,9 +1045,6 @@
case HS20_STYPE_NAI_HOME_REALM_QUERY:
rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
break;
- case HS20_STYPE_ICON_REQUEST:
- rx_anqp_hs_icon_request(hapd, pos, end, qi);
- break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
"%u", subtype);
@@ -1455,7 +1174,6 @@
buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
qi->home_realm_query,
qi->home_realm_query_len,
- qi->icon_name, qi->icon_name_len,
qi->extra_req, qi->num_extra_req);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
buf);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 4bc6b3a..65dc14d 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -162,7 +162,7 @@
else
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
- if ((hapd->conf->wpa || hapd->conf->osen) && hapd->wpa_auth == NULL) {
+ if (hapd->conf->wpa && hapd->wpa_auth == NULL) {
hostapd_setup_wpa(hapd);
if (hapd->wpa_auth)
wpa_init_keys(hapd->wpa_auth);
@@ -358,7 +358,7 @@
ifname, i);
}
}
- if (hapd->conf->ieee80211w) {
+ if (ap_pmf_enabled(hapd->conf)) {
for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
NULL, i, 0, 0, NULL,
@@ -1671,7 +1671,7 @@
return -1;
}
- if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd))
+ if (conf->wpa && hostapd_setup_wpa(hapd))
return -1;
if (accounting_init(hapd)) {
@@ -2765,7 +2765,7 @@
hostapd_neighbor_set_own_report(iface->bss[j]);
if (iface->interfaces && iface->interfaces->count > 1)
- ieee802_11_set_beacons(iface);
+ ieee802_11_update_beacons(iface);
return 0;
@@ -2965,6 +2965,7 @@
#ifdef CONFIG_SAE
dl_list_init(&hapd->sae_commit_queue);
#endif /* CONFIG_SAE */
+ dl_list_init(&hapd->erp_keys);
return hapd;
}
@@ -3354,6 +3355,7 @@
{
struct hostapd_iface *new_iface = NULL, *iface = NULL;
struct hostapd_data *hapd;
+ struct hostapd_config *conf;
int k;
size_t i, bss_idx;
@@ -3369,17 +3371,26 @@
wpa_printf(MSG_INFO, "Configuration file: %s (phy %s)%s",
config_fname, phy, iface ? "" : " --> new PHY");
+
+ conf = interfaces->config_read_cb(config_fname);
+ if (!conf)
+ return NULL;
+
+#ifdef CONFIG_IEEE80211BE
+ /* AP MLD can be enabled with the same interface name, so even if we
+ * get the interface, we still need to allocate a new hostapd_iface
+ * structure. */
+ if (conf->bss[0]->mld_ap)
+ iface = NULL;
+#endif /* CONFIG_IEEE80211BE */
+
if (iface) {
- struct hostapd_config *conf;
struct hostapd_bss_config **tmp_conf;
struct hostapd_data **tmp_bss;
struct hostapd_bss_config *bss;
const char *ifname;
/* Add new BSS to existing iface */
- conf = interfaces->config_read_cb(config_fname);
- if (conf == NULL)
- return NULL;
if (conf->num_bss > 1) {
wpa_printf(MSG_ERROR, "Multiple BSSes specified in BSS-config");
hostapd_config_free(conf);
@@ -3429,6 +3440,8 @@
conf->bss[0] = NULL;
hostapd_config_free(conf);
} else {
+ hostapd_config_free(conf);
+
/* Add a new iface with the first BSS */
new_iface = iface = hostapd_init(interfaces, config_fname);
if (!iface)
@@ -3463,21 +3476,24 @@
return;
#ifdef CONFIG_IEEE80211BE
- /* In case of non-ML operation, de-init. But if ML operation exist,
- * even if that's the last BSS in the interface, the driver (drv) could
- * be in use for a different AP MLD. Hence, need to check if drv is
- * still being used by some other BSS before de-initiallizing. */
- if (!iface->bss[0]->conf->mld_ap) {
- driver->hapd_deinit(drv_priv);
- } else if (driver->is_drv_shared &&
- !driver->is_drv_shared(drv_priv,
- iface->bss[0]->mld_link_id)) {
+ if (!driver->is_drv_shared ||
+ !driver->is_drv_shared(drv_priv, iface->bss[0]->mld_link_id)) {
driver->hapd_deinit(drv_priv);
hostapd_mld_interface_freed(iface->bss[0]);
- } else if (hostapd_if_link_remove(iface->bss[0],
- WPA_IF_AP_BSS,
- iface->bss[0]->conf->iface,
- iface->bss[0]->mld_link_id)) {
+ iface->bss[0]->drv_priv = NULL;
+ return;
+ }
+
+ if (iface->bss[0]->conf->mld_ap) {
+ if (hostapd_if_link_remove(iface->bss[0],
+ WPA_IF_AP_BSS,
+ iface->bss[0]->conf->iface,
+ iface->bss[0]->mld_link_id))
+ wpa_printf(MSG_WARNING,
+ "Failed to remove link BSS interface %s",
+ iface->bss[0]->conf->iface);
+ } else if (hostapd_if_remove(iface->bss[0], WPA_IF_AP_BSS,
+ iface->bss[0]->conf->iface)) {
wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
iface->bss[0]->conf->iface);
}
@@ -4089,6 +4105,22 @@
ap_sta_clear_disconnect_timeouts(hapd, sta);
ap_sta_clear_assoc_timeout(hapd, sta);
+
+#ifdef CONFIG_IEEE80211BE
+ if (ap_sta_is_mld(hapd, sta)) {
+ struct hostapd_data *bss;
+ struct sta_info *lsta;
+
+ for_each_mld_link(bss, hapd) {
+ if (bss == hapd)
+ continue;
+ lsta = ap_get_sta(bss, sta->addr);
+ if (lsta)
+ ap_sta_clear_assoc_timeout(bss, lsta);
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
+
sta->post_csa_sa_query = 0;
#ifdef CONFIG_P2P
@@ -4105,7 +4137,7 @@
/* Start accounting here, if IEEE 802.1X and WPA are not used.
* IEEE 802.1X/WPA code will start accounting after the station has
* been authorized. */
- if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) {
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
if (ap_sta_set_authorized(hapd, sta, 1)) {
/* Update driver authorized flag for the STA to cover
* the case where AP SME is in the driver and there is
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 846535a..bb85de9 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -892,4 +892,11 @@
u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd);
+static inline bool ap_pmf_enabled(struct hostapd_bss_config *conf)
+{
+ return conf->ieee80211w != NO_MGMT_FRAME_PROTECTION ||
+ conf->rsn_override_mfp != NO_MGMT_FRAME_PROTECTION ||
+ conf->rsn_override_mfp_2 != NO_MGMT_FRAME_PROTECTION;
+}
+
#endif /* HOSTAPD_H */
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
index 05e9b9d..4ae3b6b 100644
--- a/src/ap/hs20.c
+++ b/src/ap/hs20.c
@@ -44,113 +44,6 @@
}
-u8 * hostapd_eid_osen(struct hostapd_data *hapd, u8 *eid)
-{
- u8 *len;
- u16 capab;
-
- if (!hapd->conf->osen)
- return eid;
-
- *eid++ = WLAN_EID_VENDOR_SPECIFIC;
- len = eid++; /* to be filled */
- WPA_PUT_BE24(eid, OUI_WFA);
- eid += 3;
- *eid++ = HS20_OSEN_OUI_TYPE;
-
- /* Group Data Cipher Suite */
- RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
- eid += RSN_SELECTOR_LEN;
-
- /* Pairwise Cipher Suite Count and List */
- WPA_PUT_LE16(eid, 1);
- eid += 2;
- RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
- eid += RSN_SELECTOR_LEN;
-
- /* AKM Suite Count and List */
- WPA_PUT_LE16(eid, 1);
- eid += 2;
- RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
- eid += RSN_SELECTOR_LEN;
-
- /* RSN Capabilities */
- capab = 0;
- if (hapd->conf->wmm_enabled) {
- /* 4 PTKSA replay counters when using WMM */
- capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
- }
- if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- capab |= WPA_CAPABILITY_MFPC;
- if (hapd->conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
- capab |= WPA_CAPABILITY_MFPR;
- }
-#ifdef CONFIG_OCV
- if (hapd->conf->ocv &&
- (hapd->iface->drv_flags2 &
- (WPA_DRIVER_FLAGS2_AP_SME | WPA_DRIVER_FLAGS2_OCV)))
- capab |= WPA_CAPABILITY_OCVC;
-#endif /* CONFIG_OCV */
- WPA_PUT_LE16(eid, capab);
- eid += 2;
-
- *len = eid - len - 1;
-
- return eid;
-}
-
-
-int hs20_send_wnm_notification(struct hostapd_data *hapd, const u8 *addr,
- u8 osu_method, const char *url)
-{
- struct wpabuf *buf;
- size_t len = 0;
- int ret;
-
- /* TODO: should refuse to send notification if the STA is not associated
- * or if the STA did not indicate support for WNM-Notification */
-
- if (url) {
- len = 1 + os_strlen(url);
- if (5 + len > 255) {
- wpa_printf(MSG_INFO, "HS 2.0: Too long URL for "
- "WNM-Notification: '%s'", url);
- return -1;
- }
- }
-
- buf = wpabuf_alloc(4 + 7 + len);
- if (buf == NULL)
- return -1;
-
- wpabuf_put_u8(buf, WLAN_ACTION_WNM);
- wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ);
- wpabuf_put_u8(buf, 1); /* Dialog token */
- wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */
-
- /* Subscription Remediation subelement */
- wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
- wpabuf_put_u8(buf, 5 + len);
- wpabuf_put_be24(buf, OUI_WFA);
- wpabuf_put_u8(buf, HS20_WNM_SUB_REM_NEEDED);
- if (url) {
- wpabuf_put_u8(buf, len - 1);
- wpabuf_put_data(buf, url, len - 1);
- wpabuf_put_u8(buf, osu_method);
- } else {
- /* Server URL and Server Method fields not included */
- wpabuf_put_u8(buf, 0);
- }
-
- ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr,
- wpabuf_head(buf), wpabuf_len(buf));
-
- wpabuf_free(buf);
-
- return ret;
-}
-
-
int hs20_send_wnm_notification_deauth_req(struct hostapd_data *hapd,
const u8 *addr,
const struct wpabuf *payload)
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index a9ed6eb..523e0a3 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -117,68 +117,61 @@
}
-u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
+static size_t hostapd_supp_rates(struct hostapd_data *hapd, u8 *buf)
{
- u8 *pos = eid;
- int i, num, count;
- int h2e_required;
+ u8 *pos = buf;
+ int i;
- if (hapd->iface->current_rates == NULL)
- return eid;
+ if (!hapd->iface->current_rates)
+ return 0;
- *pos++ = WLAN_EID_SUPP_RATES;
- num = hapd->iface->num_rates;
- if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
- num++;
- if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
- num++;
-#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
- num++;
-#endif /* CONFIG_IEEE80211AX */
- h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
- hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
- hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
- wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
- if (h2e_required)
- num++;
- if (num > 8) {
- /* rest of the rates are encoded in Extended supported
- * rates element */
- num = 8;
- }
-
- *pos++ = num;
- for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
- i++) {
- count++;
+ for (i = 0; i < hapd->iface->num_rates; i++) {
*pos = hapd->iface->current_rates[i].rate / 5;
if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
*pos |= 0x80;
pos++;
}
- if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
- count++;
+ if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
- }
- if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
- count++;
+ if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
- }
#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax && hapd->iconf->require_he && count < 8) {
- count++;
+ if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
- }
#endif /* CONFIG_IEEE80211AX */
- if (h2e_required && count < 8) {
- count++;
+#ifdef CONFIG_SAE
+ if ((hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
+ hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
+ hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
+ wpa_key_mgmt_only_sae(hapd->conf->wpa_key_mgmt))
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
- }
+#endif /* CONFIG_SAE */
+
+ return pos - buf;
+}
+
+
+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+ u8 buf[100];
+ size_t len;
+
+ len = hostapd_supp_rates(hapd, buf);
+ if (len == 0)
+ return eid;
+ /* Only up to first eight values in this element */
+ if (len > 8)
+ len = 8;
+
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = len;
+ os_memcpy(pos, buf, len);
+ pos += len;
return pos;
}
@@ -187,72 +180,19 @@
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- int i, num, count;
- int h2e_required;
+ u8 buf[100];
+ size_t len;
- hapd->conf->xrates_supported = false;
- if (hapd->iface->current_rates == NULL)
+ len = hostapd_supp_rates(hapd, buf);
+ /* Starting from the 9th value for this element */
+ if (len <= 8)
return eid;
- num = hapd->iface->num_rates;
- if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
- num++;
- if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
- num++;
-#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax && hapd->iconf->require_he)
- num++;
-#endif /* CONFIG_IEEE80211AX */
- h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
- hostapd_sae_pw_id_in_use(hapd->conf) == 2) &&
- hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
- wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt);
- if (h2e_required)
- num++;
- if (num <= 8)
- return eid;
- num -= 8;
-
*pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = num;
- for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
- i++) {
- count++;
- if (count <= 8)
- continue; /* already in SuppRates IE */
- *pos = hapd->iface->current_rates[i].rate / 5;
- if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
- *pos |= 0x80;
- pos++;
- }
+ *pos++ = len - 8;
+ os_memcpy(pos, &buf[8], len - 8);
+ pos += len - 8;
- if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
- count++;
- if (count > 8)
- *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
- }
-
- if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
- count++;
- if (count > 8)
- *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
- }
-
-#ifdef CONFIG_IEEE80211AX
- if (hapd->iconf->ieee80211ax && hapd->iconf->require_he) {
- count++;
- if (count > 8)
- *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY;
- }
-#endif /* CONFIG_IEEE80211AX */
-
- if (h2e_required) {
- count++;
- if (count > 8)
- *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
- }
-
- hapd->conf->xrates_supported = true;
return pos;
}
@@ -309,11 +249,6 @@
if (hapd->conf->wpa)
privacy = 1;
-#ifdef CONFIG_HS20
- if (hapd->conf->osen)
- privacy = 1;
-#endif /* CONFIG_HS20 */
-
if (privacy)
capab |= WLAN_CAPABILITY_PRIVACY;
@@ -548,6 +483,147 @@
}
+static bool in_mac_addr_list(const u8 *list, unsigned int num, const u8 *addr)
+{
+ unsigned int i;
+
+ for (i = 0; list && i < num; i++) {
+ if (ether_addr_equal(&list[i * ETH_ALEN], addr))
+ return true;
+ }
+
+ return false;
+}
+
+
+static struct sae_password_entry *
+sae_password_find_pw(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct sae_password_entry *pw = NULL;
+
+ if (!sta->sae || !sta->sae->tmp || !sta->sae->tmp->used_pw)
+ return NULL;
+
+
+ for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
+ if (pw == sta->sae->tmp->used_pw)
+ return pw;
+ }
+
+ return NULL;
+}
+
+
+static bool is_other_sae_password(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ struct sae_password_entry *used_pw)
+{
+ struct sae_password_entry *pw;
+
+ for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
+ if (pw == used_pw ||
+ pw->identifier ||
+ !is_broadcast_ether_addr(pw->peer_addr))
+ continue;
+
+ if (in_mac_addr_list(pw->success_mac,
+ pw->num_success_mac,
+ sta->addr))
+ return true;
+
+ if (!in_mac_addr_list(pw->fail_mac, pw->num_fail_mac,
+ sta->addr))
+ return true;
+ }
+
+ return false;
+}
+
+
+static bool has_sae_success_seen(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct sae_password_entry *pw;
+
+ for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->identifier ||
+ !is_broadcast_ether_addr(pw->peer_addr))
+ continue;
+
+ if (in_mac_addr_list(pw->success_mac,
+ pw->num_success_mac,
+ sta->addr))
+ return true;
+ }
+
+ return false;
+}
+
+
+static void sae_password_track_success(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct sae_password_entry *pw;
+
+ if (!hapd->conf->sae_track_password)
+ return;
+
+ pw = sae_password_find_pw(hapd, sta);
+ if (!pw)
+ return;
+
+ if (in_mac_addr_list(pw->success_mac,
+ pw->num_success_mac,
+ sta->addr))
+ return;
+
+ if (!pw->success_mac) {
+ pw->success_mac = os_zalloc(hapd->conf->sae_track_password *
+ ETH_ALEN);
+ if (!pw->success_mac)
+ return;
+ pw->num_success_mac = hapd->conf->sae_track_password;
+ }
+
+ os_memcpy(&pw->success_mac[pw->next_success_mac * ETH_ALEN], sta->addr,
+ ETH_ALEN);
+ pw->next_success_mac = (pw->next_success_mac + 1) % pw->num_success_mac;
+}
+
+
+static bool sae_password_track_fail(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ struct sae_password_entry *pw;
+
+ if (!hapd->conf->sae_track_password)
+ return false;
+
+ pw = sae_password_find_pw(hapd, sta);
+ if (!pw)
+ return false;
+
+ if (in_mac_addr_list(pw->fail_mac,
+ pw->num_fail_mac,
+ sta->addr))
+ return is_other_sae_password(hapd, sta, pw);
+
+ if (!pw->fail_mac) {
+ pw->fail_mac = os_zalloc(hapd->conf->sae_track_password *
+ ETH_ALEN);
+ if (!pw->fail_mac)
+ return false;
+ pw->num_fail_mac = hapd->conf->sae_track_password;
+ }
+
+ os_memcpy(&pw->fail_mac[pw->next_fail_mac * ETH_ALEN], sta->addr,
+ ETH_ALEN);
+ pw->next_fail_mac = (pw->next_fail_mac + 1) % pw->num_fail_mac;
+
+ return is_other_sae_password(hapd, sta, pw);
+}
+
+
const char * sae_get_password(struct hostapd_data *hapd,
struct sta_info *sta,
const char *rx_id,
@@ -561,6 +637,45 @@
const struct sae_pk *pk = NULL;
struct hostapd_sta_wpa_psk_short *psk = NULL;
+ /* With sae_track_password functionality enabled, try to first find the
+ * next viable wildcard-address password if a password identifier was
+ * not used. Select an wildcard-addr entry if the STA is known to have
+ * used it successfully before. If no such entry exists, pick a
+ * wildcard-addr entry that does not have a failed entry tracked for the
+ * STA. */
+ if (!rx_id && sta && hapd->conf->sae_track_password) {
+ struct sae_password_entry *success = NULL, *no_fail = NULL;
+
+ for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
+ if (pw->identifier ||
+ !is_broadcast_ether_addr(pw->peer_addr))
+ continue;
+ if (in_mac_addr_list(pw->success_mac,
+ pw->num_success_mac,
+ sta->addr)) {
+ success = pw;
+ break;
+ }
+
+ if (!no_fail &&
+ !in_mac_addr_list(pw->fail_mac, pw->num_fail_mac,
+ sta->addr))
+ no_fail = pw;
+ }
+
+ pw = success ? success : no_fail;
+ if (pw) {
+ password = pw->password;
+ pt = pw->pt;
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ pk = pw->pk;
+ goto found;
+ }
+ }
+
+ /* If sae_track_password functionality is not enabled or no suitable
+ * password entry was found with it, pick the first entry that matches
+ * the STA MAC address and password identifier (if used). */
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
(!sta ||
@@ -591,6 +706,7 @@
}
}
+found:
if (pw_entry)
*pw_entry = pw;
if (s_pt)
@@ -657,6 +773,9 @@
return NULL;
}
+ if (pw && sta->sae->tmp)
+ sta->sae->tmp->used_pw = pw;
+
if (pw && pw->vlan_id) {
if (!sta->sae->tmp) {
wpa_printf(MSG_INFO,
@@ -975,7 +1094,8 @@
sta->sae->peer_commit_scalar = NULL;
wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
sta->sae->pmk, sta->sae->pmk_len,
- sta->sae->pmkid, sta->sae->akmp);
+ sta->sae->pmkid, sta->sae->akmp,
+ ap_sta_is_mld(hapd, sta));
sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS);
}
@@ -1005,6 +1125,7 @@
case SAE_NOTHING:
if (auth_transaction == 1) {
struct sae_temporary_data *tmp = sta->sae->tmp;
+ bool immediate_confirm;
if (tmp) {
sta->sae->h2e =
@@ -1046,8 +1167,22 @@
* overridden with explicit configuration so that the
* infrastructure BSS case sends both frames together.
*/
- if ((hapd->conf->mesh & MESH_ENABLED) ||
- hapd->conf->sae_confirm_immediate) {
+ immediate_confirm = (hapd->conf->mesh & MESH_ENABLED) ||
+ hapd->conf->sae_confirm_immediate;
+
+ /* If sae_track_password is enabled and the STA has not
+ * yet been tracked to having successfully completed
+ * SAE authentication with the password that the AP
+ * tries to use, do not send Confirm immediately to
+ * avoid an explicit indication on the STA side on
+ * password mismatch. */
+ if (immediate_confirm &&
+ hapd->conf->sae_track_password &&
+ (!sta->sae->tmp || !sta->sae->tmp->parsed_pw_id) &&
+ !has_sae_success_seen(hapd, sta))
+ immediate_confirm = false;
+
+ if (immediate_confirm) {
/*
* Send both Commit and Confirm immediately
* based on SAE finite state machine
@@ -1495,7 +1630,9 @@
* previously set parameters. */
pos = mgmt->u.auth.variable;
end = ((const u8 *) mgmt) + len;
- if (end - pos >= (int) sizeof(le16) &&
+ if ((!sta->sae->tmp ||
+ !sta->sae->tmp->try_other_password) &&
+ end - pos >= (int) sizeof(le16) &&
sae_group_allowed(sta->sae, groups,
WPA_GET_LE16(pos)) ==
WLAN_STATUS_SUCCESS) {
@@ -1621,9 +1758,21 @@
if (sae_check_confirm(sta->sae, var, var_len,
NULL) < 0) {
+ if (sae_password_track_fail(hapd, sta)) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Reject mismatching Confirm so that another password can be attempted by "
+ MACSTR,
+ MAC2STR(sta->addr));
+ if (sta->sae->tmp)
+ sta->sae->tmp->
+ try_other_password = 1;
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto reply;
+ }
resp = WLAN_STATUS_CHALLENGE_FAIL;
goto reply;
}
+ sae_password_track_success(hapd, sta);
sta->sae->rc = peer_send_confirm;
}
resp = sae_sm_step(hapd, sta, auth_transaction,
@@ -1975,7 +2124,8 @@
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
elems.rsnxe ? elems.rsnxe - 2 : NULL,
elems.rsnxe ? elems.rsnxe_len + 2 : 0,
- elems.mdie, elems.mdie_len, NULL, 0, NULL);
+ elems.mdie, elems.mdie_len, NULL, 0, NULL,
+ ap_sta_is_mld(hapd, sta));
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
@@ -2252,7 +2402,7 @@
sta->fils_erp_pmkid,
session_timeout,
wpa_auth_sta_key_mgmt(sta->wpa_sm),
- NULL) < 0) {
+ NULL, ap_sta_is_mld(hapd, sta)) < 0) {
wpa_printf(MSG_ERROR,
"FILS: Failed to add PMKSA cache entry based on ERP");
}
@@ -3829,7 +3979,8 @@
wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len);
wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN);
wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk,
- sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE, NULL);
+ sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE,
+ NULL, ap_sta_is_mld(hapd, sta));
return WLAN_STATUS_SUCCESS;
}
@@ -3909,7 +4060,8 @@
rsn_ie_len += 2;
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq, rsn_ie, rsn_ie_len,
- NULL, 0, NULL, 0, owe_dh, owe_dh_len, NULL);
+ NULL, 0, NULL, 0, owe_dh, owe_dh_len, NULL,
+ ap_sta_is_mld(hapd, sta));
status = wpa_res_to_status_code(res);
if (status != WLAN_STATUS_SUCCESS)
goto end;
@@ -3961,8 +4113,58 @@
#endif /* CONFIG_OWE */
+static bool hapd_is_known_sta(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ies, size_t ies_len)
+{
+ const u8 *ie, *pos, *end, *timestamp_pos, *mic;
+ u64 timestamp;
+ u8 mic_len;
+
+ if (!hapd->conf->known_sta_identification)
+ return false;
+
+ ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_KNOWN_STA_IDENTIFICATION);
+ if (!ie)
+ return false;
+
+ pos = ie + 3;
+ end = &ie[2 + ie[1]];
+ if (end - pos < 8 + 1)
+ return false; /* truncated element */
+ timestamp_pos = pos;
+ timestamp = WPA_GET_LE64(pos);
+ pos += 8;
+ mic_len = *pos++;
+ if (mic_len > end - pos)
+ return false; /* truncated element */
+ mic = pos;
+
+ wpa_printf(MSG_DEBUG, "RSN: STA " MACSTR
+ " included Known STA Identification element: Timestamp=0x%llx mic_len=%u",
+ MAC2STR(sta->addr), (unsigned long long) timestamp, mic_len);
+
+ if (timestamp <= sta->last_known_sta_id_timestamp) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Ignore reused or old Known STA Identification");
+ return false;
+ }
+
+ if (!wpa_auth_sm_known_sta_identification(sta->wpa_sm, timestamp_pos,
+ mic, mic_len)) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Ignore Known STA Identification with invalid MIC or due to KCK not available");
+ return false;
+ }
+
+ wpa_printf(MSG_DEBUG, "RSN: Valid Known STA Identification");
+ sta->last_known_sta_id_timestamp = timestamp;
+
+ return true;
+}
+
+
static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta,
- int reassoc)
+ int reassoc, const u8 *ies, size_t ies_len)
{
if ((sta->flags &
(WLAN_STA_ASSOC | WLAN_STA_MFP | WLAN_STA_AUTHORIZED)) !=
@@ -3974,6 +4176,9 @@
if (!sta->sa_query_timed_out &&
(!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
+ if (hapd_is_known_sta(hapd, sta, ies, ies_len))
+ return false;
+
/*
* STA has already been associated with MFP and SA Query timeout
* has not been reached. Reject the association attempt
@@ -4212,7 +4417,8 @@
0,
elems->mdie, elems->mdie_len,
elems->owe_dh, elems->owe_dh_len,
- assoc_sta ? assoc_sta->wpa_sm : NULL);
+ assoc_sta ? assoc_sta->wpa_sm : NULL,
+ ap_sta_is_mld(hapd, sta));
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -4222,6 +4428,11 @@
else
sta->flags &= ~WLAN_STA_MFP;
+ if (wpa_auth_uses_spp_amsdu(sta->wpa_sm))
+ sta->flags |= WLAN_STA_SPP_AMSDU;
+ else
+ sta->flags &= ~WLAN_STA_SPP_AMSDU;
+
#ifdef CONFIG_IEEE80211R_AP
if (sta->auth_alg == WLAN_AUTH_FT) {
if (!reassoc) {
@@ -4340,34 +4551,12 @@
ieee802_11_rsnx_capab_len(
elems->rsnxe, elems->rsnxe_len,
WLAN_RSNX_CAPAB_SSID_PROTECTION));
-#ifdef CONFIG_HS20
- } else if (hapd->conf->osen) {
- if (!elems->osen) {
- hostapd_logger(
- hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO,
- "No HS 2.0 OSEN element in association request");
- return WLAN_STATUS_INVALID_IE;
- }
-
- wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
- if (sta->wpa_sm == NULL)
- sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
- sta->addr, NULL);
- if (sta->wpa_sm == NULL) {
- wpa_printf(MSG_WARNING, "Failed to initialize WPA "
- "state machine");
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
- if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
- elems->osen - 2, elems->osen_len + 2) < 0)
- return WLAN_STATUS_INVALID_IE;
-#endif /* CONFIG_HS20 */
} else
wpa_auth_sta_no_wpa(sta->wpa_sm);
#ifdef CONFIG_P2P
- p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
+ if (ies && ies_len)
+ p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
#endif /* CONFIG_P2P */
#ifdef CONFIG_HS20
@@ -4627,6 +4816,7 @@
sta->flags |= origin_sta->flags | WLAN_STA_ASSOC_REQ_OK;
sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
+ ap_sta_set_mld(sta, true);
status = __check_assoc_ies(hapd, sta, NULL, 0, &elems, reassoc, true);
if (status != WLAN_STATUS_SUCCESS) {
@@ -4634,8 +4824,6 @@
goto out;
}
- ap_sta_set_mld(sta, true);
-
os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info));
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
struct mld_link_info *li = &sta->mld_info.links[i];
@@ -5617,7 +5805,7 @@
}
#endif /* CONFIG_MBO */
- if (hapd->conf->wpa && check_sa_query(hapd, sta, reassoc)) {
+ if (hapd->conf->wpa && check_sa_query(hapd, sta, reassoc, pos, left)) {
resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
goto fail;
}
@@ -6064,7 +6252,7 @@
const u8 *pos, *end;
u32 oui_type;
- pos = &mgmt->u.action.category;
+ pos = (const u8 *) &mgmt->u.action;
end = ((const u8 *) mgmt) + len;
if (end - pos < 1 + 4)
@@ -6741,8 +6929,7 @@
new_assoc = 0;
sta->flags |= WLAN_STA_ASSOC;
sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;
- if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
- !hapd->conf->osen) ||
+ if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
sta->auth_alg == WLAN_AUTH_FILS_SK ||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
sta->auth_alg == WLAN_AUTH_FILS_PK ||
@@ -7678,7 +7865,8 @@
/* If no TBTT was found, adjust the len and total_len since it
* would have incremented before we checked all BSSs. */
- if (!tbtt_count) {
+ if (!tbtt_count && len >= RNR_TBTT_HEADER_LEN &&
+ total_len >= RNR_TBTT_HEADER_LEN) {
len -= RNR_TBTT_HEADER_LEN;
total_len -= RNR_TBTT_HEADER_LEN;
}
@@ -7688,7 +7876,8 @@
/* This is possible when in the re-built case and no suitable TBTT was
* found. Adjust the length accordingly. */
- if (!tbtt_count && total_tbtt_count) {
+ if (!tbtt_count && total_tbtt_count && len >= RNR_TBTT_HEADER_LEN &&
+ total_len >= RNR_TBTT_HEADER_LEN) {
len -= RNR_TBTT_HEADER_LEN;
total_len -= RNR_TBTT_HEADER_LEN;
}
@@ -8067,8 +8256,8 @@
}
-u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
- size_t *current_len)
+static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid,
+ size_t *current_len)
{
struct hostapd_iface *iface;
size_t i;
@@ -8092,8 +8281,8 @@
}
-u8 * hostapd_eid_rnr_mlo(struct hostapd_data *hapd, u32 type,
- u8 *eid, size_t *current_len)
+static u8 * hostapd_eid_rnr_mlo(struct hostapd_data *hapd, u32 type,
+ u8 *eid, size_t *current_len)
{
#ifdef CONFIG_IEEE80211BE
struct hostapd_iface *iface;
@@ -8204,8 +8393,8 @@
size_t known_bss_len)
{
struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
- size_t len, i;
- u8 ext_capa[20];
+ size_t len, i, tx_xrate_len;
+ u8 ext_capa[20], buf[100];
/* Element ID: 1 octet
* Length: 1 octet
@@ -8218,10 +8407,12 @@
*/
len = 1;
+ tx_xrate_len = hostapd_eid_ext_supp_rates(tx_bss, buf) - buf;
+
for (i = *bss_index; i < hapd->iface->num_bss; i++) {
struct hostapd_data *bss = hapd->iface->bss[i];
const u8 *auth, *rsn = NULL, *rsnx = NULL;
- size_t nontx_profile_len, auth_len;
+ size_t nontx_profile_len, auth_len, xrate_len;
u8 ie_count = 0;
if (!bss || !bss->conf || !bss->started ||
@@ -8259,12 +8450,15 @@
ie_count++;
if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
ie_count++;
- if (bss->conf->xrates_supported)
- nontx_profile_len += 8;
- else if (hapd->conf->xrates_supported)
+
+ xrate_len = hostapd_eid_ext_supp_rates(bss, buf) - buf;
+
+ if (xrate_len)
+ nontx_profile_len += xrate_len;
+ else if (tx_xrate_len)
ie_count++;
if (ie_count)
- nontx_profile_len += 4 + ie_count;
+ nontx_profile_len += 4 + ie_count + 1;
if (len + nontx_profile_len > 255)
break;
@@ -8338,13 +8532,16 @@
const u8 *known_bss, size_t known_bss_len)
{
struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd);
- size_t i;
+ size_t i, tx_xrate_len;
u8 *eid_len_offset, *max_bssid_indicator_offset;
+ u8 buf[100];
*eid++ = WLAN_EID_MULTIPLE_BSSID;
eid_len_offset = eid++;
max_bssid_indicator_offset = eid++;
+ tx_xrate_len = hostapd_eid_ext_supp_rates(tx_bss, buf) - buf;
+
for (i = *bss_index; i < hapd->iface->num_bss; i++) {
struct hostapd_data *bss = hapd->iface->bss[i];
struct hostapd_bss_config *conf;
@@ -8352,7 +8549,7 @@
u8 *eid_len_pos, *nontx_bss_start = eid;
const u8 *auth, *rsn = NULL, *rsnx = NULL;
u8 ie_count = 0, non_inherit_ie[3];
- size_t auth_len = 0;
+ size_t auth_len = 0, xrate_len;
u16 capab_info;
u8 mbssindex = i;
@@ -8417,12 +8614,13 @@
}
eid += hostapd_mbssid_ext_capa(bss, tx_bss, eid);
+ xrate_len = hostapd_eid_ext_supp_rates(bss, eid) - eid;
+ eid += xrate_len;
/* List of Element ID values in increasing order */
if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN))
non_inherit_ie[ie_count++] = WLAN_EID_RSN;
- if (hapd->conf->xrates_supported &&
- !bss->conf->xrates_supported)
+ if (tx_xrate_len && !xrate_len)
non_inherit_ie[ie_count++] = WLAN_EID_EXT_SUPP_RATES;
if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX))
non_inherit_ie[ie_count++] = WLAN_EID_RSNX;
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
index e778041..0d0a009 100644
--- a/src/ap/ieee802_11_eht.c
+++ b/src/ap/ieee802_11_eht.c
@@ -1127,29 +1127,7 @@
/* Common Info Length and MLD MAC Address must always be present */
common_info_len = 1 + ETH_ALEN;
-
- if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID) {
- wpa_printf(MSG_DEBUG, "MLD: Link ID Info not expected");
- goto out;
- }
-
- if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT) {
- wpa_printf(MSG_DEBUG,
- "MLD: BSS Parameters Change Count not expected");
- goto out;
- }
-
- if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) {
- wpa_printf(MSG_DEBUG,
- "MLD: Medium Synchronization Delay Information not expected");
- goto out;
- }
-
- if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA)
- common_info_len += 2;
-
- if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA)
- common_info_len += 2;
+ /* Ignore optional fields */
if (sizeof(*ml) + common_info_len > ml_len) {
wpa_printf(MSG_DEBUG, "MLD: Not enough bytes for common info");
@@ -1159,7 +1137,7 @@
common_info = (struct eht_ml_basic_common_info *) ml->variable;
/* Common information length includes the length octet */
- if (common_info->len != common_info_len) {
+ if (common_info->len < common_info_len) {
wpa_printf(MSG_DEBUG,
"MLD: Invalid common info len=%u", common_info->len);
goto out;
@@ -1185,9 +1163,10 @@
size_t ml_len, common_info_len;
struct mld_link_info *link_info;
struct mld_info *info = &sta->mld_info;
- const u8 *pos;
+ const u8 *pos, *end;
int ret = -1;
u16 ml_control;
+ const u8 *ml_end;
mlbuf = ieee802_11_defrag(elems->basic_mle, elems->basic_mle_len, true);
if (!mlbuf)
@@ -1195,6 +1174,7 @@
ml = wpabuf_head(mlbuf);
ml_len = wpabuf_len(mlbuf);
+ ml_end = ((const u8 *) ml) + ml_len;
ml_control = le_to_host16(ml->ml_control);
if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) !=
@@ -1236,6 +1216,12 @@
goto out;
}
+ if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EXT_MLD_CAP) {
+ common_info_len += 2;
+ } else {
+ wpa_printf(MSG_DEBUG, "MLD: EXT ML capabilities not present");
+ }
+
wpa_printf(MSG_DEBUG, "MLD: expected_common_info_len=%zu",
common_info_len);
@@ -1247,7 +1233,7 @@
common_info = (const struct eht_ml_basic_common_info *) ml->variable;
/* Common information length includes the length octet */
- if (common_info->len != common_info_len) {
+ if (common_info->len < common_info_len) {
wpa_printf(MSG_DEBUG,
"MLD: Invalid common info len=%u (expected %zu)",
common_info->len, common_info_len);
@@ -1255,6 +1241,7 @@
}
pos = common_info->variable;
+ end = ((const u8 *) common_info) + common_info->len;
if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) {
info->common_info.eml_capa = WPA_GET_LE16(pos);
@@ -1266,6 +1253,10 @@
info->common_info.mld_capa = WPA_GET_LE16(pos);
pos += 2;
+ if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EXT_MLD_CAP) {
+ pos += 2;
+ }
+
wpa_printf(MSG_DEBUG, "MLD: addr=" MACSTR ", eml=0x%x, mld=0x%x",
MAC2STR(info->common_info.mld_addr),
info->common_info.eml_capa, info->common_info.mld_capa);
@@ -1283,21 +1274,22 @@
info->links[hapd->mld_link_id].valid = 1;
- /* Parse the link info field */
- ml_len -= sizeof(*ml) + common_info_len;
-
- while (ml_len > 2) {
+ /* Parse the Link Info field that starts after the end of the variable
+ * length Common Info field. */
+ pos = end;
+ while (ml_end - pos > 2) {
size_t sub_elem_len = *(pos + 1);
size_t sta_info_len;
u16 control;
+ const u8 *sub_elem_end;
wpa_printf(MSG_DEBUG, "MLD: sub element len=%zu",
sub_elem_len);
- if (2 + sub_elem_len > ml_len) {
+ if (2 + sub_elem_len > (size_t) (ml_end - pos)) {
wpa_printf(MSG_DEBUG,
"MLD: Invalid link info len: %zu %zu",
- 2 + sub_elem_len, ml_len);
+ 2 + sub_elem_len, ml_end - pos);
goto out;
}
@@ -1306,7 +1298,6 @@
"MLD: Skip vendor specific subelement");
pos += 2 + sub_elem_len;
- ml_len -= 2 + sub_elem_len;
continue;
}
@@ -1315,16 +1306,15 @@
"MLD: Skip unknown Multi-Link element subelement ID=%u",
*pos);
pos += 2 + sub_elem_len;
- ml_len -= 2 + sub_elem_len;
continue;
}
/* Skip the subelement ID and the length */
pos += 2;
- ml_len -= 2;
+ sub_elem_end = pos + sub_elem_len;
/* Get the station control field */
- if (sub_elem_len < 2) {
+ if (sub_elem_end - pos < 2) {
wpa_printf(MSG_DEBUG,
"MLD: Too short Per-STA Profile subelement");
goto out;
@@ -1333,8 +1323,6 @@
link_info = &info->links[control &
EHT_PER_STA_CTRL_LINK_ID_MSK];
pos += 2;
- ml_len -= 2;
- sub_elem_len -= 2;
if (!(control & EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK)) {
wpa_printf(MSG_DEBUG,
@@ -1367,15 +1355,19 @@
sta_info_len += link_info->nstr_bitmap_len;
- if (sta_info_len > ml_len || sta_info_len != *pos ||
- sta_info_len > sub_elem_len) {
+ if (sta_info_len > (size_t) (sub_elem_end - pos) ||
+ sta_info_len > *pos ||
+ *pos > sub_elem_end - pos ||
+ sta_info_len > (size_t) (sub_elem_end - pos)) {
wpa_printf(MSG_DEBUG, "MLD: Invalid STA Info length");
goto out;
}
+ sta_info_len = *pos;
+ end = pos + sta_info_len;
+
/* skip the length */
pos++;
- ml_len--;
/* get the link address */
os_memcpy(link_info->peer_addr, pos, ETH_ALEN);
@@ -1385,27 +1377,20 @@
MAC2STR(link_info->peer_addr));
pos += ETH_ALEN;
- ml_len -= ETH_ALEN;
/* Get the NSTR bitmap */
if (link_info->nstr_bitmap_len) {
os_memcpy(link_info->nstr_bitmap, pos,
link_info->nstr_bitmap_len);
pos += link_info->nstr_bitmap_len;
- ml_len -= link_info->nstr_bitmap_len;
}
- sub_elem_len -= sta_info_len;
+ pos = end;
- wpa_printf(MSG_DEBUG, "MLD: STA Profile len=%zu", sub_elem_len);
- if (sub_elem_len > ml_len)
- goto out;
-
- if (sub_elem_len > 2)
+ if (sub_elem_end - pos >= 2)
link_info->capability = WPA_GET_LE16(pos);
- pos += sub_elem_len;
- ml_len -= sub_elem_len;
+ pos = sub_elem_end;
wpa_printf(MSG_DEBUG, "MLD: link ctrl=0x%x, " MACSTR
", nstr bitmap len=%zu",
@@ -1415,12 +1400,6 @@
link_info->valid = true;
}
- if (ml_len) {
- wpa_printf(MSG_DEBUG, "MLD: %zu bytes left after parsing. fail",
- ml_len);
- goto out;
- }
-
ret = hostapd_mld_validate_assoc_info(hapd, sta);
out:
wpabuf_free(mlbuf);
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index cd9f8bc..cc731b9 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -229,6 +229,9 @@
u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
if (punct_bitmap) {
+ oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
+ seg0 = hostapd_get_oper_centr_freq_seg0_idx(
+ hapd->iconf);
punct_update_legacy_bw(punct_bitmap,
hapd->iconf->channel,
&oper_chwidth, &seg0, &seg1);
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 5e67216..986b7b8 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -479,6 +479,9 @@
case 12: /* Bits 96-103 */
if (hapd->iconf->peer_to_peer_twt)
*pos |= 0x10; /* Bit 100 - Peer to Peer TWT */
+ if (hapd->conf->known_sta_identification)
+ *pos |= 0x40; /* Bit 102 - Known STA Identification
+ * Enabled */
break;
case 13: /* Bits 104-111 */
if (hapd->iconf->channel_usage)
@@ -1042,7 +1045,8 @@
int requested_bw;
if (sta->ht_capabilities)
- ht_40mhz = !!(sta->ht_capabilities->ht_capabilities_info &
+ ht_40mhz = !!(le_to_host16(sta->ht_capabilities->
+ ht_capabilities_info) &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
if (sta->vht_operation) {
@@ -1078,9 +1082,9 @@
* normal clients), use it to determine the supported channel
* bandwidth.
*/
- vht_chanwidth = capab->vht_capabilities_info &
+ vht_chanwidth = le_to_host32(capab->vht_capabilities_info) &
VHT_CAP_SUPP_CHAN_WIDTH_MASK;
- vht_80p80 = capab->vht_capabilities_info &
+ vht_80p80 = le_to_host32(capab->vht_capabilities_info) &
VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
/* TODO: Also take into account Extended NSS BW Support field */
@@ -1136,6 +1140,9 @@
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
if (hapd->conf->ssid_protection)
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
+ if ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SPP_AMSDU) &&
+ hapd->conf->spp_amsdu)
+ capab |= BIT(WLAN_RSNX_CAPAB_SPP_A_MSDU);
if (!capab)
return eid; /* no supported extended RSN capabilities */
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index e8d21ff..efdf607 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -45,7 +45,7 @@
#endif /* CONFIG_HS20 */
static bool ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
- int remediation, bool logoff);
+ bool logoff);
static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
@@ -451,8 +451,7 @@
return -1;
}
- suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) ||
- hapd->conf->osen) ?
+ suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2)) ?
WPA_PROTO_RSN : WPA_PROTO_WPA,
hapd->conf->wpa_group);
if (!hostapd_config_get_radius_attr(req_attr,
@@ -581,7 +580,7 @@
}
#endif /* CONFIG_IEEE80211R_AP */
- if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm &&
+ if (hapd->conf->wpa && sta->wpa_sm &&
add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
return -1;
@@ -1123,7 +1122,7 @@
struct rsn_pmksa_cache_entry *pmksa;
int key_mgmt;
- if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen &&
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
!hapd->conf->wps_state)
return;
@@ -1183,7 +1182,7 @@
return;
}
- if (!hapd->conf->ieee802_1x && !hapd->conf->osen &&
+ if (!hapd->conf->ieee802_1x &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
wpa_printf(MSG_DEBUG,
"IEEE 802.1X: Ignore EAPOL message - 802.1X not enabled and WPS not used");
@@ -1251,8 +1250,10 @@
HOSTAPD_LEVEL_DEBUG,
"received EAPOL-Start from STA");
#ifdef CONFIG_IEEE80211R_AP
- if (hapd->conf->wpa && sta->wpa_sm &&
- (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) ||
+ if (hapd->conf->wpa &&
+ wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && sta->wpa_sm &&
+ ((wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) &&
+ (sta->flags & WLAN_STA_AUTHORIZED)) ||
sta->auth_alg == WLAN_AUTH_FT)) {
/* When FT is used, reauthentication to generate a new
* PMK-R0 would be complicated since the current AP
@@ -1356,7 +1357,7 @@
}
#endif /* CONFIG_WPS */
- if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) {
+ if (!force_1x && !hapd->conf->ieee802_1x) {
wpa_printf(MSG_DEBUG,
"IEEE 802.1X: Ignore STA - 802.1X not enabled or forced for WPS");
/*
@@ -1490,10 +1491,6 @@
{
struct eapol_state_machine *sm = sta->eapol_sm;
-#ifdef CONFIG_HS20
- eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
-#endif /* CONFIG_HS20 */
-
if (sta->pending_eapol_rx) {
wpabuf_free(sta->pending_eapol_rx->buf);
os_free(sta->pending_eapol_rx);
@@ -1769,32 +1766,6 @@
#ifdef CONFIG_HS20
-static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len)
-{
- sta->remediation = 1;
- os_free(sta->remediation_url);
- if (len > 2) {
- sta->remediation_url = os_malloc(len);
- if (!sta->remediation_url)
- return;
- sta->remediation_method = pos[0];
- os_memcpy(sta->remediation_url, pos + 1, len - 1);
- sta->remediation_url[len - 1] = '\0';
- wpa_printf(MSG_DEBUG,
- "HS 2.0: Subscription remediation needed for "
- MACSTR " - server method %u URL %s",
- MAC2STR(sta->addr), sta->remediation_method,
- sta->remediation_url);
- } else {
- sta->remediation_url = NULL;
- wpa_printf(MSG_DEBUG,
- "HS 2.0: Subscription remediation needed for "
- MACSTR, MAC2STR(sta->addr));
- }
- /* TODO: assign the STA into remediation VLAN or add filtering */
-}
-
-
static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd,
struct sta_info *sta, const u8 *pos,
size_t len)
@@ -1910,7 +1881,6 @@
size_t len;
buf = NULL;
- sta->remediation = 0;
sta->hs20_deauth_requested = 0;
sta->hs20_deauth_on_ack = 0;
@@ -1935,9 +1905,6 @@
continue; /* invalid WFA VSA */
switch (type) {
- case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION:
- ieee802_1x_hs20_sub_rem(sta, pos, sublen);
- break;
case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ:
ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen);
break;
@@ -2366,7 +2333,7 @@
static bool _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
- int preauth, int remediation, bool logoff)
+ int preauth, bool logoff)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
@@ -2376,7 +2343,7 @@
return false;
}
- return ieee802_1x_finished(hapd, sta, success, remediation, logoff);
+ return ieee802_1x_finished(hapd, sta, success, logoff);
}
@@ -2418,7 +2385,6 @@
user->force_version = eap_user->force_version;
user->macacl = eap_user->macacl;
user->ttls_auth = eap_user->ttls_auth;
- user->remediation = eap_user->remediation;
rv = 0;
out:
@@ -2576,8 +2542,6 @@
}
#endif /* CONFIG_IEEE80211BE */
- dl_list_init(&hapd->erp_keys);
-
os_memset(&conf, 0, sizeof(conf));
conf.eap_cfg = hapd->eap_cfg;
conf.ctx = hapd;
@@ -3060,17 +3024,6 @@
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
- if (sta->remediation) {
- wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
- MACSTR " to indicate Subscription Remediation",
- MAC2STR(sta->addr));
- hs20_send_wnm_notification(hapd, sta->addr,
- sta->remediation_method,
- sta->remediation_url);
- os_free(sta->remediation_url);
- sta->remediation_url = NULL;
- }
-
if (sta->hs20_deauth_req) {
wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to "
MACSTR " to indicate imminent deauthentication",
@@ -3093,7 +3046,7 @@
static bool ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
- int remediation, bool logoff)
+ bool logoff)
{
const u8 *key;
size_t len;
@@ -3103,16 +3056,7 @@
struct os_reltime now, remaining;
#ifdef CONFIG_HS20
- if (remediation && !sta->remediation) {
- sta->remediation = 1;
- os_free(sta->remediation_url);
- sta->remediation_url =
- os_strdup(hapd->conf->subscr_remediation_url);
- sta->remediation_method = 1; /* SOAP-XML SPP */
- }
-
- if (success && (sta->remediation || sta->hs20_deauth_req ||
- sta->hs20_t_c_filtering)) {
+ if (success && (sta->hs20_deauth_req || sta->hs20_t_c_filtering)) {
wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to "
MACSTR " in 100 ms", MAC2STR(sta->addr));
eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
@@ -3133,7 +3077,7 @@
} else {
session_timeout = dot11RSNAConfigPMKLifetime;
}
- if (success && key && len >= PMK_LEN && !sta->remediation &&
+ if (success && key && len >= PMK_LEN &&
!sta->hs20_deauth_requested &&
wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
sta->eapol_sm) == 0) {
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 2fce838..0715540 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -644,29 +644,25 @@
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
* @buf: Buffer for the list
* @len: Length of the buffer
+ * @index: Externally stored index counter
* Returns: Number of bytes written to buffer
*
* This function is used to generate a text format representation of the
* current PMKSA cache contents for the ctrl_iface PMKSA command.
*/
-int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len,
+ int *index)
{
- int i, ret;
+ int ret;
char *pos = buf;
struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
os_get_reltime(&now);
- ret = os_snprintf(pos, buf + len - pos,
- "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
- if (os_snprintf_error(buf + len - pos, ret))
- return pos - buf;
- pos += ret;
- i = 0;
entry = pmksa->pmksa;
while (entry) {
ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
- i, MAC2STR(entry->spa));
+ *index, MAC2STR(entry->spa));
if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
@@ -679,6 +675,7 @@
return pos - buf;
pos += ret;
entry = entry->next;
+ (*index)++;
}
return pos - buf;
}
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index e38e7ec..ade1c49 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -75,7 +75,8 @@
struct rsn_pmksa_cache_entry *entry);
int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
struct radius_das_attrs *attr);
-int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len,
+ int *index);
void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
char *buf, size_t len);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 9d49569..8aa96d2 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -419,7 +419,6 @@
hostapd_free_psk_list(sta->psk);
os_free(sta->identity);
os_free(sta->radius_cui);
- os_free(sta->remediation_url);
os_free(sta->t_c_url);
wpabuf_free(sta->hs20_deauth_req);
os_free(sta->hs20_session_info_url);
@@ -947,7 +946,8 @@
static void ap_sta_disconnect_common(struct hostapd_data *hapd,
- struct sta_info *sta, unsigned int timeout)
+ struct sta_info *sta, unsigned int timeout,
+ bool free_1x)
{
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
@@ -961,7 +961,8 @@
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(timeout, 0, ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
- ieee802_1x_free_station(hapd, sta);
+ if (free_1x)
+ ieee802_1x_free_station(hapd, sta);
#ifdef CONFIG_IEEE80211BE
if (!hapd->conf->mld_ap ||
hapd->mld_link_id == sta->mld_assoc_link_id) {
@@ -1005,7 +1006,8 @@
sta->timeout_next = STA_DEAUTH;
}
- ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DISASSOC);
+ ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DISASSOC,
+ true);
ap_sta_disassociate_common(hapd, sta, reason);
}
@@ -1043,7 +1045,8 @@
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
sta->timeout_next = STA_REMOVE;
- ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH);
+ ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH,
+ true);
ap_sta_deauthenticate_common(hapd, sta, reason);
}
@@ -1060,7 +1063,8 @@
sta->timeout_next = STA_REMOVE;
sta->deauth_reason = reason;
- ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH);
+ ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH,
+ false);
ap_sta_deauthenticate_common(hapd, sta, reason);
}
@@ -1767,7 +1771,7 @@
buf[0] = '\0';
res = os_snprintf(buf, buflen,
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1790,6 +1794,7 @@
(flags & WLAN_STA_EHT ? "[EHT]" : ""),
(flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
+ (flags & WLAN_STA_SPP_AMSDU ? "[SPP-A-MSDU]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
if (os_snprintf_error(buflen, res))
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index d22e86d..1730742 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -22,6 +22,7 @@
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_SPP_AMSDU BIT(2)
#define WLAN_STA_AUTHORIZED BIT(5)
#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
#define WLAN_STA_SHORT_PREAMBLE BIT(7)
@@ -131,7 +132,6 @@
unsigned int ht_20mhz_set:1;
unsigned int no_p2p_set:1;
unsigned int qos_map_enabled:1;
- unsigned int remediation:1;
unsigned int hs20_deauth_requested:1;
unsigned int hs20_deauth_on_ack:1;
unsigned int session_timeout_set:1;
@@ -217,8 +217,6 @@
struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
/* Hotspot 2.0 Roaming Consortium from (Re)Association Request */
struct wpabuf *roaming_consortium;
- u8 remediation_method;
- char *remediation_url; /* HS 2.0 Subscription Remediation Server URL */
char *t_c_url; /* HS 2.0 Terms and Conditions Server URL */
struct wpabuf *hs20_deauth_req;
char *hs20_session_info_url;
@@ -322,6 +320,8 @@
u16 max_idle_period; /* if nonzero, the granted BSS max idle period in
* units of 1000 TUs */
+
+ u64 last_known_sta_id_timestamp;
};
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 5531aae..9295dc6 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -38,6 +38,7 @@
#define STATE_MACHINE_DATA struct wpa_state_machine
#define STATE_MACHINE_DEBUG_PREFIX "WPA"
#define STATE_MACHINE_ADDR wpa_auth_get_spa(sm)
+#define KDE_ALL_LINKS 0xffff
static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
@@ -738,6 +739,19 @@
}
+static void wpa_deinit_groups(struct wpa_authenticator *wpa_auth)
+{
+ struct wpa_group *group, *prev;
+
+ group = wpa_auth->group;
+ while (group) {
+ prev = group;
+ group = group->next;
+ bin_clear_free(prev, sizeof(*prev));
+ }
+}
+
+
/**
* wpa_init - Initialize WPA authenticator
* @addr: Authenticator address
@@ -773,36 +787,48 @@
if (wpa_auth_gen_wpa_ie(wpa_auth)) {
wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
- os_free(wpa_auth);
- return NULL;
+ goto fail;
}
wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
- if (!wpa_auth->group) {
- os_free(wpa_auth->wpa_ie);
- os_free(wpa_auth);
- return NULL;
- }
+ if (!wpa_auth->group)
+ goto fail;
+ /* Per-link PMKSA cache */
wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
wpa_auth);
if (!wpa_auth->pmksa) {
wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
- os_free(wpa_auth->group);
- os_free(wpa_auth->wpa_ie);
- os_free(wpa_auth);
- return NULL;
+ goto fail;
}
+#ifdef CONFIG_IEEE80211BE
+ /* MLD-level PMKSA cache */
+ if (wpa_auth->is_ml && wpa_auth->primary_auth) {
+ wpa_auth->ml_pmksa = pmksa_cache_auth_init(
+ wpa_auth_pmksa_free_cb, wpa_auth);
+ if (!wpa_auth->ml_pmksa) {
+ wpa_printf(MSG_ERROR,
+ "MLD-level PMKSA cache initialization failed.");
+ goto fail;
+ }
+ } else if (wpa_auth->is_ml) {
+ struct wpa_authenticator *pa = wpa_get_primary_auth(wpa_auth);
+
+ if (!pa) {
+ wpa_printf(MSG_ERROR,
+ "Could not find primary authenticator.");
+ goto fail;
+ }
+ wpa_auth->ml_pmksa = pa->ml_pmksa;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_IEEE80211R_AP
wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
if (!wpa_auth->ft_pmk_cache) {
wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
- os_free(wpa_auth->group);
- os_free(wpa_auth->wpa_ie);
- pmksa_cache_auth_deinit(wpa_auth->pmksa);
- os_free(wpa_auth);
- return NULL;
+ goto fail;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -845,6 +871,17 @@
}
return wpa_auth;
+
+fail:
+ wpa_deinit_groups(wpa_auth);
+ os_free(wpa_auth->wpa_ie);
+ pmksa_cache_auth_deinit(wpa_auth->pmksa);
+#ifdef CONFIG_IEEE80211BE
+ if (wpa_auth->primary_auth)
+ pmksa_cache_auth_deinit(wpa_auth->ml_pmksa);
+#endif /* CONFIG_IEEE80211BE */
+ os_free(wpa_auth);
+ return NULL;
}
@@ -880,16 +917,35 @@
*/
void wpa_deinit(struct wpa_authenticator *wpa_auth)
{
- struct wpa_group *group, *prev;
+#ifdef CONFIG_IEEE80211BE
+ struct wpa_authenticator *next_pa;
+#endif /* CONFIG_IEEE80211BE */
eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
-
- /* TODO: Assign ML primary authenticator to next link authenticator and
- * start rekey timer. */
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
pmksa_cache_auth_deinit(wpa_auth->pmksa);
+#ifdef CONFIG_IEEE80211BE
+ if (wpa_auth->is_ml && wpa_auth->primary_auth) {
+ next_pa = wpa_auth->cb->next_primary_auth(wpa_auth->cb_ctx);
+
+ if (!next_pa) {
+ /* Deinit PMKSA entry list if last link */
+ pmksa_cache_auth_deinit(wpa_auth->ml_pmksa);
+ } else {
+ /* Assign ML primary authenticator to the next link
+ * authenticator and start rekey timer.
+ */
+ next_pa->primary_auth = true;
+ if (next_pa->conf.wpa_group_rekey)
+ eloop_register_timeout(
+ next_pa->conf.wpa_group_rekey,
+ 0, wpa_rekey_gtk, next_pa, NULL);
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
+
#ifdef CONFIG_IEEE80211R_AP
wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
wpa_auth->ft_pmk_cache = NULL;
@@ -900,16 +956,8 @@
bitfield_free(wpa_auth->ip_pool);
#endif /* CONFIG_P2P */
-
os_free(wpa_auth->wpa_ie);
-
- group = wpa_auth->group;
- while (group) {
- prev = group;
- group = group->next;
- bin_clear_free(prev, sizeof(*prev));
- }
-
+ wpa_deinit_groups(wpa_auth);
wpa_auth_free_conf(&wpa_auth->conf);
os_free(wpa_auth);
}
@@ -2087,8 +2135,9 @@
os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
#ifdef CONFIG_TESTING_OPTIONS
- if (conf->eapol_key_reserved_random)
- random_get_bytes(key->key_id, sizeof(key->key_id));
+ if (conf->eapol_key_reserved_random &&
+ random_get_bytes(key->key_id, sizeof(key->key_id)) < 0)
+ os_memset(key->key_id, 0x11, sizeof(key->key_id));
#endif /* CONFIG_TESTING_OPTIONS */
if (kde && !encr) {
@@ -2792,8 +2841,7 @@
if (sm->wpa == WPA_VERSION_WPA2 &&
(wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) ||
(sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && sm->pmksa) ||
- wpa_key_mgmt_sae(sm->wpa_key_mgmt)) &&
- sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN) {
+ wpa_key_mgmt_sae(sm->wpa_key_mgmt))) {
pmkid = buf;
kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
@@ -3440,7 +3488,7 @@
/* GTK KDE */
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -3861,9 +3909,6 @@
if (kde.rsn_ie) {
eapol_key_ie = kde.rsn_ie;
eapol_key_ie_len = kde.rsn_ie_len;
- } else if (kde.osen) {
- eapol_key_ie = kde.osen;
- eapol_key_ie_len = kde.osen_len;
} else {
eapol_key_ie = kde.wpa_ie;
eapol_key_ie_len = kde.wpa_ie_len;
@@ -4117,7 +4162,7 @@
else
os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
- if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk) {
/*
* Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS.
@@ -4148,14 +4193,6 @@
else
os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
- if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
- /*
- * Provide unique random BIGTK to each OSEN STA to prevent use
- * of BIGTK in the BSS.
- */
- if (random_get_bytes(bigtk.bigtk, len) < 0)
- return pos;
- }
pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
(const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
NULL, 0);
@@ -4301,7 +4338,8 @@
}
-static size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm)
+static size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm,
+ u16 req_links)
{
struct wpa_authenticator *wpa_auth;
size_t kde_len = 0;
@@ -4314,6 +4352,9 @@
if (!sm->mld_links[link_id].valid)
continue;
+ if (!(req_links & BIT(link_id)))
+ continue;
+
wpa_auth = sm->mld_links[link_id].wpa_auth;
if (!wpa_auth || !wpa_auth->group)
continue;
@@ -4349,7 +4390,8 @@
}
-static u8 * wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos)
+static u8 * wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos,
+ u16 req_links)
{
struct wpa_auth_ml_key_info ml_key_info;
unsigned int i, link_id;
@@ -4358,7 +4400,6 @@
/* First fetch the key information from all the authenticators */
os_memset(&ml_key_info, 0, sizeof(ml_key_info));
- ml_key_info.n_mld_links = sm->n_mld_affiliated_links + 1;
/*
* Assume that management frame protection and beacon protection are the
@@ -4371,13 +4412,19 @@
if (!sm->mld_links[link_id].valid)
continue;
+ if (!(req_links & BIT(link_id)))
+ continue;
+
ml_key_info.links[i++].link_id = link_id;
}
+ ml_key_info.n_mld_links = i;
wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info, rekey);
/* Add MLO GTK KDEs */
- for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ for (i = 0; i < ml_key_info.n_mld_links; i++) {
+ link_id = ml_key_info.links[i].link_id;
+
if (!sm->mld_links[link_id].valid ||
!ml_key_info.links[i].gtk_len)
continue;
@@ -4402,8 +4449,6 @@
os_memcpy(pos, ml_key_info.links[i].gtk,
ml_key_info.links[i].gtk_len);
pos += ml_key_info.links[i].gtk_len;
-
- i++;
}
if (!sm->mgmt_frame_prot) {
@@ -4413,7 +4458,9 @@
}
/* Add MLO IGTK KDEs */
- for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ for (i = 0; i < ml_key_info.n_mld_links; i++) {
+ link_id = ml_key_info.links[i].link_id;
+
if (!sm->mld_links[link_id].valid ||
!ml_key_info.links[i].igtk_len)
continue;
@@ -4445,8 +4492,6 @@
os_memcpy(pos, ml_key_info.links[i].igtk,
ml_key_info.links[i].igtk_len);
pos += ml_key_info.links[i].igtk_len;
-
- i++;
}
if (!sm->wpa_auth->conf.beacon_prot) {
@@ -4456,7 +4501,9 @@
}
/* Add MLO BIGTK KDEs */
- for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ for (i = 0; i < ml_key_info.n_mld_links; i++) {
+ link_id = ml_key_info.links[i].link_id;
+
if (!sm->mld_links[link_id].valid ||
!ml_key_info.links[i].bigtk ||
!ml_key_info.links[i].igtk_len)
@@ -4489,8 +4536,6 @@
os_memcpy(pos, ml_key_info.links[i].bigtk,
ml_key_info.links[i].igtk_len);
pos += ml_key_info.links[i].igtk_len;
-
- i++;
}
wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld", pos - start);
@@ -4557,7 +4602,7 @@
kde_len += 2 + ie[1];
}
- kde_len += wpa_auth_ml_group_kdes_len(sm);
+ kde_len += wpa_auth_ml_group_kdes_len(sm, KDE_ALL_LINKS);
#endif /* CONFIG_IEEE80211BE */
return kde_len;
@@ -4685,7 +4730,7 @@
wpa_printf(MSG_DEBUG,
"RSN: MLO Link KDEs and RSN Override Link KDEs len = %ld",
pos - start);
- pos = wpa_auth_ml_group_kdes(sm, pos);
+ pos = wpa_auth_ml_group_kdes(sm, pos, KDE_ALL_LINKS);
#endif /* CONFIG_IEEE80211BE */
return pos;
@@ -4808,6 +4853,20 @@
return;
}
+ if (!sm->use_ext_key_id && sm->TimeoutCtr == 1 &&
+ wpa_auth_set_key(sm->wpa_auth, 0,
+ wpa_cipher_to_alg(sm->pairwise),
+ sm->addr, 0, sm->PTK.tk,
+ wpa_cipher_key_len(sm->pairwise),
+ KEY_FLAG_PAIRWISE_NEXT)) {
+ /* Continue anyway since the many drivers do not support
+ * configuration of the TK for RX-only purposes for
+ * cases where multiple keys might be in use in parallel
+ * and this being an optional optimization to avoid race
+ * condition during TK changes that could result in some
+ * protected frames getting discarded. */
+ }
+
#ifdef CONFIG_PASN
if (sm->wpa_auth->conf.secure_ltf &&
ieee802_11_rsnx_capab(sm->rsnxe,
@@ -4827,8 +4886,7 @@
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
- if (conf->disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -5383,7 +5441,7 @@
"sending 1/2 msg of Group Key Handshake");
gtk = gsm->GTK[gsm->GN - 1];
- if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -5414,14 +5472,14 @@
kde_len = pos - kde;
#ifdef CONFIG_IEEE80211BE
} else if (sm->wpa == WPA_VERSION_WPA2 && is_mld) {
- kde_len = wpa_auth_ml_group_kdes_len(sm);
+ kde_len = wpa_auth_ml_group_kdes_len(sm, KDE_ALL_LINKS);
if (kde_len) {
kde_buf = os_malloc(kde_len);
if (!kde_buf)
return;
kde = pos = kde_buf;
- pos = wpa_auth_ml_group_kdes(sm, pos);
+ pos = wpa_auth_ml_group_kdes(sm, pos, KDE_ALL_LINKS);
kde_len = pos - kde_buf;
}
#endif /* CONFIG_IEEE80211BE */
@@ -5596,7 +5654,7 @@
wpa_hexdump_key(MSG_DEBUG, "GTK",
group->GTK[group->GN - 1], group->GTK_len);
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (wpa_auth_pmf_enabled(conf)) {
len = wpa_cipher_key_len(conf->group_mgmt_cipher);
os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
inc_byte_array(group->Counter, WPA_NONCE_LEN);
@@ -5609,7 +5667,7 @@
}
if (!wpa_auth->non_tx_beacon_prot &&
- conf->ieee80211w == NO_MGMT_FRAME_PROTECTION)
+ !wpa_auth_pmf_enabled(conf))
return ret;
if (!conf->beacon_prot)
return ret;
@@ -5764,7 +5822,7 @@
return 0;
pos += 8;
os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
- if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -5803,7 +5861,7 @@
pos += 6;
os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
- if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk) {
/*
* Provide unique random IGTK to each STA to prevent use
* of IGTK in the BSS.
@@ -5842,14 +5900,6 @@
pos += 6;
os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
- if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
- /*
- * Provide unique random BIGTK to each STA to prevent use
- * of BIGTK in the BSS.
- */
- if (random_get_bytes(pos, len) < 0)
- return 0;
- }
pos += len;
wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
@@ -5930,7 +5980,7 @@
KEY_FLAG_GROUP_TX_DEFAULT) < 0)
ret = -1;
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (wpa_auth_pmf_enabled(conf)) {
enum wpa_alg alg;
size_t len;
@@ -6486,16 +6536,27 @@
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
- int akmp)
+ int akmp, bool is_ml)
{
+ struct rsn_pmksa_cache *pmksa = wpa_auth->pmksa;
+ const u8 *aa = wpa_auth->addr;
+
if (wpa_auth->conf.disable_pmksa_caching)
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, pmk_len);
if (!akmp)
akmp = WPA_KEY_MGMT_SAE;
- if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
- NULL, 0, wpa_auth->addr, addr, 0, NULL, akmp))
+
+#ifdef CONFIG_IEEE80211BE
+ if (is_ml) {
+ pmksa = wpa_auth->ml_pmksa;
+ aa = wpa_auth->mld_addr;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
+ if (pmksa_cache_auth_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, aa, addr,
+ 0, NULL, akmp))
return 0;
return -1;
@@ -6511,17 +6572,27 @@
int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
- int session_timeout, int akmp, const u8 *dpp_pkhash)
+ int session_timeout, int akmp, const u8 *dpp_pkhash,
+ bool is_ml)
{
+ struct rsn_pmksa_cache *pmksa;
+ const u8 *aa;
struct rsn_pmksa_cache_entry *entry;
if (!wpa_auth || wpa_auth->conf.disable_pmksa_caching)
return -1;
wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (3)", pmk, PMK_LEN);
- entry = pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
- NULL, 0, wpa_auth->addr, addr, session_timeout,
- NULL, akmp);
+ pmksa = wpa_auth->pmksa;
+ aa = wpa_auth->addr;
+#ifdef CONFIG_IEEE80211BE
+ if (is_ml) {
+ pmksa = wpa_auth->ml_pmksa;
+ aa = wpa_auth->mld_addr;
+ }
+#endif /* CONFIG_IEEE80211BE */
+ entry = pmksa_cache_auth_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, aa,
+ addr, session_timeout, NULL, akmp);
if (!entry)
return -1;
@@ -6539,28 +6610,66 @@
if (!wpa_auth || !wpa_auth->pmksa)
return;
+
pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
if (pmksa) {
wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
MACSTR " based on request", MAC2STR(sta_addr));
pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
}
+
+#ifdef CONFIG_IEEE80211BE
+ if (wpa_auth->ml_pmksa) {
+ pmksa = pmksa_cache_auth_get(wpa_auth->ml_pmksa,
+ sta_addr, NULL);
+ if (pmksa) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: Remove PMKSA cache entry for " MACSTR
+ " based on request (MLD)",
+ MAC2STR(sta_addr));
+ pmksa_cache_free_entry(wpa_auth->ml_pmksa, pmksa);
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
}
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
size_t len)
{
+ int ret, index;
+ char *pos = buf, *end = buf + len;
+
if (!wpa_auth || !wpa_auth->pmksa)
return 0;
- return pmksa_cache_auth_list(wpa_auth->pmksa, buf, len);
+
+ ret = os_snprintf(pos, len,
+ "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+
+ index = 0;
+ pos += pmksa_cache_auth_list(wpa_auth->pmksa, pos, end - pos, &index);
+#ifdef CONFIG_IEEE80211BE
+ if (wpa_auth->ml_pmksa)
+ pos += pmksa_cache_auth_list(wpa_auth->ml_pmksa,
+ pos, end - pos, &index);
+#endif /* CONFIG_IEEE80211BE */
+
+ return pos - buf;
}
void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
{
- if (wpa_auth && wpa_auth->pmksa)
+ if (wpa_auth && wpa_auth->pmksa) {
pmksa_cache_auth_flush(wpa_auth->pmksa);
+#ifdef CONFIG_IEEE80211BE
+ if (wpa_auth->ml_pmksa && wpa_auth->primary_auth)
+ pmksa_cache_auth_flush(wpa_auth->ml_pmksa);
+#endif /* CONFIG_IEEE80211BE */
+ }
}
@@ -7525,3 +7634,49 @@
}
#endif /* CONFIG_IEEE80211BE */
}
+
+
+bool wpa_auth_sm_known_sta_identification(struct wpa_state_machine *sm,
+ const u8 *timestamp,
+ const u8 *mic, size_t mic_len)
+{
+ size_t exp_mic_len;
+ u8 exp_mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ int ver;
+
+ if (!sm)
+ return false;
+
+ if (!sm->PTK_valid || !mic_len || sm->PTK.kck_len == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: No KCK to verify Known STA Identification");
+ return false;
+ }
+
+ exp_mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
+ if (mic_len != exp_mic_len) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: MIC length mismatch in Known STA Identification (received %zu, expected %zu)",
+ mic_len, exp_mic_len);
+ return false;
+ }
+
+ if (wpa_use_akm_defined(sm->wpa_key_mgmt))
+ ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
+ else if (wpa_use_cmac(sm->wpa_key_mgmt))
+ ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
+ else if (sm->pairwise != WPA_CIPHER_TKIP)
+ ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+ else
+ ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+ if (wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len, sm->wpa_key_mgmt,
+ ver, timestamp, 8, exp_mic) ||
+ os_memcmp_const(mic, exp_mic, exp_mic_len) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "RSN: Invalid MIC in Known STA Identification");
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index d4ef49c..45c8dd6 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -321,6 +321,8 @@
bool ssid_protection;
int rsn_override_omit_rsnxe;
+
+ bool spp_amsdu;
};
typedef enum {
@@ -428,6 +430,7 @@
#ifdef CONFIG_IEEE80211BE
int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info,
bool rekey);
+ struct wpa_authenticator * (*next_primary_auth)(void *ctx);
#endif /* CONFIG_IEEE80211BE */
int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2);
};
@@ -456,11 +459,13 @@
const u8 *rsnxe, size_t rsnxe_len,
const u8 *mdie, size_t mdie_len,
const u8 *owe_dh, size_t owe_dh_len,
- struct wpa_state_machine *assoc_sm);
+ struct wpa_state_machine *assoc_sm,
+ bool is_ml);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *osen_ie, size_t osen_ie_len);
int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
+int wpa_auth_uses_spp_amsdu(struct wpa_state_machine *sm);
void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv);
int wpa_auth_uses_ocv(struct wpa_state_machine *sm);
struct wpa_state_machine *
@@ -508,11 +513,12 @@
struct eapol_state_machine *eapol);
int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
- int akmp);
+ int akmp, bool is_ml);
void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid,
- int session_timeout, int akmp, const u8 *dpp_pkhash);
+ int session_timeout, int akmp, const u8 *dpp_pkhash,
+ bool is_ml);
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr);
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
@@ -692,4 +698,15 @@
sm->mld_links[link_id].wpa_auth && \
sm->wpa_auth != sm->mld_links[link_id].wpa_auth)
+static inline bool wpa_auth_pmf_enabled(struct wpa_auth_config *conf)
+{
+ return conf->ieee80211w != NO_MGMT_FRAME_PROTECTION ||
+ conf->rsn_override_mfp != NO_MGMT_FRAME_PROTECTION ||
+ conf->rsn_override_mfp_2 != NO_MGMT_FRAME_PROTECTION;
+}
+
+bool wpa_auth_sm_known_sta_identification(struct wpa_state_machine *sm,
+ const u8 *timestamp,
+ const u8 *mic, size_t mic_len);
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index de16c31..d5400a9 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2247,8 +2247,7 @@
pad_len += 8;
if (pad_len && key_len < sizeof(keybuf)) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
- if (conf->disable_gtk ||
- sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk) {
/*
* Provide unique random GTK to each STA to prevent use
* of GTK in the BSS.
@@ -2260,7 +2259,7 @@
keybuf[key_len] = 0xdd;
key_len += pad_len;
key = keybuf;
- } else if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ } else if (conf->disable_gtk) {
/*
* Provide unique random GTK to each STA to prevent use of GTK
* in the BSS.
@@ -2339,7 +2338,7 @@
pos += 6;
*pos++ = igtk_len;
igtk = gsm->IGTK[gsm->GN_igtk - 4];
- if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
+ if (conf->disable_gtk) {
/*
* Provide unique random IGTK to each STA to prevent use of
* IGTK in the BSS.
@@ -2372,7 +2371,6 @@
const u8 *kek, *bigtk;
size_t kek_len;
size_t bigtk_len;
- u8 stub_bigtk[WPA_IGTK_MAX_LEN];
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kek = sm->PTK.kek2;
@@ -2400,17 +2398,6 @@
pos += 6;
*pos++ = bigtk_len;
bigtk = gsm->BIGTK[gsm->GN_bigtk - 6];
- if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) {
- /*
- * Provide unique random BIGTK to each OSEN STA to prevent use
- * of BIGTK in the BSS.
- */
- if (random_get_bytes(stub_bigtk, bigtk_len / 8) < 0) {
- os_free(subelem);
- return NULL;
- }
- bigtk = stub_bigtk;
- }
if (aes_wrap(kek, kek_len, bigtk_len / 8, bigtk, pos)) {
wpa_printf(MSG_DEBUG,
"FT: BIGTK subelem encryption failed: kek_len=%d",
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 2323a59..94cec78 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -35,7 +35,8 @@
#include "wpa_auth_glue.h"
-static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
+static void hostapd_wpa_auth_conf(struct hostapd_iface *iface,
+ struct hostapd_bss_config *conf,
struct hostapd_config *iconf,
struct wpa_auth_config *wconf)
{
@@ -109,17 +110,6 @@
#endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_HS20
wconf->disable_gtk = conf->disable_dgaf;
- if (conf->osen) {
- wconf->disable_gtk = 1;
- wconf->wpa = WPA_PROTO_OSEN;
- wconf->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
- wconf->wpa_pairwise = 0;
- wconf->wpa_group = WPA_CIPHER_CCMP;
- wconf->rsn_pairwise = WPA_CIPHER_CCMP;
- wconf->rsn_preauth = 0;
- wconf->disable_pmksa_caching = 1;
- wconf->ieee80211w = 1;
- }
#endif /* CONFIG_HS20 */
#ifdef CONFIG_TESTING_OPTIONS
wconf->corrupt_gtk_rekey_mic_probability =
@@ -280,6 +270,8 @@
conf->no_disconnect_on_group_keyerror;
wconf->rsn_override_omit_rsnxe = conf->rsn_override_omit_rsnxe;
+ wconf->spp_amsdu = conf->spp_amsdu &&
+ (iface->drv_flags2 & WPA_DRIVER_FLAGS2_SPP_AMSDU);
}
@@ -512,6 +504,7 @@
{
struct hostapd_data *hapd = ctx;
const char *ifname = hapd->conf->iface;
+ int set_tx = !(key_flag & KEY_FLAG_NEXT);
if (vlan_id > 0) {
ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
@@ -564,8 +557,8 @@
hapd->last_gtk_len = key_len;
}
#endif /* CONFIG_TESTING_OPTIONS */
- return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, vlan_id, 1,
- NULL, 0, key, key_len, key_flag);
+ return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, vlan_id,
+ set_tx, NULL, 0, key, key_len, key_flag);
}
@@ -1641,6 +1634,21 @@
return 0;
}
+
+static struct wpa_authenticator * hostapd_next_primary_auth(void *cb_ctx)
+{
+ struct hostapd_data *hapd = cb_ctx, *bss;
+
+ for_each_mld_link(bss, hapd) {
+ if (bss == hapd)
+ continue;
+ if (bss->wpa_auth)
+ return bss->wpa_auth;
+ }
+
+ return NULL;
+}
+
#endif /* CONFIG_IEEE80211BE */
@@ -1710,6 +1718,7 @@
#endif /* CONFIG_PASN */
#ifdef CONFIG_IEEE80211BE
.get_ml_key_info = hostapd_wpa_auth_get_ml_key_info,
+ .next_primary_auth = hostapd_next_primary_auth,
#endif /* CONFIG_IEEE80211BE */
.get_drv_flags = hostapd_wpa_auth_get_drv_flags,
};
@@ -1717,7 +1726,7 @@
size_t wpa_ie_len;
struct hostapd_data *tx_bss;
- hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf);
+ hostapd_wpa_auth_conf(hapd->iface, hapd->conf, hapd->iconf, &_conf);
_conf.msg_ctx = hapd->msg_ctx;
tx_bss = hostapd_mbssid_get_tx_bss(hapd);
if (tx_bss != hapd)
@@ -1843,7 +1852,9 @@
void hostapd_reconfig_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config wpa_auth_conf;
- hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &wpa_auth_conf);
+
+ hostapd_wpa_auth_conf(hapd->iface, hapd->conf, hapd->iconf,
+ &wpa_auth_conf);
wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
}
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index cb902e4..0aa25b9 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -97,6 +97,7 @@
#endif /* CONFIG_IEEE80211R_AP */
unsigned int is_wnmsleep:1;
unsigned int pmkid_set:1;
+ unsigned int spp_amsdu:1;
unsigned int ptkstart_without_success;
@@ -266,6 +267,8 @@
#endif /* CONFIG_P2P */
#ifdef CONFIG_IEEE80211BE
+ /* MLD-level PMKSA cache for non-AP MLD entries only. */
+ struct rsn_pmksa_cache *ml_pmksa;
bool is_ml;
u8 mld_addr[ETH_ALEN];
u8 link_id;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index ce7f90a..d56eeaa 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -296,13 +296,6 @@
num_suites++;
}
#endif /* CONFIG_DPP */
-#ifdef CONFIG_HS20
- if (key_mgmt & WPA_KEY_MGMT_OSEN) {
- RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
- pos += RSN_SELECTOR_LEN;
- num_suites++;
- }
-#endif /* CONFIG_HS20 */
#ifdef CONFIG_PASN
if (key_mgmt & WPA_KEY_MGMT_PASN) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
@@ -507,6 +500,8 @@
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
if (conf->ssid_protection)
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
+ if (conf->spp_amsdu)
+ capab |= BIT(WLAN_RSNX_CAPAB_SPP_A_MSDU);
return capab;
}
@@ -579,57 +574,6 @@
}
-static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
-{
- u8 *len;
- u16 capab;
-
- *eid++ = WLAN_EID_VENDOR_SPECIFIC;
- len = eid++; /* to be filled */
- WPA_PUT_BE24(eid, OUI_WFA);
- eid += 3;
- *eid++ = HS20_OSEN_OUI_TYPE;
-
- /* Group Data Cipher Suite */
- RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
- eid += RSN_SELECTOR_LEN;
-
- /* Pairwise Cipher Suite Count and List */
- WPA_PUT_LE16(eid, 1);
- eid += 2;
- RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
- eid += RSN_SELECTOR_LEN;
-
- /* AKM Suite Count and List */
- WPA_PUT_LE16(eid, 1);
- eid += 2;
- RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
- eid += RSN_SELECTOR_LEN;
-
- /* RSN Capabilities */
- capab = 0;
- if (conf->wmm_enabled) {
- /* 4 PTKSA replay counters when using WMM */
- capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
- }
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
- capab |= WPA_CAPABILITY_MFPC;
- if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
- capab |= WPA_CAPABILITY_MFPR;
- }
-#ifdef CONFIG_OCV
- if (conf->ocv)
- capab |= WPA_CAPABILITY_OCVC;
-#endif /* CONFIG_OCV */
- WPA_PUT_LE16(eid, capab);
- eid += 2;
-
- *len = eid - len - 1;
-
- return eid;
-}
-
-
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
{
u8 *pos, buf[1500];
@@ -654,9 +598,6 @@
pos = buf;
- if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {
- pos = wpa_write_osen(&wpa_auth->conf, pos);
- }
if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_auth->conf.rsne_override_set) {
@@ -850,6 +791,32 @@
}
+#ifdef CONFIG_IEEE80211BE
+
+struct wpa_auth_link_iter_data {
+ struct wpa_authenticator *wpa_auth;
+ struct rsn_pmksa_cache_entry *pmksa;
+ const u8 *spa;
+ const u8 *pmkid;
+};
+
+static int wpa_auth_pmksa_iter(struct wpa_authenticator *a, void *ctx)
+{
+ struct wpa_auth_link_iter_data *data = ctx;
+
+ if (a == data->wpa_auth ||
+ !ether_addr_equal(a->mld_addr, data->wpa_auth->mld_addr))
+ return 0;
+
+ data->pmksa = pmksa_cache_auth_get(a->pmksa, data->spa, data->pmkid);
+ if (data->pmksa)
+ return 1;
+ return 0;
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
enum wpa_validate_result
wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int freq,
@@ -857,7 +824,7 @@
const u8 *rsnxe, size_t rsnxe_len,
const u8 *mdie, size_t mdie_len,
const u8 *owe_dh, size_t owe_dh_len,
- struct wpa_state_machine *assoc_sm)
+ struct wpa_state_machine *assoc_sm, bool is_ml)
{
struct wpa_auth_config *conf = &wpa_auth->conf;
struct wpa_ie_data data;
@@ -958,10 +925,6 @@
else if (data.key_mgmt & WPA_KEY_MGMT_DPP)
selector = RSN_AUTH_KEY_MGMT_DPP;
#endif /* CONFIG_DPP */
-#ifdef CONFIG_HS20
- else if (data.key_mgmt & WPA_KEY_MGMT_OSEN)
- selector = RSN_AUTH_KEY_MGMT_OSEN;
-#endif /* CONFIG_HS20 */
#ifdef CONFIG_SHA384
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384)
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA384;
@@ -1082,10 +1045,6 @@
else if (key_mgmt & WPA_KEY_MGMT_DPP)
sm->wpa_key_mgmt = WPA_KEY_MGMT_DPP;
#endif /* CONFIG_DPP */
-#ifdef CONFIG_HS20
- else if (key_mgmt & WPA_KEY_MGMT_OSEN)
- sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
-#endif /* CONFIG_HS20 */
else
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
@@ -1156,7 +1115,7 @@
}
#endif /* CONFIG_OCV */
- if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
+ if (!wpa_auth_pmf_enabled(conf) ||
!(data.capabilities & WPA_CAPABILITY_MFPC))
sm->mgmt_frame_prot = 0;
else
@@ -1169,6 +1128,14 @@
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
+ if (wpa_auth->conf.spp_amsdu &&
+ ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SPP_A_MSDU) &&
+ (ciphers & (WPA_CIPHER_CCMP_256 | WPA_CIPHER_CCMP |
+ WPA_CIPHER_GCMP_256 | WPA_CIPHER_GCMP)))
+ sm->spp_amsdu = 1;
+ else
+ sm->spp_amsdu = 0;
+
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
@@ -1243,10 +1210,35 @@
sm->pmksa = NULL;
for (i = 0; i < data.num_pmkid; i++) {
+ struct rsn_pmksa_cache *pmksa = wpa_auth->pmksa;
+
wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
&data.pmkid[i * PMKID_LEN], PMKID_LEN);
- sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
+#ifdef CONFIG_IEEE80211BE
+ if (is_ml)
+ pmksa = wpa_auth->ml_pmksa;
+#endif /* CONFIG_IEEE80211BE */
+ sm->pmksa = pmksa_cache_auth_get(pmksa, sm->addr,
&data.pmkid[i * PMKID_LEN]);
+#ifdef CONFIG_IEEE80211BE
+ if (!sm->pmksa && !is_ml && wpa_auth->is_ml)
+ sm->pmksa = pmksa_cache_auth_get(
+ wpa_auth->ml_pmksa, sm->addr,
+ &data.pmkid[i * PMKID_LEN]);
+ if (!sm->pmksa && is_ml) {
+ struct wpa_auth_link_iter_data idata;
+
+ idata.wpa_auth = wpa_auth;
+ idata.pmksa = NULL;
+ idata.spa = sm->addr;
+ idata.pmkid = &data.pmkid[i * PMKID_LEN];
+ wpa_auth_for_each_auth(wpa_auth,
+ wpa_auth_pmksa_iter,
+ &idata);
+ if (idata.pmksa)
+ sm->pmksa = idata.pmksa;
+ }
+#endif /* CONFIG_IEEE80211BE */
if (!sm->pmksa && !is_zero_ether_addr(sm->p2p_dev_addr))
sm->pmksa = pmksa_cache_auth_get(
wpa_auth->pmksa, sm->p2p_dev_addr,
@@ -1376,42 +1368,17 @@
}
-#ifdef CONFIG_HS20
-int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm,
- const u8 *osen_ie, size_t osen_ie_len)
-{
- if (wpa_auth == NULL || sm == NULL)
- return -1;
-
- /* TODO: parse OSEN element */
- sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
- sm->mgmt_frame_prot = 1;
- sm->pairwise = WPA_CIPHER_CCMP;
- sm->wpa = WPA_VERSION_WPA2;
-
- if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) {
- os_free(sm->wpa_ie);
- sm->wpa_ie = os_malloc(osen_ie_len);
- if (sm->wpa_ie == NULL)
- return -1;
- }
-
- os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len);
- sm->wpa_ie_len = osen_ie_len;
-
- return 0;
-}
-
-#endif /* CONFIG_HS20 */
-
-
int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
{
return sm ? sm->mgmt_frame_prot : 0;
}
+int wpa_auth_uses_spp_amsdu(struct wpa_state_machine *sm)
+{
+ return sm ? sm->spp_amsdu : 0;
+}
+
#ifdef CONFIG_OCV
void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv)
diff --git a/src/ap/wpa_auth_kay.c b/src/ap/wpa_auth_kay.c
index 625f405..20a5aaa 100644
--- a/src/ap/wpa_auth_kay.c
+++ b/src/ap/wpa_auth_kay.c
@@ -331,6 +331,7 @@
hapd->conf->macsec_port,
hapd->conf->mka_priority,
hapd->conf->macsec_csindex,
+ hapd->conf->macsec_icv_indicator,
hapd->conf->iface,
hapd->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
@@ -477,7 +478,7 @@
cak->len = hapd->conf->mka_cak_len;
os_memcpy(cak->key, hapd->conf->mka_cak, cak->len);
- ckn->len = hapd->conf->mka_ckn_len;;
+ ckn->len = hapd->conf->mka_ckn_len;
os_memcpy(ckn->name, hapd->conf->mka_ckn, ckn->len);
res = ieee802_1x_kay_create_mka(hapd->kay, ckn, cak, 0, PSK, true);
diff --git a/src/common/defs.h b/src/common/defs.h
index 467051f..5147f32 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -39,7 +39,6 @@
#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
#define WPA_KEY_MGMT_CCKM BIT(14)
-#define WPA_KEY_MGMT_OSEN BIT(15)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
#define WPA_KEY_MGMT_FILS_SHA256 BIT(18)
@@ -69,7 +68,6 @@
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_FT_IEEE8021X_SHA384 |
WPA_KEY_MGMT_CCKM |
- WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SUITE_B |
WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 |
@@ -129,6 +127,15 @@
WPA_KEY_MGMT_FT_SAE_EXT_KEY));
}
+static inline int wpa_key_mgmt_only_sae(int akm)
+{
+ return wpa_key_mgmt_sae(akm) &&
+ !(akm & ~(WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_SAE_EXT_KEY |
+ WPA_KEY_MGMT_FT_SAE |
+ WPA_KEY_MGMT_FT_SAE_EXT_KEY));
+}
+
static inline int wpa_key_mgmt_fils(int akm)
{
return !!(akm & (WPA_KEY_MGMT_FILS_SHA256 |
@@ -144,7 +151,6 @@
WPA_KEY_MGMT_IEEE8021X_SHA256 |
WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE |
- WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SUITE_B |
WPA_KEY_MGMT_FILS_SHA256 |
WPA_KEY_MGMT_FT_FILS_SHA256));
@@ -196,7 +202,6 @@
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
#define WPA_PROTO_WAPI BIT(2)
-#define WPA_PROTO_OSEN BIT(3)
#define WPA_AUTH_ALG_OPEN BIT(0)
#define WPA_AUTH_ALG_SHARED BIT(1)
@@ -481,6 +486,7 @@
KEY_FLAG_GROUP = BIT(4),
KEY_FLAG_PAIRWISE = BIT(5),
KEY_FLAG_PMK = BIT(6),
+ KEY_FLAG_NEXT = BIT(7),
/* Used flag combinations */
KEY_FLAG_RX_TX = KEY_FLAG_RX | KEY_FLAG_TX,
KEY_FLAG_GROUP_RX_TX = KEY_FLAG_GROUP | KEY_FLAG_RX_TX,
@@ -493,8 +499,10 @@
KEY_FLAG_PAIRWISE_RX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX,
KEY_FLAG_PAIRWISE_RX_TX_MODIFY = KEY_FLAG_PAIRWISE_RX_TX |
KEY_FLAG_MODIFY,
+ KEY_FLAG_PAIRWISE_NEXT = KEY_FLAG_PAIRWISE_RX | KEY_FLAG_NEXT,
/* Max allowed flags for each key type */
- KEY_FLAG_PAIRWISE_MASK = KEY_FLAG_PAIRWISE_RX_TX_MODIFY,
+ KEY_FLAG_PAIRWISE_MASK = KEY_FLAG_PAIRWISE_RX_TX_MODIFY |
+ KEY_FLAG_NEXT,
KEY_FLAG_GROUP_MASK = KEY_FLAG_GROUP_RX_TX_DEFAULT,
KEY_FLAG_PMK_MASK = KEY_FLAG_PMK,
};
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 46f2551..22998ab 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -299,7 +299,8 @@
}
-int dpp_parse_uri_version(struct dpp_bootstrap_info *bi, const char *version)
+static int dpp_parse_uri_version(struct dpp_bootstrap_info *bi,
+ const char *version)
{
#ifdef CONFIG_DPP2
if (!version || DPP_VERSION < 2)
diff --git a/src/common/dpp_backup.c b/src/common/dpp_backup.c
index fb3f776..25c0bd5 100644
--- a/src/common/dpp_backup.c
+++ b/src/common/dpp_backup.c
@@ -161,7 +161,7 @@
/* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
attr = dpp_build_attribute(auth->conf);
attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
- if (!priv_key || !attr || !alg)
+ if (!attr || !alg)
goto fail;
/*
@@ -515,6 +515,7 @@
wpabuf_free(enc_cont_info);
return env;
fail:
+ wpa_printf(MSG_INFO, "DPP: Failed to build DPPEnvelopedData");
wpabuf_free(env);
env = NULL;
goto out;
diff --git a/src/common/dpp_reconfig.c b/src/common/dpp_reconfig.c
index 452c502..e55789c 100644
--- a/src/common/dpp_reconfig.c
+++ b/src/common/dpp_reconfig.c
@@ -569,7 +569,7 @@
}
-struct wpabuf *
+static struct wpabuf *
dpp_reconfig_build_conf(struct dpp_authentication *auth)
{
struct wpabuf *msg = NULL, *clear;
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 78a68aa..d9276b9 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -594,7 +594,8 @@
if (data->eht_enabled) switch (oper_chwidth) {
case CONF_OPER_CHWIDTH_320MHZ:
- if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ if (eht_cap &&
+ !(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) {
wpa_printf(MSG_ERROR,
"320 MHz channel width is not supported in 5 or 6 GHz");
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 1c36be5..c0d5265 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -111,11 +111,6 @@
elems->hs20 = pos;
elems->hs20_len = elen;
break;
- case HS20_OSEN_OUI_TYPE:
- /* Hotspot 2.0 OSEN */
- elems->osen = pos;
- elems->osen_len = elen;
- break;
case MBO_OUI_TYPE:
/* MBO-OCE */
elems->mbo = pos;
@@ -2586,6 +2581,9 @@
{
const struct element *elem;
+ if (!ies)
+ return NULL;
+
for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, len) {
if (elem->datalen >= 4 &&
vendor_type == WPA_GET_BE32(elem->data))
@@ -3411,7 +3409,7 @@
struct wpabuf * ieee802_11_defrag(const u8 *data, size_t len, bool ext_elem)
{
struct wpabuf *buf;
- const u8 *pos, *end = data + len;
+ const u8 *pos, *end;
size_t min_defrag_len = ext_elem ? 255 : 256;
if (!data || !len)
@@ -3425,6 +3423,7 @@
return NULL;
pos = &data[min_defrag_len - 1];
+ end = data + len;
len -= min_defrag_len - 1;
while (len > 2 && pos[0] == WLAN_EID_FRAGMENT && pos[1]) {
int ret;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 009073c..127375d 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -75,7 +75,6 @@
const u8 *ext_capab;
const u8 *bss_max_idle_period;
const u8 *ssid_list;
- const u8 *osen;
const u8 *mbo;
const u8 *ampe;
const u8 *mic;
@@ -151,7 +150,6 @@
u8 hs20_len;
u8 ext_capab_len;
u8 ssid_list_len;
- u8 osen_len;
u8 mbo_len;
u8 ampe_len;
u8 mic_len;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index c662e0a..ca4ff88 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -526,6 +526,7 @@
#define WLAN_EID_EXT_QOS_CHARACTERISTICS 113
#define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
#define WLAN_EID_EXT_BANDWIDTH_INDICATION 135
+#define WLAN_EID_EXT_KNOWN_STA_IDENTIFICATION 136
#define WLAN_EID_EXT_PASN_ENCRYPTED_DATA 140
/* Extended Capabilities field */
@@ -609,6 +610,7 @@
#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84
#define WLAN_EXT_CAPAB_MSCS 85
#define WLAN_EXT_CAPAB_SAE_PK_EXCLUSIVELY 88
+#define WLAN_EXT_CAPAB_KNOWN_STA_IDENTIFICATION 102
/* Extended RSN Capabilities */
/* bits 0-3: Field length (n-1) */
@@ -618,6 +620,7 @@
#define WLAN_RSNX_CAPAB_SECURE_LTF 8
#define WLAN_RSNX_CAPAB_SECURE_RTT 9
#define WLAN_RSNX_CAPAB_URNM_MFPR_X20 10
+#define WLAN_RSNX_CAPAB_SPP_A_MSDU 14
#define WLAN_RSNX_CAPAB_URNM_MFPR 15
#define WLAN_RSNX_CAPAB_KEK_IN_PASN 18
#define WLAN_RSNX_CAPAB_SSID_PROTECTION 21
@@ -778,6 +781,21 @@
#define WLAN_PROT_FTM 2
#define WLAN_PROT_FTM_REPORT 3
+/* Protected EHT Action field values */
+#define WLAN_PROT_EHT_T2L_MAPPING_REQUEST 0
+#define WLAN_PROT_EHT_T2L_MAPPING_RESPONSE 1
+#define WLAN_PROT_EHT_T2L_MAPPING_TEARDOWN 2
+#define WLAN_PROT_EHT_EPCS_ENABLE_REQUEST 3
+#define WLAN_PROT_EHT_EPCS_ENABLE_RESPONSE 4
+#define WLAN_PROT_EHT_EPCS_ENABLE_TEARDOWN 5
+#define WLAN_PROT_EHT_EML_OPMODE_NOTIF 6
+#define WLAN_PROT_EHT_LINK_RECOMMENDATION 7
+#define WLAN_PROT_EHT_MLO_UPDATE_REQUEST 8
+#define WLAN_PROT_EHT_MLO_UPDATE_RESPONSE 9
+#define WLAN_PROT_EHT_LINK_RECONFIG_NOTIFY 10
+#define WLAN_PROT_EHT_LINK_RECONFIG_REQUEST 11
+#define WLAN_PROT_EHT_LINK_RECONFIG_RESPONSE 12
+
/* Radio Measurement capabilities (from RM Enabled Capabilities element)
* IEEE Std 802.11-2020, 9.4.2.44, Table 9-179 */
/* byte 1 (out of 5) */
@@ -1439,7 +1457,6 @@
#define WFD_IE_VENDOR_TYPE 0x506f9a0a
#define WFD_OUI_TYPE 10
#define HS20_IE_VENDOR_TYPE 0x506f9a10
-#define OSEN_IE_VENDOR_TYPE 0x506f9a12
#define NAN_IE_VENDOR_TYPE 0x506f9a13
#define NAN_SDF_VENDOR_TYPE 0x506f9a13
#define NAN_OUI_TYPE 0x13
@@ -1598,7 +1615,6 @@
#define HS20_INDICATION_OUI_TYPE 16
#define HS20_ANQP_OUI_TYPE 17
-#define HS20_OSEN_OUI_TYPE 18
#define HS20_ROAMING_CONS_SEL_OUI_TYPE 29
#define HS20_STYPE_QUERY_LIST 1
#define HS20_STYPE_CAPABILITY_LIST 2
@@ -1607,11 +1623,6 @@
#define HS20_STYPE_CONNECTION_CAPABILITY 5
#define HS20_STYPE_NAI_HOME_REALM_QUERY 6
#define HS20_STYPE_OPERATING_CLASS 7
-#define HS20_STYPE_OSU_PROVIDERS_LIST 8
-#define HS20_STYPE_ICON_REQUEST 10
-#define HS20_STYPE_ICON_BINARY_FILE 11
-#define HS20_STYPE_OPERATOR_ICON_METADATA 12
-#define HS20_STYPE_OSU_PROVIDERS_NAI_LIST 13
#define HS20_DGAF_DISABLED 0x01
#define HS20_PPS_MO_ID_PRESENT 0x02
@@ -1621,7 +1632,6 @@
#endif /* HS20_VERSION */
/* WNM-Notification WFA vendors specific subtypes */
-#define HS20_WNM_SUB_REM_NEEDED 0
#define HS20_WNM_DEAUTH_IMMINENT_NOTICE 1
#define WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT 2
#define WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA 3
@@ -2801,15 +2811,16 @@
#define MULTI_LINK_SUB_ELEM_ID_VENDOR 221
#define MULTI_LINK_SUB_ELEM_ID_FRAGMENT 254
-/* IEEE P802.11be/D2.2, 9.4.2.312.2 - Basic Multi-Link element */
+/* IEEE P802.11be/D7.0, 9.4.2.322.2 - Basic Multi-Link element */
-/* Figure 9-1002g: Presence Bitmap subfield of the Basic Multi-Link element */
+/* Figure 9-1074o: Presence Bitmap subfield of the Basic Multi-Link element */
#define BASIC_MULTI_LINK_CTRL_PRES_LINK_ID 0x0010
#define BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT 0x0020
#define BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO 0x0040
#define BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA 0x0080
#define BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA 0x0100
#define BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID 0x0200
+#define BASIC_MULTI_LINK_CTRL_PRES_EXT_MLD_CAP 0x0400
/*
* STA Control field definitions of Per-STA Profile subelement in Basic
@@ -2920,6 +2931,9 @@
/* IEEE P802.11be/D4.0, 9.4.2.312.4 - Reconfiguration Multi-Link element */
#define RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR 0x0001
+#define RECONF_MULTI_LINK_CTRL_PRES_EML_CAPA 0x0002
+#define RECONF_MULTI_LINK_CTRL_PRES_MLD_CAPA 0x0004
+#define RECONF_MULTI_LINK_CTRL_PRES_EXT_MLD_CAP 0x0008
#define EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK 0x000f
#define EHT_PER_STA_RECONF_CTRL_COMPLETE_PROFILE 0x0010
@@ -2928,6 +2942,25 @@
#define EHT_PER_STA_RECONF_CTRL_OP_UPDATE_TYPE_MSK 0x0780
#define EHT_PER_STA_RECONF_CTRL_OP_PARAMS 0x0800
#define EHT_PER_STA_RECONF_CTRL_NSTR_BITMAP_SIZE 0x1000
+#define EHT_PER_STA_RECONF_CTRL_NSTR_INDICATION 0x2000
+
+/* IEEE P802.11be/D7.0, Figure 9-1074ad - Common Info field format of the
+ * Reconfiguration Multi-Link element */
+struct eht_ml_reconf_common_info {
+ u8 len;
+
+ /*
+ * Followed by optional fields based on the multi link reconf presence
+ * bitmap
+ *
+ * MLD MAC Address: 6 octets
+ * EML Capabilities: 2 octets
+ * MLD Capabilities and Operations: 2 octets
+ * Extended MLD Capabilities and Operations: 2 octets
+ */
+ u8 variable[];
+} STRUCT_PACKED;
+
/* IEEE P802.11be/D2.0, 9.4.2.312.1 - Multi-Link element / General */
diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index 2c1d0c4..4f63adc 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -1426,6 +1426,32 @@
}
+int nan_de_unpause_publish(struct nan_de *de, int publish_id,
+ u8 peer_instance_id, const u8 *peer_addr)
+{
+ struct nan_de_service *srv;
+
+ wpa_printf(MSG_DEBUG,
+ "NAN: UnpausePublish(publish_id=%d, peer_instance_id=%d peer_addr="
+ MACSTR ")",
+ publish_id, peer_instance_id, MAC2STR(peer_addr));
+
+ if (publish_id < 1 || publish_id > NAN_DE_MAX_SERVICE)
+ return -1;
+ srv = de->service[publish_id - 1];
+ if (!srv || srv->type != NAN_DE_PUBLISH)
+ return -1;
+
+ if (srv->sel_peer_id != peer_instance_id ||
+ !ether_addr_equal(peer_addr, srv->sel_peer_addr) ||
+ !os_reltime_initialized(&srv->pause_state_end))
+ return -1;
+
+ nan_de_unpause_state(srv);
+ return 0;
+}
+
+
int nan_de_subscribe(struct nan_de *de, const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi, const struct wpabuf *elems,
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index 9c1df31..41e294e 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -120,6 +120,9 @@
int nan_de_update_publish(struct nan_de *de, int publish_id,
const struct wpabuf *ssi);
+int nan_de_unpause_publish(struct nan_de *de, int publish_id,
+ u8 peer_instance_id, const u8 *peer_addr);
+
struct nan_subscribe_params {
/* configuration_parameters */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 6c80589..3cc2f93 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1325,6 +1325,27 @@
*
* The attributes used with this event are defined in
* enum qca_wlan_vendor_attr_idle_shutdown.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PRI_LINK_MIGRATE: Vendor subcommand that can
+ * be used to trigger primary link migration from user space. Either just
+ * one ML client or a bunch of clients can be migrated.
+ *
+ * The attributes used with this subcommand are defined in
+ * &enum qca_wlan_vendor_attr_pri_link_migrate.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_MLD_MAC_ADDR and
+ * @QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_CURRENT_PRI_LINK_ID are mutually
+ * exclusive attributes. Migration should be requested for either one ML
+ * client or a bunch of ML clients.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_PERIODIC_PROBE_RSP_CFG: Vendor subcommand that
+ * can be used to send periodic or on-demand directed Probe Response frames
+ * to a connected peer.
+ *
+ * This command is only applicable for AP/P2P GO mode.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_periodic_probe_rsp_cfg.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -1564,6 +1585,8 @@
QCA_NL80211_VENDOR_SUBCMD_GET_FW_SCAN_REPORT = 253,
QCA_NL80211_VENDOR_SUBCMD_IDLE_SHUTDOWN = 254,
/* 255 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_PRI_LINK_MIGRATE = 256,
+ QCA_NL80211_VENDOR_SUBCMD_PERIODIC_PROBE_RSP_CFG = 257,
};
/* Compatibility defines for previously used subcmd names.
@@ -2320,6 +2343,13 @@
* supports preferring 6 GHz PSC channel as a primary channel in ACS
* result.
*
+ * @QCA_WLAN_VENDOR_FEATURE_P2P_V2: Flag indicates that the driver supports
+ * P2P R2 functionality (P2P R2 Discovery, Pairing, TWT power save, etc).
+ *
+ * @QCA_WLAN_VENDOR_FEATURE_PCC_MODE: Flag indicates that the driver supports
+ * P2P Connection Compatibility mode in which GO allows connection
+ * with both P2P R1 and R2 clients.
+ *
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -2351,6 +2381,8 @@
QCA_WLAN_VENDOR_FEATURE_RSN_OVERRIDE_STA = 25,
QCA_WLAN_VENDOR_FEATURE_NAN_USD_OFFLOAD = 26,
QCA_WLAN_VENDOR_FEATURE_ACS_PREFER_6GHZ_PSC = 27,
+ QCA_WLAN_VENDOR_FEATURE_P2P_V2 = 28,
+ QCA_WLAN_VENDOR_FEATURE_PCC_MODE = 29,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -3849,6 +3881,13 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SWITCH_BT_RSSI_DIFF = 129,
+ /* 8-bit unsigned value to enable/disable setup link Reconfiguration
+ * feature support in STA mode.
+ * 1 - Enable
+ * 0 - Disable.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_SETUP_LINK_RECONFIG_SUPPORT = 130,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -5918,6 +5957,11 @@
* @QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN: Set if the roam has to be triggered
* based on the scan results obtained from an external scan (not triggered
* to aim roaming).
+ * @QCA_ROAM_TRIGGER_REASON_WTC: Set if the roam has to be triggered
+ * due to Wireless to Cellular BSS Transition Management (BTM) request.
+ * @QCA_ROAM_TRIGGER_REASON_BT_ACTIVITY: Set if the roam has to be triggered
+ * due to Bluetooth connection is established when the station is connected
+ * in the 2.4 GHz band.
*
* Set the corresponding roam trigger reason bit to consider it for roam
* trigger.
@@ -5938,6 +5982,8 @@
QCA_ROAM_TRIGGER_REASON_IDLE = 1 << 10,
QCA_ROAM_TRIGGER_REASON_TX_FAILURES = 1 << 11,
QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN = 1 << 12,
+ QCA_ROAM_TRIGGER_REASON_WTC = 1 << 13,
+ QCA_ROAM_TRIGGER_REASON_BT_ACTIVITY = 1 << 14,
};
/*
@@ -10585,6 +10631,40 @@
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RSNE_ADD_RANDOM_PMKIDS = 75,
+ /* 8-bit unsigned value to configure Triggered SU Beamforming Feedback
+ * support in the EHT capabilities of an Association Request frame.
+ * 1-enable, 0-disable
+ *
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_TRIG_SU_BFORMING_FEEDBACK = 76,
+
+ /* 8-bit unsigned value to configure the extra EHT-LTFs support in the
+ * EHT capabilities of an Association Request frame.
+ * 1-enable, 0-disable
+ *
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_EXTRA_LTF = 77,
+
+ /* 8-bit unsigned integer to configure the firmware to reject AP's BSS
+ * Transition Management (BTM) request frame by sending a BTM response
+ * with error status code.
+ *
+ * 1 - STA rejects AP's BTM request frame
+ * 0 - STA accepts AP's BTM request frame
+ *
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BTM_REQ_REJECT = 78,
+
+ /* Nested attribute to control the response of the driver upon receiving
+ * a BTM request from the AP.
+ * Uses the enum qca_wlan_vendor_attr_btm_req_resp attributes.
+ * This attribute is used to configure the STA.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BTM_REQ_RESP = 79,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -15086,6 +15166,56 @@
* If present, it indicates the successful PASN handshake with the peer. If
* this flag is not present, it indicates that the PASN handshake with the
* peer device failed.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_AKM: Optional u32 attribute. It indicates the
+ * AKM suite that is preferred in the PASN handshake in the event from the
+ * driver to userspace when %QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to
+ * %QCA_WLAN_VENDOR_PASN_ACTION_AUTH. In the status report from userspace
+ * to the driver, it indicates the actual AKM suite used in the handshake.
+ * Userspace can select the AKM based on the AP's capabilities, if the
+ * given AKM suite is not applicable. Possible values are defined in
+ * IEEE Std 802.11-2020, 9.4.2.24.3 (AKM suites) (e.g., 0x000FAC04)
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_CIPHER: Optional u32 attribute. It indicates
+ * the pairwise cipher suite that is preferred in the PASN handshake in
+ * the event from the driver to userspace when
+ * %QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to
+ * %QCA_WLAN_VENDOR_PASN_ACTION_AUTH. In the status report from userspace
+ * to the driver, it indicates the actual cipher used in the handshake.
+ * Userspace can select the cipher suite based on the capabilities of the
+ * P, if the given cipher suite is not applicable. Possible values are
+ * defined in IEEE Std 802.11-2020, 9.4.2.24.2 (Cipher suites)
+ * (e.g., 0x000FAC04).
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_PASSWORD: This is a variable length byte
+ * array attribute. This attribute is present if the AKM suite specified
+ * in %QCA_WLAN_VENDOR_ATTR_PASN_PEER_AKM requires a password. The
+ * password is used in PASN handshake request in an event from the driver
+ * to userspace when %QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to
+ * %QCA_WLAN_VENDOR_PASN_ACTION_AUTH.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_PMKID: This is a byte array attribute with a
+ * size of 16 bytes. When this attribute is present this PMKSA caching
+ * using the PMKSA identified by this PMKID is preferred to be used with
+ * PASN. This attribute is sent along with PASN handshake request in an
+ * event from the driver to userspace when
+ * %QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to
+ * %QCA_WLAN_VENDOR_PASN_ACTION_AUTH.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_COMEBACK_AFTER: u16 attribute in units for
+ * TUs (1024 microseconds). This attribute is sent from userspace along
+ * with the attribute %QCA_WLAN_VENDOR_ATTR_PASN_PEER_COOKIE to the
+ * driver in the status report using the %QCA_NL80211_VENDOR_SUBCMD_PASN
+ * subcommand when the AP request PASN to be retried later.
+ * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_COOKIE: This is a variable length byte array
+ * attribute. In case an AP refused PASN temporarily, the STA can retry
+ * PASN handshake by attaching this attribute data to PASN request after
+ * the time period mentioned in the attribute
+ * %QCA_WLAN_VENDOR_ATTR_PASN_PEER_COMEBACK_AFTER.
+ * In case the AP refused the PASN handshake temporarily, cookie data is
+ * received from the AP and it is sent from userspace to the driver along
+ * with the attribute %QCA_WLAN_VENDOR_ATTR_PASN_PEER_COMEBACK_AFTER in
+ * the status report using the %QCA_NL80211_VENDOR_SUBCMD_PASN subcommand.
+ * When the driver wants to retry PASN with the same AP after having
+ * received this information, this attribute must be sent along with PASN
+ * handshake request in an event from the driver to
+ * userspace when %QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to
+ * %QCA_WLAN_VENDOR_PASN_ACTION_AUTH.
*/
enum qca_wlan_vendor_attr_pasn_peer {
QCA_WLAN_VENDOR_ATTR_PASN_PEER_INVALID = 0,
@@ -15093,6 +15223,12 @@
QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR = 2,
QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED = 3,
QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS = 4,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_AKM = 5,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_CIPHER = 6,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_PASSWORD = 7,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_PMKID = 8,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_COMEBACK_AFTER = 9,
+ QCA_WLAN_VENDOR_ATTR_PASN_PEER_COOKIE = 10,
/* keep last */
QCA_WLAN_VENDOR_ATTR_PASN_PEER_AFTER_LAST,
@@ -17801,6 +17937,8 @@
* @QCA_TRAFFIC_TYPE_SCREEN_SHARE: Traffic type is screen share
* @QCA_TRAFFIC_TYPE_UNKNOWN: Traffic type is unknown
* @QCA_TRAFFIC_TYPE_INVALID: Invalid traffic type
+ * @QCA_TRAFFIC_TYPE_BROWSING: Traffic type is browsing website
+ * @QCA_TRAFFIC_TYPE_APERIODIC_BURSTS: Traffic type is aperiodic bursts
*/
enum qca_traffic_type {
QCA_TRAFFIC_TYPE_STREAMING = 0,
@@ -17810,6 +17948,8 @@
QCA_TRAFFIC_TYPE_SCREEN_SHARE = 4,
QCA_TRAFFIC_TYPE_UNKNOWN = 5,
QCA_TRAFFIC_TYPE_INVALID = 6,
+ QCA_TRAFFIC_TYPE_BROWSING = 7,
+ QCA_TRAFFIC_TYPE_APERIODIC_BURSTS = 8,
};
/**
@@ -18791,4 +18931,139 @@
QCA_WLAN_VENDOR_ATTR_IDLE_SHUTDOWN_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_vendor_attr_pri_link_migrate: Attributes used by the vendor
+ * subcommand %QCA_NL80211_VENDOR_SUBCMD_PRI_LINK_MIGRATE.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_MLD_MAC_ADDR: 6 byte MAC address. When
+ * specified, indicates that primary link migration will occur only for
+ * the ML client with the given MLD MAC address.
+ * @QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_CURRENT_PRI_LINK_ID: Optional u8
+ * attribute. When specified, all ML clients having their current primary
+ * link as specified will be considered for migration.
+ * @QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_NEW_PRI_LINK_ID: Optional u8 attribute.
+ * Indicates the new primary link to which the selected ML clients
+ * should be migrated to. If not provided, the driver will select a
+ * suitable primary link on its own.
+ */
+enum qca_wlan_vendor_attr_pri_link_migrate {
+ QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_MLD_MAC_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_CURRENT_PRI_LINK_ID = 2,
+ QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_NEW_PRI_LINK_ID = 3,
+
+ /* keep this last */
+ QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_MAX =
+ QCA_WLAN_VENDOR_ATTR_PRI_LINK_MIGR_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_btm_req_resp_type: Represents response types to follow
+ * upon receiving BTM request from AP.
+ *
+ * @QCA_WLAN_BTM_REQ_RESP_DEFAULT: Reset to default behavior.
+ * @QCA_WLAN_BTM_REQ_RESP_RECONFIG_FRAME: Send link reconfiguration request
+ * frames with specified info.
+ * @QCA_WLAN_BTM_REQ_RESP_TTLM_FRAME: Send TTLM request frame.
+ * @QCA_WLAN_BTM_REQ_RESP_REASSOC_FRAME: Send Reassociation Request frame.
+ */
+enum qca_wlan_vendor_btm_req_resp_type {
+ QCA_WLAN_BTM_REQ_RESP_DEFAULT = 0,
+ QCA_WLAN_BTM_REQ_RESP_RECONFIG_FRAME = 1,
+ QCA_WLAN_BTM_REQ_RESP_TTLM_FRAME = 2,
+ QCA_WLAN_BTM_REQ_RESP_REASSOC_FRAME = 3,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_reconfig_frame_info - Attribute used by
+ * %QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_RECONFIG_FRAME_INFO.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_RECONFIG_ADD_LINKS_BITMASK: u16 attribute. Bitmask of
+ * link IDs to be added.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_RECONFIG_DELETE_LINKS_BITMASK: u16 attribute bitmask of
+ * link IDs to be removed.
+ */
+enum qca_wlan_vendor_attr_reconfig_frame_info {
+ QCA_WLAN_VENDOR_ATTR_RECONFIG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_RECONFIG_ADD_LINKS_BITMASK = 1,
+ QCA_WLAN_VENDOR_ATTR_RECONFIG_DELETE_LINKS_BITMASK = 2,
+
+ QCA_WLAN_VENDOR_ATTR_RECONFIG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_RECONFIG_MAX =
+ QCA_WLAN_VENDOR_ATTR_RECONFIG_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_btm_req_resp - Attribute used by
+ * %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BTM_REQ_RESP.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_TYPE: u8 attribute. Indicates type of
+ * response to send. Possible values for this attribute are defined in
+ * enum qca_wlan_vendor_btm_req_resp_type. This is a mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_RECONFIG_FRAME_INFO: Array of nested
+ * attributes containing information about one or more setup link
+ * reconfiguration request frames, each set represents one link reconfiguration
+ * frame information. The driver shall send a separate link reconfiguration
+ * frame for each nested attribute set. It takes attributes as defined in enum
+ * qca_wlan_vendor_attr_reconfig_frame_info. This attribute must be present
+ * when %QCA_WLAN_BTM_REQ_RESP_RECONFIG_FRAME specified in
+ * %QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_TYPE attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_TTLM_MAP: TID to Link Mapping to
+ * be used in TTLM request frame. This nested attribute with
+ * %NL80211_ATTR_MLO_TTLM_DLINK and %NL80211_ATTR_MLO_TTLM_ULINK is used to
+ * specify the TID to Link mapping for downlink/uplink traffic. This attribute
+ * must be present when %QCA_WLAN_BTM_REQ_RESP_TTLM_FRAME specified in
+ * %QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_TYPE attribute.
+ */
+enum qca_wlan_vendor_attr_btm_req_resp {
+ QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_TYPE = 1,
+ QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_RECONFIG_FRAME_INFO = 2,
+ QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_TTLM_MAP = 3,
+
+ QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_MAX =
+ QCA_WLAN_VENDOR_ATTR_BTM_REQ_RESP_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_wlan_vendor_attr_periodic_probe_rsp_cfg: Attributes used
+ * by vendor subcmd QCA_NL80211_VENDOR_SUBCMD_PERIODIC_PROBE_RSP_CFG
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PROBE_RESP_CFG_PEER_MAC_ADDR: Connected peer
+ * MAC address to which Probe Response frames are to be sent.
+ * Multicast/Broadcast addresses are not supported.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PROBE_RESP_CFG_PERIOD: 32-bit unsigned value.
+ * This attribute specifies the interval (in microseconds) in which directed
+ * Probe Response frames are sent periodically to the peer as specified in
+ * attribute QCA_WLAN_VENDOR_ATTR_PROBE_RESP_CFG_PEER_MAC_ADDR. When the peer
+ *is in power save, sending of the frames might be delayed until the device
+ * comes out of power save. Attribute value can be in the range of minimum value
+ * of 50000 and maximum value of 1500000.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_PROBE_RESP_CFG_COUNT: 8-bit unsigned value.
+ * Specifies number of directed Probe Responses frames that can be sent as per
+ * interval defined in QCA_WLAN_VENDOR_ATTR_PROBE_RESP_CFG_PERIOD. When
+ * attribute value is 255, directed Probe Response frames are sent continuously
+ * until this attribute is sent as 0 in the command to disable period
+ * transmission. When the attribute value is 1, one directed Probe Response
+ * frame will be sent and the attribute
+ * QCA_WLAN_VENDOR_ATTR_PROBE_RESP_CFG_PERIOD will not be considered.
+ */
+enum qca_wlan_vendor_attr_periodic_probe_rsp_cfg {
+ QCA_WLAN_VENDOR_ATTR_PROBE_RSP_CFG_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_PROBE_RSP_CFG_PEER_MAC_ADDR = 1,
+ QCA_WLAN_VENDOR_ATTR_PROBE_RSP_CFG_PERIOD = 2,
+ QCA_WLAN_VENDOR_ATTR_PROBE_RSP_CFG_COUNT = 3,
+
+ QCA_WLAN_VENDOR_ATTR_PROBE_RESP_CFG_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PROBE_RESP_CFG_MAX =
+ QCA_WLAN_VENDOR_ATTR_PROBE_RESP_CFG_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index ce282db..801f363 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -366,8 +366,11 @@
const_time_select_bin(found, stub_password, password,
password_len, tmp_password);
if (hmac_sha256_vector(addrs, sizeof(addrs), 2,
- addr, len, pwd_seed) < 0)
+ addr, len, pwd_seed) < 0) {
+ wpa_printf(MSG_INFO,
+ "SAE: hmac_sha256_vector() failed - cannot derive PWE");
break;
+ }
res = sae_test_pwd_seed_ecc(sae, pwd_seed,
prime, qr_bin, qnr_bin, x_cand_bin);
diff --git a/src/common/sae.h b/src/common/sae.h
index 8f74353..0d94e1f 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -65,6 +65,7 @@
struct wpabuf *own_rejected_groups;
struct wpabuf *peer_rejected_groups;
unsigned int own_addr_higher:1;
+ unsigned int try_other_password:1;
#ifdef CONFIG_SAE_PK
u8 kek[SAE_MAX_HASH_LEN];
@@ -85,6 +86,8 @@
#endif /* CONFIG_SAE_PK */
struct os_reltime disabled_until;
+
+ const void *used_pw;
};
struct sae_pt {
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 9c96269..613ea7f 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -134,8 +134,7 @@
*/
int wpa_use_akm_defined(int akmp)
{
- return akmp == WPA_KEY_MGMT_OSEN ||
- akmp == WPA_KEY_MGMT_OWE ||
+ return akmp == WPA_KEY_MGMT_OWE ||
akmp == WPA_KEY_MGMT_DPP ||
akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 ||
akmp == WPA_KEY_MGMT_IEEE8021X_SHA384 ||
@@ -152,8 +151,7 @@
*/
int wpa_use_cmac(int akmp)
{
- return akmp == WPA_KEY_MGMT_OSEN ||
- akmp == WPA_KEY_MGMT_OWE ||
+ return akmp == WPA_KEY_MGMT_OWE ||
akmp == WPA_KEY_MGMT_DPP ||
wpa_key_mgmt_ft(akmp) ||
wpa_key_mgmt_sha256(akmp) ||
@@ -174,8 +172,7 @@
*/
int wpa_use_aes_key_wrap(int akmp)
{
- return akmp == WPA_KEY_MGMT_OSEN ||
- akmp == WPA_KEY_MGMT_OWE ||
+ return akmp == WPA_KEY_MGMT_OWE ||
akmp == WPA_KEY_MGMT_DPP ||
akmp == WPA_KEY_MGMT_IEEE8021X_SHA384 ||
wpa_key_mgmt_ft(akmp) ||
@@ -266,12 +263,6 @@
os_memcpy(mic, hash, key_len);
break;
#endif /* CONFIG_SAE */
-#ifdef CONFIG_HS20
- case WPA_KEY_MGMT_OSEN:
- wpa_printf(MSG_DEBUG,
- "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - OSEN)");
- return omac1_aes_128(key, buf, len, mic);
-#endif /* CONFIG_HS20 */
#ifdef CONFIG_SUITEB
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
wpa_printf(MSG_DEBUG,
@@ -1831,8 +1822,6 @@
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_DPP)
return WPA_KEY_MGMT_DPP;
#endif /* CONFIG_DPP */
- if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
- return WPA_KEY_MGMT_OSEN;
#ifdef CONFIG_PASN
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PASN)
return WPA_KEY_MGMT_PASN;
@@ -1893,17 +1882,7 @@
return -1;
}
- if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 &&
- rsn_ie[1] == rsn_ie_len - 2 &&
- WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) {
- pos = rsn_ie + 6;
- left = rsn_ie_len - 6;
-
- data->group_cipher = WPA_CIPHER_GTK_NOT_USED;
- data->has_group = 1;
- data->key_mgmt = WPA_KEY_MGMT_OSEN;
- data->proto = WPA_PROTO_OSEN;
- } else if (rsn_ie_len >= 2 + 4 + 2 && rsn_ie[1] >= 4 + 2 &&
+ if (rsn_ie_len >= 2 + 4 + 2 && rsn_ie[1] >= 4 + 2 &&
rsn_ie[1] == rsn_ie_len - 2 &&
(WPA_GET_BE32(&rsn_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE ||
WPA_GET_BE32(&rsn_ie[2]) ==
@@ -2801,8 +2780,6 @@
return "FT-SAE";
case WPA_KEY_MGMT_FT_SAE_EXT_KEY:
return "FT-SAE-EXT-KEY";
- case WPA_KEY_MGMT_OSEN:
- return "OSEN";
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
return "WPA2-EAP-SUITE-B";
case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
@@ -2849,8 +2826,6 @@
return RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
if (akm & WPA_KEY_MGMT_CCKM)
return RSN_AUTH_KEY_MGMT_CCKM;
- if (akm & WPA_KEY_MGMT_OSEN)
- return RSN_AUTH_KEY_MGMT_OSEN;
if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
@@ -3483,12 +3458,6 @@
return 0;
}
- if (selector == OSEN_IE_VENDOR_TYPE) {
- ie->osen = pos;
- ie->osen_len = dlen;
- return 0;
- }
-
if (left >= PMKID_LEN && selector == RSN_KEY_DATA_PMKID) {
ie->pmkid = p;
wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", pos, dlen);
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 9f1a539..d2c326c 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -94,7 +94,6 @@
#define RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY RSN_SELECTOR(0x00, 0x0f, 0xac, 25)
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
-#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
#define RSN_AUTH_KEY_MGMT_DPP RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x02)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
@@ -271,6 +270,8 @@
size_t ptk_len;
size_t ltf_keyseed_len;
int installed; /* 1 if key has already been installed to driver */
+ bool installed_rx; /* whether TK has been installed as the next TK
+ * for temporary RX-only use in the driver */
};
struct wpa_gtk {
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 40628e8..90c6749 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -343,7 +343,6 @@
/* parameters: <Venue Number> <Venue URL> */
#define RX_VENUE_URL "RX-VENUE-URL "
-#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
#define HS20_T_C_ACCEPTANCE "HS20-T-C-ACCEPTANCE "
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 2d8ff60..c84ccb4 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -186,8 +186,32 @@
#endif /* OpenSSL version < 1.1.1 */
+static void openssl_disable_fips(void)
+{
+#ifndef CONFIG_FIPS
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ static bool done = false;
+
+ if (done)
+ return;
+ done = true;
+
+ if (!EVP_default_properties_is_fips_enabled(NULL))
+ return; /* FIPS mode is not enabled */
+
+ if (!EVP_default_properties_enable_fips(NULL, 0))
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to disable FIPS mode");
+ else
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Disabled FIPS mode to enable non-FIPS-compliant algorithms and parameters");
+#endif /* OpenSSL version >= 3.0 */
+#endif /* !CONFIG_FIPS */
+}
+
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
static OSSL_PROVIDER *openssl_legacy_provider = NULL;
+static OSSL_PROVIDER *openssl_default_provider = NULL;
#endif /* OpenSSL version >= 3.0 */
void openssl_load_legacy_provider(void)
@@ -212,6 +236,36 @@
}
+static void openssl_load_default_provider_if_fips(void)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (openssl_default_provider)
+ return;
+
+ if (!OSSL_PROVIDER_available(NULL, "fips"))
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Load default provider to replace fips provider when needed");
+ openssl_default_provider = OSSL_PROVIDER_try_load(NULL, "default", 1);
+ if (!openssl_default_provider)
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Failed to load default provider");
+#endif /* OpenSSL version >= 3.0 */
+}
+
+
+static void openssl_unload_default_provider(void)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (openssl_default_provider) {
+ OSSL_PROVIDER_unload(openssl_default_provider);
+ openssl_default_provider = NULL;
+ }
+#endif /* OpenSSL version >= 3.0 */
+}
+
+
#if OPENSSL_VERSION_NUMBER < 0x30000000L
static BIGNUM * get_group5_prime(void)
@@ -319,8 +373,16 @@
#ifndef CONFIG_FIPS
+static void openssl_need_md5(void)
+{
+ openssl_disable_fips();
+ openssl_load_default_provider_if_fips();
+}
+
+
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
+ openssl_disable_fips();
openssl_load_legacy_provider();
return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
}
@@ -404,6 +466,7 @@
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
+ openssl_need_md5();
return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
}
@@ -1023,16 +1086,23 @@
struct wpabuf *pubkey = NULL, *privkey = NULL;
BIGNUM *priv_bn = NULL;
EVP_PKEY_CTX *gctx;
+ const char *propquery = NULL;
*priv = NULL;
wpabuf_free(*publ);
*publ = NULL;
+ if (OSSL_PROVIDER_available(NULL, "fips")) {
+ openssl_disable_fips();
+ openssl_load_default_provider_if_fips();
+ propquery = "provider!=fips";
+ }
+
params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
"modp_1536", 0);
params[1] = OSSL_PARAM_construct_end();
- gctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL);
+ gctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", propquery);
if (!gctx ||
EVP_PKEY_keygen_init(gctx) != 1 ||
EVP_PKEY_CTX_set_params(gctx, params) != 1 ||
@@ -1371,6 +1441,9 @@
}
if (EVP_MAC_init(ctx->ctx, key, key_len, params) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: EVP_MAC_init(hmac,digest=%s) failed: %s",
+ a, ERR_error_string(ERR_get_error(), NULL));
EVP_MAC_CTX_free(ctx->ctx);
bin_clear_free(ctx, sizeof(*ctx));
ctx = NULL;
@@ -1527,13 +1600,30 @@
EVP_MAC_CTX *ctx;
size_t i, mlen;
int res;
+ const char *property_query = NULL;
if (TEST_FAIL())
return -1;
- hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
- if (!hmac)
+#ifndef CONFIG_FIPS
+ if (os_strcmp(digest, "MD5") == 0) {
+ openssl_need_md5();
+ property_query = "provider!=fips";
+ } else if (key_len < 14 && OSSL_PROVIDER_available(NULL, "fips")) {
+ /* Need to use non-FIPS provider in OpenSSL to handle cases
+ * where HMAC is used with salt that is less than 112 bits
+ * instead of the HMAC uses with an actual key. */
+ openssl_disable_fips();
+ openssl_load_default_provider_if_fips();
+ property_query = "provider!=fips";
+ }
+#endif /* CONFIG_FIPS */
+ hmac = EVP_MAC_fetch(NULL, "HMAC", property_query);
+ if (!hmac) {
+ wpa_printf(MSG_INFO, "OpenSSL: EVP_MAC_fetch(HMAC) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
return -1;
+ }
params[0] = OSSL_PARAM_construct_utf8_string("digest", digest, 0);
params[1] = OSSL_PARAM_construct_end();
@@ -1543,8 +1633,13 @@
if (!ctx)
return -1;
- if (EVP_MAC_init(ctx, key, key_len, params) != 1)
+ if (EVP_MAC_init(ctx, key, key_len, params) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: EVP_MAC_init(hmac,digest=%s,key_len=%zu) failed: %s",
+ digest, key_len,
+ ERR_error_string(ERR_get_error(), NULL));
goto fail;
+ }
for (i = 0; i < num_elem; i++) {
if (EVP_MAC_update(ctx, addr[i], len[i]) != 1)
@@ -1822,8 +1917,12 @@
if (!emac || !cipher ||
!(ctx = EVP_MAC_CTX_new(emac)) ||
- EVP_MAC_init(ctx, key, key_len, params) != 1)
+ EVP_MAC_init(ctx, key, key_len, params) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: EVP_MAC_init(cmac,cipher=%s) failed: %s",
+ cipher, ERR_error_string(ERR_get_error(), NULL));
goto fail;
+ }
for (i = 0; i < num_elem; i++) {
if (!EVP_MAC_update(ctx, addr[i], len[i]))
@@ -2650,8 +2749,12 @@
goto fail;
ecdh->pkey = EVP_EC_gen(name);
- if (!ecdh->pkey)
+ if (!ecdh->pkey) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: EVP_EC_gen(group=%d) failed: %s",
+ group, ERR_error_string(ERR_get_error(), NULL));
goto fail;
+ }
done:
return ecdh;
@@ -3416,8 +3519,8 @@
EVP_PKEY_CTX_set_params(ctx, params) != 1 ||
EVP_PKEY_generate(ctx, &pkey) != 1) {
wpa_printf(MSG_INFO,
- "OpenSSL: failed to generate EC keypair: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ "OpenSSL: Failed to generate EC keypair (group=%d): %s",
+ group, ERR_error_string(ERR_get_error(), NULL));
pkey = NULL;
}
@@ -3680,6 +3783,8 @@
ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER",
"type-specific", NULL);
if (!ctx || OSSL_ENCODER_to_data(ctx, &pdata, &pdata_len) != 1) {
+ wpa_printf(MSG_INFO, "OpenSSL: OSSL_ENCODER failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
OSSL_ENCODER_CTX_free(ctx);
EVP_PKEY_free(copy);
return NULL;
@@ -4248,7 +4353,7 @@
}
-struct crypto_csr * crypto_csr_init()
+struct crypto_csr * crypto_csr_init(void)
{
return (struct crypto_csr *)X509_REQ_new();
}
@@ -4793,8 +4898,12 @@
if (!hctx)
return -1;
- if (EVP_MAC_init(hctx, salt, salt_len, params) != 1)
+ if (EVP_MAC_init(hctx, salt, salt_len, params) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: EVP_MAC_init(hmac,digest/HPKE) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
goto fail;
+ }
if (EVP_MAC_update(hctx, (const unsigned char *) "HPKE-v1", 7) != 1 ||
EVP_MAC_update(hctx, suite_id, suite_id_len) != 1 ||
@@ -4902,8 +5011,12 @@
if (!hctx)
goto fail;
- if (EVP_MAC_init(hctx, prk, mdlen, params) != 1)
+ if (EVP_MAC_init(hctx, prk, mdlen, params) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: EVP_MAC_init(hmac,digest/HPKE) failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
goto fail;
+ }
if (iter > 0 && EVP_MAC_update(hctx, hash, mdlen) != 1)
goto fail;
@@ -5581,4 +5694,5 @@
void crypto_unload(void)
{
openssl_unload_legacy_provider();
+ openssl_unload_default_provider();
}
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 2691743..7a91202 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -18,6 +18,7 @@
#include <wolfssl/openssl/bn.h>
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/arc4.h>
+#include <wolfssl/wolfcrypt/asn.h>
#include <wolfssl/wolfcrypt/asn_public.h>
#include <wolfssl/wolfcrypt/cmac.h>
#include <wolfssl/wolfcrypt/des3.h>
@@ -29,6 +30,7 @@
#include <wolfssl/wolfcrypt/md5.h>
#include <wolfssl/wolfcrypt/pkcs7.h>
#include <wolfssl/wolfcrypt/pwdbased.h>
+#include <wolfssl/wolfcrypt/rsa.h>
#include <wolfssl/wolfcrypt/sha.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/sha512.h>
@@ -514,8 +516,10 @@
{
int ret;
+ PRIVATE_KEY_UNLOCK();
ret = wc_PBKDF2(buf, (const byte *) passphrase, os_strlen(passphrase),
ssid, ssid_len, iterations, buflen, WC_SHA);
+ PRIVATE_KEY_LOCK();
if (ret != 0) {
if (ret == HMAC_MIN_KEYLEN_E) {
LOG_WOLF_ERROR_VA("wolfSSL: Password is too short. Make sure your password is at least %d characters long. This is a requirement for FIPS builds.",
@@ -3412,7 +3416,7 @@
{
if (!csr || !len || !type) {
LOG_INVALID_PARAMETERS();
- return NULL;;
+ return NULL;
}
switch (attr) {
@@ -3555,6 +3559,284 @@
#endif /* CONFIG_DPP */
+struct crypto_rsa_key {
+ RsaKey key;
+ WC_RNG *rng;
+};
+
+static struct crypto_rsa_key * crypto_rsa_key_init(void)
+{
+ struct crypto_rsa_key *ret;
+ int err;
+
+ ret = os_zalloc(sizeof(*ret));
+ if (!ret)
+ return NULL;
+
+ err = wc_InitRsaKey(&ret->key, NULL);
+ if (err != MP_OKAY) {
+ LOG_WOLF_ERROR_FUNC(wc_InitRsaKey, err);
+ goto fail;
+ }
+
+ ret->rng = wc_rng_init();
+ if (!ret->rng) {
+ LOG_WOLF_ERROR_FUNC_NULL(wc_rng_init);
+ goto fail;
+ }
+
+ err = wc_RsaSetRNG(&ret->key, ret->rng);
+ if (err != 0) {
+ LOG_WOLF_ERROR_FUNC(wc_RsaSetRNG, err);
+ goto fail;
+ }
+
+ return ret;
+fail:
+ crypto_rsa_key_free(ret);
+ return NULL;
+}
+
+
+void crypto_rsa_key_free(struct crypto_rsa_key *key)
+{
+ if (key) {
+ int err;
+
+ err = wc_FreeRsaKey(&key->key);
+ if (err != 0)
+ LOG_WOLF_ERROR_FUNC(wc_FreeRsaKey, err);
+ wc_rng_free(key->rng);
+ os_free(key);
+ }
+}
+
+
+static void read_rsa_key_from_x509(unsigned char *key_pem, size_t key_pem_len,
+ DerBuffer **key_der)
+{
+ struct DecodedCert cert;
+ DerBuffer *cert_der = NULL;
+ word32 der_key_sz = 0;
+ int err;
+
+ err = wc_PemToDer(key_pem, (long) key_pem_len, CERT_TYPE, &cert_der,
+ NULL, NULL, NULL);
+ if (err != 0) {
+ LOG_WOLF_ERROR_FUNC(wc_PemToDer, err);
+ goto fail;
+ }
+
+ wc_InitDecodedCert(&cert, cert_der->buffer, cert_der->length, NULL);
+ err = wc_ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL);
+ if (err != 0) {
+ LOG_WOLF_ERROR_FUNC(wc_PemToDer, err);
+ goto fail;
+ }
+
+ err = wc_GetPubKeyDerFromCert(&cert, NULL, &der_key_sz);
+ if (err != LENGTH_ONLY_E) {
+ LOG_WOLF_ERROR_FUNC(wc_GetPubKeyDerFromCert, err);
+ goto fail;
+ }
+
+ if (*key_der)
+ wc_FreeDer(key_der);
+ *key_der = NULL;
+
+ err = wc_AllocDer(key_der, der_key_sz, PUBLICKEY_TYPE, NULL);
+ if (err != 0) {
+ LOG_WOLF_ERROR_FUNC(wc_AllocDer, err);
+ goto fail;
+ }
+
+ err = wc_GetPubKeyDerFromCert(&cert, (*key_der)->buffer,
+ &(*key_der)->length);
+ if (err != 0) {
+ LOG_WOLF_ERROR_FUNC(wc_GetPubKeyDerFromCert, err);
+ goto fail;
+ }
+
+fail:
+ if (cert_der) {
+ wc_FreeDecodedCert(&cert);
+ wc_FreeDer(&cert_der);
+ }
+
+ /* caller is responsible for free'ing key_der */
+}
+
+
+struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key)
+{
+ struct crypto_rsa_key *ret = NULL;
+ unsigned char *key_pem = NULL;
+ size_t key_pem_len = 0;
+ DerBuffer *key_der = NULL;
+ int key_format = 0;
+ int err;
+ int success = 0;
+ word32 idx = 0;
+
+ key_pem = (unsigned char *) os_readfile(file, &key_pem_len);
+ if (!key_pem) {
+ LOG_WOLF_ERROR_FUNC_NULL(os_readfile);
+ goto fail;
+ }
+
+ err = wc_PemToDer(key_pem, (long) key_pem_len,
+ private_key ? PRIVATEKEY_TYPE : PUBLICKEY_TYPE,
+ &key_der, NULL, NULL, &key_format);
+ if (err != 0) {
+ if (private_key) {
+ LOG_WOLF_ERROR_FUNC(wc_PemToDer, err);
+ goto fail;
+ }
+
+ /* Input file might be public key or x509 cert we want to
+ *extract the key from */
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Trying to extract key from x509 cert");
+ read_rsa_key_from_x509(key_pem, key_pem_len, &key_der);
+ if (!key_der) {
+ LOG_WOLF_ERROR_FUNC(wc_PemToDer, err);
+ LOG_WOLF_ERROR_FUNC_NULL(read_rsa_key_from_x509);
+ goto fail;
+ }
+ }
+
+ if (private_key && key_format != RSAk) {
+ LOG_WOLF_ERROR("Private key is not RSA key");
+ goto fail;
+ }
+
+ /* No longer needed so let's free the memory early */
+ os_free(key_pem);
+ key_pem = NULL;
+
+ ret = crypto_rsa_key_init();
+ if (!ret) {
+ LOG_WOLF_ERROR_FUNC_NULL(crypto_rsa_key_init);
+ goto fail;
+ }
+
+ if (private_key)
+ err = wc_RsaPrivateKeyDecode(key_der->buffer, &idx, &ret->key,
+ key_der->length);
+ else
+ err = wc_RsaPublicKeyDecode(key_der->buffer, &idx, &ret->key,
+ key_der->length);
+
+ if (err != 0) {
+ if (private_key)
+ LOG_WOLF_ERROR_FUNC(wc_RsaPrivateKeyDecode, err);
+ else
+ LOG_WOLF_ERROR_FUNC(wc_RsaPublicKeyDecode, err);
+ goto fail;
+ }
+
+ success = 1;
+fail:
+ os_free(key_pem);
+ if (key_der)
+ wc_FreeDer(&key_der);
+ if (!success && ret) {
+ crypto_rsa_key_free(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+
+struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in)
+{
+ int err;
+ int success = 0;
+ struct wpabuf *ret = NULL;
+
+ if (!key || !in) {
+ LOG_INVALID_PARAMETERS();
+ return NULL;
+ }
+
+ ret = wpabuf_alloc(wc_RsaEncryptSize(&key->key));
+ if (!ret) {
+ LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: crypto_rsa_oaep_sha256_encrypt: wpabuf_len(in) %ld wc_RsaEncryptSize(key->key) %d",
+ wpabuf_len(in), wc_RsaEncryptSize(&key->key));
+
+ err = wc_RsaPublicEncrypt_ex(wpabuf_head_u8(in), wpabuf_len(in),
+ wpabuf_mhead_u8(ret), wpabuf_size(ret),
+ &key->key, key->rng,
+ WC_RSA_OAEP_PAD, WC_HASH_TYPE_SHA256,
+ WC_MGF1SHA256, NULL, 0);
+ if (err <= 0) {
+ LOG_WOLF_ERROR_FUNC(wc_RsaPublicEncrypt_ex, err);
+ goto fail;
+ }
+ wpabuf_put(ret, err);
+
+ success = 1;
+fail:
+ if (!success && ret) {
+ wpabuf_free(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+
+struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key,
+ const struct wpabuf *in)
+{
+ int err;
+ int success = 0;
+ struct wpabuf *ret = NULL;
+
+ if (!key || !in) {
+ LOG_INVALID_PARAMETERS();
+ return NULL;
+ }
+
+ ret = wpabuf_alloc(wc_RsaEncryptSize(&key->key));
+ if (!ret) {
+ LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc);
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: crypto_rsa_oaep_sha256_decrypt: wpabuf_len(in) %ld wc_RsaEncryptSize(key->key) %d",
+ wpabuf_len(in), wc_RsaEncryptSize(&key->key));
+
+ err = wc_RsaPrivateDecrypt_ex(wpabuf_head_u8(in), wpabuf_len(in),
+ wpabuf_mhead_u8(ret), wpabuf_size(ret),
+ &key->key, WC_RSA_OAEP_PAD,
+ WC_HASH_TYPE_SHA256, WC_MGF1SHA256,
+ NULL, 0);
+ if (err <= 0) {
+ LOG_WOLF_ERROR_FUNC(wc_RsaPublicEncrypt_ex, err);
+ goto fail;
+ }
+ wpabuf_put(ret, err);
+
+ success = 1;
+fail:
+ if (!success && ret) {
+ wpabuf_free(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+
void crypto_unload(void)
{
}
diff --git a/src/crypto/sha256-prf.c b/src/crypto/sha256-prf.c
index d665a99..de7394a 100644
--- a/src/crypto/sha256-prf.c
+++ b/src/crypto/sha256-prf.c
@@ -97,7 +97,7 @@
* Mask out unused bits in the last octet if it does not use all the
* bits.
*/
- if (buf_len_bits % 8) {
+ if (pos > 0 && (buf_len_bits % 8)) {
u8 mask = 0xff << (8 - buf_len_bits % 8);
buf[pos - 1] &= mask;
}
diff --git a/src/crypto/sha384-prf.c b/src/crypto/sha384-prf.c
index 420e78c..fdf3316 100644
--- a/src/crypto/sha384-prf.c
+++ b/src/crypto/sha384-prf.c
@@ -97,7 +97,7 @@
* Mask out unused bits in the last octet if it does not use all the
* bits.
*/
- if (buf_len_bits % 8) {
+ if (pos > 0 && (buf_len_bits % 8)) {
u8 mask = 0xff << (8 - buf_len_bits % 8);
buf[pos - 1] &= mask;
}
diff --git a/src/crypto/sha512-prf.c b/src/crypto/sha512-prf.c
index e48cf5f..be45814 100644
--- a/src/crypto/sha512-prf.c
+++ b/src/crypto/sha512-prf.c
@@ -97,7 +97,7 @@
* Mask out unused bits in the last octet if it does not use all the
* bits.
*/
- if (buf_len_bits % 8) {
+ if (pos > 0 && (buf_len_bits % 8)) {
u8 mask = 0xff << (8 - buf_len_bits % 8);
buf[pos - 1] &= mask;
}
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index e3f5b5a..8ce9390 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -62,6 +62,8 @@
char *suffix_match;
char *domain_match;
unsigned int flags;
+
+ char *prio_str;
};
@@ -213,7 +215,9 @@
if (ret < 0)
goto fail;
- ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
+ ret = gnutls_priority_set_direct(conn->session,
+ conn->prio_str ? conn->prio_str :
+ "NORMAL:-VERS-SSL3.0",
&err);
if (ret < 0) {
wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
@@ -285,6 +289,7 @@
wpabuf_free(conn->pull_buf);
os_free(conn->suffix_match);
os_free(conn->domain_match);
+ os_free(conn->prio_str);
os_free(conn);
}
@@ -410,15 +415,18 @@
if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
TLS_CONN_DISABLE_TLSv1_1 |
- TLS_CONN_DISABLE_TLSv1_2)) {
+ TLS_CONN_DISABLE_TLSv1_2 |
+ TLS_CONN_DISABLE_TLSv1_3)) {
os_snprintf(prio_buf, sizeof(prio_buf),
- "NORMAL:-VERS-SSL3.0%s%s%s",
+ "NORMAL:-VERS-SSL3.0%s%s%s%s",
params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
":-VERS-TLS1.0" : "",
params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
":-VERS-TLS1.1" : "",
params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
- ":-VERS-TLS1.2" : "");
+ ":-VERS-TLS1.2" : "",
+ params->flags & TLS_CONN_DISABLE_TLSv1_3 ?
+ ":-VERS-TLS1.3" : "");
prio = prio_buf;
}
@@ -459,6 +467,8 @@
err);
return -1;
}
+ os_free(conn->prio_str);
+ conn->prio_str = os_strdup(prio);
}
if (params->openssl_ecdh_curves) {
@@ -1513,7 +1523,7 @@
conn->global->event_cb(conn->global->cb_ctx,
TLS_ALERT, &ev);
}
- /* continue */
+ /* fallthrough */
default:
wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
"-> %s", __func__, gnutls_strerror(ret));
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index d849933..1eb3b91 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -33,6 +33,8 @@
#include <openssl/core_names.h>
#include <openssl/decoder.h>
#include <openssl/param_build.h>
+#include <openssl/store.h>
+#include <openssl/provider.h>
#else /* OpenSSL version >= 3.0 */
#ifndef OPENSSL_NO_DSA
#include <openssl/dsa.h>
@@ -165,8 +167,8 @@
BIO *ssl_in, *ssl_out;
#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
ENGINE *engine; /* functional reference to the engine */
- EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
+ EVP_PKEY *private_key; /* the private key if using engine/provider */
char *subject_match, *altsubject_match, *suffix_match, *domain_match;
char *check_cert_subject;
int read_alerts, write_alerts, failed;
@@ -394,6 +396,151 @@
}
+#ifndef ANDROID
+#ifdef OPENSSL_NO_ENGINE
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static OSSL_PROVIDER *openssl_pkcs11_provider = NULL;
+#endif /* OpenSSL version >= 3.0 */
+
+static void openssl_load_pkcs11_provider(void)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (openssl_pkcs11_provider)
+ return;
+
+ openssl_pkcs11_provider = OSSL_PROVIDER_try_load(NULL, "pkcs11", 1);
+ if (!openssl_pkcs11_provider)
+ wpa_printf(MSG_WARNING, "PKCS11 provider not present");
+#endif /* OpenSSL version >= 3.0 */
+}
+
+
+static void openssl_unload_pkcs11_provider(void)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (openssl_pkcs11_provider) {
+ OSSL_PROVIDER_unload(openssl_pkcs11_provider);
+ openssl_pkcs11_provider = NULL;
+ }
+#endif /* OpenSSL version >= 3.0 */
+}
+
+
+static bool openssl_can_use_provider(const char *engine_id, const char *req)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ if (!os_strcmp(engine_id, "pkcs11") && openssl_pkcs11_provider)
+ return true;
+
+ wpa_printf(MSG_ERROR,
+ "Cannot find OpenSSL provider for '%s' (missing '%s')",
+ req, engine_id);
+#endif /* OpenSSL version >= 3.0 */
+ return false;
+}
+
+
+static EVP_PKEY * provider_load_key(const char *uri)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ OSSL_STORE_CTX *store;
+ OSSL_STORE_INFO *info;
+ EVP_PKEY *key = NULL;
+
+ if (!uri) {
+ tls_show_errors(MSG_ERROR, __func__,
+ "Invalid NULL uri for key");
+ goto err_key;
+ }
+
+ store = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL);
+ if (!store) {
+ wpa_printf(MSG_DEBUG, "Bad uri for private key:%s", uri);
+
+ tls_show_errors(MSG_ERROR, __func__,
+ "Failed to open key store");
+ goto err_key;
+ }
+
+ if (os_strncmp(uri, "pkcs11:", 7) &&
+ os_strstr(uri, "type=private") == NULL) {
+ /* This is a workaround for OpenSSL < 3.2.0 where the code fails
+ * to correctly source public keys unless explicitly requested
+ * via an expect hint. */
+ if (OSSL_STORE_expect(store, OSSL_STORE_INFO_PUBKEY) != 1) {
+ tls_show_errors(MSG_ERROR, __func__,
+ "Failed to expect Public Key File");
+ goto err_store;
+ }
+ }
+
+ while (!OSSL_STORE_eof(store)) {
+ info = OSSL_STORE_load(store);
+ if ((OSSL_STORE_INFO_get_type(info)) == OSSL_STORE_INFO_PKEY)
+ key = OSSL_STORE_INFO_get1_PKEY(info);
+
+ OSSL_STORE_INFO_free(info);
+ if (key)
+ break;
+ }
+
+err_store:
+ OSSL_STORE_close(store);
+err_key:
+ if (!key)
+ wpa_printf(MSG_ERROR, "OpenSSL: Failed to load key from URI");
+
+ return key;
+#else /* OpenSSL version >= 3.0 */
+ return NULL;
+#endif /* OpenSSL version >= 3.0 */
+}
+
+
+static X509 * provider_load_cert(const char *cert_id)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ OSSL_STORE_CTX *store;
+ OSSL_STORE_INFO *info;
+ X509 *cert = NULL;
+
+ if (!cert_id) {
+ tls_show_errors(MSG_ERROR, __func__, "Invalid NULL uri");
+ goto err_cert;
+ }
+
+ store = OSSL_STORE_open(cert_id, NULL, NULL, NULL, NULL);
+ if (!store) {
+ tls_show_errors(MSG_ERROR, __func__, "Failed to open store");
+ goto err_cert;
+ }
+
+ while (!OSSL_STORE_eof(store)) {
+ info = OSSL_STORE_load(store);
+ if ((OSSL_STORE_INFO_get_type(info)) == OSSL_STORE_INFO_CERT)
+ cert = OSSL_STORE_INFO_get1_CERT(info);
+
+ OSSL_STORE_INFO_free(info);
+ if (cert)
+ break;
+ }
+ OSSL_STORE_close(store);
+
+err_cert:
+ if (!cert)
+ tls_show_errors(MSG_ERROR, __func__,
+ "Failed to load cert from URI");
+ return cert;
+#else /* OpenSSL version >= 3.0 */
+ return NULL;
+#endif /* OpenSSL version >= 3.0 */
+}
+
+#endif /* OPENSSL_NO_ENGINE */
+#endif /* !ANDROID */
+
+
#ifdef CONFIG_NATIVE_WINDOWS
/* Windows CryptoAPI and access to certificate stores */
@@ -1057,6 +1204,9 @@
void openssl_load_legacy_provider(void);
openssl_load_legacy_provider();
+#if !defined(ANDROID) && defined(OPENSSL_NO_ENGINE)
+ openssl_load_pkcs11_provider();
+#endif /* !ANDROID && OPENSSL_NO_ENGINE */
tls_global = context = tls_context_new(conf);
if (context == NULL)
@@ -1125,6 +1275,7 @@
else
ssl = NULL;
if (ssl == NULL) {
+ tls_show_errors(MSG_INFO, "SSL_CTX_new", "init");
tls_openssl_ref_count--;
if (context != tls_global)
os_free(context);
@@ -1248,6 +1399,9 @@
tls_openssl_ref_count--;
if (tls_openssl_ref_count == 0) {
+#if !defined(ANDROID) && defined(OPENSSL_NO_ENGINE)
+ openssl_unload_pkcs11_provider();
+#endif /* !ANDROID && OPENSSL_NO_ENGINE */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
@@ -1408,6 +1562,11 @@
return ret;
#else /* OPENSSL_NO_ENGINE */
+#ifndef ANDROID
+ conn->private_key = provider_load_key(key_id);
+ if (!conn->private_key)
+ return -1;
+#endif /* !ANDROID */
return 0;
#endif /* OPENSSL_NO_ENGINE */
}
@@ -1415,12 +1574,12 @@
static void tls_engine_deinit(struct tls_connection *conn)
{
-#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
- wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
if (conn->private_key) {
EVP_PKEY_free(conn->private_key);
conn->private_key = NULL;
}
+#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
+ wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
if (conn->engine) {
#if !defined(OPENSSL_IS_BORINGSSL)
ENGINE_finish(conn->engine);
@@ -1940,6 +2099,8 @@
len = os_strlen(pos);
if (tls_match_altsubject_component(cert, type, pos, len) > 0)
return 1;
+ if (!end)
+ break;
pos = end + 1;
} while (end);
@@ -3853,11 +4014,17 @@
static int tls_connection_engine_client_cert(struct tls_connection *conn,
const char *cert_id)
{
-#ifndef OPENSSL_NO_ENGINE
+#ifndef ANDROID
X509 *cert;
+#ifndef OPENSSL_NO_ENGINE
if (tls_engine_get_cert(conn, cert_id, &cert))
return -1;
+#else /* OPENSSL_NO_ENGINE */
+ cert = provider_load_cert(cert_id);
+ if (!cert)
+ return -1;
+#endif /* OPENSSL_NO_ENGINE */
if (!SSL_use_certificate(conn->ssl, cert)) {
tls_show_errors(MSG_ERROR, __func__,
@@ -3866,13 +4033,12 @@
return -1;
}
X509_free(cert);
- wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
+ wpa_printf(MSG_DEBUG, "ENGINE/provider: SSL_use_certificate --> "
"OK");
return 0;
-
-#else /* OPENSSL_NO_ENGINE */
+#else /* ANDROID */
return -1;
-#endif /* OPENSSL_NO_ENGINE */
+#endif /* ANDROID */
}
@@ -3880,13 +4046,19 @@
struct tls_connection *conn,
const char *ca_cert_id)
{
-#ifndef OPENSSL_NO_ENGINE
+#ifndef ANDROID
X509 *cert;
SSL_CTX *ssl_ctx = data->ssl;
X509_STORE *store;
+#ifndef OPENSSL_NO_ENGINE
if (tls_engine_get_cert(conn, ca_cert_id, &cert))
return -1;
+#else /* OPENSSL_NO_ENGINE */
+ cert = provider_load_cert(ca_cert_id);
+ if (!cert)
+ return -1;
+#endif /* OPENSSL_NO_ENGINE */
/* start off the same as tls_connection_ca_cert */
store = X509_STORE_new();
@@ -3900,7 +4072,7 @@
if (!X509_STORE_add_cert(store, cert)) {
unsigned long err = ERR_peek_error();
tls_show_errors(MSG_WARNING, __func__,
- "Failed to add CA certificate from engine "
+ "Failed to add CA certificate from engine/provider "
"to certificate store");
if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
@@ -3913,25 +4085,24 @@
}
}
X509_free(cert);
- wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
- "to certificate store", __func__);
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: %s - added CA certificate from engine/provider to certificate store",
+ __func__);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
conn->ca_cert_verify = 1;
return 0;
-
-#else /* OPENSSL_NO_ENGINE */
+#else /* ANDROID */
return -1;
-#endif /* OPENSSL_NO_ENGINE */
+#endif /* ANDROID */
}
static int tls_connection_engine_private_key(struct tls_connection *conn)
{
-#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
tls_show_errors(MSG_ERROR, __func__,
- "ENGINE: cannot use private key for TLS");
+ "ENGINE/provider: cannot use private key for TLS");
return -1;
}
if (!SSL_check_private_key(conn->ssl)) {
@@ -3940,11 +4111,6 @@
return -1;
}
return 0;
-#else /* OPENSSL_NO_ENGINE */
- wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
- "engine support was not compiled in");
- return -1;
-#endif /* OPENSSL_NO_ENGINE */
}
@@ -5495,6 +5661,10 @@
}
if (engine_id && ca_cert_id) {
+#if !defined(ANDROID) && defined(OPENSSL_NO_ENGINE)
+ if (!openssl_can_use_provider(engine_id, ca_cert_id))
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+#endif /* !ANDROID && OPENSSL_NO_ENGINE */
if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_ca_cert(data, conn, params->ca_cert,
@@ -5506,6 +5676,10 @@
}
if (engine_id && cert_id) {
+#if !defined(ANDROID) && defined(OPENSSL_NO_ENGINE)
+ if (!openssl_can_use_provider(engine_id, cert_id))
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+#endif /* !ANDROID && OPENSSL_NO_ENGINE */
if (tls_connection_engine_client_cert(conn, cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_client_cert(conn, params->client_cert,
@@ -5516,7 +5690,12 @@
}
if (engine_id && key_id) {
- wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
+#if !defined(ANDROID) && defined(OPENSSL_NO_ENGINE)
+ if (!openssl_can_use_provider(engine_id, key_id))
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+#endif /* !ANDROID && OPENSSL_NO_ENGINE */
+ wpa_printf(MSG_DEBUG,
+ "TLS: Using private key from engine/provider");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_private_key(data, conn,
diff --git a/src/crypto/tls_wolfssl.c b/src/crypto/tls_wolfssl.c
index 0b2947d..3bf52d6 100644
--- a/src/crypto/tls_wolfssl.c
+++ b/src/crypto/tls_wolfssl.c
@@ -42,7 +42,9 @@
static int tls_ref_count = 0;
-static int tls_ex_idx_session = 0;
+#define TLS_SESSION_EX_IDX (0)
+#define TLS_SSL_CTX_CTX_EX_IDX (0)
+#define TLS_SSL_CON_EX_IDX (0)
/* tls input data for wolfSSL Read Callback */
@@ -63,13 +65,15 @@
int cert_in_cb;
char *ocsp_stapling_response;
unsigned int tls_session_lifetime;
+ /* This is alloc'ed and needs to be free'd */
+ char *check_cert_subject;
};
static struct tls_context *tls_global = NULL;
/* wolfssl tls_connection */
struct tls_connection {
- struct tls_context *context;
+ const struct tls_context *context;
WOLFSSL *ssl;
int read_alerts;
int write_alerts;
@@ -80,6 +84,7 @@
char *alt_subject_match;
char *suffix_match;
char *domain_match;
+ char *check_cert_subject;
u8 srv_cert_hash[32];
@@ -120,6 +125,22 @@
}
+static void tls_context_free(struct tls_context *context)
+{
+ if (context) {
+ os_free(context->check_cert_subject);
+ os_free(context);
+ }
+}
+
+
+/* Helper to make sure the context stays const */
+static const struct tls_context * ssl_ctx_get_tls_context(void *ssl_ctx)
+{
+ return wolfSSL_CTX_get_ex_data(ssl_ctx, TLS_SSL_CTX_CTX_EX_IDX);
+}
+
+
static void wolfssl_reset_in_data(struct tls_in_data *in,
const struct wpabuf *buf)
{
@@ -184,7 +205,7 @@
{
struct wpabuf *buf;
- buf = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ buf = wolfSSL_SESSION_get_ex_data(sess, TLS_SESSION_EX_IDX);
if (!buf)
return;
wpa_printf(MSG_DEBUG,
@@ -192,7 +213,7 @@
buf, sess);
wpabuf_free(buf);
- wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+ wolfSSL_SESSION_set_ex_data(sess, TLS_SESSION_EX_IDX, NULL);
}
@@ -223,11 +244,158 @@
#endif /* DEBUG_WOLFSSL */
+#define SUITEB_OLDTLS_192_CIPHERS "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384"
+#define SUITEB_TLS13_192_CIPHERS "TLS13-AES256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256"
+#define SUITEB_TLS_192_CIPHERS SUITEB_TLS13_192_CIPHERS ":" SUITEB_OLDTLS_192_CIPHERS
+
+#define SUITEB_OLDTLS_128_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:" SUITEB_OLDTLS_192_CIPHERS
+#define SUITEB_TLS13_128_CIPHERS "TLS13-AES128-GCM-SHA256:" SUITEB_TLS13_192_CIPHERS
+#define SUITEB_TLS_128_CIPHERS SUITEB_TLS13_128_CIPHERS ":" SUITEB_OLDTLS_128_CIPHERS
+
+#define SUITEB_TLS_192_SIGALGS "ECDSA+SHA384:RSA-PSS+SHA384:RSA+SHA384"
+#define SUITEB_TLS_128_SIGALGS "ECDSA+SHA256:RSA-PSS+SHA256:RSA+SHA256:" SUITEB_TLS_192_SIGALGS
+
+#define SUITEB_TLS_192_CURVES "P-384:P-521"
+#define SUITEB_TLS_128_CURVES "P-256:" SUITEB_TLS_192_CURVES
+
+#define SUITEB_TLS_128_RSA_KEY_SZ 2048
+#define SUITEB_TLS_192_RSA_KEY_SZ 3072
+
+#define SUITEB_TLS_128_ECC_KEY_SZ 256
+#define SUITEB_TLS_192_ECC_KEY_SZ 384
+
+static int handle_ciphersuites(WOLFSSL_CTX *ssl_ctx, WOLFSSL *ssl,
+ const char *openssl_ciphers, unsigned int flags)
+{
+ const char *ciphers = "DEFAULT:!aNULL";
+ const char *sigalgs = NULL;
+ const char *curves = NULL;
+ bool tls13 = !(flags & TLS_CONN_DISABLE_TLSv1_3);
+ unsigned int tls13_only_mask = TLS_CONN_DISABLE_TLSv1_2 |
+ TLS_CONN_DISABLE_TLSv1_1 | TLS_CONN_DISABLE_TLSv1_0;
+ bool old_tls_only = ((flags & tls13_only_mask) != tls13_only_mask) &&
+ !tls13;
+ bool tls13only = ((flags & tls13_only_mask) == tls13_only_mask) &&
+ !(flags & TLS_CONN_DISABLE_TLSv1_3);
+ short key_sz = 0;
+ short ecc_key_sz = 0;
+
+ if (openssl_ciphers) {
+ if (os_strcmp(openssl_ciphers, "SUITEB128") == 0) {
+ if (tls13only)
+ ciphers = SUITEB_TLS13_128_CIPHERS;
+ else if (old_tls_only)
+ ciphers = SUITEB_OLDTLS_128_CIPHERS;
+ else
+ ciphers = SUITEB_TLS_128_CIPHERS;
+ sigalgs = SUITEB_TLS_128_SIGALGS;
+ key_sz = SUITEB_TLS_128_RSA_KEY_SZ;
+ ecc_key_sz = SUITEB_TLS_128_ECC_KEY_SZ;
+ curves = SUITEB_TLS_128_CURVES;
+ } else if (os_strcmp(openssl_ciphers, "SUITEB192") == 0) {
+ if (tls13only)
+ ciphers = SUITEB_TLS13_192_CIPHERS;
+ else if (old_tls_only)
+ ciphers = SUITEB_OLDTLS_192_CIPHERS;
+ else
+ ciphers = SUITEB_TLS_192_CIPHERS;
+ sigalgs = SUITEB_TLS_192_SIGALGS;
+ key_sz = SUITEB_TLS_192_RSA_KEY_SZ;
+ ecc_key_sz = SUITEB_TLS_192_ECC_KEY_SZ;
+ curves = SUITEB_TLS_192_CURVES;
+ } else {
+ ciphers = openssl_ciphers;
+ }
+ } else if (flags & TLS_CONN_SUITEB) {
+ if (tls13only)
+ ciphers = SUITEB_TLS13_192_CIPHERS;
+ else if (old_tls_only)
+ ciphers = SUITEB_OLDTLS_192_CIPHERS;
+ else
+ ciphers = SUITEB_TLS_192_CIPHERS;
+ sigalgs = SUITEB_TLS_192_SIGALGS;
+ key_sz = SUITEB_TLS_192_RSA_KEY_SZ;
+ ecc_key_sz = SUITEB_TLS_192_ECC_KEY_SZ;
+ curves = SUITEB_TLS_192_CURVES;
+ }
+
+ wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites for %s",
+ ssl_ctx ? "ctx" : "ssl");
+ wpa_printf(MSG_DEBUG, "wolfSSL: openssl_ciphers: %s",
+ openssl_ciphers ? openssl_ciphers : "N/A");
+ wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s",
+ ciphers ? ciphers : "N/A");
+ wpa_printf(MSG_DEBUG, "wolfSSL: sigalgs: %s",
+ sigalgs ? sigalgs : "N/A");
+ wpa_printf(MSG_DEBUG, "wolfSSL: key size: %d", key_sz);
+
+ if (ciphers) {
+ if ((ssl_ctx &&
+ wolfSSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) ||
+ (ssl && wolfSSL_set_cipher_list(ssl, ciphers) != 1)) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Failed to set cipher string '%s'",
+ ciphers);
+ return -1;
+ }
+ }
+
+ if (sigalgs) {
+ if ((ssl_ctx &&
+ wolfSSL_CTX_set1_sigalgs_list(ssl_ctx, sigalgs) != 1) ||
+ (ssl && wolfSSL_set1_sigalgs_list(ssl, sigalgs) != 1)) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Failed to set sigalgs '%s'",
+ sigalgs);
+ return -1;
+ }
+ }
+
+ if (key_sz) {
+ if ((ssl_ctx &&
+ wolfSSL_CTX_SetMinRsaKey_Sz(ssl_ctx, key_sz) != 1) ||
+ (ssl && wolfSSL_SetMinRsaKey_Sz(ssl, key_sz) != 1) ||
+ (ssl_ctx &&
+ wolfSSL_CTX_SetMinDhKey_Sz(ssl_ctx, key_sz) != 1) ||
+ (ssl && wolfSSL_SetMinDhKey_Sz(ssl, key_sz) != 1)) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Failed to set min key size");
+ return -1;
+ }
+ }
+
+ if (ecc_key_sz) {
+ if ((ssl_ctx &&
+ wolfSSL_CTX_SetMinEccKey_Sz(ssl_ctx, ecc_key_sz) != 1) ||
+ (ssl && wolfSSL_SetMinEccKey_Sz(ssl, ecc_key_sz) != 1) ||
+ (ssl_ctx &&
+ wolfSSL_CTX_SetTmpEC_DHE_Sz(ssl_ctx,
+ ecc_key_sz / 8) != 1) ||
+ (ssl &&
+ wolfSSL_SetTmpEC_DHE_Sz(ssl, ecc_key_sz / 8) != 1)) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Failed to set min ecc key size");
+ return -1;
+ }
+ }
+
+ if (curves) {
+ if ((ssl_ctx &&
+ wolfSSL_CTX_set1_curves_list(ssl_ctx, curves) != 1) ||
+ (ssl && wolfSSL_set1_curves_list(ssl, curves) != 1)) {
+ wpa_printf(MSG_ERROR, "wolfSSL: Failed to set curves");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
void * tls_init(const struct tls_config *conf)
{
WOLFSSL_CTX *ssl_ctx;
struct tls_context *context;
- const char *ciphers;
#ifdef DEBUG_WOLFSSL
wolfSSL_SetLoggingCb(wolfSSL_logging_cb);
@@ -255,16 +423,17 @@
if (!ssl_ctx) {
tls_ref_count--;
if (context != tls_global)
- os_free(context);
+ tls_context_free(context);
if (tls_ref_count == 0) {
- os_free(tls_global);
+ tls_context_free(tls_global);
tls_global = NULL;
}
+ return NULL;
}
wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb);
wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb);
context->tls_session_lifetime = conf->tls_session_lifetime;
- wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context);
+ wolfSSL_CTX_set_ex_data(ssl_ctx, TLS_SSL_CTX_CTX_EX_IDX, context);
if (conf->tls_session_lifetime > 0) {
wolfSSL_CTX_set_session_id_context(ssl_ctx,
@@ -280,36 +449,33 @@
WOLFSSL_SESS_CACHE_OFF);
}
- if (conf && conf->openssl_ciphers)
- ciphers = conf->openssl_ciphers;
- else
- ciphers = "ALL";
- wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", ciphers);
- if (wolfSSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) {
- wpa_printf(MSG_ERROR,
- "wolfSSL: Failed to set cipher string '%s'",
- ciphers);
+ if (handle_ciphersuites(ssl_ctx, NULL, conf->openssl_ciphers,
+ conf ? conf->tls_flags : 0) != 0) {
+ wpa_printf(MSG_INFO, "wolfssl: Error setting ciphersuites");
tls_deinit(ssl_ctx);
return NULL;
}
+
return ssl_ctx;
}
void tls_deinit(void *ssl_ctx)
{
- struct tls_context *context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+ struct tls_context *context;
+ /* Need to cast the const away to be able to free this */
+ context = (struct tls_context *) ssl_ctx_get_tls_context(ssl_ctx);
if (context != tls_global)
- os_free(context);
+ tls_context_free(context);
wolfSSL_CTX_free((WOLFSSL_CTX *) ssl_ctx);
tls_ref_count--;
if (tls_ref_count == 0) {
wolfSSL_Cleanup();
- os_free(tls_global);
+ tls_context_free(tls_global);
tls_global = NULL;
}
}
@@ -351,8 +517,8 @@
wolfSSL_SetIOReadCtx(conn->ssl, &conn->input);
wolfSSL_SetIOWriteCtx(conn->ssl, &conn->output);
- wolfSSL_set_ex_data(conn->ssl, 0, conn);
- conn->context = wolfSSL_CTX_get_ex_data(ssl_ctx, 0);
+ wolfSSL_set_ex_data(conn->ssl, TLS_SSL_CON_EX_IDX, conn);
+ conn->context = ssl_ctx_get_tls_context(ssl_ctx);
/* Need randoms post-hanshake for EAP-FAST, export key and deriving
* session ID in EAP methods. */
@@ -378,6 +544,7 @@
os_free(conn->suffix_match);
os_free(conn->domain_match);
os_free(conn->peer_subject);
+ os_free(conn->check_cert_subject);
/* self */
os_free(conn);
@@ -427,7 +594,8 @@
const char *subject_match,
const char *alt_subject_match,
const char *suffix_match,
- const char *domain_match)
+ const char *domain_match,
+ const char *check_cert_subject)
{
os_free(conn->subject_match);
conn->subject_match = NULL;
@@ -461,6 +629,14 @@
return -1;
}
+ os_free(conn->check_cert_subject);
+ conn->check_cert_subject = NULL;
+ if (check_cert_subject) {
+ conn->check_cert_subject = os_strdup(check_cert_subject);
+ if (!conn->check_cert_subject)
+ return -1;
+ }
+
return 0;
}
@@ -819,6 +995,8 @@
case X509_V_ERR_CERT_UNTRUSTED:
case X509_V_ERR_CERT_REJECTED:
return TLS_FAIL_BAD_CERTIFICATE;
+ case RSA_KEY_SIZE_E:
+ return TLS_FAIL_INSUFFICIENT_KEY_LEN;
default:
return TLS_FAIL_UNSPECIFIED;
}
@@ -838,6 +1016,148 @@
}
+/**
+ * match_dn_field - Match configuration DN field against Certificate DN field
+ * @cert: Certificate
+ * @nid: NID of DN field
+ * @field: Field name
+ * @value DN field value which is passed from configuration
+ * e.g., if configuration have C=US and this argument will point to US.
+ * Returns: 1 on success and 0 on failure
+ */
+static int match_dn_field(WOLFSSL_X509 *cert, int nid, const char *field,
+ const char *value)
+{
+ int ret = 0;
+ int len = os_strlen(value);
+ char buf[256];
+ /* Fetch value based on NID */
+ int buf_len = wolfSSL_X509_NAME_get_text_by_NID(
+ wolfSSL_X509_get_subject_name((WOLFSSL_X509 *) cert), nid,
+ buf, sizeof(buf));
+
+ if (buf_len >= 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfSSL: Matching fields: '%s' '%s' '%s'", field,
+ value, buf);
+
+ /* Check wildcard at the right end side */
+ /* E.g., if OU=develop* mentioned in configuration, allow 'OU'
+ * of the subject in the client certificate to start with
+ * 'develop' */
+ if (len > 0 && value[len - 1] == '*') {
+ ret = buf_len >= len &&
+ os_memcmp(buf, value, len - 1) == 0;
+ } else {
+ ret = os_strcmp(buf, value) == 0;
+ }
+ } else {
+ wpa_printf(MSG_INFO,
+ "wolfSSL: cert does not contain entry for '%s'",
+ field);
+ }
+
+ return ret;
+}
+
+
+#define DN_FIELD_LEN 20
+
+/**
+ * get_value_from_field - Get value from DN field
+ * @cert: Certificate
+ * @field_str: DN field string which is passed from configuration file (e.g.,
+ * C=US)
+ * @processed_nids: List of NIDs already processed
+ * Returns: 1 on success and 0 on failure
+ */
+static int get_value_from_field(WOLFSSL_X509 *cert, char *field_str,
+ int *processed_nids)
+{
+ int nid, i;
+ char *context = NULL, *name, *value;
+
+ if (os_strcmp(field_str, "*") == 0)
+ return 1; /* wildcard matches everything */
+
+ name = str_token(field_str, "=", &context);
+ if (!name)
+ return 0;
+
+ nid = wolfSSL_OBJ_txt2nid(name);
+ if (nid == NID_undef) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Unknown field '%s' in check_cert_subject",
+ name);
+ return 0;
+ }
+
+ /* Check for duplicates */
+ for (i = 0; processed_nids[i] != NID_undef && i < DN_FIELD_LEN; i++) {
+ if (processed_nids[i] == nid) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: No support for multiple DN's in check_cert_subject");
+ return 0;
+ }
+ }
+ if (i == DN_FIELD_LEN) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Only %d DN's are supported in check_cert_subject",
+ DN_FIELD_LEN);
+ return 0;
+ }
+ processed_nids[i] = nid;
+
+ value = str_token(field_str, "=", &context);
+ if (!value) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Distinguished Name field '%s' value is not defined in check_cert_subject",
+ name);
+ return 0;
+ }
+
+ return match_dn_field(cert, nid, name, value);
+}
+
+
+/**
+ * tls_match_dn_field - Match subject DN field with check_cert_subject
+ * @cert: Certificate
+ * @match: check_cert_subject string
+ * Returns: Return 1 on success and 0 on failure
+*/
+static int tls_match_dn_field(WOLFSSL_X509 *cert, const char *match)
+{
+ const char *token, *last = NULL;
+ /* Maximum length of each DN field is 255 characters */
+ char field[256];
+ int processed_nids[DN_FIELD_LEN], i;
+
+ for (i = 0; i < DN_FIELD_LEN; i++)
+ processed_nids[i] = NID_undef;
+
+ /* Process each '/' delimited field */
+ while ((token = cstr_token(match, "/", &last))) {
+ if (last - token >= (int) sizeof(field)) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: Too long DN matching field value in '%s'",
+ match);
+ return 0;
+ }
+ os_memcpy(field, token, last - token);
+ field[last - token] = '\0';
+
+ if (!get_value_from_field(cert, field, processed_nids)) {
+ wpa_printf(MSG_INFO, "wolfSSL: No match for DN '%s'",
+ field);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
static struct wpabuf * get_x509_cert(WOLFSSL_X509 *cert)
{
struct wpabuf *buf = NULL;
@@ -845,7 +1165,7 @@
int cert_len;
data = wolfSSL_X509_get_der(cert, &cert_len);
- if (!data)
+ if (data)
buf = wpabuf_alloc_copy(data, cert_len);
return buf;
@@ -859,7 +1179,7 @@
{
union tls_event_data ev;
struct wpabuf *cert = NULL;
- struct tls_context *context = conn->context;
+ const struct tls_context *context = conn->context;
if (!context->event_cb)
return;
@@ -877,13 +1197,44 @@
}
+static int wolfssl_cert_tod(X509 *cert)
+{
+ WOLFSSL_STACK *ext;
+ int i;
+ char *buf;
+ int tod = 0;
+
+ ext = wolfSSL_X509_get_ext_d2i(cert, CERT_POLICY_OID, NULL, NULL);
+ if (!ext)
+ return 0;
+
+ for (i = 0; i < wolfSSL_sk_num(ext); i++) {
+ WOLFSSL_ASN1_OBJECT *policy;
+
+ policy = wolfSSL_sk_value(ext, i);
+ if (!policy)
+ continue;
+
+ buf = (char*)policy->obj;
+ wpa_printf(MSG_DEBUG, "wolfSSL: Certificate Policy %s", buf);
+ if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.1") == 0)
+ tod = 1; /* TOD-STRICT */
+ else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod)
+ tod = 2; /* TOD-TOFU */
+ }
+ wolfSSL_sk_pop_free(ext, NULL);
+
+ return tod;
+}
+
+
static void wolfssl_tls_cert_event(struct tls_connection *conn,
WOLFSSL_X509 *err_cert, int depth,
const char *subject)
{
struct wpabuf *cert = NULL;
union tls_event_data ev;
- struct tls_context *context = conn->context;
+ const struct tls_context *context = conn->context;
char *alt_subject[TLS_MAX_ALT_SUBJECT];
int alt, num_alt_subject = 0;
WOLFSSL_GENERAL_NAME *gen;
@@ -964,6 +1315,7 @@
for (alt = 0; alt < num_alt_subject; alt++)
ev.peer_cert.altsubject[alt] = alt_subject[alt];
ev.peer_cert.num_altsubject = num_alt_subject;
+ ev.peer_cert.tod = wolfssl_cert_tod(err_cert);
context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
wpabuf_free(cert);
@@ -979,8 +1331,9 @@
int err, depth;
WOLFSSL *ssl;
struct tls_connection *conn;
- struct tls_context *context;
+ const struct tls_context *context;
char *match, *altmatch, *suffix_match, *domain_match;
+ const char *check_cert_subject;
const char *err_str;
err_cert = wolfSSL_X509_STORE_CTX_get_current_cert(x509_ctx);
@@ -996,7 +1349,7 @@
wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(err_cert), buf,
sizeof(buf));
- conn = wolfSSL_get_ex_data(ssl, 0);
+ conn = wolfSSL_get_ex_data(ssl, TLS_SSL_CON_EX_IDX);
if (!conn) {
wpa_printf(MSG_DEBUG, "wolfSSL: No ex_data");
return 0;
@@ -1069,6 +1422,8 @@
}
#endif /* CONFIG_SHA256 */
+ wolfssl_tls_cert_event(conn, err_cert, depth, buf);
+
if (!preverify_ok) {
wpa_printf(MSG_WARNING,
"TLS: Certificate verification failed, error %d (%s) depth %d for '%s'",
@@ -1082,7 +1437,19 @@
"TLS: %s - preverify_ok=%d err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
__func__, preverify_ok, err, err_str,
conn->ca_cert_verify, depth, buf);
- if (depth == 0 && match && os_strstr(buf, match) == NULL) {
+ check_cert_subject = conn->check_cert_subject;
+ if (!check_cert_subject)
+ check_cert_subject = conn->context->check_cert_subject;
+ if (check_cert_subject && depth == 0 &&
+ !tls_match_dn_field(err_cert, check_cert_subject)) {
+ wpa_printf(MSG_WARNING,
+ "TLS: Subject '%s' did not match with '%s'",
+ buf, check_cert_subject);
+ preverify_ok = 0;
+ wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Distinguished Name",
+ TLS_FAIL_DN_MISMATCH);
+ } else if (depth == 0 && match && os_strstr(buf, match) == NULL) {
wpa_printf(MSG_WARNING,
"TLS: Subject '%s' did not match with '%s'",
buf, match);
@@ -1116,8 +1483,6 @@
wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
"Domain mismatch",
TLS_FAIL_DOMAIN_MISMATCH);
- } else {
- wolfssl_tls_cert_event(conn, err_cert, depth, buf);
}
if (conn->cert_probe && preverify_ok && depth == 0) {
@@ -1129,31 +1494,6 @@
TLS_FAIL_SERVER_CHAIN_PROBE);
}
-#ifdef HAVE_OCSP_WOLFSSL
- if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
- preverify_ok) {
- enum ocsp_result res;
-
- res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
- conn->peer_issuer,
- conn->peer_issuer_issuer);
- if (res == OCSP_REVOKED) {
- preverify_ok = 0;
- wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
- "certificate revoked",
- TLS_FAIL_REVOKED);
- if (err == X509_V_OK)
- X509_STORE_CTX_set_error(
- x509_ctx, X509_V_ERR_CERT_REVOKED);
- } else if (res != OCSP_GOOD &&
- (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
- preverify_ok = 0;
- wolfssl_tls_fail_event(conn, err_cert, err, depth, buf,
- "bad certificate status response",
- TLS_FAIL_UNSPECIFIED);
- }
- }
-#endif /* HAVE_OCSP_WOLFSSL */
if (depth == 0 && preverify_ok && context->event_cb != NULL)
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
@@ -1237,15 +1577,9 @@
}
if (ca_cert || ca_path) {
- WOLFSSL_X509_STORE *cm = wolfSSL_X509_STORE_new();
-
- if (!cm) {
- wpa_printf(MSG_INFO,
- "SSL: failed to create certificate store");
- return -1;
- }
- wolfSSL_CTX_set_cert_store(ctx, cm);
-
+ wpa_printf(MSG_DEBUG, "SSL: Loading CA's from '%s' and '%s'",
+ ca_cert ? ca_cert : "N/A",
+ ca_path ? ca_path : "N/A");
if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, ca_path) !=
SSL_SUCCESS) {
wpa_printf(MSG_INFO,
@@ -1262,6 +1596,7 @@
return -1;
}
}
+ wpa_printf(MSG_DEBUG, "SSL: Loaded ca_cert or ca_path");
return 0;
}
@@ -1272,19 +1607,24 @@
static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags)
{
+ long op = 0;
+
#ifdef HAVE_SESSION_TICKET
if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET))
wolfSSL_UseSessionTicket(ssl);
#endif /* HAVE_SESSION_TICKET */
+ wpa_printf(MSG_DEBUG, "SSL: conn_flags: %d", flags);
+
if (flags & TLS_CONN_DISABLE_TLSv1_0)
- wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1);
+ op |= WOLFSSL_OP_NO_TLSv1;
if (flags & TLS_CONN_DISABLE_TLSv1_1)
- wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+ op |= WOLFSSL_OP_NO_TLSv1_1;
if (flags & TLS_CONN_DISABLE_TLSv1_2)
- wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+ op |= WOLFSSL_OP_NO_TLSv1_2;
if (flags & TLS_CONN_DISABLE_TLSv1_3)
- wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_3);
+ op |= WOLFSSL_OP_NO_TLSv1_3;
+ wolfSSL_set_options(ssl, op);
}
@@ -1296,7 +1636,8 @@
if (tls_connection_set_subject_match(conn, params->subject_match,
params->altsubject_match,
params->suffix_match,
- params->domain_match) < 0) {
+ params->domain_match,
+ params->check_cert_subject) < 0) {
wpa_printf(MSG_INFO, "Error setting subject match");
return -1;
}
@@ -1324,13 +1665,17 @@
return -1;
}
- wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s",
- params->openssl_ciphers ? params->openssl_ciphers : "N/A");
- if (params->openssl_ciphers &&
- wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
- wpa_printf(MSG_INFO,
- "wolfSSL: Failed to set cipher string '%s'",
- params->openssl_ciphers);
+ if (handle_ciphersuites(NULL, conn->ssl, params->openssl_ciphers,
+ params->flags) != 0) {
+ wpa_printf(MSG_INFO, "wolfssl: Error setting ciphersuites");
+ return -1;
+ }
+
+ if (params->openssl_ecdh_curves &&
+ wolfSSL_set1_curves_list(conn->ssl, params->openssl_ecdh_curves) !=
+ 1) {
+ wpa_printf(MSG_INFO, "wolfSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
return -1;
}
@@ -1524,10 +1869,25 @@
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
+ /* Need to cast away const as this is one of the only places
+ * where we should modify it */
+ struct tls_context *context =
+ (struct tls_context *) ssl_ctx_get_tls_context(tls_ctx);
+
wpa_printf(MSG_DEBUG, "SSL: global set params");
- if (params->check_cert_subject)
- return -1; /* not yet supported */
+ os_free(context->check_cert_subject);
+ context->check_cert_subject = NULL;
+ if (params->check_cert_subject) {
+ context->check_cert_subject =
+ os_strdup(params->check_cert_subject);
+ if (!context->check_cert_subject) {
+ wpa_printf(MSG_ERROR,
+ "SSL: Failed to copy check_cert_subject '%s'",
+ params->check_cert_subject);
+ return -1;
+ }
+ }
if (tls_global_ca_cert(tls_ctx, params->ca_cert) < 0) {
wpa_printf(MSG_INFO, "SSL: Failed to load ca cert file '%s'",
@@ -1556,35 +1916,74 @@
return -1;
}
- wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s",
- params->openssl_ciphers ? params->openssl_ciphers : "N/A");
- if (params->openssl_ciphers &&
- wolfSSL_CTX_set_cipher_list(tls_ctx,
- params->openssl_ciphers) != 1) {
- wpa_printf(MSG_INFO,
- "wolfSSL: Failed to set cipher string '%s'",
- params->openssl_ciphers);
+ if (handle_ciphersuites(tls_ctx, NULL, params->openssl_ciphers,
+ params->flags) != 0) {
+ wpa_printf(MSG_INFO, "wolfssl: Error setting ciphersuites");
return -1;
}
- if (params->openssl_ecdh_curves) {
- wpa_printf(MSG_INFO,
- "wolfSSL: openssl_ecdh_curves not supported");
+ if (params->openssl_ecdh_curves &&
+ wolfSSL_CTX_set1_curves_list((WOLFSSL_CTX *) tls_ctx,
+ params->openssl_ecdh_curves) != 1) {
+ wpa_printf(MSG_INFO, "wolfSSL: Failed to set ECDH curves '%s'",
+ params->openssl_ecdh_curves);
return -1;
}
#ifdef HAVE_SESSION_TICKET
/* Session ticket is off by default - can't disable once on. */
- if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET))
- wolfSSL_CTX_UseSessionTicket(tls_ctx);
+ if (!(params->flags & TLS_CONN_DISABLE_SESSION_TICKET) &&
+ wolfSSL_CTX_UseSessionTicket(tls_ctx) != WOLFSSL_SUCCESS) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: wolfSSL_CTX_UseSessionTicket failed");
+ return -1;
+ }
#endif /* HAVE_SESSION_TICKET */
#ifdef HAVE_OCSP
if (params->ocsp_stapling_response) {
- wolfSSL_CTX_SetOCSP_OverrideURL(tls_ctx,
- params->ocsp_stapling_response);
- wolfSSL_CTX_SetOCSP_Cb(tls_ctx, ocsp_status_cb,
- ocsp_resp_free_cb, NULL);
+ if (wolfSSL_CTX_EnableOCSP(tls_ctx,
+ WOLFSSL_OCSP_URL_OVERRIDE) !=
+ WOLFSSL_SUCCESS ||
+ /* Workaround to force using the override URL without
+ * enabling OCSP */
+ wolfSSL_CTX_DisableOCSP(tls_ctx) != WOLFSSL_SUCCESS) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: wolfSSL_CTX_UseOCSPStapling() failed");
+ return -1;
+ }
+
+ if (wolfSSL_CTX_UseOCSPStapling(tls_ctx, WOLFSSL_CSR_OCSP,
+ WOLFSSL_CSR_OCSP_USE_NONCE) !=
+ WOLFSSL_SUCCESS) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: wolfSSL_CTX_UseOCSPStapling() failed");
+ return -1;
+ }
+
+ if (wolfSSL_CTX_EnableOCSPStapling(tls_ctx) !=
+ WOLFSSL_SUCCESS) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: wolfSSL_EnableOCSPStapling() failed");
+ return -1;
+ }
+
+ if (wolfSSL_CTX_SetOCSP_OverrideURL(
+ tls_ctx,
+ params->ocsp_stapling_response) !=
+ WOLFSSL_SUCCESS) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: wolfSSL_CTX_SetOCSP_OverrideURL() failed");
+ return -1;
+ }
+
+ if (wolfSSL_CTX_SetOCSP_Cb(tls_ctx, ocsp_status_cb,
+ ocsp_resp_free_cb, NULL) !=
+ WOLFSSL_SUCCESS) {
+ wpa_printf(MSG_ERROR,
+ "wolfSSL: wolfSSL_CTX_SetOCSP_Cb() failed");
+ return -1;
+ }
}
#endif /* HAVE_OCSP */
@@ -1610,12 +2009,13 @@
const u8 *session_ctx, size_t session_ctx_len)
{
static int counter = 0;
- struct tls_context *context;
+ const struct tls_context *context;
if (!conn)
return -1;
wpa_printf(MSG_DEBUG, "SSL: set verify: %d", verify_peer);
+ wpa_printf(MSG_DEBUG, "SSL: flags: %d", flags);
if (verify_peer) {
conn->ca_cert_verify = 1;
@@ -1629,7 +2029,7 @@
wolfSSL_set_accept_state(conn->ssl);
- context = wolfSSL_CTX_get_ex_data((WOLFSSL_CTX *) ssl_ctx, 0);
+ context = ssl_ctx_get_tls_context(ssl_ctx);
if (context && context->tls_session_lifetime == 0) {
/*
* Set session id context to a unique value to make sure
@@ -1645,7 +2045,7 @@
session_ctx_len);
}
- /* TODO: do we need to fake a session like OpenSSL does here? */
+ tls_set_conn_flags(conn->ssl, flags);
return 0;
}
@@ -1692,12 +2092,28 @@
char msg[80];
wpa_printf(MSG_DEBUG,
- "SSL: %s - failed %s",
+ "SSL: %s - failed (%d) %s",
server ? "wolfSSL_accept" :
- "wolfSSL_connect",
+ "wolfSSL_connect", err,
wolfSSL_ERR_error_string(err, msg));
conn->failed++;
}
+
+ /* Generate extra events */
+ if (err == OCSP_CERT_REVOKED ||
+ err == BAD_CERTIFICATE_STATUS_ERROR ||
+ err == OCSP_CERT_REVOKED) {
+ char buf[256];
+ WOLFSSL_X509 *err_cert;
+
+ err_cert = wolfSSL_get_peer_certificate(conn->ssl);
+ wolfSSL_X509_NAME_oneline(
+ wolfSSL_X509_get_subject_name(err_cert),
+ buf, sizeof(buf));
+ wolfssl_tls_fail_event(conn, err_cert, err, 0, buf,
+ "bad certificate status response",
+ TLS_FAIL_UNSPECIFIED);
+ }
}
return conn->output.out_data;
@@ -1866,11 +2282,12 @@
char buf[128], *pos, *end;
u8 *c;
int ret;
+ bool set_sig_algs = false;
if (!conn || !conn->ssl || !ciphers)
return -1;
- buf[0] = '\0';
+ buf[0] = buf[1] = '\0';
pos = buf;
end = pos + sizeof(buf);
@@ -1890,6 +2307,7 @@
break;
case TLS_CIPHER_ANON_DH_AES128_SHA:
suite = "ADH-AES128-SHA";
+ set_sig_algs = true;
break;
case TLS_CIPHER_RSA_DHE_AES256_SHA:
suite = "DHE-RSA-AES256-SHA";
@@ -1910,10 +2328,16 @@
c++;
}
- wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", buf + 1);
+ /* +1 to skip the ":" */
+ if (handle_ciphersuites(NULL, conn->ssl, buf + 1, conn->flags) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "wolfssl: Cipher suite configuration failed");
+ return -1;
+ }
- if (wolfSSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
- wpa_printf(MSG_DEBUG, "Cipher suite configuration failed");
+ if (set_sig_algs &&
+ wolfSSL_set1_sigalgs_list(conn->ssl, SUITEB_TLS_128_SIGALGS) != 1) {
+ wpa_printf(MSG_DEBUG, "wolfssl: Sigalg configuration failed");
return -1;
}
@@ -1924,34 +2348,19 @@
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
- WOLFSSL_CIPHER *cipher;
const char *name;
if (!conn || !conn->ssl)
return -1;
- cipher = wolfSSL_get_current_cipher(conn->ssl);
- if (!cipher)
- return -1;
-
- name = wolfSSL_CIPHER_get_name(cipher);
+ if (wolfSSL_version(conn->ssl) == TLS1_3_VERSION)
+ name = wolfSSL_get_cipher(conn->ssl);
+ else
+ name = wolfSSL_get_cipher_name(conn->ssl);
if (!name)
return -1;
- if (os_strcmp(name, "SSL_RSA_WITH_RC4_128_SHA") == 0)
- os_strlcpy(buf, "RC4-SHA", buflen);
- else if (os_strcmp(name, "TLS_RSA_WITH_AES_128_CBC_SHA") == 0)
- os_strlcpy(buf, "AES128-SHA", buflen);
- else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA") == 0)
- os_strlcpy(buf, "DHE-RSA-AES128-SHA", buflen);
- else if (os_strcmp(name, "TLS_DH_anon_WITH_AES_128_CBC_SHA") == 0)
- os_strlcpy(buf, "ADH-AES128-SHA", buflen);
- else if (os_strcmp(name, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA") == 0)
- os_strlcpy(buf, "DHE-RSA-AES256-SHA", buflen);
- else if (os_strcmp(name, "TLS_RSA_WITH_AES_256_CBC_SHA") == 0)
- os_strlcpy(buf, "AES256-SHA", buflen);
- else
- os_strlcpy(buf, name, buflen);
+ os_strlcpy(buf, name, buflen);
return 0;
}
@@ -2273,13 +2682,13 @@
goto fail;
}
- old = wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ old = wolfSSL_SESSION_get_ex_data(sess, TLS_SESSION_EX_IDX);
if (old) {
wpa_printf(MSG_DEBUG, "wolfSSL: Replacing old success data %p",
old);
wpabuf_free(old);
}
- if (wolfSSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+ if (wolfSSL_SESSION_set_ex_data(sess, TLS_SESSION_EX_IDX, data) != 1)
goto fail;
wpa_printf(MSG_DEBUG, "wolfSSL: Stored success data %p", data);
@@ -2302,7 +2711,7 @@
sess = wolfSSL_get_session(conn->ssl);
if (!sess)
return NULL;
- return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ return wolfSSL_SESSION_get_ex_data(sess, TLS_SESSION_EX_IDX);
}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 9ce5ec0..8a7e673 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1404,11 +1404,15 @@
*/
struct wpa_driver_mld_params mld_params;
-
/**
* rsn_overriding - wpa_supplicant RSN overriding support
*/
bool rsn_overriding;
+
+ /**
+ * spp_amsdu - SPP A-MSDU used on this connection
+ */
+ bool spp_amsdu;
};
enum hide_ssid {
@@ -1653,11 +1657,6 @@
int disable_dgaf;
/**
- * osen - Whether OSEN security is enabled
- */
- int osen;
-
- /**
* freq - Channel parameters for dynamic bandwidth changes
*/
struct hostapd_freq_params *freq;
@@ -2034,10 +2033,17 @@
* %KEY_FLAG_GROUP_TX_DEFAULT
* GTK key valid for TX only, immediately taking over TX.
* %KEY_FLAG_PAIRWISE_RX_TX
- * Pairwise key immediately becoming the active pairwise key.
+ * Pairwise key immediately becoming the active pairwise key. If this
+ * key was previously set as an alternative RX-only key with
+ * %KEY_FLAG_PAIRWISE_RX | %KEY_FLAG_NEXT, the alternative RX-only key
+ * is taken into use for both TX and RX without changing the RX counter
+ * values.
* %KEY_FLAG_PAIRWISE_RX
* Pairwise key not yet valid for TX. (Only usable when Extended
- * Key ID is supported by the driver.)
+ * Key ID is supported by the driver or when configuring the next TK
+ * for RX-only with %KEY_FLAG_NEXT in which case the new TK can be used
+ * as an alternative key for decrypting received frames without
+ * replacing the possibly already configured old TK.)
* %KEY_FLAG_PAIRWISE_RX_TX_MODIFY
* Enable TX for a pairwise key installed with
* KEY_FLAG_PAIRWISE_RX.
@@ -2149,7 +2155,6 @@
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE 0x00100000
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384 0x00200000
#define WPA_DRIVER_CAPA_KEY_MGMT_CCKM 0x00400000
-#define WPA_DRIVER_CAPA_KEY_MGMT_OSEN 0x00800000
#define WPA_DRIVER_CAPA_KEY_MGMT_SAE_EXT_KEY 0x01000000
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY 0x02000000
/** Bitfield of supported key management suites */
@@ -2380,6 +2385,12 @@
#define WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA 0x0000000000400000ULL
/** Driver supports NAN offload */
#define WPA_DRIVER_FLAGS2_NAN_OFFLOAD 0x0000000000800000ULL
+/** Driver/device supports SPP A-MSDUs */
+#define WPA_DRIVER_FLAGS2_SPP_AMSDU 0x0000000001000000ULL
+/** Driver supports P2P V2 */
+#define WPA_DRIVER_FLAGS2_P2P_FEATURE_V2 0x0000000002000000ULL
+/** Driver supports P2P PCC mode */
+#define WPA_DRIVER_FLAGS2_P2P_FEATURE_PCC_MODE 0x0000000004000000ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2658,6 +2669,7 @@
#define WPA_STA_TDLS_PEER BIT(4)
#define WPA_STA_AUTHENTICATED BIT(5)
#define WPA_STA_ASSOCIATED BIT(6)
+#define WPA_STA_SPP_AMSDU BIT(7)
enum tdls_oper {
TDLS_DISCOVERY_REQ,
@@ -3157,6 +3169,53 @@
* broadcast keys, so key index 0 is available for this kind of
* configuration.
*
+ * For pairwise keys, there are potential race conditions between
+ * enabling a new TK on each end of the connection and sending the first
+ * protected frame. Drivers have multiple options on which style of key
+ * configuration to support with the simplest option not providing any
+ * protection for the race condition while the more complex options do
+ * provide partial or full protection.
+ *
+ * Option 1: Do not support extended key IDs (i.e., use only Key ID 0
+ * for pairwise keys) and do not support configuration of the next TK
+ * as an alternative RX key. This provides no protection, but is simple
+ * to support. The driver needs to ignore set_key() calls with
+ * KEY_FLAG_NEXT.
+ *
+ * Option 2: Do not support extended key IDs (i.e., use only Key ID 0
+ * for pairwise keys), but support configuration of the next TK as an
+ * alternative RX key for the initial 4-way handshake. This provides
+ * protection for the initial key setup at the beginning of an
+ * association. The driver needs to configure the initial TK for RX-only
+ * when receiving a set_key() call with KEY_FLAG_NEXT. This RX-only key
+ * is ready for receiving protected Data frames from the peer before the
+ * local device has enabled the key for TX. Unprotected EAPOL frames
+ * need to be allowed even when this next TK is configured as RX-only
+ * key. The same key is then set with KEY_FLAG_PAIRWISE_RX_TX to enable
+ * its use for both TX and RX. The driver ignores set_key() calls with
+ * KEY_FLAG_NEXT when a TK has been configured. When fully enabling the
+ * TK for TX and RX, the RX counters associated with the TK must not be
+ * cleared.
+ *
+ * Option 3: Same as option 2, but the driver supports multiple RX keys
+ * in parallel during PTK rekeying. The driver processed set_key() calls
+ * with KEY_FLAG_NEXT also when a TK has been configured. At that point
+ * in the rekeying sequence the driver uses the previously configured TK
+ * for TX and decrypts received frames with either the previously
+ * configured TK or the next TK (RX-only).
+ *
+ * Option 4: The driver supports extended Key IDs and they are used for
+ * an association but does not support KEY_FLAG_NEXT (options 2 and 3).
+ * The next TK is configured as RX-only with KEY_FLAG_PAIRWISE_RX and
+ * it is enabled for TX and RX with KEY_FLAG_PAIRWISE_RX_TX_MODIFY. When
+ * extended key ID is not used for an association, the driver behaves
+ * like in option 1.
+ *
+ * Option 5 and 6: Like option 4 but with support for KEY_FLAG_NEXT as
+ * described above for options 2 and 3, respectively. Option 4 is used
+ * for cases where extended key IDs are used for an association. Option
+ * 2 or 3 is used for cases where extended key IDs are not used.
+ *
* Please note that TKIP keys include separate TX and RX MIC keys and
* some drivers may expect them in different order than wpa_supplicant
* is using. If the TX/RX keys are swapped, all TKIP encrypted packets
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 7186330..8fb23a8 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -504,6 +504,9 @@
const u8 *key = params->key;
size_t key_len = params->key_len;
+ if (params->key_flag & KEY_FLAG_NEXT)
+ return -1;
+
if (alg == WPA_ALG_NONE)
return atheros_del_key(drv, addr, key_idx);
@@ -1940,25 +1943,6 @@
wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
params->assocresp_ies);
-#if defined(CONFIG_HS20) && (defined(IEEE80211_PARAM_OSEN) || defined(CONFIG_ATHEROS_OSEN))
- if (params->osen) {
- struct wpa_bss_params bss_params;
-
- os_memset(&bss_params, 0, sizeof(struct wpa_bss_params));
- bss_params.enabled = 1;
- bss_params.wpa = 2;
- bss_params.wpa_pairwise = WPA_CIPHER_CCMP;
- bss_params.wpa_group = WPA_CIPHER_CCMP;
- bss_params.ieee802_1x = 1;
-
- if (atheros_set_privacy(priv, 1) ||
- set80211param(priv, IEEE80211_PARAM_OSEN, 1))
- return -1;
-
- return atheros_set_ieee8021x(priv, &bss_params);
- }
-#endif /* CONFIG_HS20 && IEEE80211_PARAM_OSEN */
-
return 0;
}
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 0979fc5..66155b4 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -325,6 +325,9 @@
const u8 *key = params->key;
size_t key_len = params->key_len;
+ if (params->key_flag & KEY_FLAG_NEXT)
+ return -1;
+
wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
"seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
set_tx, seq_len, key_len);
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 9589183..7a9f18c 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -374,6 +374,7 @@
DF2S(MLO);
DF2S(SCAN_MIN_PREQ);
DF2S(SAE_OFFLOAD_STA);
+ DF2S(SPP_AMSDU);
}
return "UNKNOWN";
#undef DF2S
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 3aa5860..74c7767 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -411,6 +411,9 @@
const u8 *key = params->key;
size_t key_len = params->key_len;
+ if (params->key_flag & KEY_FLAG_NEXT)
+ return -1;
+
blen = sizeof(*param) + key_len;
buf = os_zalloc(blen);
if (buf == NULL)
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 0351705..b030b0b 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -1037,6 +1037,9 @@
wpa_driver_ndis_set_key_wrapper(void *priv,
struct wpa_driver_set_key_params *params)
{
+ if (params->key_flag & KEY_FLAG_NEXT)
+ return -1;
+
return wpa_driver_ndis_set_key(params->ifname, priv,
params->alg, params->addr,
params->key_idx, params->set_tx,
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 95e678f..0848d16 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -525,13 +525,19 @@
/* try to set NETLINK_EXT_ACK to 1, ignoring errors */
opt = 1;
- setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
- NETLINK_EXT_ACK, &opt, sizeof(opt));
+ if (setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+ NETLINK_EXT_ACK, &opt, sizeof(opt)) < 0)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: setsockopt(NETLINK_EXT_ACK) failed: %s (ignored)",
+ strerror(errno));
/* try to set NETLINK_CAP_ACK to 1, ignoring errors */
opt = 1;
- setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
- NETLINK_CAP_ACK, &opt, sizeof(opt));
+ if (setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK,
+ NETLINK_CAP_ACK, &opt, sizeof(opt)) < 0)
+ wpa_printf(MSG_DEBUG,
+ "nl80211: setsockopt(NETLINK_CAP_ACK) failed: %s (ignored)",
+ strerror(errno));
err.err = nl_send_auto_complete(nl_handle, msg);
if (err.err < 0) {
@@ -2355,8 +2361,6 @@
bss->ctx = ctx;
os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
- drv->monitor_ifidx = -1;
- drv->monitor_sock = -1;
drv->eapol_tx_sock = -1;
drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
@@ -2385,9 +2389,7 @@
"nl80211: wifi status sockopt failed: %s",
strerror(errno));
drv->data_tx_status = 0;
- if (!drv->use_monitor)
- drv->capa.flags &=
- ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+ drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
} else {
eloop_register_read_sock(
drv->eapol_tx_sock,
@@ -3248,8 +3250,6 @@
bss->brname, strerror(errno));
}
- nl80211_remove_monitor_interface(drv);
-
if (is_ap_interface(drv->nlmode)) {
wpa_driver_nl80211_del_beacon_all(bss);
nl80211_remove_links(bss);
@@ -3436,7 +3436,6 @@
__AKM(FT_SAE, FT_SAE);
__AKM(FT_SAE_EXT_KEY, FT_SAE_EXT_KEY);
__AKM(CCKM, CCKM);
- __AKM(OSEN, OSEN);
__AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B);
__AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192);
__AKM(FILS_SHA256, FILS_SHA256);
@@ -3637,6 +3636,14 @@
return 0;
}
+ if (key_flag & KEY_FLAG_NEXT) {
+ /* For now, ignore these since this needs support from the
+ * driver to handle the special cases of two active RX keys. */
+ wpa_printf(MSG_DEBUG,
+ "nl80211: set_key for the next TK for RX-only - ignored");
+ return -EOPNOTSUPP;
+ }
+
ret = -ENOBUFS;
key_msg = nlmsg_alloc();
if (!key_msg)
@@ -4104,6 +4111,33 @@
}
+static int
+nl80211_put_bss_membership_selectors(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg)
+{
+ u8 selectors[ARRAY_SIZE(drv->extra_bss_membership_selectors) + 1];
+ size_t selectors_len;
+
+ if (!nl80211_attr_supported(drv, NL80211_ATTR_SUPPORTED_SELECTORS))
+ return 0;
+
+ for (selectors_len = 0;
+ drv->extra_bss_membership_selectors[selectors_len];
+ selectors_len++) {
+ selectors[selectors_len] =
+ drv->extra_bss_membership_selectors[selectors_len];
+ }
+
+#ifdef CONFIG_SAE
+ /* Always add the SAE H2E selector as it is handled by wpa_supplicant */
+ selectors[selectors_len++] = BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+#endif /* CONFIG_SAE */
+
+ return nla_put(msg, NL80211_ATTR_SUPPORTED_SELECTORS,
+ selectors_len, selectors);
+}
+
+
static int wpa_driver_nl80211_authenticate(
struct i802_bss *bss, struct wpa_driver_auth_params *params)
{
@@ -4205,6 +4239,10 @@
goto fail;
}
+ ret = nl80211_put_bss_membership_selectors(drv, msg);
+ if (ret)
+ goto fail;
+
if (params->mld && params->ap_mld_addr) {
wpa_printf(MSG_DEBUG, " * MLD: link_id=%u, MLD addr=" MACSTR,
params->mld_link_id, MAC2STR(params->ap_mld_addr));
@@ -4409,7 +4447,6 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ieee80211_mgmt *mgmt;
- int encrypt = !no_encrypt;
u16 fc;
int use_cookie = 1;
int res;
@@ -4458,20 +4495,6 @@
goto send_frame_cmd;
}
- if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
- WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
- /*
- * Only one of the authentication frame types is encrypted.
- * In order for static WEP encryption to work properly (i.e.,
- * to not encrypt the frame), we need to tell mac80211 about
- * the frames that must not be encrypted.
- */
- u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
- u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
- if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
- encrypt = 0;
- }
-
if ((is_sta_interface(drv->nlmode) ||
drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -4520,29 +4543,17 @@
freq = link->freq;
}
- if (drv->use_monitor && is_ap_interface(drv->nlmode)) {
- wpa_printf(MSG_DEBUG,
- "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
- freq, link->freq);
- return nl80211_send_monitor(drv, data, data_len, encrypt,
- noack);
- }
-
if ((noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) &&
link_id == NL80211_DRV_LINK_ID_NA)
use_cookie = 0;
send_frame_cmd:
#ifdef CONFIG_TESTING_OPTIONS
- if (no_encrypt && !encrypt && !drv->use_monitor) {
+ if (no_encrypt) {
wpa_printf(MSG_DEBUG,
"nl80211: Request to send an unencrypted frame - use a monitor interface for this");
- if (nl80211_create_monitor_interface(drv) < 0)
- return -1;
- res = nl80211_send_monitor(drv, data, data_len, encrypt,
- noack);
- nl80211_remove_monitor_interface(drv);
- return res;
+ return nl80211_send_monitor(drv, data, data_len, !no_encrypt,
+ noack);
}
#endif /* CONFIG_TESTING_OPTIONS */
@@ -4888,7 +4899,7 @@
{
u8 sae_pwe;
- wpa_printf(MSG_DEBUG, "nl802111: sae_pwe=%d", pwe);
+ wpa_printf(MSG_DEBUG, "nl80211: sae_pwe=%d", pwe);
if (pwe == SAE_PWE_HUNT_AND_PECK)
sae_pwe = NL80211_SAE_PWE_HUNT_AND_PECK;
else if (pwe == SAE_PWE_HASH_TO_ELEMENT)
@@ -5242,8 +5253,7 @@
beacon_set);
if (beacon_set)
cmd = NL80211_CMD_SET_BEACON;
- else if (!drv->device_ap_sme && !drv->use_monitor &&
- !nl80211_get_wiphy_data_ap(bss))
+ else if (!drv->device_ap_sme && !nl80211_get_wiphy_data_ap(bss))
return -ENOBUFS;
wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
@@ -5701,6 +5711,8 @@
f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
if (flags & WPA_STA_ASSOCIATED)
f |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+ if (flags & WPA_STA_SPP_AMSDU)
+ f |= BIT(NL80211_STA_FLAG_SPP_AMSDU);
return f;
}
@@ -6233,19 +6245,8 @@
nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
goto fail;
- if (iftype == NL80211_IFTYPE_MONITOR) {
- struct nlattr *flags;
-
- flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
- if (!flags ||
- nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
- goto fail;
-
- nla_nest_end(msg, flags);
- } else if (wds) {
- if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
- goto fail;
- }
+ if (wds && nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
+ goto fail;
/*
* Tell cfg80211 that the interface belongs to the socket that created
@@ -6353,8 +6354,8 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
- wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
- bss->ifname, drv->device_ap_sme, drv->use_monitor);
+ wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d",
+ bss->ifname, drv->device_ap_sme);
/*
* Disable Probe Request reporting unless we need it in this way for
@@ -6364,20 +6365,13 @@
if (!drv->device_ap_sme)
wpa_driver_nl80211_probe_req_report(bss, 0);
- if (!drv->device_ap_sme && !drv->use_monitor)
- if (nl80211_mgmt_subscribe_ap(bss))
- return -1;
-
- if (drv->device_ap_sme && !drv->use_monitor)
- if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
- wpa_printf(MSG_DEBUG,
- "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
-
- if (!drv->device_ap_sme && drv->use_monitor &&
- nl80211_create_monitor_interface(drv) &&
- !drv->device_ap_sme)
+ if (!drv->device_ap_sme && nl80211_mgmt_subscribe_ap(bss))
return -1;
+ if (drv->device_ap_sme && nl80211_mgmt_subscribe_ap_dev_sme(bss))
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to subscribe for mgmt frames from SME driver - trying to run without it");
+
if (drv->device_ap_sme &&
wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
@@ -6393,16 +6387,14 @@
{
struct wpa_driver_nl80211_data *drv = bss->drv;
- wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
- bss->ifname, drv->device_ap_sme, drv->use_monitor);
+ wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d",
+ bss->ifname, drv->device_ap_sme);
if (drv->device_ap_sme) {
wpa_driver_nl80211_probe_req_report(bss, 0);
- if (!drv->use_monitor)
- nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
- } else if (drv->use_monitor)
- nl80211_remove_monitor_interface(drv);
- else
+ nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
+ } else {
nl80211_mgmt_unsubscribe(bss, "AP teardown");
+ }
nl80211_put_wiphy_data_ap(bss);
if (bss->flink)
@@ -6488,8 +6480,6 @@
}
-static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
static int wpa_driver_nl80211_hapd_send_eapol(
void *priv, const u8 *addr, const u8 *data,
size_t data_len, int encrypt, const u8 *own_addr, u32 flags,
@@ -6497,11 +6487,6 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct ieee80211_hdr *hdr;
- size_t len;
- u8 *pos;
- int res;
- int qos = flags & WPA_STA_WMM;
/* For now, disable EAPOL TX over control port in AP mode by default
* since it does not provide TX status notifications. */
@@ -6511,55 +6496,7 @@
data, data_len, !encrypt,
link_id);
- if (drv->device_ap_sme || !drv->use_monitor)
- return nl80211_send_eapol_data(bss, addr, data, data_len);
-
- len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
- data_len;
- hdr = os_zalloc(len);
- if (hdr == NULL) {
- wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
- (unsigned long) len);
- return -1;
- }
-
- hdr->frame_control =
- IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
- hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
- if (encrypt)
- hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
- if (qos) {
- hdr->frame_control |=
- host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
- }
-
- memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
- memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
- memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
- pos = (u8 *) (hdr + 1);
-
- if (qos) {
- /* Set highest priority in QoS header */
- pos[0] = 7;
- pos[1] = 0;
- pos += 2;
- }
-
- memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
- pos += sizeof(rfc1042_header);
- WPA_PUT_BE16(pos, ETH_P_PAE);
- pos += 2;
- memcpy(pos, data, data_len);
-
- res = nl80211_send_monitor(drv, hdr, len, encrypt, 0);
- if (res < 0) {
- wpa_printf(MSG_ERROR,
- "hapd_send_eapol - packet len: %lu - failed",
- (unsigned long) len);
- }
- os_free(hdr);
-
- return res;
+ return nl80211_send_eapol_data(bss, addr, data, data_len);
}
@@ -6657,16 +6594,13 @@
nlmode = NL80211_IFTYPE_AP;
old_mode = drv->nlmode;
- if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
- nl80211_remove_monitor_interface(drv);
+ if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode))
return -1;
- }
if (params->freq.freq &&
nl80211_set_channel(drv->first_bss, ¶ms->freq, 0)) {
if (old_mode != nlmode)
wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
- nl80211_remove_monitor_interface(drv);
return -1;
}
@@ -7088,7 +7022,6 @@
params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X ||
params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
- params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
@@ -7146,9 +7079,6 @@
case WPA_KEY_MGMT_PSK_SHA256:
mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_SHA256;
break;
- case WPA_KEY_MGMT_OSEN:
- mgmt[0] = RSN_AUTH_KEY_MGMT_OSEN;
- break;
case WPA_KEY_MGMT_SAE:
mgmt[0] = RSN_AUTH_KEY_MGMT_SAE;
break;
@@ -7304,6 +7234,12 @@
nla_put_flag(msg, NL80211_ATTR_MLO_SUPPORT))
return -1;
+ if (params->spp_amsdu) {
+ wpa_printf(MSG_DEBUG, " * SPP A-MSDU");
+ if (nla_put_flag(msg, NL80211_ATTR_ASSOC_SPP_AMSDU))
+ return -1;
+ }
+
return 0;
}
@@ -7521,7 +7457,7 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- struct nl80211_err_info err_info;
+ struct nl80211_err_info err_info = { -1 };
int ret = -1;
struct nl_msg *msg;
@@ -7555,6 +7491,10 @@
if (ret)
goto fail;
+ ret = nl80211_put_bss_membership_selectors(drv, msg);
+ if (ret)
+ goto fail;
+
if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
goto fail;
@@ -9482,10 +9422,7 @@
}
#endif /* CONFIG_MESH */
- if (is_ap_interface(drv->nlmode) &&
- (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
- (int) freq == bss->flink->freq || drv->device_ap_sme ||
- !drv->use_monitor))
+ if (is_ap_interface(drv->nlmode))
ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
0, freq, no_cck, offchanok,
wait_time, NULL, 0, 0,
@@ -10150,6 +10087,7 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
+ const char *pos;
if (param == NULL)
return 0;
@@ -10164,12 +10102,14 @@
}
#endif /* CONFIG_P2P */
- if (os_strstr(param, "use_monitor=1"))
- drv->use_monitor = 1;
-
if (os_strstr(param, "force_connect_cmd=1")) {
drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
drv->force_connect_cmd = 1;
+ /*
+ * mac80211_hwsim does not implement SPP A-MSDU in
+ * offload mode.
+ */
+ drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_SPP_AMSDU;
}
if (os_strstr(param, "force_bss_selection=1"))
@@ -10218,6 +10158,33 @@
if (os_strstr(param, "rsn_override_in_driver=1"))
drv->capa.flags2 |= WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA;
+ pos = os_strstr(param, "extra_bss_membership_selectors=");
+ if (pos) {
+ int i = 0;
+
+ pos += 31;
+
+ while (*pos) {
+ char *end;
+ int sel;
+
+ sel = strtol(pos, &end, 10);
+ if (pos == end)
+ return -EINVAL;
+
+ if (sel > 127 || sel < 0)
+ return -EINVAL;
+ if (i ==
+ ARRAY_SIZE(drv->extra_bss_membership_selectors))
+ return -EINVAL;
+ drv->extra_bss_membership_selectors[i++] = sel;
+
+ pos = end;
+ if (*pos == ',')
+ pos++;
+ }
+ }
+
return 0;
}
@@ -11081,8 +11048,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret;
- if (type != WPA_IF_AP_BSS ||
- !nl80211_link_valid(bss->valid_links, link_id))
+ if (type != WPA_IF_AP_BSS)
return -1;
wpa_printf(MSG_DEBUG,
@@ -11367,12 +11333,9 @@
"prev_bssid=" MACSTR "\n"
"associated=%d\n"
"assoc_freq=%u\n"
- "monitor_sock=%d\n"
- "monitor_ifidx=%d\n"
- "monitor_refcount=%d\n"
"last_mgmt_freq=%u\n"
"eapol_tx_sock=%d\n"
- "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s",
drv->phyname,
MAC2STR(drv->perm_addr),
drv->ifindex,
@@ -11384,9 +11347,6 @@
MAC2STR(drv->prev_bssid),
drv->associated,
drv->assoc_freq,
- drv->monitor_sock,
- drv->monitor_ifidx,
- drv->monitor_refcount,
drv->last_mgmt_freq,
drv->eapol_tx_sock,
drv->ignore_if_down_event ?
@@ -11404,7 +11364,6 @@
drv->data_tx_status ? "data_tx_status=1\n" : "",
drv->scan_for_auth ? "scan_for_auth=1\n" : "",
drv->retry_auth ? "retry_auth=1\n" : "",
- drv->use_monitor ? "use_monitor=1\n" : "",
drv->ignore_next_local_disconnect ?
"ignore_next_local_disconnect\n" : "",
drv->ignore_next_local_deauth ?
@@ -14766,9 +14725,9 @@
static int wpa_driver_get_phyname(struct wpa_driver_nl80211_data *drv)
{
struct nl_msg *msg;
- u32 feat, nl_flags;
+ u32 nl_flags = 0;
+ u32 feat = get_nl80211_protocol_features(drv);
- feat = get_nl80211_protocol_features(drv);
if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
nl_flags = NLM_F_DUMP;
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index da74030..bf3442a 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -151,10 +151,6 @@
enum nl80211_iftype ap_scan_as_station;
unsigned int assoc_freq;
- int monitor_sock;
- int monitor_ifidx;
- int monitor_refcount;
-
unsigned int disabled_11b_rates:1;
unsigned int pending_remain_on_chan:1;
unsigned int in_interface_list:1;
@@ -163,7 +159,6 @@
unsigned int data_tx_status:1;
unsigned int scan_for_auth:1;
unsigned int retry_auth:1;
- unsigned int use_monitor:1;
unsigned int hostapd:1;
unsigned int start_mode_sta:1;
unsigned int start_iface_up:1;
@@ -202,6 +197,8 @@
unsigned int qca_ap_allowed_freqs:1;
unsigned int connect_ext_vendor_cmd_avail:1;
+ u8 extra_bss_membership_selectors[8];
+
u32 ignore_next_local_disconnect;
u32 ignore_next_local_deauth;
@@ -368,8 +365,6 @@
int local_state_change,
struct i802_bss *bss);
-int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
-void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
const void *data, size_t len,
int encrypt, int noack);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 1aaeae9..1dbfc22 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -302,9 +302,6 @@
case RSN_AUTH_KEY_MGMT_CCKM:
key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_CCKM;
break;
- case RSN_AUTH_KEY_MGMT_OSEN:
- key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_OSEN;
- break;
case RSN_AUTH_KEY_MGMT_802_1X_SUITE_B:
key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B;
break;
@@ -719,6 +716,10 @@
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_SAE_OFFLOAD_AP))
capa->flags2 |= WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_SPP_AMSDU;
}
@@ -1471,6 +1472,12 @@
if (check_feature(QCA_WLAN_VENDOR_FEATURE_NAN_USD_OFFLOAD, &info))
drv->capa.flags2 |= WPA_DRIVER_FLAGS2_NAN_OFFLOAD;
+ if (!check_feature(QCA_WLAN_VENDOR_FEATURE_P2P_V2, &info))
+ drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_P2P_FEATURE_V2;
+
+ if (!check_feature(QCA_WLAN_VENDOR_FEATURE_PCC_MODE, &info))
+ drv->capa.flags2 &= ~WPA_DRIVER_FLAGS2_P2P_FEATURE_PCC_MODE;
+
os_free(info.flags);
}
@@ -1585,20 +1592,18 @@
drv->have_low_prio_scan = info.have_low_prio_scan;
/*
- * If poll command and tx status are supported, mac80211 is new enough
- * to have everything we need to not need monitor interfaces.
- */
- drv->use_monitor = !info.device_ap_sme &&
- (!info.poll_command_supported || !info.data_tx_status);
-
- /*
- * If we aren't going to use monitor interfaces, but the
- * driver doesn't support data TX status, we won't get TX
+ * If the driver doesn't support data TX status, we won't get TX
* status for EAPOL frames.
*/
- if (!drv->use_monitor && !info.data_tx_status)
+ if (!info.data_tx_status)
drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+ /* Enable P2P2 and PCC mode capabilities by default for the drivers
+ * which can't explicitly indicate whether these capabilities are
+ * supported. */
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_P2P_FEATURE_V2;
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_P2P_FEATURE_PCC_MODE;
+
#ifdef CONFIG_DRIVER_NL80211_QCA
if (!(info.capa->flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD))
qca_nl80211_check_dfs_capa(drv);
@@ -2006,12 +2011,9 @@
len);
}
- if (tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]) {
- u16 capa;
-
- capa = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]);
- he_capab->he_6ghz_capa = le_to_host16(capa);
- }
+ if (tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA])
+ he_capab->he_6ghz_capa =
+ nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]);
if (!tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC] ||
!tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY])
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index f297e40..246d49d 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -186,6 +186,8 @@
C2S(NL80211_CMD_SET_HW_TIMESTAMP)
C2S(NL80211_CMD_LINKS_REMOVED)
C2S(NL80211_CMD_SET_TID_TO_LINK_MAPPING)
+ C2S(NL80211_CMD_ASSOC_MLO_RECONF)
+ C2S(NL80211_CMD_EPCS_CFG)
C2S(__NL80211_CMD_AFTER_LAST)
}
#undef C2S
@@ -1250,6 +1252,8 @@
os_memset(&data, 0, sizeof(data));
data.ch_switch.freq = nla_get_u32(freq);
+ if (is_6ghz_freq(data.ch_switch.freq))
+ ht_enabled = 0;
data.ch_switch.ht_enabled = ht_enabled;
data.ch_switch.ch_offset = chan_offset;
if (punct_bitmap)
@@ -1719,7 +1723,7 @@
}
if (cmd == NL80211_CMD_FRAME && stype == WLAN_FC_STYPE_AUTH &&
- auth_type == host_to_le16(WLAN_AUTH_PASN)) {
+ auth_type == WLAN_AUTH_PASN) {
wpa_printf(MSG_DEBUG,
"nl80211: %s: Allow PASN frame for foreign address",
bss->ifname);
diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c
index 7ff55f1..ca9bb1e 100644
--- a/src/drivers/driver_nl80211_monitor.c
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -23,259 +23,14 @@
#include "driver_nl80211.h"
-static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
- union wpa_event_data event;
-
- hdr = (struct ieee80211_hdr *) buf;
- fc = le_to_host16(hdr->frame_control);
-
- os_memset(&event, 0, sizeof(event));
- event.tx_status.type = WLAN_FC_GET_TYPE(fc);
- event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
- event.tx_status.dst = hdr->addr1;
- event.tx_status.data = buf;
- event.tx_status.data_len = len;
- event.tx_status.ack = ok;
- wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
-}
-
-
-static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
- u8 *buf, size_t len)
-{
- struct ieee80211_hdr *hdr = (void *)buf;
- u16 fc;
- union wpa_event_data event;
-
- if (len < sizeof(*hdr))
- return;
-
- fc = le_to_host16(hdr->frame_control);
-
- os_memset(&event, 0, sizeof(event));
- event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
- event.rx_from_unknown.addr = hdr->addr2;
- event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
- (WLAN_FC_FROMDS | WLAN_FC_TODS);
- wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
-}
-
-
-static void handle_frame(struct wpa_driver_nl80211_data *drv,
- u8 *buf, size_t len, int datarate, int ssi_signal)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
- union wpa_event_data event;
-
- if (!drv->use_monitor)
- return;
-
- hdr = (struct ieee80211_hdr *) buf;
- fc = le_to_host16(hdr->frame_control);
-
- switch (WLAN_FC_GET_TYPE(fc)) {
- case WLAN_FC_TYPE_MGMT:
- os_memset(&event, 0, sizeof(event));
- event.rx_mgmt.frame = buf;
- event.rx_mgmt.frame_len = len;
- event.rx_mgmt.datarate = datarate;
- event.rx_mgmt.ssi_signal = ssi_signal;
- wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
- break;
- case WLAN_FC_TYPE_CTRL:
- /* can only get here with PS-Poll frames */
- wpa_printf(MSG_DEBUG, "CTRL");
- from_unknown_sta(drv, buf, len);
- break;
- case WLAN_FC_TYPE_DATA:
- from_unknown_sta(drv, buf, len);
- break;
- }
-}
-
-
-static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct wpa_driver_nl80211_data *drv = eloop_ctx;
- int len;
- unsigned char buf[3000];
- struct ieee80211_radiotap_iterator iter;
- int ret;
- int datarate = 0, ssi_signal = 0;
- int injected = 0, failed = 0, rxflags = 0;
-
- len = recv(sock, buf, sizeof(buf), 0);
- if (len < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
- strerror(errno));
- return;
- }
-
- if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
- wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
- return;
- }
-
- while (1) {
- ret = ieee80211_radiotap_iterator_next(&iter);
- if (ret == -ENOENT)
- break;
- if (ret) {
- wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
- ret);
- return;
- }
- switch (iter.this_arg_index) {
- case IEEE80211_RADIOTAP_FLAGS:
- if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
- len -= 4;
- break;
- case IEEE80211_RADIOTAP_RX_FLAGS:
- rxflags = 1;
- break;
- case IEEE80211_RADIOTAP_TX_FLAGS:
- injected = 1;
- failed = le_to_host16((*(le16 *) iter.this_arg)) &
- IEEE80211_RADIOTAP_F_TX_FAIL;
- break;
- case IEEE80211_RADIOTAP_DATA_RETRIES:
- break;
- case IEEE80211_RADIOTAP_CHANNEL:
- /* TODO: convert from freq/flags to channel number */
- break;
- case IEEE80211_RADIOTAP_RATE:
- datarate = *iter.this_arg * 5;
- break;
- case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
- ssi_signal = (s8) *iter.this_arg;
- break;
- }
- }
-
- if (rxflags && injected)
- return;
-
- if (!injected)
- handle_frame(drv, buf + iter._max_length,
- len - iter._max_length, datarate, ssi_signal);
- else
- handle_tx_callback(drv->ctx, buf + iter._max_length,
- len - iter._max_length, !failed);
-}
-
-
-/*
- * we post-process the filter code later and rewrite
- * this to the offset to the last instruction
- */
-#define PASS 0xFF
-#define FAIL 0xFE
+#ifdef CONFIG_TESTING_OPTIONS
static struct sock_filter msock_filter_insns[] = {
- /*
- * do a little-endian load of the radiotap length field
- */
- /* load lower byte into A */
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2),
- /* put it into X (== index register) */
- BPF_STMT(BPF_MISC| BPF_TAX, 0),
- /* load upper byte into A */
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3),
- /* left-shift it by 8 */
- BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
- /* or with X */
- BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
- /* put result into X */
- BPF_STMT(BPF_MISC| BPF_TAX, 0),
-
- /*
- * Allow management frames through, this also gives us those
- * management frames that we sent ourselves with status
- */
- /* load the lower byte of the IEEE 802.11 frame control field */
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
- /* mask off frame type and version */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
- /* accept frame if it's both 0, fall through otherwise */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
-
- /*
- * TODO: add a bit to radiotap RX flags that indicates
- * that the sending station is not associated, then
- * add a filter here that filters on our DA and that flag
- * to allow us to deauth frames to that bad station.
- *
- * For now allow all To DS data frames through.
- */
- /* load the IEEE 802.11 frame control field */
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, 0),
- /* mask off frame type, version and DS status */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
- /* accept frame if version 0, type 2 and To DS, fall through otherwise
- */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
-
-#if 0
- /*
- * drop non-data frames
- */
- /* load the lower byte of the frame control field */
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
- /* mask off QoS bit */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
- /* drop non-data frames */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
-#endif
- /* load the upper byte of the frame control field */
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 1),
- /* mask off toDS/fromDS */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
- /* accept WDS frames */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, PASS, 0),
-
- /*
- * add header length to index
- */
- /* load the lower byte of the frame control field */
- BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
- /* mask off QoS bit */
- BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80),
- /* right shift it by 6 to give 0 or 2 */
- BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6),
- /* add data frame header length */
- BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24),
- /* add index, was start of 802.11 header */
- BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
- /* move to index, now start of LL header */
- BPF_STMT(BPF_MISC | BPF_TAX, 0),
-
- /*
- * Accept empty data frames, we use those for
- * polling activity.
- */
- BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
-
- /*
- * Accept EAPOL frames
- */
- BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
- BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
-
- /* keep these last two statements or change the code below */
- /* return 0 == "DROP" */
+ /* return 0 == "DROP", we don't want RX */
BPF_STMT(BPF_RET | BPF_K, 0),
- /* return ~0 == "keep all" */
- BPF_STMT(BPF_RET | BPF_K, ~0),
};
-static struct sock_fprog msock_filter = {
+static const struct sock_fprog msock_filter = {
.len = ARRAY_SIZE(msock_filter_insns),
.filter = msock_filter_insns,
};
@@ -283,32 +38,6 @@
static int add_monitor_filter(int s)
{
- int idx;
-
- /* rewrite all PASS/FAIL jump offsets */
- for (idx = 0; idx < msock_filter.len; idx++) {
- struct sock_filter *insn = &msock_filter_insns[idx];
-
- if (BPF_CLASS(insn->code) == BPF_JMP) {
- if (insn->code == (BPF_JMP|BPF_JA)) {
- if (insn->k == PASS)
- insn->k = msock_filter.len - idx - 2;
- else if (insn->k == FAIL)
- insn->k = msock_filter.len - idx - 3;
- }
-
- if (insn->jt == PASS)
- insn->jt = msock_filter.len - idx - 2;
- else if (insn->jt == FAIL)
- insn->jt = msock_filter.len - idx - 3;
-
- if (insn->jf == PASS)
- insn->jf = msock_filter.len - idx - 2;
- else if (insn->jf == FAIL)
- insn->jf = msock_filter.len - idx - 3;
- }
- }
-
if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
&msock_filter, sizeof(msock_filter))) {
wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
@@ -320,40 +49,29 @@
}
-void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv)
+static void
+nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv,
+ int ifidx, int sock)
{
- if (drv->monitor_refcount > 0)
- drv->monitor_refcount--;
- wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
- drv->monitor_refcount);
- if (drv->monitor_refcount > 0)
- return;
+ wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface");
- if (drv->monitor_ifidx >= 0) {
- nl80211_remove_iface(drv, drv->monitor_ifidx);
- drv->monitor_ifidx = -1;
- }
- if (drv->monitor_sock >= 0) {
- eloop_unregister_read_sock(drv->monitor_sock);
- close(drv->monitor_sock);
- drv->monitor_sock = -1;
- }
+ if (ifidx >= 0)
+ nl80211_remove_iface(drv, ifidx);
+ if (sock >= 0)
+ close(sock);
}
-int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
+static int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv,
+ int *ifidx, int *sock)
{
char buf[IFNAMSIZ];
struct sockaddr_ll ll;
int optval;
socklen_t optlen;
- if (drv->monitor_ifidx >= 0) {
- drv->monitor_refcount++;
- wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
- drv->monitor_refcount);
- return 0;
- }
+ *ifidx = -1;
+ *sock = -1;
if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
/*
@@ -379,23 +97,10 @@
buf[IFNAMSIZ - 1] = '\0';
- drv->monitor_ifidx =
- nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
- 0, NULL, NULL, 0);
+ *ifidx = nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
+ 0, NULL, NULL, 0);
- if (drv->monitor_ifidx == -EOPNOTSUPP) {
- /*
- * This is backward compatibility for a few versions of
- * the kernel only that didn't advertise the right
- * attributes for the only driver that then supported
- * AP mode w/o monitor -- ath6kl.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
- "monitor interface type - try to run without it");
- drv->device_ap_sme = 1;
- }
-
- if (drv->monitor_ifidx < 0)
+ if (*ifidx < 0)
return -1;
if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
@@ -403,21 +108,21 @@
memset(&ll, 0, sizeof(ll));
ll.sll_family = AF_PACKET;
- ll.sll_ifindex = drv->monitor_ifidx;
- drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (drv->monitor_sock < 0) {
+ ll.sll_ifindex = *ifidx;
+ *sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (*sock < 0) {
wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
strerror(errno));
goto error;
}
- if (add_monitor_filter(drv->monitor_sock)) {
+ if (add_monitor_filter(*sock)) {
wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
"interface; do filtering in user space");
/* This works, but will cost in performance. */
}
- if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ if (bind(*sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
strerror(errno));
goto error;
@@ -425,30 +130,22 @@
optlen = sizeof(optval);
optval = 20;
- if (setsockopt
- (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+ if (setsockopt(*sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
strerror(errno));
goto error;
}
- if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
- drv, NULL)) {
- wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
- goto error;
- }
-
- drv->monitor_refcount++;
return 0;
error:
- nl80211_remove_monitor_interface(drv);
+ nl80211_remove_monitor_interface(drv, *ifidx, *sock);
return -1;
}
-int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
- const void *data, size_t len,
- int encrypt, int noack)
+static int _nl80211_send_monitor(int monitor_sock,
+ const void *data, size_t len,
+ int encrypt, int noack)
{
__u8 rtap_hdr[] = {
0x00, 0x00, /* radiotap version */
@@ -484,20 +181,32 @@
if (encrypt)
rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
- if (drv->monitor_sock < 0) {
- wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
- "for %s", __func__);
- return -1;
- }
-
if (noack)
txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
WPA_PUT_LE16(&rtap_hdr[12], txflags);
- res = sendmsg(drv->monitor_sock, &msg, 0);
+ res = sendmsg(monitor_sock, &msg, 0);
if (res < 0) {
wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
return -1;
}
return 0;
}
+
+
+int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
+ const void *data, size_t len,
+ int encrypt, int noack)
+{
+ int res, ifidx, sock;
+
+ res = nl80211_create_monitor_interface(drv, &ifidx, &sock);
+ if (res < 0)
+ return res;
+
+ res = _nl80211_send_monitor(sock, data, len, encrypt, noack);
+ nl80211_remove_monitor_interface(drv, ifidx, sock);
+ return res;
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
index bfc2311..dac312a 100644
--- a/src/drivers/driver_openbsd.c
+++ b/src/drivers/driver_openbsd.c
@@ -77,6 +77,9 @@
const u8 *key = params->key;
size_t key_len = params->key_len;
+ if (params->key_flag & KEY_FLAG_NEXT)
+ return -1;
+
if (key_len > IEEE80211_PMK_LEN ||
(key_flag & KEY_FLAG_PMK_MASK) != KEY_FLAG_PMK) {
return -1;
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index d6735b4..d7c6b01 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -219,6 +219,9 @@
const u8 *key = params->key;
size_t key_len = params->key_len;
+ if (params->key_flag & KEY_FLAG_NEXT)
+ return -1;
+
wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
__func__, priv, alg, key_idx, set_tx);
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 2c656fb..c34c13b 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1833,6 +1833,9 @@
const u8 *key = params->key;
size_t key_len = params->key_len;
+ if (params->key_flag & KEY_FLAG_NEXT)
+ return -1;
+
wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
"key_len=%lu",
__FUNCTION__, alg, key_idx, set_tx,
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index f97f5ad..f6c1b18 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1329,6 +1329,13 @@
* %NL80211_ATTR_MLO_TTLM_ULINK attributes are used to specify the
* TID to Link mapping for downlink/uplink traffic.
*
+ * @NL80211_CMD_ASSOC_MLO_RECONF: For a non-AP MLD station, request to
+ * add/remove links to/from the association.
+ *
+ * @NL80211_CMD_EPCS_CFG: EPCS configuration for a station. Used by userland to
+ * control EPCS configuration. Used to notify userland on the current state
+ * of EPCS.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1586,6 +1593,9 @@
NL80211_CMD_SET_TID_TO_LINK_MAPPING,
+ NL80211_CMD_ASSOC_MLO_RECONF,
+ NL80211_CMD_EPCS_CFG,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -2868,6 +2878,21 @@
* nested item, it contains attributes defined in
* &enum nl80211_if_combination_attrs.
*
+ * @NL80211_ATTR_VIF_RADIO_MASK: Bitmask of allowed radios (u32).
+ * A value of 0 means all radios.
+ *
+ * @NL80211_ATTR_SUPPORTED_SELECTORS: supported selectors, array of
+ * supported selectors as defined by IEEE 802.11 7.3.2.2 but without the
+ * length restriction (at most %NL80211_MAX_SUPP_SELECTORS).
+ * This can be used to provide a list of selectors that are implemented
+ * by the supplicant. If not given, support for SAE_H2E is assumed.
+ *
+ * @NL80211_ATTR_MLO_RECONF_REM_LINKS: (u16) A bitmask of the links requested
+ * to be removed from the MLO association.
+ *
+ * @NL80211_ATTR_EPCS: Flag attribute indicating that EPCS is enabled for a
+ * station interface.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3416,6 +3441,13 @@
NL80211_ATTR_WIPHY_RADIOS,
NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS,
+ NL80211_ATTR_VIF_RADIO_MASK,
+
+ NL80211_ATTR_SUPPORTED_SELECTORS,
+
+ NL80211_ATTR_MLO_RECONF_REM_LINKS,
+ NL80211_ATTR_EPCS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3460,6 +3492,7 @@
#define NL80211_WIPHY_NAME_MAXLEN 64
#define NL80211_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_SELECTORS 128
#define NL80211_MAX_SUPP_HT_RATES 77
#define NL80211_MAX_SUPP_REG_RULES 128
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
@@ -4698,6 +4731,7 @@
* overrides all other flags.
* @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
* and ACK incoming unicast packets.
+ * @NL80211_MNTR_FLAG_SKIP_TX: do not pass local tx packets
*
* @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
* @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
@@ -4710,6 +4744,7 @@
NL80211_MNTR_FLAG_OTHER_BSS,
NL80211_MNTR_FLAG_COOK_FRAMES,
NL80211_MNTR_FLAG_ACTIVE,
+ NL80211_MNTR_FLAG_SKIP_TX,
/* keep last */
__NL80211_MNTR_FLAG_AFTER_LAST,
@@ -8031,6 +8066,8 @@
* @NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION: Supported interface
* combination for this radio. Attribute may be present multiple times
* and contains attributes defined in &enum nl80211_if_combination_attrs.
+ * @NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK: bitmask (u32) of antennas
+ * connected to this radio.
*
* @__NL80211_WIPHY_RADIO_ATTR_LAST: Internal
* @NL80211_WIPHY_RADIO_ATTR_MAX: Highest attribute
@@ -8041,6 +8078,7 @@
NL80211_WIPHY_RADIO_ATTR_INDEX,
NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE,
NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION,
+ NL80211_WIPHY_RADIO_ATTR_ANTENNA_MASK,
/* keep last */
__NL80211_WIPHY_RADIO_ATTR_LAST,
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index ff8ad8d..fa7ecd0 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -76,7 +76,7 @@
}
/* since we're expanding to a bit length, mask off the excess */
- if (resultbitlen % 8) {
+ if (resultbytelen > 0 && (resultbitlen % 8)) {
u8 mask = 0xff;
mask <<= (8 - (resultbitlen % 8));
result[resultbytelen - 1] &= mask;
diff --git a/src/eap_peer/eap_teap.c b/src/eap_peer/eap_teap.c
index 8ce7cb7..b9c1ece 100644
--- a/src/eap_peer/eap_teap.c
+++ b/src/eap_peer/eap_teap.c
@@ -666,7 +666,7 @@
data->session_id[0] = EAP_TYPE_TEAP;
res = tls_get_tls_unique(data->ssl.conn, data->session_id + 1,
max_id_len - 1);
- if (res < 0) {
+ if (res < 0 || (size_t) res >= max_id_len) {
os_free(data->session_id);
data->session_id = NULL;
wpa_printf(MSG_ERROR, "EAP-TEAP: Failed to derive Session-Id");
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index 4167e99..7e167f0 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -106,33 +106,6 @@
#endif /* EAP_UNAUTH_TLS */
-#ifdef CONFIG_HS20
-static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
-{
- struct eap_tls_data *data;
- struct eap_peer_config *config = eap_get_config(sm);
-
- data = os_zalloc(sizeof(*data));
- if (data == NULL)
- return NULL;
-
- data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
- sm->ssl_ctx;
-
- if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
- EAP_WFA_UNAUTH_TLS_TYPE)) {
- wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
- eap_tls_deinit(sm, data);
- return NULL;
- }
-
- data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
-
- return data;
-}
-#endif /* CONFIG_HS20 */
-
-
static void eap_tls_free_key(struct eap_tls_data *data)
{
if (data->key_data) {
@@ -478,31 +451,3 @@
return eap_peer_method_register(eap);
}
#endif /* EAP_UNAUTH_TLS */
-
-
-#ifdef CONFIG_HS20
-int eap_peer_wfa_unauth_tls_register(void)
-{
- struct eap_method *eap;
-
- eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
- EAP_VENDOR_WFA_NEW,
- EAP_VENDOR_WFA_UNAUTH_TLS,
- "WFA-UNAUTH-TLS");
- if (eap == NULL)
- return -1;
-
- eap->init = eap_wfa_unauth_tls_init;
- eap->deinit = eap_tls_deinit;
- eap->process = eap_tls_process;
- eap->isKeyAvailable = eap_tls_isKeyAvailable;
- eap->getKey = eap_tls_getKey;
- eap->get_status = eap_tls_get_status;
- eap->has_reauth_data = eap_tls_has_reauth_data;
- eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
- eap->init_for_reauth = eap_tls_init_for_reauth;
- eap->get_emsk = eap_tls_get_emsk;
-
- return eap_peer_method_register(eap);
-}
-#endif /* CONFIG_HS20 */
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index c539738..47d21c6 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -23,10 +23,6 @@
return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
code, identifier);
- if (type == EAP_WFA_UNAUTH_TLS_TYPE)
- return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
- EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
- code, identifier);
return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
identifier);
}
@@ -195,8 +191,7 @@
}
#ifndef EAP_TLSV1_3
if (data->eap_type == EAP_TYPE_TLS ||
- data->eap_type == EAP_UNAUTH_TLS_TYPE ||
- data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) {
+ data->eap_type == EAP_UNAUTH_TLS_TYPE) {
/* While the current EAP-TLS implementation is more or less
* complete for TLS v1.3, there has been only minimal
* interoperability testing with other implementations, so
@@ -932,10 +927,6 @@
pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
&left);
- else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
- pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
- EAP_VENDOR_WFA_UNAUTH_TLS, reqData,
- &left);
else
pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
&left);
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 3348634..2551ff5 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -99,7 +99,6 @@
/* stub type used as a flag for UNAUTH-TLS */
#define EAP_UNAUTH_TLS_TYPE 255
-#define EAP_WFA_UNAUTH_TLS_TYPE 254
int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 0a987e6..dd02b0c 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -35,7 +35,6 @@
size_t salt_len;
int phase2;
int force_version;
- unsigned int remediation:1;
unsigned int macacl:1;
int ttls_auth; /* bitfield of
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 443c293..0caa4c3 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -114,29 +114,6 @@
#endif /* EAP_SERVER_UNAUTH_TLS */
-#ifdef CONFIG_HS20
-static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
-{
- struct eap_tls_data *data;
-
- data = os_zalloc(sizeof(*data));
- if (data == NULL)
- return NULL;
- data->state = START;
-
- if (eap_server_tls_ssl_init(sm, &data->ssl, 0,
- EAP_WFA_UNAUTH_TLS_TYPE)) {
- wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
- eap_tls_reset(sm, data);
- return NULL;
- }
-
- data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
- return data;
-}
-#endif /* CONFIG_HS20 */
-
-
static void eap_tls_reset(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
@@ -237,10 +214,6 @@
pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
&len);
- else if (data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
- pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
- EAP_VENDOR_WFA_UNAUTH_TLS, respData,
- &len);
else
pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
respData, &len);
@@ -474,30 +447,3 @@
return eap_server_method_register(eap);
}
#endif /* EAP_SERVER_UNAUTH_TLS */
-
-
-#ifdef CONFIG_HS20
-int eap_server_wfa_unauth_tls_register(void)
-{
- struct eap_method *eap;
-
- eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
- EAP_VENDOR_WFA_NEW,
- EAP_VENDOR_WFA_UNAUTH_TLS,
- "WFA-UNAUTH-TLS");
- if (eap == NULL)
- return -1;
-
- eap->init = eap_wfa_unauth_tls_init;
- eap->reset = eap_tls_reset;
- eap->buildReq = eap_tls_buildReq;
- eap->check = eap_tls_check;
- eap->process = eap_tls_process;
- eap->isDone = eap_tls_isDone;
- eap->getKey = eap_tls_getKey;
- eap->isSuccess = eap_tls_isSuccess;
- eap->get_emsk = eap_tls_get_emsk;
-
- return eap_server_method_register(eap);
-}
-#endif /* CONFIG_HS20 */
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 717af2e..81d1eed 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -25,10 +25,6 @@
return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
code, identifier);
- else if (type == EAP_WFA_UNAUTH_TLS_TYPE)
- return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
- EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
- code, identifier);
return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
identifier);
}
@@ -541,10 +537,6 @@
pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
&left);
- else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
- pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
- EAP_VENDOR_WFA_UNAUTH_TLS, respData,
- &left);
else
pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData,
&left);
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index ad28c79..2a8faf9 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -72,7 +72,6 @@
/* stub type used as a flag for UNAUTH-TLS */
#define EAP_UNAUTH_TLS_TYPE 255
-#define EAP_WFA_UNAUTH_TLS_TYPE 254
struct wpabuf * eap_tls_msg_alloc(enum eap_type type, size_t payload_len,
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index e1b82eb..af962ee 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -237,7 +237,7 @@
if (!from_initialize && !pre_auth_logoff) {
if (sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
sm->flags & EAPOL_SM_PREAUTH,
- sm->remediation, logoff)) {
+ logoff)) {
wpa_printf(MSG_DEBUG,
"EAPOL: Do not restart since lower layers will disconnect the port after EAPOL-Logoff");
sm->stopped = true;
@@ -298,8 +298,7 @@
eap_server_get_name(0, sm->eap_type_supp));
}
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
- sm->flags & EAPOL_SM_PREAUTH, sm->remediation,
- false);
+ sm->flags & EAPOL_SM_PREAUTH, false);
}
@@ -327,8 +326,7 @@
if (sm->authSuccess)
sm->authenticated++;
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
- sm->flags & EAPOL_SM_PREAUTH, sm->remediation,
- false);
+ sm->flags & EAPOL_SM_PREAUTH, false);
}
@@ -1029,13 +1027,9 @@
struct eap_user *user)
{
struct eapol_state_machine *sm = ctx;
- int ret;
- ret = sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
- identity_len, phase2, user);
- if (user->remediation)
- sm->remediation = 1;
- return ret;
+ return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
+ identity_len, phase2, user);
}
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 7296a3a..83f5c5d 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -47,7 +47,7 @@
void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
size_t datalen);
bool (*finished)(void *ctx, void *sta_ctx, int success, int preauth,
- int remediation, bool logoff);
+ bool logoff);
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
int (*sta_entry_alive)(void *ctx, const u8 *addr);
diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
index a0cef0f..c970e73 100644
--- a/src/eapol_auth/eapol_auth_sm_i.h
+++ b/src/eapol_auth/eapol_auth_sm_i.h
@@ -168,8 +168,6 @@
void *sta; /* station context pointer to use in callbacks */
- int remediation;
-
u64 acct_multi_session_id;
unsigned int authenticated; /* The number of times authentication has
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 0bc6f0d..4503830 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -4139,6 +4139,20 @@
}
+void p2p_listen_failed(struct p2p_data *p2p, unsigned int freq)
+{
+ if (freq != p2p->pending_listen_freq) {
+ p2p_dbg(p2p,
+ "Unexpected listen failed callback for freq=%u (pending_listen_freq=%u)",
+ freq, p2p->pending_listen_freq);
+ return;
+ }
+
+ p2p_dbg(p2p, "Listen failed on freq=%u", freq);
+ p2p->pending_listen_freq = 0;
+}
+
+
static void p2p_timeout_connect(struct p2p_data *p2p)
{
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
@@ -4319,9 +4333,11 @@
p2p_dbg(p2p, "Invitation Request retry limit reached");
if (p2p->cfg->invitation_result)
p2p->cfg->invitation_result(
- p2p->cfg->cb_ctx, -1, NULL, NULL,
+ p2p->cfg->cb_ctx, -1, NULL, 0, NULL,
+ NULL,
p2p->invite_peer->info.p2p_device_addr,
- 0, 0, NULL, NULL, 0);
+ 0, 0, NULL, NULL, 0,
+ p2p->invite_go_dev_addr);
}
p2p_set_state(p2p, P2P_IDLE);
}
@@ -6056,13 +6072,49 @@
}
-static void p2p_validate_dira(struct p2p_data *p2p, struct p2p_device *dev,
- const u8 *dira, u16 dira_len)
+static int p2p_validate_dira(struct p2p_data *p2p, struct p2p_device *dev,
+ const u8 *dira, u16 dira_len)
{
- if (p2p->cfg->validate_dira)
- p2p->cfg->validate_dira(p2p->cfg->cb_ctx,
- dev->info.p2p_device_addr,
- dira, dira_len);
+ if (dira_len < 1 || dira[0] != DIRA_CIPHER_VERSION_128) {
+ p2p_dbg(p2p, "Unsupported DIRA cipher version %d",
+ dira[0]);
+ return 0;
+ }
+
+ if (dira_len < 1 + DEVICE_IDENTITY_NONCE_LEN + DEVICE_IDENTITY_TAG_LEN)
+ {
+ p2p_dbg(p2p, "Truncated DIRA (length %u)", dira_len);
+ return 0;
+ }
+
+ if (p2p->cfg->validate_dira) {
+ const u8 *nonce = &dira[1];
+ const u8 *tag = &dira[1 + DEVICE_IDENTITY_NONCE_LEN];
+
+ return p2p->cfg->validate_dira(p2p->cfg->cb_ctx,
+ dev->info.p2p_device_addr,
+ nonce, tag);
+ }
+
+ return 0;
+}
+
+
+void p2p_usd_service_hash(struct p2p_data *p2p, const char *service_name)
+{
+ u8 buf[P2PS_HASH_LEN];
+
+ p2p->usd_service = false;
+
+ if (!service_name)
+ return;
+
+ if (!p2ps_gen_hash(p2p, service_name, buf))
+ return;
+ p2p_dbg(p2p, "USD service %s hash " MACSTR,
+ service_name, MAC2STR(buf));
+ p2p->usd_service = true;
+ os_memcpy(&p2p->p2p_service_hash, buf, P2PS_HASH_LEN);
}
@@ -6176,8 +6228,20 @@
if (!ether_addr_equal(peer_addr, p2p_dev_addr))
os_memcpy(dev->interface_addr, peer_addr, ETH_ALEN);
- if (msg.dira && msg.dira_len)
- p2p_validate_dira(p2p, dev, msg.dira, msg.dira_len);
+ if (msg.dira && msg.dira_len) {
+ dev->info.nonce_tag_valid = false;
+ dev->info.dik_id = p2p_validate_dira(p2p, dev, msg.dira,
+ msg.dira_len);
+ if (dev->info.dik_id) {
+ os_memcpy(dev->info.nonce, &msg.dira[1],
+ DEVICE_IDENTITY_NONCE_LEN);
+ os_memcpy(dev->info.tag,
+ &msg.dira[1 + DEVICE_IDENTITY_NONCE_LEN],
+ DEVICE_IDENTITY_TAG_LEN);
+ dev->info.pairing_config.dik_cipher = msg.dira[0];
+ dev->info.nonce_tag_valid = true;
+ }
+ }
p2p_dbg(p2p, "Updated device entry based on USD frame: " MACSTR
" dev_capab=0x%x group_capab=0x%x listen_freq=%d",
@@ -6192,6 +6256,18 @@
}
+int p2p_get_dik_id(struct p2p_data *p2p, const u8 *peer)
+{
+ struct p2p_device *dev;
+
+ dev = p2p_get_device(p2p, peer);
+ if (!dev)
+ return 0;
+
+ return dev->info.dik_id;
+}
+
+
#ifdef CONFIG_PASN
int p2p_config_sae_password(struct p2p_data *p2p, const char *pw)
@@ -6207,7 +6283,7 @@
static int p2p_prepare_pasn_extra_ie(struct p2p_data *p2p,
struct wpabuf *extra_ies,
- const struct wpabuf *frame)
+ const struct wpabuf *frame, bool add_dira)
{
struct wpabuf *buf, *buf2;
size_t len;
@@ -6222,6 +6298,11 @@
/* P2P Capability Extension attribute */
p2p_buf_add_pcea(buf, p2p);
+ if (add_dira) {
+ /* Device Identity Resolution attribute */
+ p2p_buf_add_dira(buf, p2p);
+ }
+
if (frame) {
p2p_dbg(p2p, "Add Action frame wrapper for PASN");
wpabuf_put_u8(buf, P2P_ATTR_ACTION_FRAME_WRAPPER);
@@ -6244,6 +6325,30 @@
}
+static struct wpabuf * p2p_pasn_service_hash(struct p2p_data *p2p,
+ struct wpabuf *extra_ies)
+{
+ struct wpabuf *buf;
+ u8 *ie_len = NULL;
+
+ if (!p2p->usd_service)
+ return extra_ies;
+
+ p2p_dbg(p2p, "Add P2P2 USD service hash in extra IE");
+ buf = wpabuf_alloc(100);
+ if (!buf) {
+ wpabuf_free(extra_ies);
+ return NULL;
+ }
+
+ ie_len = p2p_buf_add_ie_hdr(buf);
+ p2p_buf_add_usd_service_hash(buf, p2p);
+ p2p_buf_update_ie_hdr(buf, ie_len);
+
+ return wpabuf_concat(buf, extra_ies);
+}
+
+
static struct wpabuf * p2p_pairing_generate_rsnxe(struct p2p_data *p2p,
int akmp)
{
@@ -6391,6 +6496,7 @@
pasn->send_mgmt = p2p->cfg->pasn_send_mgmt;
pasn->prepare_data_element = p2p->cfg->prepare_data_element;
pasn->parse_data_element = p2p->cfg->parse_data_element;
+ pasn->validate_custom_pmkid = p2p->cfg->pasn_validate_pmkid;
pasn->freq = freq;
}
@@ -6435,6 +6541,7 @@
struct wpabuf *extra_ies, *req;
int ret = 0;
u8 *pasn_extra_ies = NULL;
+ u8 pmkid[PMKID_LEN];
if (!peer_addr) {
p2p_dbg(p2p, "Peer address NULL");
@@ -6473,12 +6580,26 @@
return -1;
}
- if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req)) {
+ if (os_get_random(pmkid, PMKID_LEN) < 0) {
+ wpabuf_free(req);
+ wpabuf_free(extra_ies);
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "P2P2: Use new random PMKID for pairing verification",
+ pmkid, PMKID_LEN);
+ pasn_set_custom_pmkid(pasn, pmkid);
+
+ if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req, true)) {
p2p_dbg(p2p, "Prepare PASN extra IEs failed");
ret = -1;
goto out;
}
+ extra_ies = p2p_pasn_service_hash(p2p, extra_ies);
+ if (!extra_ies)
+ goto out;
+
pasn_extra_ies = os_memdup(wpabuf_head_u8(extra_ies),
wpabuf_len(extra_ies));
if (!pasn_extra_ies) {
@@ -6529,6 +6650,9 @@
return -1;
}
+ if (freq == 0)
+ freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+
dev->role = P2P_ROLE_PAIRING_INITIATOR;
p2p_pasn_initialize(p2p, dev, addr, freq, false, true);
pasn = dev->pasn;
@@ -6548,12 +6672,16 @@
return -1;
}
- if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req)) {
+ if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req, false)) {
p2p_dbg(p2p, "Failed to prepare PASN extra elements");
ret = -1;
goto out;
}
+ extra_ies = p2p_pasn_service_hash(p2p, extra_ies);
+ if (!extra_ies)
+ goto out;
+
ies_len = wpabuf_len(extra_ies);
ies = os_memdup(wpabuf_head_u8(extra_ies), ies_len);
if (!ies) {
@@ -6656,6 +6784,18 @@
derive_kek);
wpabuf_free(dev->action_frame_wrapper);
dev->action_frame_wrapper = resp;
+ if (msg.dira && msg.dira_len &&
+ p2p_validate_dira(p2p, dev, msg.dira,
+ msg.dira_len)) {
+ struct wpa_ie_data rsn_data;
+
+ if (wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2,
+ elems.rsn_ie_len + 2,
+ &rsn_data) == 0 &&
+ rsn_data.num_pmkid)
+ pasn_set_custom_pmkid(dev->pasn,
+ rsn_data.pmkid);
+ }
} else if (data && data_len >= 1 && data[0] == P2P_GO_NEG_REQ) {
struct wpabuf *resp;
@@ -6795,7 +6935,7 @@
extra_ies = wpabuf_alloc(1500);
if (!extra_ies ||
p2p_prepare_pasn_extra_ie(p2p, extra_ies,
- dev->action_frame_wrapper)) {
+ dev->action_frame_wrapper, false)) {
p2p_dbg(p2p, "Failed to prepare PASN extra elements");
goto out;
}
@@ -6915,6 +7055,72 @@
}
+static int p2p_validate_custom_pmkid(struct p2p_data *p2p,
+ struct p2p_device *dev, const u8 *pmkid)
+{
+ if (dev->pasn->custom_pmkid_valid &&
+ os_memcmp(dev->pasn->custom_pmkid, pmkid, PMKID_LEN) == 0) {
+ p2p_dbg(p2p, "Customized PMKID valid");
+ return 0;
+ }
+ return -1;
+}
+
+
+static int p2p_pasn_pmksa_get_pmk(struct p2p_data *p2p, const u8 *addr,
+ u8 *pmkid, u8 *pmk, size_t *pmk_len)
+{
+ struct p2p_device *dev;
+
+ dev = p2p_get_device(p2p, addr);
+ if (!dev) {
+ p2p_dbg(p2p, "PASN: Peer not found " MACSTR, MAC2STR(addr));
+ return -1;
+ }
+
+ if (dev->role == P2P_ROLE_PAIRING_INITIATOR)
+ return pasn_initiator_pmksa_cache_get(p2p->initiator_pmksa,
+ addr, pmkid, pmk,
+ pmk_len);
+ else
+ return pasn_responder_pmksa_cache_get(p2p->responder_pmksa,
+ addr, pmkid, pmk,
+ pmk_len);
+}
+
+
+int p2p_pasn_validate_and_update_pmkid(struct p2p_data *p2p, const u8 *addr,
+ const u8 *rsn_pmkid)
+{
+ size_t pmk_len;
+ u8 pmkid[PMKID_LEN];
+ u8 pmk[PMK_LEN_MAX];
+ struct p2p_device *dev;
+
+ if (!p2p)
+ return -1;
+
+ dev = p2p_get_device(p2p, addr);
+ if (!dev || !dev->pasn) {
+ p2p_dbg(p2p, "P2P PASN: Peer not found " MACSTR,
+ MAC2STR(addr));
+ return -1;
+ }
+
+ if (p2p_validate_custom_pmkid(p2p, dev, rsn_pmkid))
+ return -1;
+
+ if (p2p_pasn_pmksa_get_pmk(p2p, addr, pmkid, pmk, &pmk_len)) {
+ p2p_dbg(p2p, "P2P PASN: Failed to get PMK from cache");
+ return -1;
+ }
+
+ p2p_pasn_pmksa_set_pmk(p2p, p2p->cfg->dev_addr, addr, pmk, pmk_len,
+ rsn_pmkid);
+ return 0;
+}
+
+
int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
size_t data_len, bool acked, bool verify)
{
@@ -7074,7 +7280,8 @@
pasn->frame = NULL;
pasn_register_callbacks(pasn, p2p->cfg->cb_ctx,
- p2p->cfg->pasn_send_mgmt, NULL);
+ p2p->cfg->pasn_send_mgmt,
+ p2p->cfg->pasn_validate_pmkid);
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
if (dev->role == P2P_ROLE_PAIRING_INITIATOR && auth_transaction == 2) {
@@ -7156,3 +7363,52 @@
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_PASN */
+
+
+int p2p_get_dira_info(struct p2p_data *p2p, char *buf, size_t buflen)
+{
+ int res;
+ char *pos, *end;
+ struct p2p_id_key *dev_ik;
+
+ if (!p2p->pairing_info ||
+ !p2p->cfg->pairing_config.pairing_capable ||
+ !p2p->cfg->pairing_config.enable_pairing_cache)
+ return 0;
+
+ if (p2p_derive_nonce_tag(p2p))
+ return 0;
+
+ pos = buf;
+ end = buf + buflen;
+ dev_ik = &p2p->pairing_info->dev_ik;
+
+ res = os_snprintf(pos, end - pos, MACSTR,
+ MAC2STR(p2p->cfg->dev_addr));
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ res = os_snprintf(pos, end - pos, " ");
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ pos += wpa_snprintf_hex(pos, end - pos, dev_ik->dira_nonce,
+ dev_ik->dira_nonce_len);
+
+ res = os_snprintf(pos, end - pos, " ");
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ pos += wpa_snprintf_hex(pos, end - pos, dev_ik->dira_tag,
+ dev_ik->dira_tag_len);
+
+ res = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, res))
+ return pos - buf;
+ pos += res;
+
+ return pos - buf;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 60a4a34..db70fd6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -511,6 +511,26 @@
* p2p_pairing_config - P2P pairing configuration
*/
struct p2p_pairing_config pairing_config;
+
+ /**
+ * dik_id - For paired peers Identity block ID with PMK
+ */
+ int dik_id;
+
+ /**
+ * nonce_tag_valid - Whether nonce and tag are valid
+ */
+ bool nonce_tag_valid;
+
+ /**
+ * nonce - Valid nonce received in a recent discovery frame
+ */
+ u8 nonce[DEVICE_IDENTITY_NONCE_LEN];
+
+ /**
+ * tag - Valid tag received in a recent discovery frame
+ */
+ u8 tag[DEVICE_IDENTITY_TAG_LEN];
};
enum p2p_prov_disc_status {
@@ -1091,6 +1111,8 @@
* used
* @p2p2: Whether invitation request was wrapped in PASN authentication
* received from a P2P2 device
+ * @new_ssid: Pointer to hold new SSID
+ * @new_ssid_len: Length of new SSID buffer in octets
* Returns: Status code (P2P_SC_*)
*
* This optional callback can be used to implement persistent reconnect
@@ -1113,7 +1135,8 @@
size_t ssid_len, int *go, u8 *group_bssid,
int *force_freq, int persistent_group,
const struct p2p_channels *channels,
- int dev_pw_id, bool p2p2);
+ int dev_pw_id, bool p2p2, const u8 **new_ssid,
+ size_t *new_ssid_len);
/**
* invitation_received - Callback on Invitation Request RX
@@ -1142,12 +1165,18 @@
* invitation_result - Callback on Invitation result
* @ctx: Callback context from cb_ctx
* @status: Negotiation result (Status Code)
+ * @new_ssid: New SSID received in invitation response
+ * @new_ssid_len: Length of new SSID received
* @bssid: P2P Group BSSID or %NULL if not received
* @channels: Available operating channels for the group
* @addr: Peer address
* @freq: Frequency (in MHz) indicated during invitation or 0
* @peer_oper_freq: Operating frequency (in MHz) advertized by the peer
* during invitation or 0
+ * @pmkid: PMKID used during invitation handshake
+ * @pmk: The derived PMK
+ * @pmk_len: PMK length in octets
+ * @go_dev_addr: The P2P Device Address of the GO
*
* This callback is used to indicate result of an Invitation procedure
* started with a call to p2p_invite(). The indicated status code is
@@ -1155,11 +1184,12 @@
* (P2P_SC_SUCCESS) indicating success or -1 to indicate a timeout or a
* local failure in transmitting the Invitation Request.
*/
- void (*invitation_result)(void *ctx, int status, const u8 *bssid,
+ void (*invitation_result)(void *ctx, int status, const u8 *new_ssid,
+ size_t new_ssid_len, const u8 *bssid,
const struct p2p_channels *channels,
const u8 *addr, int freq, int peer_oper_freq,
const u8 *pmkid, const u8 *pmk,
- size_t pmk_len);
+ size_t pmk_len, const u8 *go_dev_addr);
/**
* go_connected - Check whether we are connected to a GO
@@ -1332,33 +1362,36 @@
u16 bootstrap_method);
/**
- * bootstrap_completed - Indicate bootstrapping completed with P2P peer
+ * bootstrap_rsp_rx - Indicate bootstrapping response from a P2P peer
* @ctx: Callback context from cb_ctx
* @addr: P2P device address with which bootstrapping is completed
* @status: P2P Status Code of bootstrapping handshake
* @freq: Frequency in which bootstrapping is done
+ * @bootstrap_method: Bootstrapping method by the peer device
*
* This function can be used to notify the status of bootstrapping
* handshake.
*/
- void (*bootstrap_completed)(void *ctx, const u8 *addr,
- enum p2p_status_code status, int freq);
+ void (*bootstrap_rsp_rx)(void *ctx, const u8 *addr,
+ enum p2p_status_code status, int freq,
+ u16 bootstrap_method);
/**
* validate_dira - Indicate reception of DIRA to be validated against a
* list of available device identity keys
* @ctx: Callback context from cb_ctx
* @peer_addr: P2P Device address of the peer
- * @dira: DIRA attribute present in the USD frames
- * @dira_len: Length of DIRA
+ * @dira_nonce: DIRA Nonce
+ * @dira_tag: DIRA Tag
+ * Returns: Identity block ID on success, 0 on failure
*
* This function can be used to validate DIRA and configure PMK of a
* paired/persistent peer from configuration. The handler function is
* expected to call p2p_pasn_pmksa_set_pmk() to set the PMK/PMKID in
* case a matching entry is found.
*/
- void (*validate_dira)(void *ctx, const u8 *peer_addr,
- const u8 *dira, size_t dira_len);
+ int (*validate_dira)(void *ctx, const u8 *peer_addr,
+ const u8 *dira_nonce, const u8 *dira_tag);
/**
* pasn_send_mgmt - Function handler to transmit a Management frame
@@ -1390,6 +1423,15 @@
* Returns: 0 on success, -1 on failure
*/
int (*parse_data_element)(void *ctx, const u8 *data, size_t len);
+
+ /**
+ * pasn_validate_pmkid - Function handler to validate RSN PMKID
+ * @ctx: Callback context from cb_ctx
+ * @addr: Peer MAC address
+ * @pmkid: PMKID in the PASN frame
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*pasn_validate_pmkid)(void *ctx, const u8 *addr, const u8 *pmkid);
};
@@ -1628,6 +1670,17 @@
int p2p_reject(struct p2p_data *p2p, const u8 *peer_addr);
/**
+ * p2p_set_req_bootstrap_method - Send Provision Discovery Request to initiate
+ * bootstrapping
+ * @p2p: P2P module context from p2p_init()
+ * @peer_addr: MAC address of the peer P2P client
+ * @boostrap: Bootstrapping method
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_req_bootstrap_method(struct p2p_data *p2p, const u8 *peer_addr,
+ u16 bootstrap);
+
+/**
* p2p_prov_disc_req - Send Provision Discovery Request
* @p2p: P2P module context from p2p_init()
* @peer_addr: MAC address of the peer P2P client
@@ -1952,6 +2005,8 @@
*/
int p2p_listen_end(struct p2p_data *p2p, unsigned int freq);
+void p2p_listen_failed(struct p2p_data *p2p, unsigned int freq);
+
void p2p_deauth_notif(struct p2p_data *p2p, const u8 *bssid, u16 reason_code,
const u8 *ie, size_t ie_len);
@@ -2214,6 +2269,14 @@
size_t p2p_scan_ie_buf_len(struct p2p_data *p2p);
/**
+ * p2p_build_ssid - Generate a random P2P SSID
+ * @p2p: P2P module context from p2p_init()
+ * @ssid: Buffer for SSID
+ * @ssid_len: Pointer to hold SSID length
+ */
+void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len);
+
+/**
* p2p_go_params - Generate random P2P group parameters
* @p2p: P2P module context from p2p_init()
* @params: Buffer for parameters
@@ -2717,6 +2780,7 @@
struct wpabuf * p2p_usd_elems(struct p2p_data *p2p);
void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
const u8 *peer_addr, unsigned int freq);
+int p2p_get_dik_id(struct p2p_data *p2p, const u8 *peer);
void p2p_set_pairing_setup(struct p2p_data *p2p, int pairing_setup);
void p2p_set_pairing_cache(struct p2p_data *p2p, int pairing_cache);
@@ -2740,6 +2804,8 @@
size_t len, int freq);
int p2p_prepare_data_element(struct p2p_data *p2p, const u8 *peer_addr);
int p2p_parse_data_element(struct p2p_data *p2p, const u8 *data, size_t len);
+int p2p_pasn_validate_and_update_pmkid(struct p2p_data *p2p, const u8 *addr,
+ const u8 *pmkid);
int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
size_t data_len, bool acked, bool verify);
int p2p_config_sae_password(struct p2p_data *p2p, const char *pw);
@@ -2748,5 +2814,7 @@
void p2p_set_store_pasn_ptk(struct p2p_data *p2p, u8 val);
void p2p_pasn_store_ptk(struct p2p_data *p2p, struct wpa_ptk *ptk);
int p2p_pasn_get_ptk(struct p2p_data *p2p, const u8 **buf, size_t *buf_len);
+void p2p_usd_service_hash(struct p2p_data *p2p, const char *service_name);
+int p2p_get_dira_info(struct p2p_data *p2p, char *buf, size_t buflen);
#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 343566d..bc67ec2 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -418,6 +418,20 @@
}
+void p2p_buf_add_usd_service_hash(struct wpabuf *buf, struct p2p_data *p2p)
+{
+ if (!p2p)
+ return;
+
+ /* USD Service Hash */
+ wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH);
+ wpabuf_put_le16(buf, P2PS_HASH_LEN);
+ wpabuf_put_data(buf, p2p->p2p_service_hash, P2PS_HASH_LEN);
+ wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash",
+ p2p->p2p_service_hash, P2PS_HASH_LEN);
+}
+
+
void p2p_buf_add_session_info(struct wpabuf *buf, const char *info)
{
size_t info_len = 0;
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index ac6bbf7..4b787a5 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -260,6 +260,8 @@
return -1;
return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
NULL, config_method, 0, 0, 1);
+ } else if (dev->p2p2) {
+ return 0;
}
freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index a54e375..1353652 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -204,6 +204,8 @@
int inv_freq;
int inv_peer_oper_freq;
u8 inv_bssid[ETH_ALEN];
+ u8 inv_ssid[SSID_MAX_LEN];
+ size_t inv_ssid_len;
bool inv_all_channels;
};
@@ -701,6 +703,9 @@
*/
size_t pasn_ptk_len;
#endif /* CONFIG_TESTING_OPTIONS */
+
+ bool usd_service;
+ u8 p2p_service_hash[P2PS_HASH_LEN];
};
/**
@@ -1074,7 +1079,6 @@
struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p,
const u8 *query_hash,
u8 query_count);
-void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len);
int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *buf,
size_t len, unsigned int wait_time);
@@ -1094,6 +1098,7 @@
void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev,
const u8 *addr, int freq, bool verify,
bool derive_kek);
+void p2p_buf_add_usd_service_hash(struct wpabuf *buf, struct p2p_data *p2p);
void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 766b63e..6d112ee 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -117,7 +117,9 @@
u8 dialog_token, u8 status,
const u8 *group_bssid,
u8 reg_class, u8 channel,
- struct p2p_channels *channels)
+ struct p2p_channels *channels,
+ const u8 *ssid,
+ size_t ssid_len)
{
struct wpabuf *buf;
u8 *len;
@@ -162,6 +164,18 @@
reg_class, channel);
if (group_bssid)
p2p_buf_add_group_bssid(buf, group_bssid);
+
+ if (ssid_len && ssid) {
+ const u8 *dev_addr;
+
+ if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
+ dev_addr = peer->info.p2p_device_addr;
+ else
+ dev_addr = p2p->cfg->dev_addr;
+
+ p2p_buf_add_group_id(buf, dev_addr, ssid, ssid_len);
+ }
+
if (channels) {
bool is_6ghz_capab;
@@ -196,6 +210,8 @@
u8 group_bssid[ETH_ALEN], *bssid;
int op_freq = 0;
u8 reg_class = 0, channel = 0;
+ const u8 *new_ssid = NULL;
+ size_t new_ssid_len = 0;
struct p2p_channels all_channels, intersection, *channels = NULL;
int persistent;
@@ -272,7 +288,7 @@
msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
&go, group_bssid, &op_freq, persistent, &intersection,
msg.dev_password_id_present ? msg.dev_password_id : -1,
- p2p2);
+ p2p2, &new_ssid, &new_ssid_len);
}
if (go) {
@@ -401,7 +417,8 @@
else
bssid = NULL;
resp = p2p_build_invitation_resp(p2p, dev, msg.dialog_token, status,
- bssid, reg_class, channel, channels);
+ bssid, reg_class, channel, channels,
+ new_ssid, new_ssid_len);
/*
* Store copy of invitation data to be used when processing TX status
@@ -413,7 +430,12 @@
p2p->inv_group_bssid_ptr = p2p->inv_group_bssid;
} else
p2p->inv_group_bssid_ptr = NULL;
- if (msg.group_id) {
+
+ if (p2p2 && new_ssid_len) {
+ os_memcpy(p2p->inv_ssid, new_ssid, new_ssid_len);
+ p2p->inv_ssid_len = new_ssid_len;
+ os_memcpy(p2p->inv_go_dev_addr, p2p->cfg->dev_addr, ETH_ALEN);
+ } else if (msg.group_id) {
if (msg.group_id_len - ETH_ALEN <= SSID_MAX_LEN) {
os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN,
msg.group_id_len - ETH_ALEN);
@@ -467,6 +489,7 @@
struct p2p_message msg;
struct p2p_channels intersection, *channels = NULL;
bool all_channels = false;
+ const u8 *go_dev_addr = NULL;
p2p_dbg(p2p, "Received Invitation Response from " MACSTR,
MAC2STR(sa));
@@ -593,13 +616,26 @@
if (msg.group_bssid)
os_memcpy(dev->inv_bssid, msg.group_bssid,
ETH_ALEN);
+ if (msg.group_id) {
+ dev->inv_ssid_len = msg.group_id_len - ETH_ALEN;
+ os_memcpy(dev->inv_ssid,
+ msg.group_id + ETH_ALEN,
+ dev->inv_ssid_len);
+
+ os_memcpy(p2p->invite_go_dev_addr_buf,
+ msg.group_id, ETH_ALEN);
+ p2p->invite_go_dev_addr =
+ p2p->invite_go_dev_addr_buf;
+ go_dev_addr = p2p->invite_go_dev_addr;
+ }
goto out;
}
p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
+ NULL, 0,
msg.group_bssid, channels, sa,
freq, peer_oper_freq, NULL, NULL,
- 0);
+ 0, go_dev_addr);
}
p2p_clear_timeout(p2p);
@@ -638,11 +674,13 @@
p2p_dbg(p2p, "Invitation connect: msg status %d", dev->inv_status);
if (p2p->cfg->invitation_result)
p2p->cfg->invitation_result(p2p->cfg->cb_ctx, dev->inv_status,
+ dev->inv_ssid, dev->inv_ssid_len,
dev->inv_bssid, inv_channels,
dev->info.p2p_device_addr,
dev->inv_freq,
dev->inv_peer_oper_freq, pmkid,
- pmk, pmk_len);
+ pmk, pmk_len,
+ p2p->invite_go_dev_addr);
/* Reset PMK and PMKID from stack */
forced_memzero(pmkid, sizeof(pmkid));
@@ -650,6 +688,8 @@
p2p_clear_timeout(p2p);
p2p_set_state(p2p, P2P_IDLE);
+ os_memset(dev->inv_ssid, 0, sizeof(dev->inv_ssid));
+ dev->inv_ssid_len = 0;
p2p->invite_peer = NULL;
}
#endif /* CONFIG_PASN */
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index a55e7e6..f08fa0e 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -780,9 +780,6 @@
if (!dev->req_bootstrap_method) {
status = P2P_SC_COMEBACK;
- if (p2p->cfg->bootstrap_req_rx)
- p2p->cfg->bootstrap_req_rx(p2p->cfg->cb_ctx,
- sa, bootstrap);
goto out;
}
} else {
@@ -1646,6 +1643,7 @@
size_t cookie_len = 0;
const u8 *pos, *cookie;
u16 comeback_after;
+ u16 bootstrap = 0;
/* Parse the P2P status present */
if (msg->status)
@@ -1712,16 +1710,24 @@
p2p->cfg->register_bootstrap_comeback(p2p->cfg->cb_ctx, sa,
comeback_after);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+
+ if (p2p->cfg->bootstrap_rsp_rx)
+ p2p->cfg->bootstrap_rsp_rx(p2p->cfg->cb_ctx, sa, status,
+ rx_freq, bootstrap);
return;
}
+ /* PBMA response */
+ if (msg->pbma_info_len >= 2)
+ bootstrap = WPA_GET_LE16(msg->pbma_info);
+
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG)
dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
- if (p2p->cfg->bootstrap_completed)
- p2p->cfg->bootstrap_completed(p2p->cfg->cb_ctx, sa, status,
- rx_freq);
+ if (p2p->cfg->bootstrap_rsp_rx)
+ p2p->cfg->bootstrap_rsp_rx(p2p->cfg->cb_ctx, sa, status,
+ rx_freq, bootstrap);
}
@@ -2117,6 +2123,24 @@
}
+int p2p_set_req_bootstrap_method(struct p2p_data *p2p, const u8 *peer_addr,
+ u16 bootstrap)
+{
+ struct p2p_device *dev;
+
+ dev = p2p_get_device(p2p, peer_addr);
+ if (!dev) {
+ p2p_dbg(p2p, "Bootstrap request for peer " MACSTR
+ " not yet known", MAC2STR(peer_addr));
+ return -1;
+ }
+
+ dev->p2p2 = 1;
+ dev->req_bootstrap_method = bootstrap;
+ return 0;
+}
+
+
int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
struct p2ps_provision *p2ps_prov,
u16 config_methods, int join, int force_freq,
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index be7293f..61a234b 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -1892,7 +1892,7 @@
/* Determine if we need space for the ICV Indicator */
if (mka_alg_tbl[participant->kay->mka_algindex].icv_len !=
- DEFAULT_ICV_LEN)
+ DEFAULT_ICV_LEN || participant->kay->include_icv_indicator)
length = sizeof(struct ieee802_1x_mka_icv_body);
else
length = 0;
@@ -1915,7 +1915,7 @@
length = ieee802_1x_mka_get_icv_length(participant);
if (mka_alg_tbl[participant->kay->mka_algindex].icv_len !=
- DEFAULT_ICV_LEN) {
+ DEFAULT_ICV_LEN || participant->kay->include_icv_indicator) {
wpa_printf(MSG_DEBUG, "KaY: ICV Indicator");
body = wpabuf_put(buf, MKA_HDR_LEN);
body->type = MKA_ICV_INDICATOR;
@@ -3538,7 +3538,8 @@
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
u8 macsec_offload, u16 port, u8 priority,
- u32 macsec_csindex, const char *ifname, const u8 *addr)
+ u32 macsec_csindex, bool include_icv_indicator,
+ const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
@@ -3576,6 +3577,7 @@
kay->pn_exhaustion = PENDING_PN_EXHAUSTION;
kay->macsec_csindex = macsec_csindex;
+ kay->include_icv_indicator = include_icv_indicator;
kay->mka_algindex = DEFAULT_MKA_ALG_INDEX;
kay->mka_version = MKA_VERSION_ID;
@@ -3929,33 +3931,28 @@
dl_list_del(&participant->list);
/* remove live peer */
- while (!dl_list_empty(&participant->live_peers)) {
- peer = dl_list_entry(participant->live_peers.next,
- struct ieee802_1x_kay_peer, list);
+ while ((peer = dl_list_first(&participant->live_peers,
+ struct ieee802_1x_kay_peer, list))) {
dl_list_del(&peer->list);
os_free(peer);
}
/* remove potential peer */
- while (!dl_list_empty(&participant->potential_peers)) {
- peer = dl_list_entry(participant->potential_peers.next,
- struct ieee802_1x_kay_peer, list);
+ while ((peer = dl_list_first(&participant->potential_peers,
+ struct ieee802_1x_kay_peer, list))) {
dl_list_del(&peer->list);
os_free(peer);
}
/* remove sak */
- while (!dl_list_empty(&participant->sak_list)) {
- sak = dl_list_entry(participant->sak_list.next,
- struct data_key, list);
+ while ((sak = dl_list_first(&participant->sak_list,
+ struct data_key, list))) {
dl_list_del(&sak->list);
ieee802_1x_kay_deinit_data_key(sak);
}
- while (!dl_list_empty(&participant->rxsc_list)) {
- rxsc = dl_list_entry(participant->rxsc_list.next,
- struct receive_sc, list);
+ while ((rxsc = dl_list_first(&participant->rxsc_list,
+ struct receive_sc, list)))
ieee802_1x_kay_deinit_receive_sc(participant, rxsc);
- }
ieee802_1x_kay_deinit_transmit_sc(participant, participant->txsc);
os_memset(&participant->cak, 0, sizeof(participant->cak));
diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h
index 545a99b..280f8d4 100644
--- a/src/pae/ieee802_1x_kay.h
+++ b/src/pae/ieee802_1x_kay.h
@@ -206,6 +206,7 @@
struct ieee802_1x_kay_ctx *ctx;
bool is_key_server;
bool is_obliged_key_server;
+ bool include_icv_indicator; /* Always include ICV Indicator */
char if_name[IFNAMSIZ];
u8 macsec_offload;
@@ -243,7 +244,8 @@
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
u8 macsec_offload, u16 port, u8 priority,
- u32 macsec_csindex, const char *ifname, const u8 *addr);
+ u32 macsec_csindex, bool include_icv_indicator,
+ const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
struct ieee802_1x_mka_participant *
diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c
index 035ae81..bee7e58 100644
--- a/src/pasn/pasn_initiator.c
+++ b/src/pasn/pasn_initiator.c
@@ -44,7 +44,7 @@
size_t pmk_len, const u8 *pmkid)
{
if (pmksa_cache_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, bssid,
- own_addr, NULL, WPA_KEY_MGMT_SAE, 0))
+ own_addr, NULL, WPA_KEY_MGMT_SAE, NULL))
return 0;
return -1;
}
@@ -126,7 +126,7 @@
wpabuf_put_le16(buf, 1);
wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
- sae_write_commit(&pasn->sae, buf, NULL, 0);
+ sae_write_commit(&pasn->sae, buf, NULL, NULL);
pasn->sae.state = SAE_COMMITTED;
return buf;
@@ -175,8 +175,8 @@
return -1;
}
- res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, 0, groups,
- 1, NULL);
+ res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, NULL,
+ groups, 1, NULL);
if (res != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG, "PASN: SAE failed parsing commit");
return -1;
@@ -499,7 +499,7 @@
pasn->pmk_len, pasn->fils.erp_pmkid,
NULL, 0, pasn->peer_addr,
pasn->own_addr, NULL,
- pasn->akmp, 0);
+ pasn->akmp, NULL);
pasn->fils.completed = true;
return 0;
@@ -915,7 +915,7 @@
pasn->sae.pmkid,
NULL, 0, pasn->peer_addr,
pasn->own_addr, NULL,
- pasn->akmp, 0);
+ pasn->akmp, NULL);
return 0;
}
#endif /* CONFIG_SAE */
diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c
index 11f27e1..b4137b4 100644
--- a/src/pasn/pasn_responder.c
+++ b/src/pasn/pasn_responder.c
@@ -153,7 +153,7 @@
return -1;
}
- res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0,
+ res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, NULL,
groups, 0, NULL);
if (res != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit");
@@ -252,7 +252,7 @@
wpabuf_put_le16(buf, WLAN_STATUS_SAE_HASH_TO_ELEMENT);
/* Write the actual commit and update the length accordingly */
- sae_write_commit(&pasn->sae, buf, NULL, 0);
+ sae_write_commit(&pasn->sae, buf, NULL, NULL);
len = wpabuf_len(buf);
WPA_PUT_LE16(len_ptr, len - 2);
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 37aa216..029e622 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -469,8 +469,10 @@
return -1;
msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
- wpabuf_len(msg->buf), pos) < 0)
+ wpabuf_len(msg->buf), pos) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
return -1;
+ }
} else
msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
@@ -497,8 +499,10 @@
os_memcpy(msg->hdr->authenticator, req_authenticator,
sizeof(msg->hdr->authenticator));
if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
- wpabuf_len(msg->buf), pos) < 0)
+ wpabuf_len(msg->buf), pos) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
return -1;
+ }
/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
addr[0] = (u8 *) msg->hdr;
@@ -509,7 +513,10 @@
len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
addr[3] = secret;
len[3] = secret_len;
- md5_vector(4, addr, len, msg->hdr->authenticator);
+ if (md5_vector(4, addr, len, msg->hdr->authenticator) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ return -1;
+ }
if (wpabuf_len(msg->buf) > 0xffff) {
wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
@@ -535,16 +542,20 @@
msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
- wpabuf_len(msg->buf), pos) < 0)
+ wpabuf_len(msg->buf), pos) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
return -1;
+ }
/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
addr[0] = wpabuf_head_u8(msg->buf);
len[0] = wpabuf_len(msg->buf);
addr[1] = secret;
len[1] = secret_len;
- if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0)
+ if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
return -1;
+ }
if (wpabuf_len(msg->buf) > 0xffff) {
wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
@@ -555,8 +566,8 @@
}
-void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
- size_t secret_len)
+int radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len)
{
const u8 *addr[2];
size_t len[2];
@@ -567,17 +578,22 @@
len[0] = wpabuf_len(msg->buf);
addr[1] = secret;
len[1] = secret_len;
- md5_vector(2, addr, len, msg->hdr->authenticator);
+ if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ return -1;
+ }
if (wpabuf_len(msg->buf) > 0xffff) {
wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
(unsigned long) wpabuf_len(msg->buf));
+ return -1;
}
+ return 0;
}
-void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
- size_t secret_len, const u8 *req_authenticator)
+int radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, const u8 *req_authenticator)
{
const u8 *addr[2];
size_t len[2];
@@ -588,12 +604,17 @@
len[0] = wpabuf_len(msg->buf);
addr[1] = secret;
len[1] = secret_len;
- md5_vector(2, addr, len, msg->hdr->authenticator);
+ if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ return -1;
+ }
if (wpabuf_len(msg->buf) > 0xffff) {
wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
(unsigned long) wpabuf_len(msg->buf));
+ return -1;
}
+ return 0;
}
@@ -614,7 +635,10 @@
len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
addr[3] = secret;
len[3] = secret_len;
- md5_vector(4, addr, len, hash);
+ if (md5_vector(4, addr, len, hash) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ return 1;
+ }
return os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
}
@@ -642,7 +666,10 @@
len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
addr[3] = secret;
len[3] = secret_len;
- md5_vector(4, addr, len, hash);
+ if (md5_vector(4, addr, len, hash) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ return 1;
+ }
if (os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
return 1;
@@ -674,8 +701,11 @@
sizeof(orig_authenticator));
os_memset(msg->hdr->authenticator, 0,
sizeof(msg->hdr->authenticator));
- hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
- wpabuf_len(msg->buf), auth);
+ if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), auth) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ return 1;
+ }
os_memcpy(attr + 1, orig, MD5_MAC_LEN);
os_memcpy(msg->hdr->authenticator, orig_authenticator,
sizeof(orig_authenticator));
@@ -972,8 +1002,10 @@
sizeof(msg->hdr->authenticator));
}
if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
- wpabuf_len(msg->buf), auth) < 0)
+ wpabuf_len(msg->buf), auth) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
return 1;
+ }
os_memcpy(attr + 1, orig, MD5_MAC_LEN);
if (req_auth) {
os_memcpy(msg->hdr->authenticator, orig_authenticator,
@@ -1185,6 +1217,7 @@
elen[1] = MD5_MAC_LEN;
}
if (md5_vector(first ? 3 : 2, addr, elen, hash) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
os_free(plain);
return NULL;
}
@@ -1213,10 +1246,10 @@
}
-static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
- const u8 *req_authenticator,
- const u8 *secret, size_t secret_len,
- u8 *ebuf, size_t *elen)
+static int encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
+ const u8 *req_authenticator,
+ const u8 *secret, size_t secret_len,
+ u8 *ebuf, size_t *elen)
{
int i, len, first = 1;
u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
@@ -1250,7 +1283,10 @@
addr[1] = pos - MD5_MAC_LEN;
_len[1] = MD5_MAC_LEN;
}
- md5_vector(first ? 3 : 2, addr, _len, hash);
+ if (md5_vector(first ? 3 : 2, addr, _len, hash) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ return -1;
+ }
first = 0;
for (i = 0; i < MD5_MAC_LEN; i++)
@@ -1258,6 +1294,8 @@
len -= MD5_MAC_LEN;
}
+
+ return 0;
}
@@ -1375,8 +1413,9 @@
salt |= 0x8000;
WPA_PUT_BE16(pos, salt);
pos += 2;
- encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
- secret_len, pos, &elen);
+ if (encrypt_ms_key(send_key, send_key_len, salt, req_authenticator,
+ secret, secret_len, pos, &elen) < 0)
+ return 0;
vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
@@ -1400,8 +1439,9 @@
salt ^= 1;
WPA_PUT_BE16(pos, salt);
pos += 2;
- encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
- secret_len, pos, &elen);
+ if (encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator,
+ secret, secret_len, pos, &elen) < 0)
+ return 0;
vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
@@ -1492,7 +1532,10 @@
len[0] = secret_len;
addr[1] = msg->hdr->authenticator;
len[1] = 16;
- md5_vector(2, addr, len, hash);
+ if (md5_vector(2, addr, len, hash) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ return -1;
+ }
for (i = 0; i < 16; i++)
buf[i] ^= hash[i];
@@ -1503,7 +1546,10 @@
len[0] = secret_len;
addr[1] = &buf[pos - 16];
len[1] = 16;
- md5_vector(2, addr, len, hash);
+ if (md5_vector(2, addr, len, hash) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ return -1;
+ }
for (i = 0; i < 16; i++)
buf[pos + i] ^= hash[i];
@@ -1792,7 +1838,10 @@
len[0] = secret_len;
addr[1] = pos - 16;
len[1] = 16;
- md5_vector(2, addr, len, hash);
+ if (md5_vector(2, addr, len, hash) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ goto out;
+ }
for (i = 0; i < 16; i++)
pos[i] ^= hash[i];
@@ -1809,7 +1858,10 @@
len[1] = 16;
addr[2] = salt;
len[2] = 2;
- md5_vector(3, addr, len, hash);
+ if (md5_vector(3, addr, len, hash) < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: MD5 not available");
+ goto out;
+ }
for (i = 0; i < 16; i++)
pos[i] ^= hash[i];
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 05fddba..09d3591 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -221,7 +221,6 @@
#define RADIUS_VENDOR_ID_WFA 40808
enum {
- RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION = 1,
RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION = 2,
RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION = 3,
RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ = 4,
@@ -276,11 +275,10 @@
int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
size_t secret_len,
const struct radius_hdr *req_hdr);
-void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
- size_t secret_len);
-void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
- size_t secret_len,
- const u8 *req_authenticator);
+int radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len);
+int radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, const u8 *req_authenticator);
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 2a7f361..705aaef 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -482,8 +482,11 @@
wpa_printf(MSG_DEBUG,
"RADIUS: Updated Acct-Delay-Time to %u for retransmission",
delay_time);
- radius_msg_finish_acct(entry->msg, entry->shared_secret,
- entry->shared_secret_len);
+ if (radius_msg_finish_acct(entry->msg, entry->shared_secret,
+ entry->shared_secret_len) < 0) {
+ wpa_printf(MSG_INFO, "Failed to build RADIUS message");
+ return -1;
+ }
if (radius->conf->msg_dumps)
radius_msg_dump(entry->msg);
}
@@ -878,7 +881,14 @@
}
shared_secret = conf->acct_server->shared_secret;
shared_secret_len = conf->acct_server->shared_secret_len;
- radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
+ if (radius_msg_finish_acct(msg, shared_secret,
+ shared_secret_len) < 0) {
+ hostapd_logger(radius->ctx, NULL,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Failed to build RADIUS accounting message");
+ return -1;
+ }
name = "accounting";
s = radius->acct_sock;
conf->acct_server->requests++;
@@ -900,7 +910,14 @@
}
shared_secret = conf->auth_server->shared_secret;
shared_secret_len = conf->auth_server->shared_secret_len;
- radius_msg_finish(msg, shared_secret, shared_secret_len);
+ if (radius_msg_finish(msg, shared_secret, shared_secret_len) <
+ 0) {
+ hostapd_logger(radius->ctx, NULL,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Failed to build RADIUS authentication message");
+ return -1;
+ }
name = "authentication";
s = radius->auth_sock;
conf->auth_server->requests++;
@@ -1099,7 +1116,7 @@
struct radius_hdr *hdr;
struct radius_rx_handler *handlers;
size_t num_handlers, i;
- struct radius_msg_list *req, *prev_req;
+ struct radius_msg_list *req, *prev_req, *r;
struct os_reltime now;
struct hostapd_radius_server *rconf;
int invalid_authenticator = 0;
@@ -1224,7 +1241,6 @@
break;
}
- prev_req = NULL;
req = radius->msgs;
while (req) {
/* TODO: also match by src addr:port of the packet when using
@@ -1236,7 +1252,6 @@
hdr->identifier)
break;
- prev_req = req;
req = req->next;
}
@@ -1259,13 +1274,6 @@
roundtrip / 100, roundtrip % 100);
rconf->round_trip_time = roundtrip;
- /* Remove ACKed RADIUS packet from retransmit list */
- if (prev_req)
- prev_req->next = req->next;
- else
- radius->msgs = req->next;
- radius->num_msgs--;
-
for (i = 0; i < num_handlers; i++) {
RadiusRxResult res;
res = handlers[i].handler(msg, req->msg, req->shared_secret,
@@ -1276,6 +1284,19 @@
radius_msg_free(msg);
/* fall through */
case RADIUS_RX_QUEUED:
+ /* Remove ACKed RADIUS packet from retransmit list */
+ prev_req = NULL;
+ for (r = radius->msgs; r; r = r->next) {
+ if (r == req)
+ break;
+ prev_req = r;
+ }
+ if (prev_req)
+ prev_req->next = req->next;
+ else
+ radius->msgs = req->next;
+ radius->num_msgs--;
+
radius_client_msg_free(req);
return;
case RADIUS_RX_INVALID_AUTHENTICATOR:
@@ -1297,7 +1318,6 @@
msg_type, hdr->code, hdr->identifier,
invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
"");
- radius_client_msg_free(req);
fail:
radius_msg_free(msg);
@@ -1509,8 +1529,10 @@
if (entry->msg_type == RADIUS_ACCT) {
entry->shared_secret = shared_secret;
entry->shared_secret_len = shared_secret_len;
- radius_msg_finish_acct(entry->msg, shared_secret,
- shared_secret_len);
+ if (radius_msg_finish_acct(entry->msg, shared_secret,
+ shared_secret_len) < 0)
+ wpa_printf(MSG_INFO,
+ "RADIUS: Failed to update accounting message");
}
}
}
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index fa36915..c9497c0 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -86,7 +86,6 @@
struct radius_msg *last_reply;
u8 last_authenticator[16];
- unsigned int remediation:1;
unsigned int macacl:1;
unsigned int t_c_filtering:1;
@@ -147,7 +146,8 @@
/**
* conf_ctx - Context pointer for callbacks
*
- * This is used as the ctx argument in get_eap_user() calls.
+ * This is used as the ctx argument in get_eap_user() and acct_req_cb()
+ * calls.
*/
void *conf_ctx;
@@ -195,6 +195,27 @@
int phase2, struct eap_user *user);
/**
+ * acct_req_cb - Callback for processing received RADIUS accounting
+ * requests
+ * @ctx: Context data from conf_ctx
+ * @msg: Received RADIUS accounting request
+ * @status_type: Status type from the message (parsed Acct-Status-Type
+ * attribute)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to log accounting information into file, database,
+ * syslog server, etc.
+ * Callback should not modify the message.
+ * If 0 is returned, response is automatically created. Otherwise,
+ * no response is created.
+ *
+ * acct_req_cb can be set to null to omit any custom processing of
+ * account requests. Statistics counters will be incremented in any
+ * case.
+ */
+ int (*acct_req_cb)(void *ctx, struct radius_msg *msg, u32 status_type);
+
+ /**
* eap_req_id_text - Optional data for EAP-Request/Identity
*
* This can be used to configure an optional, displayable message that
@@ -215,10 +236,6 @@
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
- char *subscr_remediation_url;
- u8 subscr_remediation_method;
- char *hs20_sim_provisioning_url;
-
char *t_c_server_url;
#ifdef CONFIG_SQLITE
@@ -243,44 +260,6 @@
static void radius_server_session_remove_timeout(void *eloop_ctx,
void *timeout_ctx);
-#ifdef CONFIG_SQLITE
-#ifdef CONFIG_HS20
-
-static int db_table_exists(sqlite3 *db, const char *name)
-{
- char cmd[128];
-
- os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
- return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
-}
-
-
-static int db_table_create_sim_provisioning(sqlite3 *db)
-{
- char *err = NULL;
- const char *sql =
- "CREATE TABLE sim_provisioning("
- " mobile_identifier_hash TEXT PRIMARY KEY,"
- " imsi TEXT,"
- " mac_addr TEXT,"
- " eap_method TEXT,"
- " timestamp TEXT"
- ");";
-
- RADIUS_DEBUG("Adding database table for SIM provisioning information");
- if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
- RADIUS_ERROR("SQLite error: %s", err);
- sqlite3_free(err);
- return -1;
- }
-
- return 0;
-}
-
-#endif /* CONFIG_HS20 */
-#endif /* CONFIG_SQLITE */
-
-
void srv_log(struct radius_session *sess, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
@@ -780,117 +759,6 @@
}
-#ifdef CONFIG_HS20
-
-static int radius_server_is_sim_method(struct radius_session *sess)
-{
- const char *name;
-
- name = eap_get_method(sess->eap);
- return name &&
- (os_strcmp(name, "SIM") == 0 ||
- os_strcmp(name, "AKA") == 0 ||
- os_strcmp(name, "AKA'") == 0);
-}
-
-
-static int radius_server_hs20_missing_sim_pps(struct radius_msg *request)
-{
- u8 *buf, *pos, *end, type, sublen;
- size_t len;
-
- buf = NULL;
- for (;;) {
- if (radius_msg_get_attr_ptr(request,
- RADIUS_ATTR_VENDOR_SPECIFIC,
- &buf, &len, buf) < 0)
- return 0;
- if (len < 6)
- continue;
- pos = buf;
- end = buf + len;
- if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA)
- continue;
- pos += 4;
-
- type = *pos++;
- sublen = *pos++;
- if (sublen < 2)
- continue; /* invalid length */
- sublen -= 2; /* skip header */
- if (pos + sublen > end)
- continue; /* invalid WFA VSA */
-
- if (type != RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION)
- continue;
-
- RADIUS_DUMP("HS2.0 mobile device version", pos, sublen);
- if (sublen < 1 + 2)
- continue;
- if (pos[0] == 0)
- continue; /* Release 1 STA does not support provisioning
-
- */
- /* UpdateIdentifier 0 indicates no PPS MO */
- return WPA_GET_BE16(pos + 1) == 0;
- }
-}
-
-
-#define HS20_MOBILE_ID_HASH_LEN 16
-
-static int radius_server_sim_provisioning_session(struct radius_session *sess,
- const u8 *hash)
-{
-#ifdef CONFIG_SQLITE
- char *sql;
- char addr_txt[ETH_ALEN * 3];
- char hash_txt[2 * HS20_MOBILE_ID_HASH_LEN + 1];
- struct os_time now;
- int res;
- const char *imsi, *eap_method;
-
- if (!sess->server->db ||
- (!db_table_exists(sess->server->db, "sim_provisioning") &&
- db_table_create_sim_provisioning(sess->server->db) < 0))
- return -1;
-
- imsi = eap_get_imsi(sess->eap);
- if (!imsi)
- return -1;
-
- eap_method = eap_get_method(sess->eap);
- if (!eap_method)
- return -1;
-
- os_snprintf(addr_txt, sizeof(addr_txt), MACSTR,
- MAC2STR(sess->mac_addr));
- wpa_snprintf_hex(hash_txt, sizeof(hash_txt), hash,
- HS20_MOBILE_ID_HASH_LEN);
-
- os_get_time(&now);
- sql = sqlite3_mprintf("INSERT INTO sim_provisioning(mobile_identifier_hash,imsi,mac_addr,eap_method,timestamp) VALUES (%Q,%Q,%Q,%Q,%u)",
- hash_txt, imsi, addr_txt, eap_method, now.sec);
- if (!sql)
- return -1;
-
- if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) !=
- SQLITE_OK) {
- RADIUS_ERROR("Failed to add SIM provisioning entry into sqlite database: %s",
- sqlite3_errmsg(sess->server->db));
- res = -1;
- } else {
- res = 0;
- }
- sqlite3_free(sql);
- return res;
-#endif /* CONFIG_SQLITE */
- return -1;
-}
-
-#endif /* CONFIG_HS20 */
-
-
static struct radius_msg *
radius_server_encapsulate_eap(struct radius_server_data *data,
struct radius_client *client,
@@ -992,74 +860,6 @@
}
#ifdef CONFIG_HS20
- if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation &&
- data->subscr_remediation_url) {
- u8 *buf;
- size_t url_len = os_strlen(data->subscr_remediation_url);
- buf = os_malloc(1 + url_len);
- if (buf == NULL) {
- radius_msg_free(msg);
- return NULL;
- }
- buf[0] = data->subscr_remediation_method;
- os_memcpy(&buf[1], data->subscr_remediation_url, url_len);
- if (!radius_msg_add_wfa(
- msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
- buf, 1 + url_len)) {
- RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
- }
- os_free(buf);
- } else if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation) {
- u8 buf[1];
- if (!radius_msg_add_wfa(
- msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
- buf, 0)) {
- RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
- }
- } else if (code == RADIUS_CODE_ACCESS_ACCEPT &&
- data->hs20_sim_provisioning_url &&
- radius_server_is_sim_method(sess) &&
- radius_server_hs20_missing_sim_pps(request)) {
- u8 *buf, *pos, hash[HS20_MOBILE_ID_HASH_LEN];
- size_t prefix_len, url_len;
-
- RADIUS_DEBUG("Device needs HS 2.0 SIM provisioning");
-
- if (os_get_random(hash, HS20_MOBILE_ID_HASH_LEN) < 0) {
- radius_msg_free(msg);
- return NULL;
- }
- RADIUS_DUMP("hotspot2dot0-mobile-identifier-hash",
- hash, HS20_MOBILE_ID_HASH_LEN);
-
- if (radius_server_sim_provisioning_session(sess, hash) < 0) {
- radius_msg_free(msg);
- return NULL;
- }
-
- prefix_len = os_strlen(data->hs20_sim_provisioning_url);
- url_len = prefix_len + 2 * HS20_MOBILE_ID_HASH_LEN;
- buf = os_malloc(1 + url_len + 1);
- if (!buf) {
- radius_msg_free(msg);
- return NULL;
- }
- pos = buf;
- *pos++ = data->subscr_remediation_method;
- os_memcpy(pos, data->hs20_sim_provisioning_url, prefix_len);
- pos += prefix_len;
- wpa_snprintf_hex((char *) pos, 2 * HS20_MOBILE_ID_HASH_LEN + 1,
- hash, HS20_MOBILE_ID_HASH_LEN);
- RADIUS_DEBUG("HS 2.0 subscription remediation URL: %s",
- (char *) &buf[1]);
- if (!radius_msg_add_wfa(
- msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
- buf, 1 + url_len)) {
- RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
- }
- os_free(buf);
- }
-
if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->t_c_filtering) {
u8 buf[4] = { 0x01, 0x00, 0x00, 0x00 }; /* E=1 */
const char *url = data->t_c_server_url, *pos;
@@ -1148,6 +948,8 @@
client->shared_secret_len,
hdr->authenticator) < 0) {
RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
+ radius_msg_free(msg);
+ return NULL;
}
if (code == RADIUS_CODE_ACCESS_ACCEPT)
@@ -1237,6 +1039,8 @@
client->shared_secret_len,
hdr->authenticator) < 0) {
RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
+ radius_msg_free(msg);
+ return NULL;
}
return msg;
@@ -1288,6 +1092,8 @@
hdr->authenticator) <
0) {
RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
+ radius_msg_free(msg);
+ return -1;
}
if (wpa_debug_level <= MSG_MSGDUMP) {
@@ -1815,6 +1621,7 @@
int from_port = 0;
struct radius_hdr *hdr;
struct wpabuf *rbuf;
+ u32 status_type;
buf = os_malloc(RADIUS_MAX_MSG_LEN);
if (buf == NULL) {
@@ -1896,7 +1703,20 @@
goto fail;
}
- /* TODO: Write accounting information to a file or database */
+ /* Parse Acct-Status-Type from Accounting-Request */
+ if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
+ &status_type) != 0) {
+ RADIUS_DEBUG("Unable to parse Acct-Status-Type from %s", abuf);
+ goto fail;
+ }
+
+ /* Process accounting information by configured callback */
+ if (data->acct_req_cb &&
+ data->acct_req_cb(data->conf_ctx, msg, status_type) != 0) {
+ RADIUS_DEBUG("Accounting request callback returned non-zero code indicating processing failure (from %s)",
+ abuf);
+ goto fail;
+ }
hdr = radius_msg_get_hdr(msg);
@@ -1904,9 +1724,12 @@
if (resp == NULL)
goto fail;
- radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret,
- client->shared_secret_len,
- hdr->authenticator);
+ if (radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret,
+ client->shared_secret_len,
+ hdr->authenticator) < 0) {
+ RADIUS_ERROR("Failed to add Message-Authenticator attribute");
+ goto fail;
+ }
RADIUS_DEBUG("Reply to %s:%d", abuf, from_port);
if (wpa_debug_level <= MSG_MSGDUMP) {
@@ -2221,6 +2044,7 @@
conf->eap_cfg->eap_server = 1;
data->ipv6 = conf->ipv6;
data->get_eap_user = conf->get_eap_user;
+ data->acct_req_cb = conf->acct_req_cb;
if (conf->eap_req_id_text) {
data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
if (!data->eap_req_id_text)
@@ -2231,20 +2055,6 @@
}
data->erp_domain = conf->erp_domain;
- if (conf->subscr_remediation_url) {
- data->subscr_remediation_url =
- os_strdup(conf->subscr_remediation_url);
- if (!data->subscr_remediation_url)
- goto fail;
- }
- data->subscr_remediation_method = conf->subscr_remediation_method;
- if (conf->hs20_sim_provisioning_url) {
- data->hs20_sim_provisioning_url =
- os_strdup(conf->hs20_sim_provisioning_url);
- if (!data->hs20_sim_provisioning_url)
- goto fail;
- }
-
if (conf->t_c_server_url) {
data->t_c_server_url = os_strdup(conf->t_c_server_url);
if (!data->t_c_server_url)
@@ -2359,8 +2169,6 @@
#ifdef CONFIG_RADIUS_TEST
os_free(data->dump_msk_file);
#endif /* CONFIG_RADIUS_TEST */
- os_free(data->subscr_remediation_url);
- os_free(data->hs20_sim_provisioning_url);
os_free(data->t_c_server_url);
#ifdef CONFIG_SQLITE
@@ -2528,7 +2336,6 @@
phase2, user);
if (ret == 0 && user) {
sess->accept_attr = user->accept_attr;
- sess->remediation = user->remediation;
sess->macacl = user->macacl;
sess->t_c_timestamp = user->t_c_timestamp;
}
@@ -2827,8 +2634,12 @@
return -1;
}
- radius_msg_finish_acct(msg, (u8 *) client->shared_secret,
- client->shared_secret_len);
+ if (radius_msg_finish_acct(msg, (u8 *) client->shared_secret,
+ client->shared_secret_len) < 0) {
+ RADIUS_ERROR("Failed to add Message-Authenticator attribute");
+ radius_msg_free(msg);
+ return -1;
+ }
if (wpa_debug_level <= MSG_MSGDUMP)
radius_msg_dump(msg);
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 43192e5..5440558 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -10,6 +10,7 @@
#define RADIUS_SERVER_H
struct radius_server_data;
+struct radius_msg;
struct eap_user;
/**
@@ -47,7 +48,8 @@
/**
* conf_ctx - Context pointer for callbacks
*
- * This is used as the ctx argument in get_eap_user() calls.
+ * This is used as the ctx argument in get_eap_user() and acct_req_cb()
+ * calls.
*/
void *conf_ctx;
@@ -76,6 +78,27 @@
int phase2, struct eap_user *user);
/**
+ * acct_req_cb - Callback for processing received RADIUS accounting
+ * requests
+ * @ctx: Context data from conf_ctx
+ * @msg: Received RADIUS accounting request
+ * @status_type: Status type from the message (parsed Acct-Status-Type
+ * attribute)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This can be used to log accounting information into file, database,
+ * syslog server, etc.
+ * Callback should not modify the message.
+ * If 0 is returned, response is automatically created. Otherwise,
+ * no response is created.
+ *
+ * acct_req_cb can be set to NULL to omit any custom processing of
+ * accounting requests. Statistics counters will be incremented in any
+ * case.
+ */
+ int (*acct_req_cb)(void *ctx, struct radius_msg *msg, u32 status_type);
+
+ /**
* eap_req_id_text - Optional data for EAP-Request/Identity
*
* This can be used to configure an optional, displayable message that
@@ -96,10 +119,6 @@
const char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
- char *subscr_remediation_url;
- u8 subscr_remediation_method;
- char *hs20_sim_provisioning_url;
-
char *t_c_server_url;
struct eap_config *eap_cfg;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index d8cdebb..264013c 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -256,8 +256,7 @@
if (rbuf == NULL)
return;
- reply->type = (sm->proto == WPA_PROTO_RSN ||
- sm->proto == WPA_PROTO_OSEN) ?
+ reply->type = (sm->proto == WPA_PROTO_RSN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = WPA_KEY_INFO_REQUEST | ver;
key_info |= WPA_KEY_INFO_SECURE;
@@ -482,8 +481,7 @@
if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
- !wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
- {
+ !wpa_key_mgmt_ft(sm->key_mgmt)) {
/* Send EAPOL-Start to trigger full EAP authentication. */
u8 *buf;
size_t buflen;
@@ -637,8 +635,7 @@
return -1;
}
- reply->type = (sm->proto == WPA_PROTO_RSN ||
- sm->proto == WPA_PROTO_OSEN) ?
+ reply->type = (sm->proto == WPA_PROTO_RSN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = ver | WPA_KEY_INFO_KEY_TYPE;
if (sm->ptk_set && sm->proto != WPA_PROTO_WPA)
@@ -654,7 +651,7 @@
key_info |= sm->eapol_2_key_info_set_mask;
#endif /* CONFIG_TESTING_OPTIONS */
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
+ if (sm->proto == WPA_PROTO_RSN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
@@ -1228,14 +1225,16 @@
enum wpa_alg alg;
const u8 *key_rsc;
- if (sm->ptk.installed) {
+ if (sm->ptk.installed ||
+ (sm->ptk.installed_rx && (key_flag & KEY_FLAG_NEXT))) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: Do not re-install same PTK to the driver");
return 0;
}
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: Installing PTK to the driver");
+ "WPA: Installing %sTK to the driver",
+ (key_flag & KEY_FLAG_NEXT) ? "next " : "");
if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher "
@@ -1259,7 +1258,7 @@
}
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
- if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
+ if (sm->proto == WPA_PROTO_RSN) {
key_rsc = null_rsc;
} else {
key_rsc = key->key_rsc;
@@ -1269,6 +1268,9 @@
if (wpa_sm_set_key(sm, -1, alg, wpa_sm_get_auth_addr(sm),
sm->keyidx_active, 1, key_rsc, rsclen, sm->ptk.tk,
keylen, KEY_FLAG_PAIRWISE | key_flag) < 0) {
+ if (key_flag & KEY_FLAG_NEXT)
+ return 0; /* Not all drivers support this, so do not
+ * report failures on the RX-only set_key */
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set PTK to the driver (alg=%d keylen=%d auth_addr="
MACSTR " idx=%d key_flag=0x%x)",
@@ -1294,11 +1296,15 @@
wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher,
sm->dot11RSNAConfigPMKLifetime, &sm->ptk);
- /* TK is not needed anymore in supplicant */
- os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
- sm->ptk.tk_len = 0;
- sm->ptk.installed = 1;
- sm->tk_set = true;
+ if (key_flag & KEY_FLAG_NEXT) {
+ sm->ptk.installed_rx = true;
+ } else {
+ /* TK is not needed anymore in supplicant */
+ os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+ sm->ptk.tk_len = 0;
+ sm->ptk.installed = 1;
+ sm->tk_set = true;
+ }
if (sm->wpa_ptk_rekey) {
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
@@ -2363,8 +2369,7 @@
return -1;
}
- reply->type = (sm->proto == WPA_PROTO_RSN ||
- sm->proto == WPA_PROTO_OSEN) ?
+ reply->type = (sm->proto == WPA_PROTO_RSN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_SECURE;
key_info |= ver | WPA_KEY_INFO_KEY_TYPE;
@@ -2377,7 +2382,7 @@
key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
#endif /* CONFIG_TESTING_OPTIONS */
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
+ if (sm->proto == WPA_PROTO_RSN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
@@ -2900,6 +2905,16 @@
wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX))
goto failed;
+ if (!sm->use_ext_key_id &&
+ wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX | KEY_FLAG_NEXT)) {
+ /* Continue anyway since the many drivers do not support
+ * configuration of the TK for RX-only purposes for cases where
+ * multiple keys might be in use in parallel and this being an
+ * optional optimization to avoid race condition during TK
+ * changes that could result in some protected frames getting
+ * discarded. */
+ }
+
if (wpa_supplicant_send_4_of_4(sm, wpa_sm_get_auth_addr(sm), key, ver,
key_info, &sm->ptk) < 0)
goto failed;
@@ -3019,8 +3034,7 @@
if (rbuf == NULL)
return -1;
- reply->type = (sm->proto == WPA_PROTO_RSN ||
- sm->proto == WPA_PROTO_OSEN) ?
+ reply->type = (sm->proto == WPA_PROTO_RSN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
key_info |= ver | WPA_KEY_INFO_SECURE;
@@ -3029,7 +3043,7 @@
else
key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
+ if (sm->proto == WPA_PROTO_RSN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
@@ -3428,6 +3442,28 @@
}
+static void wpa_sm_tptk_to_ptk(struct wpa_sm *sm)
+{
+ sm->tptk_set = 0;
+ sm->ptk_set = 1;
+ os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+
+ if (wpa_sm_pmf_enabled(sm)) {
+ os_memcpy(sm->last_kck, sm->ptk.kck, sm->ptk.kck_len);
+ sm->last_kck_len = sm->ptk.kck_len;
+ sm->last_kck_pmk_len = sm->pmk_len;
+ sm->last_kck_key_mgmt = sm->key_mgmt;
+ sm->last_kck_eapol_key_ver = sm->last_eapol_key_ver;
+ os_memcpy(sm->last_kck_aa, wpa_sm_get_auth_addr(sm), ETH_ALEN);
+ } else {
+ os_memset(sm->last_kck, 0, sizeof(sm->last_kck));
+ sm->last_kck_len = 0;
+ os_memset(sm->last_kck_aa, 0, ETH_ALEN);
+ }
+}
+
+
static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_eapol_key *key,
u16 ver,
@@ -3457,10 +3493,7 @@
continue_fuzz:
#endif /* TEST_FUZZ */
ok = 1;
- sm->tptk_set = 0;
- sm->ptk_set = 1;
- os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
- os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+ wpa_sm_tptk_to_ptk(sm);
/*
* This assures the same TPTK in sm->tptk can never be
* copied twice to sm->ptk as the new PTK. In
@@ -3713,12 +3746,8 @@
WPA_PUT_BE16(pos, *key_data_len);
bin_clear_free(tmp, *key_data_len);
- if (sm->tptk_set) {
- sm->tptk_set = 0;
- sm->ptk_set = 1;
- os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
- os_memset(&sm->tptk, 0, sizeof(sm->tptk));
- }
+ if (sm->tptk_set)
+ wpa_sm_tptk_to_ptk(sm);
os_memcpy(sm->rx_replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
@@ -4043,6 +4072,8 @@
goto out;
}
+ sm->last_eapol_key_ver = ver;
+
if ((key_info & WPA_KEY_INFO_MIC) &&
wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
goto out;
@@ -4054,7 +4085,7 @@
}
#endif /* CONFIG_FILS */
- if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
+ if (sm->proto == WPA_PROTO_RSN &&
(key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && mic_len) {
/*
* Only decrypt the Key Data field if the frame's authenticity
@@ -4124,8 +4155,7 @@
{
switch (sm->key_mgmt) {
case WPA_KEY_MGMT_IEEE8021X:
- return ((sm->proto == WPA_PROTO_RSN ||
- sm->proto == WPA_PROTO_OSEN) ?
+ return ((sm->proto == WPA_PROTO_RSN) ?
RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
case WPA_KEY_MGMT_PSK:
@@ -4393,6 +4423,7 @@
#ifdef CONFIG_DPP2
wpabuf_clear_free(sm->dpp_z);
#endif /* CONFIG_DPP2 */
+ os_memset(sm->last_kck, 0, sizeof(sm->last_kck));
os_free(sm);
}
@@ -4954,6 +4985,9 @@
case WPA_PARAM_USE_EXT_KEY_ID:
sm->use_ext_key_id = value;
break;
+ case WPA_PARAM_SPP_AMSDU:
+ sm->spp_amsdu = !!value;
+ break;
#ifdef CONFIG_TESTING_OPTIONS
case WPA_PARAM_FT_RSNXE_USED:
sm->ft_rsnxe_used = value;
@@ -7226,6 +7260,12 @@
}
+bool wpa_sm_uses_spp_amsdu(struct wpa_sm *sm)
+{
+ return sm ? sm->spp_amsdu : false;
+}
+
+
struct rsn_pmksa_cache * wpa_sm_get_pmksa_cache(struct wpa_sm *sm)
{
return sm ? sm->pmksa : NULL;
@@ -7246,3 +7286,41 @@
if (sm)
sm->driver_bss_selection = driver_bss_selection;
}
+
+
+struct wpabuf * wpa_sm_known_sta_identification(struct wpa_sm *sm, const u8 *aa,
+ u64 timestamp)
+{
+ struct wpabuf *ie;
+ unsigned int mic_len;
+ const u8 *start;
+ u8 *mic;
+
+ if (!sm || sm->last_kck_len == 0)
+ return NULL;
+
+ if (!ether_addr_equal(aa, sm->last_kck_aa))
+ return NULL;
+
+ mic_len = wpa_mic_len(sm->last_kck_key_mgmt, sm->last_kck_pmk_len);
+
+ ie = wpabuf_alloc(3 + 8 + 1 + mic_len);
+ if (!ie)
+ return NULL;
+
+ wpabuf_put_u8(ie, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(ie, 1 + 8 + 1 + mic_len);
+ wpabuf_put_u8(ie, WLAN_EID_EXT_KNOWN_STA_IDENTIFICATION);
+ start = wpabuf_put(ie, 0);
+ wpabuf_put_le64(ie, timestamp);
+ wpabuf_put_u8(ie, mic_len);
+ mic = wpabuf_put(ie, mic_len);
+ if (wpa_eapol_key_mic(sm->last_kck, sm->last_kck_len,
+ sm->last_kck_key_mgmt, sm->last_kck_eapol_key_ver,
+ start, 8, mic) < 0) {
+ wpabuf_free(ie);
+ return NULL;
+ }
+
+ return ie;
+}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 39a1e93..55a22e5 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -140,6 +140,7 @@
WPA_PARAM_RSN_OVERRIDE,
WPA_PARAM_RSN_OVERRIDE_SUPPORT,
WPA_PARAM_EAPOL_2_KEY_INFO_SET_MASK,
+ WPA_PARAM_SPP_AMSDU,
};
enum wpa_rsn_override {
@@ -284,6 +285,7 @@
int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo);
void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm,
bool driver_bss_selection);
+bool wpa_sm_uses_spp_amsdu(struct wpa_sm *sm);
#else /* CONFIG_NO_WPA */
@@ -532,6 +534,11 @@
{
}
+static inline bool wpa_sm_uses_spp_amsdu(struct wpa_sm *sm)
+{
+ return false;
+}
+
#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_IEEE80211R
@@ -687,5 +694,7 @@
void wpa_sm_set_cur_pmksa(struct wpa_sm *sm,
struct rsn_pmksa_cache_entry *entry);
const u8 * wpa_sm_get_auth_addr(struct wpa_sm *sm);
+struct wpabuf * wpa_sm_known_sta_identification(struct wpa_sm *sm, const u8 *aa,
+ u64 timestamp);
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 2fd08b0..9315268 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -69,7 +69,7 @@
u8 ssid[32];
size_t ssid_len;
int wpa_ptk_rekey;
- int wpa_deny_ptk0_rekey:1;
+ unsigned int wpa_deny_ptk0_rekey:1;
int p2p;
int wpa_rsc_relaxation;
int owe_ptk_workaround;
@@ -113,6 +113,7 @@
unsigned int secure_rtt:1;
unsigned int prot_range_neg:1;
unsigned int ssid_protection:1;
+ unsigned int spp_amsdu:1;
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
@@ -238,6 +239,14 @@
bool rsn_override_support;
enum wpa_rsn_override rsn_override;
+
+ u8 last_kck[WPA_KCK_MAX_LEN];
+ size_t last_kck_len;
+ size_t last_kck_pmk_len;
+ unsigned int last_kck_key_mgmt;
+ int last_kck_eapol_key_ver;
+ u8 last_kck_aa[ETH_ALEN];
+ int last_eapol_key_ver;
};
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 515f1b0..d27bcf9 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -31,9 +31,6 @@
if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
- wpa_ie[1] >= 4 && WPA_GET_BE32(&wpa_ie[2]) == OSEN_IE_VENDOR_TYPE)
- return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
- if (wpa_ie_len >= 6 && wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC &&
wpa_ie[1] >= 4 &&
WPA_GET_BE32(&wpa_ie[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE)
return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
@@ -233,10 +230,6 @@
} else if (key_mgmt & WPA_KEY_MGMT_DPP) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
#endif /* CONFIG_DPP */
-#ifdef CONFIG_HS20
- } else if (key_mgmt & WPA_KEY_MGMT_OSEN) {
- RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
-#endif /* CONFIG_HS20 */
#ifdef CONFIG_SHA384
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA384) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA384);
@@ -282,64 +275,6 @@
}
-#ifdef CONFIG_HS20
-static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
- int pairwise_cipher, int group_cipher,
- int key_mgmt)
-{
- u8 *pos, *len;
- u32 suite;
-
- if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
- 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
- return -1;
-
- pos = wpa_ie;
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- len = pos++; /* to be filled */
- WPA_PUT_BE24(pos, OUI_WFA);
- pos += 3;
- *pos++ = HS20_OSEN_OUI_TYPE;
-
- /* Group Data Cipher Suite */
- suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
- if (suite == 0) {
- wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
- group_cipher);
- return -1;
- }
- RSN_SELECTOR_PUT(pos, suite);
- pos += RSN_SELECTOR_LEN;
-
- /* Pairwise Cipher Suite Count and List */
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
- if (suite == 0 ||
- (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
- pairwise_cipher != WPA_CIPHER_NONE)) {
- wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
- pairwise_cipher);
- return -1;
- }
- RSN_SELECTOR_PUT(pos, suite);
- pos += RSN_SELECTOR_LEN;
-
- /* AKM Suite Count and List */
- WPA_PUT_LE16(pos, 1);
- pos += 2;
- RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
- pos += RSN_SELECTOR_LEN;
-
- *len = pos - len - 1;
-
- WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
-
- return pos - wpa_ie;
-}
-#endif /* CONFIG_HS20 */
-
-
/**
* wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -355,13 +290,6 @@
sm->group_cipher,
sm->key_mgmt, sm->mgmt_group_cipher,
sm);
-#ifdef CONFIG_HS20
- else if (sm->proto == WPA_PROTO_OSEN)
- return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
- sm->pairwise_cipher,
- sm->group_cipher,
- sm->key_mgmt);
-#endif /* CONFIG_HS20 */
else
return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
sm->pairwise_cipher,
@@ -394,6 +322,8 @@
capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
if (sm->ssid_protection)
capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
+ if (sm->spp_amsdu)
+ capab |= BIT(WLAN_RSNX_CAPAB_SPP_A_MSDU);
if (!capab)
return 0; /* no supported extended RSN capabilities */
diff --git a/src/utils/ext_password_file.c b/src/utils/ext_password_file.c
index 3122512..158500c 100644
--- a/src/utils/ext_password_file.c
+++ b/src/utils/ext_password_file.c
@@ -83,6 +83,7 @@
struct ext_password_file_data *data = ctx;
struct wpabuf *password = NULL;
char buf[512], *pos;
+ size_t name_len;
int line = 0;
FILE *f;
@@ -94,6 +95,8 @@
return NULL;
}
+ name_len = os_strlen(name);
+
wpa_printf(MSG_DEBUG, "EXT PW FILE: get(%s)", name);
while ((pos = fgets(buf, sizeof(buf), f))) {
@@ -121,7 +124,8 @@
}
- if (os_strncmp(name, pos, sep - pos) != 0)
+ if (name_len != (size_t) (sep - pos) ||
+ os_strncmp(name, pos, sep - pos) != 0)
continue;
password = wpabuf_alloc_copy(sep + 1, os_strlen(sep + 1));
diff --git a/src/utils/http-utils.h b/src/utils/http-utils.h
index 23e9ecd..14efaf8 100644
--- a/src/utils/http-utils.h
+++ b/src/utils/http-utils.h
@@ -11,38 +11,6 @@
struct http_ctx;
-struct http_othername {
- char *oid;
- u8 *data;
- size_t len;
-};
-
-#define HTTP_MAX_CERT_LOGO_HASH 32
-
-struct http_logo {
- char *alg_oid;
- u8 *hash;
- size_t hash_len;
- char *uri;
-};
-
-struct http_cert {
- char **dnsname;
- size_t num_dnsname;
- struct http_othername *othername;
- size_t num_othername;
- struct http_logo *logo;
- size_t num_logo;
- const char *url;
-};
-
-int soap_init_client(struct http_ctx *ctx, const char *address,
- const char *ca_fname, const char *username,
- const char *password, const char *client_cert,
- const char *client_key);
-int soap_reinit_client(struct http_ctx *ctx);
-xml_node_t * soap_send_receive(struct http_ctx *ctx, xml_node_t *node);
-
struct http_ctx * http_init_ctx(void *upper_ctx, struct xml_node_ctx *xml_ctx);
void http_ocsp_set(struct http_ctx *ctx, int val);
void http_deinit_ctx(struct http_ctx *ctx);
@@ -55,10 +23,6 @@
const char *username, const char *password,
const char *client_cert, const char *client_key,
size_t *resp_len);
-void http_set_cert_cb(struct http_ctx *ctx,
- int (*cb)(void *ctx, struct http_cert *cert),
- void *cb_ctx);
const char * http_get_err(struct http_ctx *ctx);
-void http_parse_x509_certificate(struct http_ctx *ctx, const char *fname);
#endif /* HTTP_UTILS_H */
diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c
index 77d5b35..1cf2f7e 100644
--- a/src/utils/http_curl.c
+++ b/src/utils/http_curl.c
@@ -31,31 +31,15 @@
#endif /* EAP_TLS_OPENSSL */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
-{
- return ASN1_STRING_data((ASN1_STRING *) x);
-}
-#endif /* OpenSSL < 1.1.0 */
-
-
struct http_ctx {
void *ctx;
struct xml_node_ctx *xml;
CURL *curl;
struct curl_slist *curl_hdr;
char *svc_address;
- char *svc_ca_fname;
- char *svc_username;
- char *svc_password;
- char *svc_client_cert;
- char *svc_client_key;
char *curl_buf;
size_t curl_buf_len;
- int (*cert_cb)(void *ctx, struct http_cert *cert);
- void *cert_cb_ctx;
-
enum {
NO_OCSP, OPTIONAL_OCSP, MANDATORY_OCSP
} ocsp;
@@ -81,16 +65,6 @@
}
-static void clone_str(char **dst, const char *src)
-{
- os_free(*dst);
- if (src)
- *dst = os_strdup(src);
- else
- *dst = NULL;
-}
-
-
static void debug_dump(struct http_ctx *ctx, const char *title,
const char *buf, size_t len)
{
@@ -202,773 +176,6 @@
}
-static void add_alt_name_othername(struct http_ctx *ctx, struct http_cert *cert,
- OTHERNAME *o)
-{
- char txt[100];
- int res;
- struct http_othername *on;
- ASN1_TYPE *val;
-
- on = os_realloc_array(cert->othername, cert->num_othername + 1,
- sizeof(struct http_othername));
- if (on == NULL)
- return;
- cert->othername = on;
- on = &on[cert->num_othername];
- os_memset(on, 0, sizeof(*on));
-
- res = OBJ_obj2txt(txt, sizeof(txt), o->type_id, 1);
- if (res < 0 || res >= (int) sizeof(txt))
- return;
-
- on->oid = os_strdup(txt);
- if (on->oid == NULL)
- return;
-
- val = o->value;
- on->data = val->value.octet_string->data;
- on->len = val->value.octet_string->length;
-
- cert->num_othername++;
-}
-
-
-static void add_alt_name_dns(struct http_ctx *ctx, struct http_cert *cert,
- ASN1_STRING *name)
-{
- char *buf;
- char **n;
-
- buf = NULL;
- if (ASN1_STRING_to_UTF8((unsigned char **) &buf, name) < 0)
- return;
-
- n = os_realloc_array(cert->dnsname, cert->num_dnsname + 1,
- sizeof(char *));
- if (n == NULL)
- return;
-
- cert->dnsname = n;
- n[cert->num_dnsname] = buf;
- cert->num_dnsname++;
-}
-
-
-static void add_alt_name(struct http_ctx *ctx, struct http_cert *cert,
- const GENERAL_NAME *name)
-{
- switch (name->type) {
- case GEN_OTHERNAME:
- add_alt_name_othername(ctx, cert, name->d.otherName);
- break;
- case GEN_DNS:
- add_alt_name_dns(ctx, cert, name->d.dNSName);
- break;
- }
-}
-
-
-static void add_alt_names(struct http_ctx *ctx, struct http_cert *cert,
- GENERAL_NAMES *names)
-{
- int num, i;
-
- num = sk_GENERAL_NAME_num(names);
- for (i = 0; i < num; i++) {
- const GENERAL_NAME *name;
- name = sk_GENERAL_NAME_value(names, i);
- add_alt_name(ctx, cert, name);
- }
-}
-
-
-/* RFC 3709 */
-
-typedef struct {
- X509_ALGOR *hashAlg;
- ASN1_OCTET_STRING *hashValue;
-} HashAlgAndValue;
-
-typedef struct {
- STACK_OF(HashAlgAndValue) *refStructHash;
- STACK_OF(ASN1_IA5STRING) *refStructURI;
-} LogotypeReference;
-
-typedef struct {
- ASN1_IA5STRING *mediaType;
- STACK_OF(HashAlgAndValue) *logotypeHash;
- STACK_OF(ASN1_IA5STRING) *logotypeURI;
-} LogotypeDetails;
-
-typedef struct {
- int type;
- union {
- ASN1_INTEGER *numBits;
- ASN1_INTEGER *tableSize;
- } d;
-} LogotypeImageResolution;
-
-typedef struct {
- ASN1_INTEGER *type; /* LogotypeImageType ::= INTEGER */
- ASN1_INTEGER *fileSize;
- ASN1_INTEGER *xSize;
- ASN1_INTEGER *ySize;
- LogotypeImageResolution *resolution;
- ASN1_IA5STRING *language;
-} LogotypeImageInfo;
-
-typedef struct {
- LogotypeDetails *imageDetails;
- LogotypeImageInfo *imageInfo;
-} LogotypeImage;
-
-typedef struct {
- ASN1_INTEGER *fileSize;
- ASN1_INTEGER *playTime;
- ASN1_INTEGER *channels;
- ASN1_INTEGER *sampleRate;
- ASN1_IA5STRING *language;
-} LogotypeAudioInfo;
-
-typedef struct {
- LogotypeDetails *audioDetails;
- LogotypeAudioInfo *audioInfo;
-} LogotypeAudio;
-
-typedef struct {
- STACK_OF(LogotypeImage) *image;
- STACK_OF(LogotypeAudio) *audio;
-} LogotypeData;
-
-typedef struct {
- int type;
- union {
- LogotypeData *direct;
- LogotypeReference *indirect;
- } d;
-} LogotypeInfo;
-
-typedef struct {
- ASN1_OBJECT *logotypeType;
- LogotypeInfo *info;
-} OtherLogotypeInfo;
-
-typedef struct {
- STACK_OF(LogotypeInfo) *communityLogos;
- LogotypeInfo *issuerLogo;
- LogotypeInfo *subjectLogo;
- STACK_OF(OtherLogotypeInfo) *otherLogos;
-} LogotypeExtn;
-
-ASN1_SEQUENCE(HashAlgAndValue) = {
- ASN1_SIMPLE(HashAlgAndValue, hashAlg, X509_ALGOR),
- ASN1_SIMPLE(HashAlgAndValue, hashValue, ASN1_OCTET_STRING)
-} ASN1_SEQUENCE_END(HashAlgAndValue);
-
-ASN1_SEQUENCE(LogotypeReference) = {
- ASN1_SEQUENCE_OF(LogotypeReference, refStructHash, HashAlgAndValue),
- ASN1_SEQUENCE_OF(LogotypeReference, refStructURI, ASN1_IA5STRING)
-} ASN1_SEQUENCE_END(LogotypeReference);
-
-ASN1_SEQUENCE(LogotypeDetails) = {
- ASN1_SIMPLE(LogotypeDetails, mediaType, ASN1_IA5STRING),
- ASN1_SEQUENCE_OF(LogotypeDetails, logotypeHash, HashAlgAndValue),
- ASN1_SEQUENCE_OF(LogotypeDetails, logotypeURI, ASN1_IA5STRING)
-} ASN1_SEQUENCE_END(LogotypeDetails);
-
-ASN1_CHOICE(LogotypeImageResolution) = {
- ASN1_IMP(LogotypeImageResolution, d.numBits, ASN1_INTEGER, 1),
- ASN1_IMP(LogotypeImageResolution, d.tableSize, ASN1_INTEGER, 2)
-} ASN1_CHOICE_END(LogotypeImageResolution);
-
-ASN1_SEQUENCE(LogotypeImageInfo) = {
- ASN1_IMP_OPT(LogotypeImageInfo, type, ASN1_INTEGER, 0),
- ASN1_SIMPLE(LogotypeImageInfo, fileSize, ASN1_INTEGER),
- ASN1_SIMPLE(LogotypeImageInfo, xSize, ASN1_INTEGER),
- ASN1_SIMPLE(LogotypeImageInfo, ySize, ASN1_INTEGER),
- ASN1_OPT(LogotypeImageInfo, resolution, LogotypeImageResolution),
- ASN1_IMP_OPT(LogotypeImageInfo, language, ASN1_IA5STRING, 4),
-} ASN1_SEQUENCE_END(LogotypeImageInfo);
-
-ASN1_SEQUENCE(LogotypeImage) = {
- ASN1_SIMPLE(LogotypeImage, imageDetails, LogotypeDetails),
- ASN1_OPT(LogotypeImage, imageInfo, LogotypeImageInfo)
-} ASN1_SEQUENCE_END(LogotypeImage);
-
-ASN1_SEQUENCE(LogotypeAudioInfo) = {
- ASN1_SIMPLE(LogotypeAudioInfo, fileSize, ASN1_INTEGER),
- ASN1_SIMPLE(LogotypeAudioInfo, playTime, ASN1_INTEGER),
- ASN1_SIMPLE(LogotypeAudioInfo, channels, ASN1_INTEGER),
- ASN1_IMP_OPT(LogotypeAudioInfo, sampleRate, ASN1_INTEGER, 3),
- ASN1_IMP_OPT(LogotypeAudioInfo, language, ASN1_IA5STRING, 4)
-} ASN1_SEQUENCE_END(LogotypeAudioInfo);
-
-ASN1_SEQUENCE(LogotypeAudio) = {
- ASN1_SIMPLE(LogotypeAudio, audioDetails, LogotypeDetails),
- ASN1_OPT(LogotypeAudio, audioInfo, LogotypeAudioInfo)
-} ASN1_SEQUENCE_END(LogotypeAudio);
-
-ASN1_SEQUENCE(LogotypeData) = {
- ASN1_SEQUENCE_OF_OPT(LogotypeData, image, LogotypeImage),
- ASN1_IMP_SEQUENCE_OF_OPT(LogotypeData, audio, LogotypeAudio, 1)
-} ASN1_SEQUENCE_END(LogotypeData);
-
-ASN1_CHOICE(LogotypeInfo) = {
- ASN1_IMP(LogotypeInfo, d.direct, LogotypeData, 0),
- ASN1_IMP(LogotypeInfo, d.indirect, LogotypeReference, 1)
-} ASN1_CHOICE_END(LogotypeInfo);
-
-ASN1_SEQUENCE(OtherLogotypeInfo) = {
- ASN1_SIMPLE(OtherLogotypeInfo, logotypeType, ASN1_OBJECT),
- ASN1_SIMPLE(OtherLogotypeInfo, info, LogotypeInfo)
-} ASN1_SEQUENCE_END(OtherLogotypeInfo);
-
-ASN1_SEQUENCE(LogotypeExtn) = {
- ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, communityLogos, LogotypeInfo, 0),
- ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 1),
- ASN1_EXP_OPT(LogotypeExtn, issuerLogo, LogotypeInfo, 2),
- ASN1_EXP_SEQUENCE_OF_OPT(LogotypeExtn, otherLogos, OtherLogotypeInfo, 3)
-} ASN1_SEQUENCE_END(LogotypeExtn);
-
-IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn);
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-#define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st))
-#define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i))
-#define sk_LogotypeImage_num(st) SKM_sk_num(LogotypeImage, (st))
-#define sk_LogotypeImage_value(st, i) SKM_sk_value(LogotypeImage, (st), (i))
-#define sk_LogotypeAudio_num(st) SKM_sk_num(LogotypeAudio, (st))
-#define sk_LogotypeAudio_value(st, i) SKM_sk_value(LogotypeAudio, (st), (i))
-#define sk_HashAlgAndValue_num(st) SKM_sk_num(HashAlgAndValue, (st))
-#define sk_HashAlgAndValue_value(st, i) SKM_sk_value(HashAlgAndValue, (st), (i))
-#define sk_ASN1_IA5STRING_num(st) SKM_sk_num(ASN1_IA5STRING, (st))
-#define sk_ASN1_IA5STRING_value(st, i) SKM_sk_value(ASN1_IA5STRING, (st), (i))
-#else
-DEFINE_STACK_OF(LogotypeInfo)
-DEFINE_STACK_OF(LogotypeImage)
-DEFINE_STACK_OF(LogotypeAudio)
-DEFINE_STACK_OF(HashAlgAndValue)
-DEFINE_STACK_OF(ASN1_IA5STRING)
-#endif
-
-
-static void add_logo(struct http_ctx *ctx, struct http_cert *hcert,
- HashAlgAndValue *hash, ASN1_IA5STRING *uri)
-{
- char txt[100];
- int res, len;
- struct http_logo *n;
-
- if (hash == NULL || uri == NULL)
- return;
-
- res = OBJ_obj2txt(txt, sizeof(txt), hash->hashAlg->algorithm, 1);
- if (res < 0 || res >= (int) sizeof(txt))
- return;
-
- n = os_realloc_array(hcert->logo, hcert->num_logo + 1,
- sizeof(struct http_logo));
- if (n == NULL)
- return;
- hcert->logo = n;
- n = &hcert->logo[hcert->num_logo];
- os_memset(n, 0, sizeof(*n));
-
- n->alg_oid = os_strdup(txt);
- if (n->alg_oid == NULL)
- return;
-
- n->hash_len = ASN1_STRING_length(hash->hashValue);
- n->hash = os_memdup(ASN1_STRING_get0_data(hash->hashValue),
- n->hash_len);
- if (n->hash == NULL) {
- os_free(n->alg_oid);
- return;
- }
-
- len = ASN1_STRING_length(uri);
- n->uri = os_malloc(len + 1);
- if (n->uri == NULL) {
- os_free(n->alg_oid);
- os_free(n->hash);
- return;
- }
- os_memcpy(n->uri, ASN1_STRING_get0_data(uri), len);
- n->uri[len] = '\0';
-
- hcert->num_logo++;
-}
-
-
-static void add_logo_direct(struct http_ctx *ctx, struct http_cert *hcert,
- LogotypeData *data)
-{
- int i, num;
-
- if (data->image == NULL)
- return;
-
- num = sk_LogotypeImage_num(data->image);
- for (i = 0; i < num; i++) {
- LogotypeImage *image;
- LogotypeDetails *details;
- int j, hash_num, uri_num;
- HashAlgAndValue *found_hash = NULL;
-
- image = sk_LogotypeImage_value(data->image, i);
- if (image == NULL)
- continue;
-
- details = image->imageDetails;
- if (details == NULL)
- continue;
-
- hash_num = sk_HashAlgAndValue_num(details->logotypeHash);
- for (j = 0; j < hash_num; j++) {
- HashAlgAndValue *hash;
- char txt[100];
- int res;
- hash = sk_HashAlgAndValue_value(details->logotypeHash,
- j);
- if (hash == NULL)
- continue;
- res = OBJ_obj2txt(txt, sizeof(txt),
- hash->hashAlg->algorithm, 1);
- if (res < 0 || res >= (int) sizeof(txt))
- continue;
- if (os_strcmp(txt, "2.16.840.1.101.3.4.2.1") == 0) {
- found_hash = hash;
- break;
- }
- }
-
- if (!found_hash) {
- wpa_printf(MSG_DEBUG, "OpenSSL: No SHA256 hash found for the logo");
- continue;
- }
-
- uri_num = sk_ASN1_IA5STRING_num(details->logotypeURI);
- for (j = 0; j < uri_num; j++) {
- ASN1_IA5STRING *uri;
- uri = sk_ASN1_IA5STRING_value(details->logotypeURI, j);
- add_logo(ctx, hcert, found_hash, uri);
- }
- }
-}
-
-
-static void add_logo_indirect(struct http_ctx *ctx, struct http_cert *hcert,
- LogotypeReference *ref)
-{
- int j, hash_num, uri_num;
-
- hash_num = sk_HashAlgAndValue_num(ref->refStructHash);
- uri_num = sk_ASN1_IA5STRING_num(ref->refStructURI);
- if (hash_num != uri_num) {
- wpa_printf(MSG_INFO, "Unexpected LogotypeReference array size difference %d != %d",
- hash_num, uri_num);
- return;
- }
-
- for (j = 0; j < hash_num; j++) {
- HashAlgAndValue *hash;
- ASN1_IA5STRING *uri;
- hash = sk_HashAlgAndValue_value(ref->refStructHash, j);
- uri = sk_ASN1_IA5STRING_value(ref->refStructURI, j);
- add_logo(ctx, hcert, hash, uri);
- }
-}
-
-
-static void i2r_HashAlgAndValue(HashAlgAndValue *hash, BIO *out, int indent)
-{
- int i;
- const unsigned char *data;
-
- BIO_printf(out, "%*shashAlg: ", indent, "");
- i2a_ASN1_OBJECT(out, hash->hashAlg->algorithm);
- BIO_printf(out, "\n");
-
- BIO_printf(out, "%*shashValue: ", indent, "");
- data = hash->hashValue->data;
- for (i = 0; i < hash->hashValue->length; i++)
- BIO_printf(out, "%s%02x", i > 0 ? ":" : "", data[i]);
- BIO_printf(out, "\n");
-}
-
-static void i2r_LogotypeDetails(LogotypeDetails *details, BIO *out, int indent)
-{
- int i, num;
-
- BIO_printf(out, "%*sLogotypeDetails\n", indent, "");
- if (details->mediaType) {
- BIO_printf(out, "%*smediaType: ", indent, "");
- ASN1_STRING_print(out, details->mediaType);
- BIO_printf(out, "\n");
- }
-
- num = details->logotypeHash ?
- sk_HashAlgAndValue_num(details->logotypeHash) : 0;
- for (i = 0; i < num; i++) {
- HashAlgAndValue *hash;
- hash = sk_HashAlgAndValue_value(details->logotypeHash, i);
- i2r_HashAlgAndValue(hash, out, indent);
- }
-
- num = details->logotypeURI ?
- sk_ASN1_IA5STRING_num(details->logotypeURI) : 0;
- for (i = 0; i < num; i++) {
- ASN1_IA5STRING *uri;
- uri = sk_ASN1_IA5STRING_value(details->logotypeURI, i);
- BIO_printf(out, "%*slogotypeURI: ", indent, "");
- ASN1_STRING_print(out, uri);
- BIO_printf(out, "\n");
- }
-}
-
-static void i2r_LogotypeImageInfo(LogotypeImageInfo *info, BIO *out, int indent)
-{
- long val;
-
- BIO_printf(out, "%*sLogotypeImageInfo\n", indent, "");
- if (info->type) {
- val = ASN1_INTEGER_get(info->type);
- BIO_printf(out, "%*stype: %ld\n", indent, "", val);
- } else {
- BIO_printf(out, "%*stype: default (1)\n", indent, "");
- }
- val = ASN1_INTEGER_get(info->fileSize);
- BIO_printf(out, "%*sfileSize: %ld\n", indent, "", val);
- val = ASN1_INTEGER_get(info->xSize);
- BIO_printf(out, "%*sxSize: %ld\n", indent, "", val);
- val = ASN1_INTEGER_get(info->ySize);
- BIO_printf(out, "%*sySize: %ld\n", indent, "", val);
- if (info->resolution) {
- BIO_printf(out, "%*sresolution [%d]\n", indent, "",
- info->resolution->type);
- switch (info->resolution->type) {
- case 0:
- val = ASN1_INTEGER_get(info->resolution->d.numBits);
- BIO_printf(out, "%*snumBits: %ld\n", indent, "", val);
- break;
- case 1:
- val = ASN1_INTEGER_get(info->resolution->d.tableSize);
- BIO_printf(out, "%*stableSize: %ld\n", indent, "", val);
- break;
- }
- }
- if (info->language) {
- BIO_printf(out, "%*slanguage: ", indent, "");
- ASN1_STRING_print(out, info->language);
- BIO_printf(out, "\n");
- }
-}
-
-static void i2r_LogotypeImage(LogotypeImage *image, BIO *out, int indent)
-{
- BIO_printf(out, "%*sLogotypeImage\n", indent, "");
- if (image->imageDetails) {
- i2r_LogotypeDetails(image->imageDetails, out, indent + 4);
- }
- if (image->imageInfo) {
- i2r_LogotypeImageInfo(image->imageInfo, out, indent + 4);
- }
-}
-
-static void i2r_LogotypeData(LogotypeData *data, const char *title, BIO *out,
- int indent)
-{
- int i, num;
-
- BIO_printf(out, "%*s%s - LogotypeData\n", indent, "", title);
-
- num = data->image ? sk_LogotypeImage_num(data->image) : 0;
- for (i = 0; i < num; i++) {
- LogotypeImage *image = sk_LogotypeImage_value(data->image, i);
- i2r_LogotypeImage(image, out, indent + 4);
- }
-
- num = data->audio ? sk_LogotypeAudio_num(data->audio) : 0;
- for (i = 0; i < num; i++) {
- BIO_printf(out, "%*saudio: TODO\n", indent, "");
- }
-}
-
-static void i2r_LogotypeReference(LogotypeReference *ref, const char *title,
- BIO *out, int indent)
-{
- int i, hash_num, uri_num;
-
- BIO_printf(out, "%*s%s - LogotypeReference\n", indent, "", title);
-
- hash_num = ref->refStructHash ?
- sk_HashAlgAndValue_num(ref->refStructHash) : 0;
- uri_num = ref->refStructURI ?
- sk_ASN1_IA5STRING_num(ref->refStructURI) : 0;
- if (hash_num != uri_num) {
- BIO_printf(out, "%*sUnexpected LogotypeReference array size difference %d != %d\n",
- indent, "", hash_num, uri_num);
- return;
- }
-
- for (i = 0; i < hash_num; i++) {
- HashAlgAndValue *hash;
- ASN1_IA5STRING *uri;
-
- hash = sk_HashAlgAndValue_value(ref->refStructHash, i);
- i2r_HashAlgAndValue(hash, out, indent);
-
- uri = sk_ASN1_IA5STRING_value(ref->refStructURI, i);
- BIO_printf(out, "%*srefStructURI: ", indent, "");
- ASN1_STRING_print(out, uri);
- BIO_printf(out, "\n");
- }
-}
-
-static void i2r_LogotypeInfo(LogotypeInfo *info, const char *title, BIO *out,
- int indent)
-{
- switch (info->type) {
- case 0:
- i2r_LogotypeData(info->d.direct, title, out, indent);
- break;
- case 1:
- i2r_LogotypeReference(info->d.indirect, title, out, indent);
- break;
- }
-}
-
-static void debug_print_logotypeext(LogotypeExtn *logo)
-{
- BIO *out;
- int i, num;
- int indent = 0;
-
- out = BIO_new_fp(stdout, BIO_NOCLOSE);
- if (out == NULL)
- return;
-
- if (logo->communityLogos) {
- num = sk_LogotypeInfo_num(logo->communityLogos);
- for (i = 0; i < num; i++) {
- LogotypeInfo *info;
- info = sk_LogotypeInfo_value(logo->communityLogos, i);
- i2r_LogotypeInfo(info, "communityLogo", out, indent);
- }
- }
-
- if (logo->issuerLogo) {
- i2r_LogotypeInfo(logo->issuerLogo, "issuerLogo", out, indent );
- }
-
- if (logo->subjectLogo) {
- i2r_LogotypeInfo(logo->subjectLogo, "subjectLogo", out, indent);
- }
-
- if (logo->otherLogos) {
- BIO_printf(out, "%*sotherLogos - TODO\n", indent, "");
- }
-
- BIO_free(out);
-}
-
-
-static void add_logotype_ext(struct http_ctx *ctx, struct http_cert *hcert,
- X509 *cert)
-{
- ASN1_OBJECT *obj;
- int pos;
- X509_EXTENSION *ext;
- ASN1_OCTET_STRING *os;
- LogotypeExtn *logo;
- const unsigned char *data;
- int i, num;
-
- obj = OBJ_txt2obj("1.3.6.1.5.5.7.1.12", 0);
- if (obj == NULL)
- return;
-
- pos = X509_get_ext_by_OBJ(cert, obj, -1);
- if (pos < 0) {
- wpa_printf(MSG_INFO, "No logotype extension included");
- return;
- }
-
- wpa_printf(MSG_INFO, "Parsing logotype extension");
- ext = X509_get_ext(cert, pos);
- if (!ext) {
- wpa_printf(MSG_INFO, "Could not get logotype extension");
- return;
- }
-
- os = X509_EXTENSION_get_data(ext);
- if (os == NULL) {
- wpa_printf(MSG_INFO, "Could not get logotype extension data");
- return;
- }
-
- wpa_hexdump(MSG_DEBUG, "logotypeExtn",
- ASN1_STRING_get0_data(os), ASN1_STRING_length(os));
-
- data = ASN1_STRING_get0_data(os);
- logo = d2i_LogotypeExtn(NULL, &data, ASN1_STRING_length(os));
- if (logo == NULL) {
- wpa_printf(MSG_INFO, "Failed to parse logotypeExtn");
- return;
- }
-
- if (wpa_debug_level < MSG_INFO)
- debug_print_logotypeext(logo);
-
- if (!logo->communityLogos) {
- wpa_printf(MSG_INFO, "No communityLogos included");
- LogotypeExtn_free(logo);
- return;
- }
-
- num = sk_LogotypeInfo_num(logo->communityLogos);
- for (i = 0; i < num; i++) {
- LogotypeInfo *info;
- info = sk_LogotypeInfo_value(logo->communityLogos, i);
- switch (info->type) {
- case 0:
- add_logo_direct(ctx, hcert, info->d.direct);
- break;
- case 1:
- add_logo_indirect(ctx, hcert, info->d.indirect);
- break;
- }
- }
-
- LogotypeExtn_free(logo);
-}
-
-
-static void parse_cert(struct http_ctx *ctx, struct http_cert *hcert,
- X509 *cert, GENERAL_NAMES **names)
-{
- os_memset(hcert, 0, sizeof(*hcert));
- hcert->url = ctx->url ? ctx->url : ctx->svc_address;
-
- *names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
- if (*names)
- add_alt_names(ctx, hcert, *names);
-
- add_logotype_ext(ctx, hcert, cert);
-}
-
-
-static void parse_cert_free(struct http_cert *hcert, GENERAL_NAMES *names)
-{
- unsigned int i;
-
- for (i = 0; i < hcert->num_dnsname; i++)
- OPENSSL_free(hcert->dnsname[i]);
- os_free(hcert->dnsname);
-
- for (i = 0; i < hcert->num_othername; i++)
- os_free(hcert->othername[i].oid);
- os_free(hcert->othername);
-
- for (i = 0; i < hcert->num_logo; i++) {
- os_free(hcert->logo[i].alg_oid);
- os_free(hcert->logo[i].hash);
- os_free(hcert->logo[i].uri);
- }
- os_free(hcert->logo);
-
- sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
-}
-
-
-static int validate_server_cert(struct http_ctx *ctx, X509 *cert)
-{
- GENERAL_NAMES *names;
- struct http_cert hcert;
- int ret;
-
- if (ctx->cert_cb == NULL) {
- wpa_printf(MSG_DEBUG, "%s: no cert_cb configured", __func__);
- return 0;
- }
-
- if (0) {
- BIO *out;
- out = BIO_new_fp(stdout, BIO_NOCLOSE);
- X509_print_ex(out, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
- BIO_free(out);
- }
-
- parse_cert(ctx, &hcert, cert, &names);
- ret = ctx->cert_cb(ctx->cert_cb_ctx, &hcert);
- parse_cert_free(&hcert, names);
-
- return ret;
-}
-
-
-void http_parse_x509_certificate(struct http_ctx *ctx, const char *fname)
-{
- BIO *in, *out;
- X509 *cert;
- GENERAL_NAMES *names;
- struct http_cert hcert;
- unsigned int i;
-
- in = BIO_new_file(fname, "r");
- if (in == NULL) {
- wpa_printf(MSG_ERROR, "Could not read '%s'", fname);
- return;
- }
-
- cert = d2i_X509_bio(in, NULL);
- BIO_free(in);
-
- if (cert == NULL) {
- wpa_printf(MSG_ERROR, "Could not parse certificate");
- return;
- }
-
- out = BIO_new_fp(stdout, BIO_NOCLOSE);
- if (out) {
- X509_print_ex(out, cert, XN_FLAG_COMPAT,
- X509_FLAG_COMPAT);
- BIO_free(out);
- }
-
- wpa_printf(MSG_INFO, "Additional parsing information:");
- parse_cert(ctx, &hcert, cert, &names);
- for (i = 0; i < hcert.num_othername; i++) {
- if (os_strcmp(hcert.othername[i].oid,
- "1.3.6.1.4.1.40808.1.1.1") == 0) {
- char *name = os_zalloc(hcert.othername[i].len + 1);
- if (name) {
- os_memcpy(name, hcert.othername[i].data,
- hcert.othername[i].len);
- wpa_printf(MSG_INFO,
- "id-wfa-hotspot-friendlyName: %s",
- name);
- os_free(name);
- }
- wpa_hexdump_ascii(MSG_INFO,
- "id-wfa-hotspot-friendlyName",
- hcert.othername[i].data,
- hcert.othername[i].len);
- } else {
- wpa_printf(MSG_INFO, "subjAltName[othername]: oid=%s",
- hcert.othername[i].oid);
- wpa_hexdump_ascii(MSG_INFO, "unknown othername",
- hcert.othername[i].data,
- hcert.othername[i].len);
- }
- }
- parse_cert_free(&hcert, names);
-
- X509_free(cert);
-}
-
-
static int curl_cb_ssl_verify(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
struct http_ctx *ctx;
@@ -1011,9 +218,6 @@
depth, err, err_str, buf);
debug_dump_cert("Server certificate chain - certificate", cert);
- if (depth == 0 && preverify_ok && validate_server_cert(ctx, cert) < 0)
- return 0;
-
#ifdef OPENSSL_IS_BORINGSSL
if (depth == 0 && ctx->ocsp != NO_OCSP && preverify_ok) {
enum ocsp_result res;
@@ -1387,91 +591,6 @@
}
-static int post_init_client(struct http_ctx *ctx, const char *address,
- const char *ca_fname, const char *username,
- const char *password, const char *client_cert,
- const char *client_key)
-{
- char *pos;
- int count;
-
- clone_str(&ctx->svc_address, address);
- clone_str(&ctx->svc_ca_fname, ca_fname);
- clone_str(&ctx->svc_username, username);
- clone_str(&ctx->svc_password, password);
- clone_str(&ctx->svc_client_cert, client_cert);
- clone_str(&ctx->svc_client_key, client_key);
-
- /*
- * Workaround for Apache "Hostname 'FOO' provided via SNI and hostname
- * 'foo' provided via HTTP are different.
- */
- for (count = 0, pos = ctx->svc_address; count < 3 && pos && *pos;
- pos++) {
- if (*pos == '/')
- count++;
- *pos = tolower(*pos);
- }
-
- ctx->curl = setup_curl_post(ctx, ctx->svc_address, ca_fname, username,
- password, client_cert, client_key);
- if (ctx->curl == NULL)
- return -1;
-
- return 0;
-}
-
-
-int soap_init_client(struct http_ctx *ctx, const char *address,
- const char *ca_fname, const char *username,
- const char *password, const char *client_cert,
- const char *client_key)
-{
- if (post_init_client(ctx, address, ca_fname, username, password,
- client_cert, client_key) < 0)
- return -1;
-
- ctx->curl_hdr = curl_slist_append(ctx->curl_hdr,
- "Content-Type: application/soap+xml");
- ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "SOAPAction: ");
- ctx->curl_hdr = curl_slist_append(ctx->curl_hdr, "Expect:");
- curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->curl_hdr);
-
- return 0;
-}
-
-
-int soap_reinit_client(struct http_ctx *ctx)
-{
- char *address = NULL;
- char *ca_fname = NULL;
- char *username = NULL;
- char *password = NULL;
- char *client_cert = NULL;
- char *client_key = NULL;
- int ret;
-
- clear_curl(ctx);
-
- clone_str(&address, ctx->svc_address);
- clone_str(&ca_fname, ctx->svc_ca_fname);
- clone_str(&username, ctx->svc_username);
- clone_str(&password, ctx->svc_password);
- clone_str(&client_cert, ctx->svc_client_cert);
- clone_str(&client_key, ctx->svc_client_key);
-
- ret = soap_init_client(ctx, address, ca_fname, username, password,
- client_cert, client_key);
- os_free(address);
- os_free(ca_fname);
- str_clear_free(username);
- str_clear_free(password);
- os_free(client_cert);
- os_free(client_key);
- return ret;
-}
-
-
static void free_curl_buf(struct http_ctx *ctx)
{
os_free(ctx->curl_buf);
@@ -1480,73 +599,6 @@
}
-xml_node_t * soap_send_receive(struct http_ctx *ctx, xml_node_t *node)
-{
- char *str;
- xml_node_t *envelope, *ret, *resp, *n;
- CURLcode res;
- long http = 0;
-
- ctx->last_err = NULL;
-
- wpa_printf(MSG_DEBUG, "SOAP: Sending message");
- envelope = soap_build_envelope(ctx->xml, node);
- str = xml_node_to_str(ctx->xml, envelope);
- xml_node_free(ctx->xml, envelope);
- wpa_printf(MSG_MSGDUMP, "SOAP[%s]", str);
-
- curl_easy_setopt(ctx->curl, CURLOPT_POSTFIELDS, str);
- free_curl_buf(ctx);
-
- res = curl_easy_perform(ctx->curl);
- if (res != CURLE_OK) {
- if (!ctx->last_err)
- ctx->last_err = curl_easy_strerror(res);
- wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s",
- ctx->last_err);
- os_free(str);
- free_curl_buf(ctx);
- return NULL;
- }
- os_free(str);
-
- curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &http);
- wpa_printf(MSG_DEBUG, "SOAP: Server response code %ld", http);
- if (http != 200) {
- ctx->last_err = "HTTP download failed";
- wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http);
- free_curl_buf(ctx);
- return NULL;
- }
-
- if (ctx->curl_buf == NULL)
- return NULL;
-
- wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ctx->curl_buf);
- resp = xml_node_from_buf(ctx->xml, ctx->curl_buf);
- free_curl_buf(ctx);
- if (resp == NULL) {
- wpa_printf(MSG_INFO, "Could not parse SOAP response");
- ctx->last_err = "Could not parse SOAP response";
- return NULL;
- }
-
- ret = soap_get_body(ctx->xml, resp);
- if (ret == NULL) {
- wpa_printf(MSG_INFO, "Could not get SOAP body");
- ctx->last_err = "Could not get SOAP body";
- return NULL;
- }
-
- wpa_printf(MSG_DEBUG, "SOAP body localname: '%s'",
- xml_node_get_localname(ctx->xml, ret));
- n = xml_node_copy(ctx->xml, ret);
- xml_node_free(ctx->xml, resp);
-
- return n;
-}
-
-
struct http_ctx * http_init_ctx(void *upper_ctx, struct xml_node_ctx *xml_ctx)
{
struct http_ctx *ctx;
@@ -1582,11 +634,6 @@
curl_global_cleanup();
os_free(ctx->svc_address);
- os_free(ctx->svc_ca_fname);
- str_clear_free(ctx->svc_username);
- str_clear_free(ctx->svc_password);
- os_free(ctx->svc_client_cert);
- os_free(ctx->svc_client_key);
os_free(ctx);
}
@@ -1726,15 +773,6 @@
}
-void http_set_cert_cb(struct http_ctx *ctx,
- int (*cb)(void *ctx, struct http_cert *cert),
- void *cb_ctx)
-{
- ctx->cert_cb = cb;
- ctx->cert_cb_ctx = cb_ctx;
-}
-
-
const char * http_get_err(struct http_ctx *ctx)
{
return ctx->last_err;
diff --git a/src/utils/json.c b/src/utils/json.c
index dd12f1b..5523f28 100644
--- a/src/utils/json.c
+++ b/src/utils/json.c
@@ -269,7 +269,8 @@
case ']': /* end array */
case '}': /* end object */
if (!curr_token || !curr_token->parent ||
- curr_token->parent->state != JSON_STARTED) {
+ curr_token->parent->state != JSON_STARTED ||
+ depth == 0) {
wpa_printf(MSG_DEBUG,
"JSON: Invalid state for end array/object");
goto fail;
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 0b8612a..45c4ea8 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -566,7 +566,7 @@
#ifdef WPA_TRACE
#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
-struct wpa_trace_test_fail {
+static struct wpa_trace_test_fail {
unsigned int fail_after;
char pattern[256];
} wpa_trace_test_fail[5][4];
diff --git a/src/utils/trace.c b/src/utils/trace.c
index 7c9a17f..1ec2265 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -197,6 +197,8 @@
if (abfd == NULL)
return;
+ if (start_offset > (uintptr_t) pc)
+ return;
data.pc = (uintptr_t) ((u8 *) pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -238,6 +240,8 @@
if (abfd == NULL)
return NULL;
+ if (start_offset > (uintptr_t) pc)
+ return NULL;
data.pc = (uintptr_t) ((u8 *) pc - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
@@ -310,6 +314,8 @@
for (i = 0; i < btrace_num; i++) {
struct bfd_data data;
+ if (start_offset > (uintptr_t) btrace_res[i])
+ continue;
data.pc = (uintptr_t) ((u8 *) btrace_res[i] - start_offset);
data.found = FALSE;
bfd_map_over_sections(abfd, find_addr_sect, &data);
diff --git a/src/utils/xml-utils.c b/src/utils/xml-utils.c
index dae91fe..5280382 100644
--- a/src/utils/xml-utils.c
+++ b/src/utils/xml-utils.c
@@ -438,34 +438,3 @@
return NULL;
return tnds_to_mo_iter(ctx, NULL, node, NULL);
}
-
-
-xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node)
-{
- xml_node_t *envelope, *body;
- xml_namespace_t *ns;
-
- envelope = xml_node_create_root(
- ctx, "http://www.w3.org/2003/05/soap-envelope", "soap12", &ns,
- "Envelope");
- if (envelope == NULL)
- return NULL;
- body = xml_node_create(ctx, envelope, ns, "Body");
- xml_node_add_child(ctx, body, node);
- return envelope;
-}
-
-
-xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap)
-{
- xml_node_t *body, *child;
-
- body = get_node_uri(ctx, soap, "Envelope/Body");
- if (body == NULL)
- return NULL;
- xml_node_for_each_child(ctx, child, body) {
- xml_node_for_each_check(ctx, child);
- return child;
- }
- return NULL;
-}
diff --git a/src/utils/xml-utils.h b/src/utils/xml-utils.h
index fb6208c..eb83bd4 100644
--- a/src/utils/xml-utils.h
+++ b/src/utils/xml-utils.h
@@ -15,19 +15,11 @@
/* XML library wrappers */
-int xml_validate(struct xml_node_ctx *ctx, xml_node_t *node,
- const char *xml_schema_fname, char **ret_err);
-int xml_validate_dtd(struct xml_node_ctx *ctx, xml_node_t *node,
- const char *dtd_fname, char **ret_err);
void xml_node_free(struct xml_node_ctx *ctx, xml_node_t *node);
-xml_node_t * xml_node_get_parent(struct xml_node_ctx *ctx, xml_node_t *node);
xml_node_t * xml_node_from_buf(struct xml_node_ctx *ctx, const char *buf);
const char * xml_node_get_localname(struct xml_node_ctx *ctx,
xml_node_t *node);
char * xml_node_to_str(struct xml_node_ctx *ctx, xml_node_t *node);
-void xml_node_detach(struct xml_node_ctx *ctx, xml_node_t *node);
-void xml_node_add_child(struct xml_node_ctx *ctx, xml_node_t *parent,
- xml_node_t *child);
xml_node_t * xml_node_create_root(struct xml_node_ctx *ctx, const char *ns_uri,
const char *ns_prefix,
xml_namespace_t **ret_ns, const char *name);
@@ -41,13 +33,6 @@
const char *name, const char *value);
void xml_node_set_text(struct xml_node_ctx *ctx, xml_node_t *node,
const char *value);
-int xml_node_add_attr(struct xml_node_ctx *ctx, xml_node_t *node,
- xml_namespace_t *ns, const char *name, const char *value);
-char * xml_node_get_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
- char *name);
-char * xml_node_get_attr_value_ns(struct xml_node_ctx *ctx, xml_node_t *node,
- const char *ns_uri, char *name);
-void xml_node_get_attr_value_free(struct xml_node_ctx *ctx, char *val);
xml_node_t * xml_node_first_child(struct xml_node_ctx *ctx,
xml_node_t *parent);
xml_node_t * xml_node_next_sibling(struct xml_node_ctx *ctx,
@@ -57,7 +42,6 @@
void xml_node_get_text_free(struct xml_node_ctx *ctx, char *val);
char * xml_node_get_base64_text(struct xml_node_ctx *ctx, xml_node_t *node,
int *ret_len);
-xml_node_t * xml_node_copy(struct xml_node_ctx *ctx, xml_node_t *node);
#define xml_node_for_each_child(ctx, child, parent) \
for (child = xml_node_first_child(ctx, parent); \
@@ -91,7 +75,4 @@
int use_path, const char *urn, const char *ns_uri);
xml_node_t * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds);
-xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node);
-xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap);
-
#endif /* XML_UTILS_H */
diff --git a/src/utils/xml_libxml2.c b/src/utils/xml_libxml2.c
index 7b7aeb7..26ad748 100644
--- a/src/utils/xml_libxml2.c
+++ b/src/utils/xml_libxml2.c
@@ -21,161 +21,12 @@
};
-struct str_buf {
- char *buf;
- size_t len;
-};
-
-#define MAX_STR 1000
-
-static void add_str(void *ctx_ptr, const char *fmt, ...)
-{
- struct str_buf *str = ctx_ptr;
- va_list ap;
- char *n;
- int len;
-
- n = os_realloc(str->buf, str->len + MAX_STR + 2);
- if (n == NULL)
- return;
- str->buf = n;
-
- va_start(ap, fmt);
- len = vsnprintf(str->buf + str->len, MAX_STR, fmt, ap);
- va_end(ap);
- if (len >= MAX_STR)
- len = MAX_STR - 1;
- str->len += len;
- str->buf[str->len] = '\0';
-}
-
-
-int xml_validate(struct xml_node_ctx *ctx, xml_node_t *node,
- const char *xml_schema_fname, char **ret_err)
-{
- xmlDocPtr doc;
- xmlNodePtr n;
- xmlSchemaParserCtxtPtr pctx;
- xmlSchemaValidCtxtPtr vctx;
- xmlSchemaPtr schema;
- int ret;
- struct str_buf errors;
-
- if (ret_err)
- *ret_err = NULL;
-
- doc = xmlNewDoc((xmlChar *) "1.0");
- if (doc == NULL)
- return -1;
- n = xmlDocCopyNode((xmlNodePtr) node, doc, 1);
- if (n == NULL) {
- xmlFreeDoc(doc);
- return -1;
- }
- xmlDocSetRootElement(doc, n);
-
- os_memset(&errors, 0, sizeof(errors));
-
- pctx = xmlSchemaNewParserCtxt(xml_schema_fname);
- xmlSchemaSetParserErrors(pctx, (xmlSchemaValidityErrorFunc) add_str,
- (xmlSchemaValidityWarningFunc) add_str,
- &errors);
- schema = xmlSchemaParse(pctx);
- xmlSchemaFreeParserCtxt(pctx);
-
- vctx = xmlSchemaNewValidCtxt(schema);
- xmlSchemaSetValidErrors(vctx, (xmlSchemaValidityErrorFunc) add_str,
- (xmlSchemaValidityWarningFunc) add_str,
- &errors);
-
- ret = xmlSchemaValidateDoc(vctx, doc);
- xmlSchemaFreeValidCtxt(vctx);
- xmlFreeDoc(doc);
- xmlSchemaFree(schema);
-
- if (ret == 0) {
- os_free(errors.buf);
- return 0;
- } else if (ret > 0) {
- if (ret_err)
- *ret_err = errors.buf;
- else
- os_free(errors.buf);
- return -1;
- } else {
- if (ret_err)
- *ret_err = errors.buf;
- else
- os_free(errors.buf);
- return -1;
- }
-}
-
-
-int xml_validate_dtd(struct xml_node_ctx *ctx, xml_node_t *node,
- const char *dtd_fname, char **ret_err)
-{
- xmlDocPtr doc;
- xmlNodePtr n;
- xmlValidCtxt vctx;
- xmlDtdPtr dtd;
- int ret;
- struct str_buf errors;
-
- if (ret_err)
- *ret_err = NULL;
-
- doc = xmlNewDoc((xmlChar *) "1.0");
- if (doc == NULL)
- return -1;
- n = xmlDocCopyNode((xmlNodePtr) node, doc, 1);
- if (n == NULL) {
- xmlFreeDoc(doc);
- return -1;
- }
- xmlDocSetRootElement(doc, n);
-
- os_memset(&errors, 0, sizeof(errors));
-
- dtd = xmlParseDTD(NULL, (const xmlChar *) dtd_fname);
- if (dtd == NULL) {
- xmlFreeDoc(doc);
- return -1;
- }
-
- os_memset(&vctx, 0, sizeof(vctx));
- vctx.userData = &errors;
- vctx.error = add_str;
- vctx.warning = add_str;
- ret = xmlValidateDtd(&vctx, doc, dtd);
- xmlFreeDoc(doc);
- xmlFreeDtd(dtd);
-
- if (ret == 1) {
- os_free(errors.buf);
- return 0;
- } else {
- if (ret_err)
- *ret_err = errors.buf;
- else
- os_free(errors.buf);
- return -1;
- }
-}
-
-
void xml_node_free(struct xml_node_ctx *ctx, xml_node_t *node)
{
xmlFreeNode((xmlNodePtr) node);
}
-xml_node_t * xml_node_get_parent(struct xml_node_ctx *ctx, xml_node_t *node)
-{
- return (xml_node_t *) ((xmlNodePtr) node)->parent;
-}
-
-
xml_node_t * xml_node_from_buf(struct xml_node_ctx *ctx, const char *buf)
{
xmlDocPtr doc;
@@ -242,19 +93,6 @@
}
-void xml_node_detach(struct xml_node_ctx *ctx, xml_node_t *node)
-{
- xmlUnlinkNode((xmlNodePtr) node);
-}
-
-
-void xml_node_add_child(struct xml_node_ctx *ctx, xml_node_t *parent,
- xml_node_t *child)
-{
- xmlAddChild((xmlNodePtr) parent, (xmlNodePtr) child);
-}
-
-
xml_node_t * xml_node_create_root(struct xml_node_ctx *ctx, const char *ns_uri,
const char *ns_prefix,
xml_namespace_t **ret_ns, const char *name)
@@ -322,47 +160,6 @@
}
-int xml_node_add_attr(struct xml_node_ctx *ctx, xml_node_t *node,
- xml_namespace_t *ns, const char *name, const char *value)
-{
- xmlAttrPtr attr;
-
- if (ns) {
- attr = xmlNewNsProp((xmlNodePtr) node, (xmlNsPtr) ns,
- (const xmlChar *) name,
- (const xmlChar *) value);
- } else {
- attr = xmlNewProp((xmlNodePtr) node, (const xmlChar *) name,
- (const xmlChar *) value);
- }
-
- return attr ? 0 : -1;
-}
-
-
-char * xml_node_get_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
- char *name)
-{
- return (char *) xmlGetNoNsProp((xmlNodePtr) node,
- (const xmlChar *) name);
-}
-
-
-char * xml_node_get_attr_value_ns(struct xml_node_ctx *ctx, xml_node_t *node,
- const char *ns_uri, char *name)
-{
- return (char *) xmlGetNsProp((xmlNodePtr) node, (const xmlChar *) name,
- (const xmlChar *) ns_uri);
-}
-
-
-void xml_node_get_attr_value_free(struct xml_node_ctx *ctx, char *val)
-{
- if (val)
- xmlFree((xmlChar *) val);
-}
-
-
xml_node_t * xml_node_first_child(struct xml_node_ctx *ctx,
xml_node_t *parent)
{
@@ -426,14 +223,6 @@
}
-xml_node_t * xml_node_copy(struct xml_node_ctx *ctx, xml_node_t *node)
-{
- if (node == NULL)
- return NULL;
- return (xml_node_t *) xmlCopyNode((xmlNodePtr) node, 1);
-}
-
-
struct xml_node_ctx * xml_node_init_ctx(void *upper_ctx,
const void *env)
{
diff --git a/src/wps/wps_upnp_ap.c b/src/wps/wps_upnp_ap.c
index b6c9478..573eb59 100644
--- a/src/wps/wps_upnp_ap.c
+++ b/src/wps/wps_upnp_ap.c
@@ -51,7 +51,7 @@
s->dev_password_id = attr.dev_password_id ?
WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT;
s->config_methods = attr.sel_reg_config_methods ?
- WPA_GET_BE16(attr.sel_reg_config_methods) : -1;
+ WPA_GET_BE16(attr.sel_reg_config_methods) : 0xffff;
if (attr.authorized_macs) {
int count = attr.authorized_macs_len / ETH_ALEN;
if (count > WPS_MAX_AUTHORIZED_MACS)